// @vitest-environment jsdom // // E22 round-2 review: locks the stacking that makes an admin config row usable on a phone. The // control column cannot shrink, so beside a wide control it left the label and its hint a sliver of // the ~250 px a phone leaves next to the navigation rail. The sibling fix — a long-labelled choice // becoming a dropdown — is covered in ConfigPanel.choice.dom.test.tsx, but that one does nothing for // a text, number or secret key, whose `w-52` input is the wide control: this is their only fix. // // jsdom does no layout, so what is asserted is the class contract those rules rest on, the same // trade SearchBar.dom.test.tsx already makes for the narrow-header rules. import { afterEach, describe, expect, it, vi } from "vitest"; import { cleanup, render, screen } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { ConfigItem } from "../lib/api"; vi.mock("react-i18next", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, useTranslation: () => ({ t: (key: string) => key, i18n: { language: "en" } }), }; }); const text = (key: string): ConfigItem => ({ key, type: "str", group: "g", secret: false, min: null, max: null, is_set: false, allow_empty: true, choices: [], value: "", default: "", }); vi.mock("../lib/api", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, api: { ...actual.api, adminConfig: () => Promise.resolve({ groups: { g: [text("site_name")] }, secrets_manageable: true }), }, }; }); vi.mock("../lib/useMe", () => ({ useMe: () => ({ email_configured: true }) })); import ConfigPanel from "./ConfigPanel"; afterEach(() => { cleanup(); vi.clearAllMocks(); }); describe("ConfigPanel field row (E22 round 2)", () => { it("stacks the label above the control below `sm`, and lets the control fit the screen", async () => { render( , ); const label = await screen.findByText("config.fields.site_name.label"); const row = label.parentElement!.parentElement!; // label → the label/hint column → the row // One column on a phone, the two-column row only from `sm` up: expect(row.className).toContain("flex-col"); expect(row.className).toContain("sm:flex-row"); // The control column may not out-width the screen, and only stops shrinking from `sm` up: const control = row.lastElementChild as HTMLElement; expect(control.className).toContain("max-w-full"); expect(control.className).toContain("sm:shrink-0"); expect(control.className).not.toMatch(/(^|\s)shrink-0(\s|$)/); }); });