// @vitest-environment jsdom import { describe, it, expect, vi } from "vitest"; import { fireEvent, render, screen } from "@testing-library/react"; import { I18nProvider } from "@multica/core/i18n/react"; import enCommon from "../../locales/en/common.json"; import enAgents from "../../locales/en/agents.json"; import type { AccessChange } from "./inspector/access-picker"; import { AccessPicker } from "./inspector/access-picker"; const TEST_RESOURCES = { en: { common: enCommon, agents: enAgents } }; vi.mock("../../common/actor-avatar", () => ({ ActorAvatar: () =>
avatar
, })); function Harness({ onReadyChange, onChange, }: { onReadyChange?: (ready: boolean, change?: AccessChange) => void; onChange?: (next: unknown) => void; }) { return ( ); } describe("AccessPicker bulk mode (hideFooter)", () => { it("isReady starts false (private is the persisted default)", () => { const readyFn = vi.fn(); render(); expect(readyFn).toHaveBeenCalledWith(false, undefined); }); it("clicking Workspace radio fires onReadyChange(true) with a Workspace change", () => { const readyFn = vi.fn(); render(); const workspaceRadio = screen.getByRole("radio", { name: /Entire workspace/, }); fireEvent.click(workspaceRadio); expect(readyFn).toHaveBeenCalledWith(true, expect.objectContaining({ permission_mode: "public_to", invocation_targets: [expect.objectContaining({ target_type: "workspace" })], })); }); it("clicking Specific people without selecting a member keeps onReadyChange(false)", () => { const readyFn = vi.fn(); render(); const membersRadio = screen.getByRole("radio", { name: /Specific people/, }); fireEvent.click(membersRadio); expect(readyFn).toHaveBeenCalledWith(false, undefined); }); // The loop this guards: a parent that stores the change in state re-renders // the picker. If the picker re-notifies on that render (unstable change // object / callback in the effect deps), the parent stores again and never // settles. Fails fast here; in the real toolbar it hangs the flow instead. it("does not re-notify the parent when re-rendered with a stable callback", () => { const readyFn = vi.fn(); const { rerender } = render(); fireEvent.click(screen.getByRole("radio", { name: /Entire workspace/ })); const callsAfterSelect = readyFn.mock.calls.length; const changeAfterSelect = readyFn.mock.calls.at(-1)?.[1]; rerender(); rerender(); expect(readyFn.mock.calls.length).toBe(callsAfterSelect); // And the committed value keeps its identity, so storing it is idempotent. expect(readyFn.mock.calls.at(-1)?.[1]).toBe(changeAfterSelect); }); });