From 3e8c79f0573020ae8cd12a402ad845feefe6b8f9 Mon Sep 17 00:00:00 2001 From: le king fu Date: Sun, 18 Oct 2026 19:46:47 -0400 Subject: [PATCH 1/3] test: pin the \r path stop and the surviving marked-t keys (#437) - db.test.ts: `\r` joins the path stops of withoutFolders (removing it from PATH_STOP now fails). - The six keys whose "t removed" mutation survived the review of PR #435 (comment 23499) are asserted in their marked form: transactions.transferIcon.ariaLabel (a row linked to a transfer) and transactions.notes.placeholder (title of every row's notes button) in TransactionTable.render.test.tsx; license.keyPlaceholder and license.activate in LicenseKeyForm.render.test.tsx; dashboard.kpiSectionTitle in DashboardPage.render.test.tsx; balance.priceFetching.consent.accept in PriceFetchControl.test.tsx, the consent dialog opened by presetting the control's first harness slot (the dialog's title, body and decline texts are pinned with it). - TransactionTable.wiring.test.ts opens a row's notes through its button and pins the textarea placeholder, the second call of the notes key. Co-Authored-By: Claude Opus 5.5 --- .../balance/PriceFetchControl.test.tsx | 53 +++++++++++++++---- .../settings/LicenseKeyForm.render.test.tsx | 9 +++- .../TransactionTable.render.test.tsx | 28 +++++++++- .../TransactionTable.wiring.test.ts | 21 +++++++- src/pages/DashboardPage.render.test.tsx | 6 +++ src/services/db.test.ts | 2 +- 6 files changed, 105 insertions(+), 14 deletions(-) diff --git a/src/components/balance/PriceFetchControl.test.tsx b/src/components/balance/PriceFetchControl.test.tsx index d70ca60..f4deb51 100644 --- a/src/components/balance/PriceFetchControl.test.tsx +++ b/src/components/balance/PriceFetchControl.test.tsx @@ -11,6 +11,10 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; // Mocks — declared before imports to satisfy vi.mock hoisting // --------------------------------------------------------------------------- +// React's hooks from the shared harness (#409): the consent dialog opens on a +// click (internal state), so the render test below presets its slot (#437). +vi.mock("react", async (orig) => (await import("../../test/hookHarness")).fakeReact(await orig())); + vi.mock("../../hooks/useIsPremium", () => ({ useIsPremium: vi.fn(), })); @@ -40,6 +44,7 @@ vi.mock("lucide-react", () => ({ // Imports (after mock declarations) // --------------------------------------------------------------------------- +import type { ReactNode } from "react"; import { useIsPremium } from "../../hooks/useIsPremium"; import { prices } from "../../services/balance.service"; import type { PriceResult } from "../../services/balance.service"; @@ -48,6 +53,7 @@ import { setPreference, } from "../../services/userPreferenceService"; import { renderToStaticMarkup } from "react-dom/server"; +import { hookHarness } from "../../test/hookHarness"; import PriceFetchControl, { __resetBestEffortDismissForTests, } from "./PriceFetchControl"; @@ -56,6 +62,7 @@ import PriceFetchControl, { // Helpers // --------------------------------------------------------------------------- +const harness = hookHarness(); const mockUseIsPremium = vi.mocked(useIsPremium); const mockFetchPrice = vi.mocked(prices.fetchPrice); const mockGetPreference = vi.mocked(getPreference); @@ -363,18 +370,35 @@ describe("PriceFetchControl — displayed texts", () => { __resetBestEffortDismissForTests(); vi.resetAllMocks(); setPremium(true); + harness.clear(); }); - it("names the fetch button and the stock best-effort notice through t", () => { - const html = renderToStaticMarkup( - , + /** + * One render of a stock's control, its hooks from the harness. `consentOpen` + * presets slot 0, the control's first hook (`showConsentModal`). The slots + * follow the order of the control's hook calls: a hook of any kind added + * before it shifts them without a word, and the preset lands on another hook + * (one slot per hook call: the `slot` helper of `fakeReact`, + * src/test/hookHarness.ts). + */ + function markup(consentOpen = false): string { + if (consentOpen) harness.slots[0] = true; + return renderToStaticMarkup( + harness.render( + () => + PriceFetchControl({ + symbol: "AAPL", + date: "2026-04-25", + categoryKind: "priced", + assetType: "stock", + onPriceFetched: vi.fn(), + }) as ReactNode, + ), ); + } + + it("names the fetch button and the stock best-effort notice through t", () => { + const html = markup(); expect(html).toContain('aria-label="t(balance.priceFetching.button)"'); expect(html).toContain(">t(balance.priceFetching.button)<"); expect(html).toContain(">t(balance.priceFetching.bestEffortNotice)<"); @@ -382,4 +406,15 @@ describe("PriceFetchControl — displayed texts", () => { expect(html).not.toContain(">best-effort<"); expect(html).toContain('aria-label="t(common.close)"'); }); + + it("names the consent dialog through t once it is open (#437)", () => { + expect(markup()).not.toContain('role="dialog"'); + harness.clear(); + const html = markup(true); + expect(html).toContain('role="dialog"'); + expect(html).toContain(">t(balance.priceFetching.consent.title)<"); + expect(html).toContain(">t(balance.priceFetching.consent.body)<"); + expect(html).toContain(">t(balance.priceFetching.consent.decline)<"); + expect(html).toContain(">t(balance.priceFetching.consent.accept)<"); + }); }); diff --git a/src/components/settings/LicenseKeyForm.render.test.tsx b/src/components/settings/LicenseKeyForm.render.test.tsx index c28ba59..6ecacc1 100644 --- a/src/components/settings/LicenseKeyForm.render.test.tsx +++ b/src/components/settings/LicenseKeyForm.render.test.tsx @@ -1,5 +1,6 @@ // Render tests for the key entry form of the License card (#347). No jsdom needed: -// react-dom/server renders in vitest's node environment, and `t` echoes its key. +// react-dom/server renders in vitest's node environment, and the marked `t` of +// src/test/i18nMock.ts renders `t(key)`. import { describe, it, expect, vi } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; @@ -44,4 +45,10 @@ describe("LicenseKeyForm", () => { expect(render(null, true)).toMatch(/