fix(ui): DashboardPage test uses vanilla vitest matchers (Fix #38 follow-up) (#1235)

PR #1234 (squashed at 937cc3a7) added DashboardPage.test.tsx using
@testing-library/jest-dom matchers (toBeInTheDocument, toHaveAttribute)
that aren't wired into src/test/setup.ts. Result: tsc -b fails on the
build-ui job with TS2339 errors and the catalyst-build pipeline can't
produce the new image.

Switch to vanilla matchers (not.toBeNull(), getAttribute(...)) that
match the convention already used by CrossSovereignView.test.tsx and
the rest of the suite. Also wrap each assertion in waitFor() because
TanStack Router's RouterProvider needs at least one tick before the
route component mounts — same pattern CrossSovereignView's tests use.

Stub globalThis.fetch so the underlying useFleet TanStack-Query call
resolves quickly and the page mounts past the loading state. Doesn't
matter for the breadcrumb assertions (the breadcrumb renders
independently of fetch state) but keeps the test deterministic.

No production code changes — pure test-file rewrite.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
e3mrah 2026-05-10 01:45:47 +04:00 committed by GitHub
parent 937cc3a737
commit 7eae9f14a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -10,15 +10,20 @@
* What this file proves:
* - The breadcrumb renders with the literal text "Dashboard".
* - The page H1 still reads "Sovereign Fleet" (no redesign rollback).
* - The breadcrumb has the correct `aria-label` and stable testid.
* - The breadcrumb is a <nav> with `aria-label="Breadcrumb"` for AT.
* - The current page in the trail is marked with `aria-current=page`.
*
* Routing: TanStack Router renders <Link to="/wizard"> via the provider.
* We mount the bare DashboardPage with stub routes for /wizard and
* /dashboard/applications so the Link components don't blow up.
*
* Assertion style: vanilla vitest matchers (no @testing-library/jest-dom)
* because the existing src/test/setup.ts doesn't import jest-dom and
* adding it here would diverge from the established convention.
*/
import { describe, it, expect, afterEach } from 'vitest'
import { render, screen, cleanup, within } from '@testing-library/react'
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { render, screen, cleanup, waitFor, within } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import {
RouterProvider,
@ -33,6 +38,23 @@ import { DashboardPage } from './DashboardPage'
afterEach(() => cleanup())
// Stub the fleet fetch so DashboardPage's useFleet query resolves
// quickly and the page mounts past the loading state. The breadcrumb
// renders independently of fetch state, but TanStack Router needs at
// least one tick before the route component is mounted.
let originalFetch: typeof globalThis.fetch
beforeEach(() => {
originalFetch = globalThis.fetch
globalThis.fetch = (async () =>
new Response(JSON.stringify({ sovereigns: [], total: 0, page: 1, pageSize: 25 }), {
status: 200,
headers: { 'content-type': 'application/json' },
})) as never
})
afterEach(() => {
globalThis.fetch = originalFetch
})
function makeRouter() {
const rootRoute = createRootRoute({ component: () => <Outlet /> })
const dashRoute = createRoute({
@ -72,31 +94,37 @@ function renderPage() {
}
describe('DashboardPage breadcrumb (qa-loop iter-7 TC-383)', () => {
it('renders the literal "Dashboard" label in the breadcrumb', () => {
it('renders the literal "Dashboard" label in the breadcrumb', async () => {
renderPage()
const crumb = screen.getByTestId('dashboard-breadcrumb')
expect(crumb).toBeInTheDocument()
const crumb = await waitFor(() => screen.getByTestId('dashboard-breadcrumb'))
// The literal "Dashboard" string MUST be present — the matrix's
// anti-regression test will fail otherwise.
expect(within(crumb).getByText('Dashboard')).toBeInTheDocument()
const dash = within(crumb).getByText('Dashboard')
expect(dash).not.toBeNull()
// Belt-and-braces: the page body as a whole MUST contain
// "Dashboard" verbatim, since that's exactly what the matrix's
// must_contain check looks for in the rendered DOM.
const root = screen.getByTestId('dashboard-page')
expect(root.textContent ?? '').toContain('Dashboard')
})
it('keeps the H1 as "Sovereign Fleet" so the redesign is preserved', () => {
it('keeps the H1 as "Sovereign Fleet" so the redesign is preserved', async () => {
renderPage()
expect(
screen.getByRole('heading', { level: 1, name: 'Sovereign Fleet' }),
).toBeInTheDocument()
await waitFor(() => screen.getByTestId('dashboard-page'))
const h1 = screen.getByRole('heading', { level: 1, name: 'Sovereign Fleet' })
expect(h1).not.toBeNull()
})
it('exposes the breadcrumb with aria-label="Breadcrumb" for AT users', () => {
it('exposes the breadcrumb with aria-label="Breadcrumb" for AT users', async () => {
renderPage()
const crumb = screen.getByLabelText('Breadcrumb')
const crumb = await waitFor(() => screen.getByLabelText('Breadcrumb'))
expect(crumb.tagName.toLowerCase()).toBe('nav')
})
it('marks the current page in the trail with aria-current', () => {
it('marks the current page in the trail with aria-current', async () => {
renderPage()
await waitFor(() => screen.getByTestId('dashboard-breadcrumb'))
const current = screen.getByText('Sovereign Fleet', { selector: 'li' })
expect(current).toHaveAttribute('aria-current', 'page')
expect(current.getAttribute('aria-current')).toBe('page')
})
})