| 1 | import assert from "node:assert/strict"; |
| 2 | import React, { act } from "react"; |
| 3 | import { createRoot } from "react-dom/client"; |
| 4 | import { JSDOM } from "jsdom"; |
| 5 | import { SessionExperienceSettings } from "../components/SessionExperienceSettings"; |
| 6 | import { LocaleProvider, t } from "../lib/i18n"; |
| 7 | import type { SettingsView } from "../lib/types"; |
| 8 | import { installDesktopHostStub } from "./desktopHostStub"; |
| 9 | |
| 10 | const dom = new JSDOM("<div id='root'></div>", { url: "http://localhost" }); |
| 11 | Object.assign(globalThis, { window: dom.window, document: dom.window.document, localStorage: dom.window.localStorage, |
| 12 | CustomEvent: dom.window.CustomEvent, IS_REACT_ACT_ENVIRONMENT: true }); |
| 13 | const writes: string[] = []; |
| 14 | let legacyWrites = 0; |
| 15 | installDesktopHostStub({ SetSessionExperience: async () => { legacyWrites++; }, |
| 16 | SetDefaultToolApprovalMode: async (mode: string) => { writes.push(mode); } }); |
| 17 | const root = createRoot(document.getElementById("root")!); |
| 18 | const apply = async (write: () => Promise<unknown>) => { await write(); return true; }; |
| 19 | try { |
| 20 | for (const mode of ["standard", "deep"] as const) { |
| 21 | await act(async () => root.render(<LocaleProvider><SessionExperienceSettings snapshot={{ sessionExperience: mode, defaultToolApprovalMode: "workspace-write" } as SettingsView} busy={false} apply={apply} /></LocaleProvider>)); |
| 22 | const groups = [...document.querySelectorAll<HTMLElement>("[role=radiogroup]")]; |
| 23 | assert.ok(!groups.some(group => group.getAttribute("aria-label") === t("settings.sessionExperience")), "legacy display preference has no settings control"); |
| 24 | const approval = groups.find(group => group.getAttribute("aria-label") === t("settings.defaultToolApprovalMode"))!; |
| 25 | assert.equal(approval.querySelectorAll("[role=radio]").length, 3); |
| 26 | await act(async () => approval.querySelectorAll<HTMLButtonElement>("button")[0].click()); |
| 27 | } |
| 28 | assert.deepEqual(writes, ["read-only", "read-only"], "permission settings send the selected preset to the host"); |
| 29 | assert.equal(legacyWrites, 0, "opening settings never rewrites the persisted legacy preference"); |
| 30 | |
| 31 | await act(async () => root.render(<LocaleProvider><SessionExperienceSettings snapshot={{ defaultToolApprovalMode: "workspace-write" } as SettingsView} busy={false} apply={apply} /></LocaleProvider>)); |
| 32 | const approval = [...document.querySelectorAll<HTMLElement>("[role=radiogroup]")] |
| 33 | .find(group => group.getAttribute("aria-label") === t("settings.defaultToolApprovalMode"))!; |
| 34 | await act(async () => approval.querySelectorAll<HTMLButtonElement>("button")[2].click()); |
| 35 | assert.deepEqual(writes, ["read-only", "read-only"], "selecting a Full access default does not persist before confirmation"); |
| 36 | const dialog = document.querySelector<HTMLElement>('[role="dialog"]')!; |
| 37 | assert.ok(dialog.textContent?.includes(t("permission.fullAccessConfirm.title"))); |
| 38 | const enable = [...dialog.querySelectorAll<HTMLButtonElement>("button")] |
| 39 | .find(button => button.textContent?.includes(t("permission.fullAccessConfirm.enable")))!; |
| 40 | assert.equal(enable.disabled, true, "default Full access stays disabled until risk acknowledgement"); |
| 41 | await act(async () => dialog.querySelector<HTMLInputElement>('input[type="checkbox"]')!.click()); |
| 42 | assert.equal(enable.disabled, false); |
| 43 | await act(async () => enable.click()); |
| 44 | assert.deepEqual(writes, ["read-only", "read-only", "danger-full-access"], "confirmed Full access becomes the new-session default"); |
| 45 | |
| 46 | await act(async () => root.render(<LocaleProvider><SessionExperienceSettings snapshot={{} as SettingsView} busy apply={apply} /></LocaleProvider>)); |
| 47 | assert.ok([...document.querySelectorAll<HTMLButtonElement>("[role=radio]")].every(button => button.disabled)); |
| 48 | console.log("settings: retired conversation display control, preserved approval and busy states passed"); |
| 49 | } finally { await act(async () => root.unmount()); dom.window.close(); } |
| 50 |