// @vitest-environment happy-dom // React Query's internal state updates need an `act`-aware environment or // it logs noisy warnings. Match the convention from useClaimDetail.test.ts. (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; import React, { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import { describe, expect, it } from "vitest"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ClaimDrawerSkeleton } from "./ClaimDrawerSkeleton"; function renderIntoContainer(element: React.ReactElement): { container: HTMLDivElement; unmount: () => void; } { const container = document.createElement("div"); document.body.appendChild(container); const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } }); const root: Root = createRoot(container); act(() => { root.render( React.createElement(QueryClientProvider, { client: qc }, element) ); }); return { container, unmount: () => { act(() => root.unmount()); container.remove(); }, }; } describe("ClaimDrawerSkeleton", () => { it("renders_eight_to_twelve_skeleton_primitives", () => { // The Skeleton primitive marks itself aria-busy="true" for AT. // Counting aria-busy elements tells us how many primitives rendered, // independent of layout or copy. const { unmount } = renderIntoContainer(); const busyCount = document.querySelectorAll('[aria-busy="true"]').length; expect(busyCount).toBeGreaterThanOrEqual(8); expect(busyCount).toBeLessThanOrEqual(12); unmount(); }); it("renders_one_primitives_per_drawer_section", () => { // The skeleton must mirror the drawer's section structure so the // layout doesn't jump when real data arrives. Each section gets a // labelled testid primitive. const { container, unmount } = renderIntoContainer(); const header = container.querySelector('[data-testid="skeleton-header"]'); const validation = container.querySelector( '[data-testid="skeleton-validation"]' ); const lines1 = container.querySelector('[data-testid="skeleton-lines-1"]'); const lines2 = container.querySelector('[data-testid="skeleton-lines-2"]'); const lines3 = container.querySelector('[data-testid="skeleton-lines-3"]'); const dx1 = container.querySelector('[data-testid="skeleton-dx-1"]'); const dx2 = container.querySelector('[data-testid="skeleton-dx-2"]'); const parties1 = container.querySelector( '[data-testid="skeleton-parties-1"]' ); const parties2 = container.querySelector( '[data-testid="skeleton-parties-2"]' ); const history = container.querySelector('[data-testid="skeleton-history"]'); // Every section primitive is present. expect(header).not.toBeNull(); expect(validation).not.toBeNull(); expect(lines1).not.toBeNull(); expect(lines2).not.toBeNull(); expect(lines3).not.toBeNull(); expect(dx1).not.toBeNull(); expect(dx2).not.toBeNull(); expect(parties1).not.toBeNull(); expect(parties2).not.toBeNull(); expect(history).not.toBeNull(); // Header band should be visibly taller than the validation row — it // hosts the claim id, status, billed amount etc. // happy-dom doesn't do layout, so we read the inline styles the // Skeleton primitive writes from `height`/`width` props. const headerHeight = Number( (header as HTMLElement).style.height.replace("px", "") ); const validationHeight = Number( (validation as HTMLElement).style.height.replace("px", "") || "36" ); expect(headerHeight).toBeGreaterThan(validationHeight); // Header should be wider than the dx rows (60% / 45%). const headerWidth = (header as HTMLElement).style.width || "100%"; const dx1Width = (dx1 as HTMLElement).style.width; // "100%" vs "60%" — compare as percentage strings. const headerPct = Number(headerWidth.replace("%", "")); const dx1Pct = Number(dx1Width.replace("%", "")); expect(headerPct).toBeGreaterThan(dx1Pct); // History block is taller than the validation row. const historyHeight = Number( (history as HTMLElement).style.height.replace("px", "") ); expect(historyHeight).toBeGreaterThan(validationHeight); unmount(); }); it("no_props_required", () => { // The contract: "No props." Calling the component with no props // must not throw and must render something. expect(() => { const { unmount } = renderIntoContainer(); unmount(); }).not.toThrow(); }); });