import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, waitFor, fireEvent, cleanup } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { MemoryRouter } from 'react-router-dom'; import type { ReactNode } from 'react'; // ----------------------------------------------------------------------------- // T-1 closure (cat-s2-c24a548076c6): CertificatesPage Vitest coverage. // // Pre-T-1 the page had no test file. F-1 just landed three new operator-facing // filters (team_id, expires_before, sort) plus reusable DataTable pagination — // real regression vectors that deserve test coverage. This file pins: // // 1. Rows render when getCertificates resolves. // 2. Setting the team filter wires team_id into the getCertificates params. // 3. Setting expires_before wires it through. // 4. Setting sort wires it through. // 5. Changing a filter resets page back to 1 (the F-1 contract). // 6. Changing per_page resets page to 1. // ----------------------------------------------------------------------------- vi.mock('../api/client', () => ({ getCertificates: vi.fn(), getIssuers: vi.fn(), getOwners: vi.fn(), getTeams: vi.fn(), getProfiles: vi.fn(), getRenewalPolicies: vi.fn(), createCertificate: vi.fn(), revokeCertificate: vi.fn(), bulkRevokeCertificates: vi.fn(), bulkRenewCertificates: vi.fn(), bulkReassignCertificates: vi.fn(), })); import CertificatesPage from './CertificatesPage'; import * as client from '../api/client'; function renderWithQuery(ui: ReactNode) { const qc = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0, staleTime: 0 } }, }); return render( {ui} , ); } const cert = { id: 'mc-prod-001', name: 'prod-001', common_name: 'app.example.com', status: 'Active', environment: 'production', issuer_id: 'iss-letsencrypt', owner_id: 'o-platform', team_id: 't-platform', expires_at: new Date(Date.now() + 30 * 86400000).toISOString(), created_at: new Date().toISOString(), }; const emptyResp = { data: [], total: 0, page: 1, per_page: 50 }; function mockAll() { vi.mocked(client.getCertificates).mockResolvedValue({ data: [cert], total: 1, page: 1, per_page: 50 } as never); vi.mocked(client.getIssuers).mockResolvedValue({ data: [{ id: 'iss-letsencrypt', name: 'Let’s Encrypt' }], total: 1, page: 1, per_page: 100 } as never); vi.mocked(client.getOwners).mockResolvedValue({ data: [{ id: 'o-platform', name: 'Platform', email: 'platform@example.com' }], total: 1, page: 1, per_page: 100 } as never); vi.mocked(client.getTeams).mockResolvedValue({ data: [{ id: 't-platform', name: 'Platform' }], total: 1, page: 1, per_page: 100 } as never); vi.mocked(client.getProfiles).mockResolvedValue({ data: [{ id: 'cp-tls-server', name: 'TLS Server' }], total: 1, page: 1, per_page: 100 } as never); vi.mocked(client.getRenewalPolicies).mockResolvedValue(emptyResp as never); } describe('CertificatesPage — T-1 page coverage', () => { beforeEach(() => { vi.clearAllMocks(); cleanup(); mockAll(); }); it('renders the certificate list when getCertificates resolves', async () => { renderWithQuery(); await waitFor(() => { expect(screen.getByText('app.example.com')).toBeInTheDocument(); }); expect(screen.getByText('mc-prod-001')).toBeInTheDocument(); }); it('changing the team filter wires team_id into the getCertificates params', async () => { renderWithQuery(); await waitFor(() => expect(client.getCertificates).toHaveBeenCalled()); // The team filter is the 6th