feat(09-03): InspectTab UI + inspectCertAction + render tests

- Added inspectCertAction to actions.ts (JSON path for pemText, multipart path for file)
- Added CertDetails interface to actions.ts (mirrors API response shape)
- Implemented InspectTab: Analysieren button, loading state, grid-cols-2 result grid
- InspectTab handles wrong-password error (t('error.wrongPassword')) and generic error
- Added 2 new InspectTab tests: success grid (subject CN + SHA-256) and error (text-destructive)
- Fixed setup.ts: explicit expect.extend(matchers) for vitest@4.x compatibility
  (Rule 1: @testing-library/jest-dom/vitest not extending global expect in vitest 4)
- Fixed existing test: getByText -> getAllByText for 'Analysieren' (now appears in tab nav + button)
- 9/9 cert-manager tests pass
This commit is contained in:
2026-07-01 23:55:41 +02:00
parent ba994635e8
commit 64a8e725e7
4 changed files with 285 additions and 7 deletions
@@ -1,6 +1,64 @@
export const API_URL =
process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
// ---------------------------------------------------------------------------
// CertDetails — mirrors the API response shape from CertManagerService
// ---------------------------------------------------------------------------
export interface CertDetails {
subject: { cn: string; o: string; ou: string; c: string };
issuer: { cn: string; o: string; c: string };
validity: { notBefore: string; notAfter: string; isExpired: boolean; daysLeft: number };
san: string[];
keyType: string;
keyBits: number;
serialNumber: string;
signatureAlgorithm: string;
fingerprint: { sha1: string; sha256: string };
pemPreview: string;
}
// ---------------------------------------------------------------------------
// inspectCertAction — calls POST /modules/cert-manager/parse
// ---------------------------------------------------------------------------
/**
* Call POST /modules/cert-manager/parse.
* - If pemText is present → JSON body { pemText, password }
* - Otherwise → multipart FormData with file + optional password
*
* T-09-02: password is never placed in URL, logged, or echoed.
* T-09-04: credentials:'include' ensures JWT cookie is sent.
*/
export async function inspectCertAction(input: {
file?: File | null;
pemText?: string;
password?: string;
}): Promise<CertDetails> {
const { file, pemText, password } = input;
if (pemText) {
// JSON path — content-type must be application/json (not multipart)
const response = await fetch(`${API_URL}/modules/cert-manager/parse`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pemText, password }),
credentials: 'include',
});
if (!response.ok) {
const body = await response.text().catch(() => '');
throw new Error(`${response.status} ${body}`.trim());
}
return response.json() as Promise<CertDetails>;
} else {
// Multipart path — let browser set Content-Type with boundary
const form = new FormData();
if (file) form.append('file', file);
if (password) form.append('password', password);
return postForm('parse', form) as Promise<CertDetails>;
}
}
/**
* Download a base64-encoded file as a browser download.
* T-09-02: password is never placed in URL, console.log, or filename.