From 2cb01f743d108b51c70f8edb803ddac6d0e17b4a Mon Sep 17 00:00:00 2001 From: Schalli Date: Wed, 1 Jul 2026 23:23:17 +0200 Subject: [PATCH] test(09-02): add shell render tests for CertManagerPage (GREEN) - 7 tests passing: title, all 4 tab labels, hidden password field, per-tab empty states - Tests use vi.mock('next-intl') pattern per project convention (matches sidebar, VehicleTable tests) - Validates T-09-02 threat mitigation: password field absent on initial render --- .../cert-manager/cert-manager.test.tsx | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx diff --git a/apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx b/apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx new file mode 100644 index 0000000..501a37f --- /dev/null +++ b/apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx @@ -0,0 +1,101 @@ +import { cleanup, render, screen, fireEvent } from '@testing-library/react'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +// Mock next-intl — provide certManager namespace keys +vi.mock('next-intl', () => ({ + useTranslations: (ns: string) => (key: string) => { + const certManager: Record = { + 'title': 'Zertifikat-Manager', + 'description': 'Zertifikate analysieren, aufteilen, zusammenfuehren und konvertieren.', + 'tabs.inspect': 'Analysieren', + 'tabs.split': 'Aufteilen', + 'tabs.merge': 'Zusammenfuehren', + 'tabs.convert': 'Konvertieren', + 'dropZone.placeholder': 'Datei hierher ziehen oder klicken', + 'dropZone.formats': '.pem, .crt, .cer, .der, .pfx, .p12, .p7b, .p7c', + 'paste.placeholder': 'PEM-Inhalt einfuegen (-----BEGIN ...)', + 'password.label': 'Passwort (PFX/P12)', + 'or': 'oder', + 'actions.inspect': 'Analysieren', + 'actions.split': 'Aufteilen', + 'actions.merge': 'Zusammenfuehren', + 'actions.convert': 'Konvertieren', + 'actions.download': 'Herunterladen', + 'actions.processing': 'Wird verarbeitet...', + 'emptyState.inspect': 'Kein Zertifikat geladen.', + 'emptyState.inspectBody': 'Lade eine Datei hoch oder fuege PEM-Text ein.', + 'emptyState.split': 'Keine Datei geladen.', + 'emptyState.splitBody': 'Lade eine Fullchain- oder P7B-Datei hoch.', + 'emptyState.merge': 'Keine Zertifikate ausgewaehlt.', + 'emptyState.mergeBody': 'Lade mindestens zwei Dateien hoch.', + 'emptyState.convert': 'Keine Datei geladen.', + 'emptyState.convertBody': 'Lade eine Datei hoch und waehle ein Ausgabeformat.', + 'error.generic': 'Verarbeitung fehlgeschlagen. Pruefe das Dateiformat oder das Passwort.', + 'error.wrongPassword': 'Falsches Passwort. PFX/P12-Datei konnte nicht entschluesselt werden.', + 'error.unknownFormat': 'Unbekanntes Format. Die Datei konnte nicht als Zertifikat erkannt werden.', + }; + if (ns === 'certManager') { + return certManager[key] ?? key; + } + return key; + }, +})); + +import CertManagerPage from './page'; + +afterEach(() => { + cleanup(); +}); + +describe('CertManagerPage shell', () => { + it('renders the page title and description', () => { + render(); + expect(screen.getByText('Zertifikat-Manager')).toBeInTheDocument(); + expect(screen.getByText('Zertifikate analysieren, aufteilen, zusammenfuehren und konvertieren.')).toBeInTheDocument(); + }); + + it('renders all four tab labels', () => { + render(); + expect(screen.getByText('Analysieren')).toBeInTheDocument(); + expect(screen.getByText('Aufteilen')).toBeInTheDocument(); + expect(screen.getByText('Zusammenfuehren')).toBeInTheDocument(); + expect(screen.getByText('Konvertieren')).toBeInTheDocument(); + }); + + it('does NOT render the password field on initial render (no PFX file selected)', () => { + render(); + // Password field label should not be in document when no PFX is selected + expect(screen.queryByText('Passwort (PFX/P12)')).not.toBeInTheDocument(); + }); + + it('shows Inspect tab empty state on initial render', () => { + render(); + expect(screen.getByText('Kein Zertifikat geladen.')).toBeInTheDocument(); + expect(screen.getByText('Lade eine Datei hoch oder fuege PEM-Text ein.')).toBeInTheDocument(); + }); + + it('shows Split tab empty state when Split tab is active', () => { + render(); + // Click the "Aufteilen" tab button (second one in nav) + const tabButtons = screen.getAllByText('Aufteilen'); + // The tab nav button is the one that triggers tab change + fireEvent.click(tabButtons[0]); + expect(screen.getByText('Keine Datei geladen.')).toBeInTheDocument(); + expect(screen.getByText('Lade eine Fullchain- oder P7B-Datei hoch.')).toBeInTheDocument(); + }); + + it('shows Merge tab empty state when Merge tab is active', () => { + render(); + fireEvent.click(screen.getByText('Zusammenfuehren')); + expect(screen.getByText('Keine Zertifikate ausgewaehlt.')).toBeInTheDocument(); + expect(screen.getByText('Lade mindestens zwei Dateien hoch.')).toBeInTheDocument(); + }); + + it('shows Convert tab empty state when Convert tab is active', () => { + render(); + // "Konvertieren" appears once as tab label + fireEvent.click(screen.getByText('Konvertieren')); + expect(screen.getAllByText('Keine Datei geladen.').length).toBeGreaterThanOrEqual(1); + expect(screen.getByText('Lade eine Datei hoch und waehle ein Ausgabeformat.')).toBeInTheDocument(); + }); +});