feat(09-05): implement ConvertTab + convertCertAction + render tests
- Add FileResponse interface to actions.ts - Add convertCertAction(input, targetFormat): builds FormData with file/pemText/password + targetFormat, calls postForm convert endpoint - Implement ConvertTab: native select for pem/der/p7b targetFormat, Konvertieren button with loading swap, error classification, empty state - On success: calls downloadBase64(filename, content, mimeType) - 3 new ConvertTab tests: format selector options, downloadBase64 invoked on success, text-destructive error on format rejection - All 14 web cert-manager tests green
This commit is contained in:
@@ -44,6 +44,7 @@ vi.mock('next-intl', () => ({
|
||||
import CertManagerPage from './page';
|
||||
import { InspectTab } from './components/InspectTab';
|
||||
import { SplitTab } from './components/SplitTab';
|
||||
import { ConvertTab } from './components/ConvertTab';
|
||||
import * as actions from './actions';
|
||||
|
||||
afterEach(() => {
|
||||
@@ -265,3 +266,74 @@ describe('SplitTab', () => {
|
||||
expect(errorEl.className).toContain('text-destructive');
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ConvertTab — unit tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const MOCK_FILE_RESPONSE: actions.FileResponse = {
|
||||
filename: 'converted.der',
|
||||
content: btoa('fake der bytes'),
|
||||
mimeType: 'application/x-x509-ca-cert',
|
||||
};
|
||||
|
||||
describe('ConvertTab', () => {
|
||||
it('renders format selector with pem, der, p7b options', () => {
|
||||
render(<ConvertTab file={null} pemText="" password="" />);
|
||||
const select = screen.getByRole('combobox');
|
||||
const optionValues = Array.from(select.querySelectorAll('option')).map(
|
||||
(o) => (o as HTMLOptionElement).value,
|
||||
);
|
||||
expect(optionValues).toContain('pem');
|
||||
expect(optionValues).toContain('der');
|
||||
expect(optionValues).toContain('p7b');
|
||||
});
|
||||
|
||||
it('calls downloadBase64 after clicking Konvertieren when convertCertAction resolves', async () => {
|
||||
vi.spyOn(actions, 'convertCertAction').mockResolvedValue(MOCK_FILE_RESPONSE);
|
||||
const downloadSpy = vi.spyOn(actions, 'downloadBase64').mockImplementation(() => {});
|
||||
|
||||
const testFile = new File(['cert data'], 'cert.pem', {
|
||||
type: 'application/x-pem-file',
|
||||
});
|
||||
|
||||
render(<ConvertTab file={testFile} pemText="" password="" />);
|
||||
|
||||
// Click the Konvertieren button
|
||||
fireEvent.click(screen.getByText('Konvertieren'));
|
||||
|
||||
// Wait for async action to resolve and downloadBase64 to be called
|
||||
await waitFor(() => {
|
||||
expect(downloadSpy).toHaveBeenCalledWith(
|
||||
MOCK_FILE_RESPONSE.filename,
|
||||
MOCK_FILE_RESPONSE.content,
|
||||
MOCK_FILE_RESPONSE.mimeType,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('shows text-destructive error when convertCertAction rejects with format error', async () => {
|
||||
vi.spyOn(actions, 'convertCertAction').mockRejectedValue(
|
||||
new Error('unknown format or invalid certificate'),
|
||||
);
|
||||
|
||||
const testFile = new File(['garbage'], 'bad.bin', { type: 'application/octet-stream' });
|
||||
|
||||
render(<ConvertTab file={testFile} pemText="" password="" />);
|
||||
|
||||
fireEvent.click(screen.getByText('Konvertieren'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Unbekanntes Format. Die Datei konnte nicht als Zertifikat erkannt werden.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const errorEl = screen.getByText(
|
||||
'Unbekanntes Format. Die Datei konnte nicht als Zertifikat erkannt werden.',
|
||||
);
|
||||
expect(errorEl.className).toContain('text-destructive');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user