From 27f60e14eceb0e7147a14683a9c151ff1caebf33 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 27 Aug 2026 00:46:34 +0200 Subject: [PATCH] fix(test): wire SendQuoteModal stub to props.onSend The SendQuoteModal test stub had a noop triggerSend placeholder that never called props.onSend, so the click on the modal's "Submit modal" button would silently fail. Tests 3-7 (which assert on fetch / refresh / toast effects from sendApprove) would all hang even after Task 2 implements the page correctly. Fix: call props.onSend directly from the button's onClick. Drop the unused triggerSend hoisted spy. Tighten the stub's props type to SendQuoteModalProps so Task 2's prop-name typos surface as TS errors. Also widen the PB mock fallback's getList to return the full envelope (items + totalItems + totalPages) so Task 2 reading quote_attachments or any other collection doesn't crash on undefined totalItems. Co-Authored-By: Claude --- src/app/(app)/quotes/approvals/page.test.tsx | 31 ++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/app/(app)/quotes/approvals/page.test.tsx b/src/app/(app)/quotes/approvals/page.test.tsx index 849767a..0ba4eb2 100644 --- a/src/app/(app)/quotes/approvals/page.test.tsx +++ b/src/app/(app)/quotes/approvals/page.test.tsx @@ -1,4 +1,5 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; +import * as React from "react"; import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import ApprovalsPage from "./page"; @@ -9,13 +10,11 @@ const { refreshMock, pushMock, captureModalProps, - triggerSend, } = vi.hoisted(() => ({ getListMock: vi.fn(), refreshMock: vi.fn(), pushMock: vi.fn(), captureModalProps: vi.fn(), - triggerSend: vi.fn(), })); // Stub the PocketBase client so we can drive list contents from the test. @@ -29,7 +28,14 @@ vi.mock("@/lib/pocketbase", () => ({ if (name === "quote_items") { return { getFullList: async () => [] }; } - return { getFullList: async () => [], getList: async () => ({ items: [] }) }; + // Defensive fallback for any other collection the page or + // SendQuoteModal may read in Tasks 2-3 (e.g. quote_attachments, + // users). Match the PB envelope shape so code that consumes + // totalItems / totalPages doesn't crash on undefined. + return { + getFullList: async () => [], + getList: async () => ({ items: [], totalItems: 0, totalPages: 1 }), + }; }, }), })); @@ -40,15 +46,16 @@ vi.mock("next/navigation", () => ({ })); // Replace SendQuoteModal with a thin stub. The test grabs the props the -// page passed in via captureModalProps; triggerSend becomes the onSend -// prop, so tests can fire the modal submit callback directly. +// page passed in via captureModalProps; clicking the test's "Submit +// modal" button calls props.onSend directly, which is the page's +// sendApprove callback — so the fetch / refresh / toast assertions +// downstream observe real effects. +type SendQuoteModalProps = React.ComponentProps< + typeof import("@/components/quotes/send-quote-modal").SendQuoteModal +>; + vi.mock("@/components/quotes/send-quote-modal", () => ({ - SendQuoteModal: (props: { - open: boolean; - submitLabel?: string; - onSend: (p: unknown) => Promise; - quote: { id: string }; - }) => { + SendQuoteModal: (props: SendQuoteModalProps) => { captureModalProps(props); if (!props.open) return null; return ( @@ -58,7 +65,7 @@ vi.mock("@/components/quotes/send-quote-modal", () => ({