| 1 | // Run: pnpm exec tsx src/__tests__/project-tree-organization-reset.test.tsx |
| 2 | import assert from "node:assert/strict"; |
| 3 | import { JSDOM } from "jsdom"; |
| 4 | import React, { act } from "react"; |
| 5 | import { createRoot } from "react-dom/client"; |
| 6 | import { useProjectTreeOrganization } from "../components/ProjectTreeOrganization"; |
| 7 | import type { ProjectNode, ProjectTreeOrganizationBindings } from "../lib/types"; |
| 8 | import type { SessionOrganizationMutation, SessionOrganizationSnapshot } from "../generated/desktopContract.generated"; |
| 9 | import { ToastProvider } from "../lib/toast"; |
| 10 | import { LocaleProvider, t } from "../lib/i18n"; |
| 11 | |
| 12 | const dom = new JSDOM('<html><body><div id="root"></div></body></html>', { url: "http://localhost/" }); |
| 13 | Object.assign(globalThis, { window: dom.window, document: dom.window.document, Node: dom.window.Node, Element: dom.window.Element, |
| 14 | HTMLElement: dom.window.HTMLElement, IS_REACT_ACT_ENVIRONMENT: true }); |
| 15 | |
| 16 | const folder: ProjectNode = { key: "project-/repo", kind: "project", label: "Repo", root: "/repo", children: [] }; |
| 17 | const initialOrder = ["ref\0local\0older", "ref\0local\0newer"]; |
| 18 | let snapshot: SessionOrganizationSnapshot = { revision: 1, applied: true, manualOrderEnabled: true, order: initialOrder, groups: [] }; |
| 19 | const mutations: SessionOrganizationMutation[] = []; |
| 20 | let refreshes = 0; |
| 21 | const bindings: ProjectTreeOrganizationBindings = { |
| 22 | GetSessionOrganization: async () => snapshot, |
| 23 | UpdateSessionOrganization: async (_workspace, revision, mutation) => { |
| 24 | assert.equal(revision, snapshot.revision); |
| 25 | mutations.push(mutation); |
| 26 | snapshot = { ...snapshot, revision: revision + 1, manualOrderEnabled: false }; |
| 27 | return snapshot; |
| 28 | }, |
| 29 | }; |
| 30 | |
| 31 | function Harness() { |
| 32 | const organization = useProjectTreeOrganization({ tree: [folder], refresh: async () => { refreshes += 1; }, bindings }); |
| 33 | const resetItem = organization.resetOrderMenuItems(folder, t, () => {}); |
| 34 | return <><output id="order">{organization.orderFor?.(folder).join(",")}</output> |
| 35 | {resetItem.map(item => <button key={item.key} id="reset" onClick={item.onSelect}>Reset</button>)}</>; |
| 36 | } |
| 37 | |
| 38 | const root = createRoot(document.getElementById("root")!); |
| 39 | const flush = async () => { await act(async () => { await new Promise(resolve => setTimeout(resolve, 0)); }); }; |
| 40 | try { |
| 41 | await act(async () => root.render(<LocaleProvider><ToastProvider><Harness /></ToastProvider></LocaleProvider>)); |
| 42 | await flush(); |
| 43 | assert.equal(document.getElementById("order")?.textContent, initialOrder.join(",")); |
| 44 | await act(async () => { document.getElementById("reset")!.click(); }); |
| 45 | await flush(); |
| 46 | assert.deepEqual(mutations.map(mutation => mutation.kind), ["reset-order"]); |
| 47 | assert.equal(document.getElementById("order")?.textContent, ""); |
| 48 | assert.equal(refreshes, 1); |
| 49 | } finally { |
| 50 | await act(async () => root.unmount()); |
| 51 | dom.window.close(); |
| 52 | } |
| 53 |