Files
Charon/frontend/src/components/__tests__/CertificateValidationPreview.test.tsx
GitHub Actions e1bc648dfc 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%
2026-04-13 04:02:31 +00:00

136 lines
4.5 KiB
TypeScript

import { render, screen } from '@testing-library/react'
import { describe, it, expect, vi } from 'vitest'
import type { ValidationResult } from '../../api/certificates'
import CertificateValidationPreview from '../CertificateValidationPreview'
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
i18n: { language: 'en', changeLanguage: vi.fn() },
}),
}))
function makeResult(overrides: Partial<ValidationResult> = {}): ValidationResult {
return {
valid: true,
common_name: 'example.com',
domains: ['example.com', 'www.example.com'],
issuer_org: 'Test CA',
expires_at: '2026-06-01T00:00:00Z',
key_match: true,
chain_valid: true,
chain_depth: 2,
warnings: [],
errors: [],
...overrides,
}
}
describe('CertificateValidationPreview', () => {
it('renders valid certificate state', () => {
render(<CertificateValidationPreview result={makeResult()} />)
expect(screen.getByText('certificates.validCertificate')).toBeTruthy()
expect(screen.getByTestId('certificate-validation-preview')).toBeTruthy()
})
it('renders invalid certificate state', () => {
render(
<CertificateValidationPreview result={makeResult({ valid: false })} />,
)
expect(screen.getByText('certificates.invalidCertificate')).toBeTruthy()
})
it('displays common name', () => {
render(<CertificateValidationPreview result={makeResult()} />)
expect(screen.getByText('example.com')).toBeTruthy()
})
it('displays domains joined by comma', () => {
render(<CertificateValidationPreview result={makeResult()} />)
expect(screen.getByText('example.com, www.example.com')).toBeTruthy()
})
it('displays dash when no domains provided', () => {
render(
<CertificateValidationPreview result={makeResult({ domains: [] })} />,
)
const dashes = screen.getAllByText('-')
expect(dashes.length).toBeGreaterThan(0)
})
it('displays issuer organization', () => {
render(<CertificateValidationPreview result={makeResult()} />)
expect(screen.getByText('Test CA')).toBeTruthy()
})
it('displays formatted expiration date', () => {
render(<CertificateValidationPreview result={makeResult()} />)
const dateStr = new Date('2026-06-01T00:00:00Z').toLocaleDateString()
expect(screen.getByText(dateStr)).toBeTruthy()
})
it('shows Yes for key match', () => {
render(<CertificateValidationPreview result={makeResult({ key_match: true, chain_valid: false })} />)
expect(screen.getByText('Yes')).toBeTruthy()
})
it('shows No key provided when no key match', () => {
render(
<CertificateValidationPreview result={makeResult({ key_match: false })} />,
)
expect(screen.getByText('No key provided')).toBeTruthy()
})
it('shows chain depth when > 0', () => {
render(
<CertificateValidationPreview result={makeResult({ chain_depth: 3 })} />,
)
expect(screen.getByText('3')).toBeTruthy()
})
it('does not show chain depth when 0', () => {
render(
<CertificateValidationPreview result={makeResult({ chain_depth: 0 })} />,
)
expect(screen.queryByText('certificates.chainDepth')).toBeFalsy()
})
it('renders warnings when present', () => {
render(
<CertificateValidationPreview
result={makeResult({ warnings: ['Expiring soon', 'Weak key'] })}
/>,
)
expect(screen.getByText('certificates.warnings')).toBeTruthy()
expect(screen.getByText('Expiring soon')).toBeTruthy()
expect(screen.getByText('Weak key')).toBeTruthy()
})
it('does not render warnings section when empty', () => {
render(<CertificateValidationPreview result={makeResult({ warnings: [] })} />)
expect(screen.queryByText('certificates.warnings')).toBeFalsy()
})
it('renders errors when present', () => {
render(
<CertificateValidationPreview
result={makeResult({ errors: ['Certificate revoked'] })}
/>,
)
expect(screen.getByText('certificates.errors')).toBeTruthy()
expect(screen.getByText('Certificate revoked')).toBeTruthy()
})
it('does not render errors section when empty', () => {
render(<CertificateValidationPreview result={makeResult({ errors: [] })} />)
expect(screen.queryByText('certificates.errors')).toBeFalsy()
})
it('has correct region role and aria-label', () => {
render(<CertificateValidationPreview result={makeResult()} />)
const region = screen.getByRole('region')
expect(region.getAttribute('aria-label')).toBe('certificates.validationPreview')
})
})