import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import { describe, expect, it, vi } from 'vitest'; import { makeAuditData, makeResult } from '../test-utils'; // Mock Headlamp lib vi.mock('@kinvolk/headlamp-plugin/lib', () => ({ ApiProxy: { request: vi.fn() }, Router: { createRouteURL: (name: string, params: Record) => `/polaris/ns/${params.namespace}`, }, })); // Mock MUI components vi.mock('@mui/material/Drawer', () => ({ default: ({ open, children, }: { open: boolean; children: React.ReactNode; onClose?: () => void; anchor?: string; }) => (open ?
{children}
: null), })); vi.mock('@mui/material/IconButton', () => ({ default: ({ children, onClick, 'aria-label': ariaLabel, }: { children: React.ReactNode; onClick: () => void; 'aria-label': string; title?: string; size?: string; }) => ( ), })); vi.mock('@mui/material/styles', () => ({ useTheme: () => ({ palette: { primary: { main: '#1976d2' }, text: { primary: '#000', secondary: '#666' }, action: { hover: 'rgba(0,0,0,0.04)' }, background: { default: '#fafafa' }, }, }), })); // Mock Headlamp CommonComponents vi.mock('@kinvolk/headlamp-plugin/lib/CommonComponents', () => ({ Loader: ({ title }: { title: string }) =>
{title}
, SectionBox: ({ title, children }: { title?: string; children?: React.ReactNode }) => (
{children}
), SectionHeader: ({ title }: { title: string }) =>
{title}
, StatusLabel: ({ status, children }: { status: string; children?: React.ReactNode }) => ( {children} ), NameValueTable: ({ rows }: { rows: Array<{ name: string; value: React.ReactNode }> }) => ( {rows.map(row => ( ))}
{row.name} {row.value}
), SimpleTable: ({ columns, data, emptyMessage, }: { columns: Array<{ label: string; getter: (row: unknown) => React.ReactNode }>; data: unknown[]; emptyMessage?: string; }) => data.length === 0 ? (
{emptyMessage}
) : ( {columns.map(col => ( ))} {data.map((row, i) => ( {columns.map(col => ( ))} ))}
{col.label}
{col.getter(row)}
), })); const mockUsePolarisDataContext = vi.fn(); vi.mock('../api/PolarisDataContext', () => ({ usePolarisDataContext: () => mockUsePolarisDataContext(), })); import NamespacesListView from './NamespacesListView'; function renderWithRouter(ui: React.ReactElement) { return render({ui}); } describe('NamespacesListView', () => { it('renders loader when loading', () => { mockUsePolarisDataContext.mockReturnValue({ data: null, loading: true, error: null, }); renderWithRouter(); expect(screen.getByTestId('loader')).toHaveTextContent('Loading Polaris audit data'); }); it('renders error message when error is set', () => { mockUsePolarisDataContext.mockReturnValue({ data: null, loading: false, error: 'Polaris dashboard not reachable', }); renderWithRouter(); expect(screen.getByText('Polaris dashboard not reachable')).toBeInTheDocument(); }); it('renders "No Data" when no data and no error', () => { mockUsePolarisDataContext.mockReturnValue({ data: null, loading: false, error: null, }); renderWithRouter(); expect(screen.getByText('No Polaris audit results found.')).toBeInTheDocument(); }); it('renders namespace rows with correct scores and buttons', () => { const data = makeAuditData([ makeResult({ Name: 'deploy-a', Namespace: 'alpha', Results: { c1: { ID: 'c1', Message: '', Details: [], Success: true, Severity: 'warning', Category: 'X', }, }, }), makeResult({ Name: 'deploy-b', Namespace: 'beta', Results: { c2: { ID: 'c2', Message: '', Details: [], Success: false, Severity: 'danger', Category: 'X', }, }, }), ]); mockUsePolarisDataContext.mockReturnValue({ data, loading: false, error: null, }); renderWithRouter(); // Namespace buttons (now buttons instead of links for drawer) const alphaButton = screen.getByText('alpha'); expect(alphaButton).toBeInTheDocument(); expect(alphaButton.tagName).toBe('BUTTON'); const betaButton = screen.getByText('beta'); expect(betaButton).toBeInTheDocument(); expect(betaButton.tagName).toBe('BUTTON'); }); it('uses correct scoreStatus: >=80 success, >=50 warning, <50 error', () => { // Create a namespace with 100% score (1 pass) and one with 0% (1 danger) const data = makeAuditData([ makeResult({ Name: 'perfect', Namespace: 'good-ns', Results: { c1: { ID: 'c1', Message: '', Details: [], Success: true, Severity: 'warning', Category: 'X', }, }, }), makeResult({ Name: 'bad', Namespace: 'bad-ns', Results: { c2: { ID: 'c2', Message: '', Details: [], Success: false, Severity: 'danger', Category: 'X', }, }, }), ]); mockUsePolarisDataContext.mockReturnValue({ data, loading: false, error: null, }); renderWithRouter(); // Find score StatusLabels - good-ns has 100% (success), bad-ns has 0% (error) const statusLabels = screen.getAllByTestId('status-label'); const scoreLabels = statusLabels.filter(el => el.textContent?.includes('%')); const successScore = scoreLabels.find(el => el.textContent === '100%'); expect(successScore).toHaveAttribute('data-status', 'success'); const errorScore = scoreLabels.find(el => el.textContent === '0%'); expect(errorScore).toHaveAttribute('data-status', 'error'); }); it('opens drawer when namespace button is clicked and URL hash is updated', async () => { const user = userEvent.setup(); const data = makeAuditData([ makeResult({ Name: 'deploy-a', Namespace: 'alpha', Results: { c1: { ID: 'c1', Message: '', Details: [], Success: true, Severity: 'warning', Category: 'X', }, }, }), ]); mockUsePolarisDataContext.mockReturnValue({ data, loading: false, error: null, }); renderWithRouter(); // Click the namespace button const alphaButton = screen.getByText('alpha'); await user.click(alphaButton); // Drawer should open (check for the panel title) expect(screen.getByText(/Polaris — alpha/)).toBeInTheDocument(); }); it('initializes drawer from URL hash', () => { const data = makeAuditData([ makeResult({ Name: 'deploy-a', Namespace: 'test-ns', Results: { c1: { ID: 'c1', Message: '', Details: [], Success: true, Severity: 'warning', Category: 'X', }, }, }), ]); mockUsePolarisDataContext.mockReturnValue({ data, loading: false, error: null, }); // Render with initial hash in URL render( ); // Drawer should be open with the namespace from hash expect(screen.getByText(/Polaris — test-ns/)).toBeInTheDocument(); }); });