// AdjustmentForm — each adjustment line picks its category in a combobox // (#429). No jsdom: react-dom/server renders the initial markup in vitest's // node environment, the combobox closed, so without its list in a portal. import { describe, it, expect, vi } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; vi.mock("react-i18next", async () => (await import("../../test/i18nMock")).i18nMock()); import AdjustmentForm from "./AdjustmentForm"; import type { Category } from "../../shared/types"; import type { EntryFormData } from "../../hooks/useAdjustments"; const category = (id: number, name: string, extra: Partial = {}): Category => ({ id, name, type: "expense", is_active: true, is_inputable: true, sort_order: id, created_at: "", ...extra, }); /** A seed category, translated through its key, and one the user created. */ const GROCERIES = category(10, "Épicerie régulière", { i18n_key: "categoriesSeed.alimentation.epicerie.reguliere", }); const CABIN = category(20, "Chalet"); const line = (categoryId: number): EntryFormData => ({ category_id: categoryId, amount: 12.5, description: "", }); const markup = (entries: EntryFormData[]) => renderToStaticMarkup( , ); /** The comboboxes' inputs, in the order of the lines. */ const comboboxes = (html: string) => html.match(/]*role="combobox"[^>]*>/g) ?? []; describe("AdjustmentForm — category of a line (#429)", () => { it("gives every line a combobox, and no select", () => { const html = markup([line(10), line(20)]); expect(comboboxes(html)).toHaveLength(2); expect(html).not.toContain(" { const [seed, user] = comboboxes(markup([line(10), line(20)])); expect(seed).toContain( 'value="t(categoriesSeed.alimentation.epicerie.reguliere[defaultValue=Épicerie régulière])"', ); expect(user).toContain('value="Chalet"'); }); it("names every combobox and renders it compact, as in the split window", () => { const inputs = comboboxes(markup([line(10), line(20)])); expect(inputs).toHaveLength(2); for (const input of inputs) { expect(input).toContain('aria-label="t(adjustments.category)"'); expect(input).toMatch(/class="w-full px-2 py-1 /); } }); it("leaves the field empty for a line on a category the list does not offer (D2)", () => { // A category hidden from input is not in the list: nothing to show. const [input] = comboboxes(markup([line(99)])); expect(input).toContain('value=""'); }); it("keeps the empty state of an adjustment without a line", () => { const html = markup([]); expect(comboboxes(html)).toHaveLength(0); expect(html).toContain(">t(adjustments.noEntries)<"); }); });