test: add certificate feature unit tests and null-safety fix
Add comprehensive unit tests for the certificate upload, export, and detail management feature: - CertificateExportDialog: 21 tests covering format selection, blob download, error handling, and password-protected exports - CertificateUploadDialog: 23 tests covering file validation, format detection, drag-and-drop, and upload flow - CertificateDetailDialog: 19 tests covering detail display, loading state, missing fields, and branch coverage - CertificateChainViewer: 8 tests covering chain visualization - CertificateValidationPreview: 16 tests covering validation display - FileDropZone: 18 tests covering drag-and-drop interactions - useCertificates hooks: 10 tests covering all React Query hooks - certificates API: 7 new tests for previously uncovered endpoints Fix null-safety issue in ProxyHosts where cert.domains could be undefined, causing a runtime error on split(). Frontend patch coverage: 90.6%, overall lines: 89.09%
This commit is contained in:
@@ -1,12 +1,23 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import { getCertificates, uploadCertificate, deleteCertificate, type Certificate } from '../certificates';
|
||||
import {
|
||||
getCertificates,
|
||||
getCertificateDetail,
|
||||
uploadCertificate,
|
||||
updateCertificate,
|
||||
deleteCertificate,
|
||||
exportCertificate,
|
||||
validateCertificate,
|
||||
type Certificate,
|
||||
type CertificateDetail,
|
||||
} from '../certificates';
|
||||
import client from '../client';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
put: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
},
|
||||
}));
|
||||
@@ -52,4 +63,73 @@ describe('certificates API', () => {
|
||||
await deleteCertificate('abc-123');
|
||||
expect(client.delete).toHaveBeenCalledWith('/certificates/abc-123');
|
||||
});
|
||||
|
||||
it('getCertificateDetail calls client.get with uuid', async () => {
|
||||
const detail: CertificateDetail = {
|
||||
...mockCert,
|
||||
assigned_hosts: [],
|
||||
chain: [],
|
||||
auto_renew: false,
|
||||
created_at: '2023-01-01',
|
||||
updated_at: '2023-01-01',
|
||||
};
|
||||
vi.mocked(client.get).mockResolvedValue({ data: detail });
|
||||
const result = await getCertificateDetail('abc-123');
|
||||
expect(client.get).toHaveBeenCalledWith('/certificates/abc-123');
|
||||
expect(result).toEqual(detail);
|
||||
});
|
||||
|
||||
it('updateCertificate calls client.put with name', async () => {
|
||||
vi.mocked(client.put).mockResolvedValue({ data: mockCert });
|
||||
const result = await updateCertificate('abc-123', 'New Name');
|
||||
expect(client.put).toHaveBeenCalledWith('/certificates/abc-123', { name: 'New Name' });
|
||||
expect(result).toEqual(mockCert);
|
||||
});
|
||||
|
||||
it('exportCertificate calls client.post with blob response type', async () => {
|
||||
const blob = new Blob(['data']);
|
||||
vi.mocked(client.post).mockResolvedValue({ data: blob });
|
||||
const result = await exportCertificate('abc-123', 'pem', true, 'pass', 'pfx-pass');
|
||||
expect(client.post).toHaveBeenCalledWith(
|
||||
'/certificates/abc-123/export',
|
||||
{ format: 'pem', include_key: true, password: 'pass', pfx_password: 'pfx-pass' },
|
||||
{ responseType: 'blob' },
|
||||
);
|
||||
expect(result).toEqual(blob);
|
||||
});
|
||||
|
||||
it('validateCertificate calls client.post with FormData', async () => {
|
||||
const validation = { valid: true, common_name: 'example.com', domains: ['example.com'], issuer_org: 'LE', expires_at: '2024-01-01', key_match: true, chain_valid: true, chain_depth: 1, warnings: [], errors: [] };
|
||||
vi.mocked(client.post).mockResolvedValue({ data: validation });
|
||||
const certFile = new File(['cert'], 'cert.pem', { type: 'text/plain' });
|
||||
const keyFile = new File(['key'], 'key.pem', { type: 'text/plain' });
|
||||
|
||||
const result = await validateCertificate(certFile, keyFile);
|
||||
expect(client.post).toHaveBeenCalledWith('/certificates/validate', expect.any(FormData), {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
expect(result).toEqual(validation);
|
||||
});
|
||||
|
||||
it('uploadCertificate includes chain file when provided', async () => {
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockCert });
|
||||
const certFile = new File(['cert'], 'cert.pem');
|
||||
const keyFile = new File(['key'], 'key.pem');
|
||||
const chainFile = new File(['chain'], 'chain.pem');
|
||||
|
||||
await uploadCertificate('My Cert', certFile, keyFile, chainFile);
|
||||
const formData = vi.mocked(client.post).mock.calls[0][1] as FormData;
|
||||
expect(formData.get('chain_file')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('validateCertificate includes chain file when provided', async () => {
|
||||
vi.mocked(client.post).mockResolvedValue({ data: {} });
|
||||
const certFile = new File(['cert'], 'cert.pem');
|
||||
const chainFile = new File(['chain'], 'chain.pem');
|
||||
|
||||
await validateCertificate(certFile, undefined, chainFile);
|
||||
const formData = vi.mocked(client.post).mock.calls[0][1] as FormData;
|
||||
expect(formData.get('chain_file')).toBeTruthy();
|
||||
expect(formData.get('key_file')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user