// @vitest-environment happy-dom // Tell React this is an `act`-aware test environment so react-query's // internal state updates flush through without noisy console warnings. (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; import React, { act, useEffect } from "react"; import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; import { MemoryRouter, useLocation } from "react-router-dom"; import { createRoot, type Root } from "react-dom/client"; import { ClaimCard837 } from "@/components/ClaimCard837"; import { ClaimCard835 } from "./Upload"; import { useAppStore } from "@/store"; import type { ClaimOutput, ClaimPayment, ParsedBatch } from "@/types"; // Fixtures — kept tiny, just enough to exercise the drill logic. const CLAIM_837: ClaimOutput = { claim_id: "CLM-PERSISTED", subscriber: { first_name: "Jane", last_name: "Doe", member_id: "MEM-1", }, payer: { name: "Test Payer", id: "P1" }, billing_provider: { npi: "1234567890" }, claim: { total_charge: 100, place_of_service: "11", frequency_code: "1", prior_auth: null, }, service_lines: [ { line_number: 1, procedure: { qualifier: "HC", code: "99213", modifiers: [] }, charge: "100", units: "1", unit_type: "UN", service_date: "2026-06-01", }, ], diagnoses: [{ qualifier: "ABK", code: "J20.9" }], validation: { passed: true, errors: [], warnings: [] }, }; const CLAIM_835: ClaimPayment = { payer_claim_control_number: "PCN-PERSISTED", status_code: "1", status_label: "Processed as Primary", claim_filing_indicator: "CI", facility_type: "11", frequency_code: "1", total_charge: "100", total_paid: "80", patient_responsibility: "20", service_payments: [ { line_number: 1, procedure_qualifier: "HC", procedure_code: "99213", modifiers: [], service_date: "2026-06-01", units: "1", unit_type: "UN", charge: "100", payment: "80", adjustments: [], }, ], original_claim_id: null, }; // Mount the card inside a MemoryRouter so the useNavigate call has // a router context (without this, clicking the drill link would // throw "useNavigate may be used only in a Router"). function renderCard( element: React.ReactElement, initialEntries: string[] = ["/upload"], ): { container: HTMLDivElement; unmount: () => void; tracker: { pathname: string; search: string }; } { const container = document.createElement("div"); document.body.appendChild(container); const tracker = { pathname: "/upload", search: "" }; const Tracker = () => { const loc = useLocation(); useEffect(() => { tracker.pathname = loc.pathname; tracker.search = loc.search; }, [loc.pathname, loc.search]); return null; }; const root: Root = createRoot(container); act(() => { root.render( React.createElement( MemoryRouter, { initialEntries }, React.createElement(Tracker, null), element, ), ); }); return { container, unmount: () => { act(() => root.unmount()); container.remove(); }, tracker, }; } describe("ClaimCard837 / ClaimCard835 drill link (SP21 Phase 5 Task 5.7)", () => { beforeEach(() => { // Reset parsedBatches to empty by default — individual tests // populate it as needed. useAppStore.setState({ parsedBatches: [] }); }); afterEach(() => { useAppStore.setState({ parsedBatches: [] }); }); it("ClaimCard837: renders the drill link when the claim_id is in a persisted batch", async () => { // Pre-populate the store with a parsed batch that contains this // claim id, then expand the card and verify the link is present. const persisted: ParsedBatch = { id: "batch-1", kind: "837p", inputFilename: "test.837", parsedAt: "2026-06-21T12:00:00Z", claimCount: 1, passed: 1, failed: 0, claimIds: ["CLM-PERSISTED"], summary: { total_claims: 1, passed: 1, failed: 0 }, }; useAppStore.setState({ parsedBatches: [persisted] }); const { container, unmount } = renderCard( React.createElement(ClaimCard837, { claim: CLAIM_837 }), ); // Expand the card. const header = container.querySelector("button[aria-expanded]"); await act(async () => { (header as HTMLButtonElement).click(); await Promise.resolve(); }); // The drill link should now be visible. const link = container.querySelector('[data-testid="upload-claim-drill"]'); expect(link).not.toBeNull(); expect(link?.textContent).toContain("See claim in detail"); unmount(); }); it("ClaimCard837: does NOT render the drill link when the claim_id is not persisted", async () => { // Streaming-only claim — the parsedBatches slice is empty, so // the link must be absent (clicking would 404 ClaimDrawer). const { container, unmount } = renderCard( React.createElement(ClaimCard837, { claim: CLAIM_837 }), ); const header = container.querySelector("button[aria-expanded]"); await act(async () => { (header as HTMLButtonElement).click(); await Promise.resolve(); }); expect( container.querySelector('[data-testid="upload-claim-drill"]'), ).toBeNull(); unmount(); }); it("ClaimCard837: clicking the drill link navigates to /claims?claim=ID", async () => { const persisted: ParsedBatch = { id: "batch-1", kind: "837p", inputFilename: "test.837", parsedAt: "2026-06-21T12:00:00Z", claimCount: 1, passed: 1, failed: 0, claimIds: ["CLM-PERSISTED"], summary: { total_claims: 1, passed: 1, failed: 0 }, }; useAppStore.setState({ parsedBatches: [persisted] }); const { container, unmount, tracker } = renderCard( React.createElement(ClaimCard837, { claim: CLAIM_837 }), ); const header = container.querySelector("button[aria-expanded]"); await act(async () => { (header as HTMLButtonElement).click(); await Promise.resolve(); }); const link = container.querySelector( '[data-testid="upload-claim-drill"]', ) as HTMLButtonElement; await act(async () => { link.click(); await Promise.resolve(); }); expect(tracker.pathname).toBe("/claims"); expect(tracker.search).toBe("?claim=CLM-PERSISTED"); unmount(); }); it("ClaimCard835: renders the drill link when the PCN is persisted", async () => { const persisted: ParsedBatch = { id: "batch-1", kind: "835", inputFilename: "test.835", parsedAt: "2026-06-21T12:00:00Z", claimCount: 1, passed: 1, failed: 0, claimIds: ["PCN-PERSISTED"], summary: { total_claims: 1, passed: 1, failed: 0 }, }; useAppStore.setState({ parsedBatches: [persisted] }); const { container, unmount, tracker } = renderCard( React.createElement(ClaimCard835, { claim: CLAIM_835 }), ); const header = container.querySelector("button[aria-expanded]"); await act(async () => { (header as HTMLButtonElement).click(); await Promise.resolve(); }); const link = container.querySelector('[data-testid="upload-remit-drill"]'); expect(link).not.toBeNull(); await act(async () => { (link as HTMLButtonElement).click(); await Promise.resolve(); }); // 835 cards drill to /remittances?remit=PCN (not /claims), since // the RemitDrawer is the right surface for the payment side. expect(tracker.pathname).toBe("/remittances"); expect(tracker.search).toBe("?remit=PCN-PERSISTED"); unmount(); }); it("ClaimCard835: does NOT render the drill link when the PCN is not persisted", async () => { const { container, unmount } = renderCard( React.createElement(ClaimCard835, { claim: CLAIM_835 }), ); const header = container.querySelector("button[aria-expanded]"); await act(async () => { (header as HTMLButtonElement).click(); await Promise.resolve(); }); expect( container.querySelector('[data-testid="upload-remit-drill"]'), ).toBeNull(); unmount(); }); });