| 1 | import assert from "node:assert/strict"; |
| 2 | import { JSDOM } from "jsdom"; |
| 3 | import { |
| 4 | loadWorkbenchSortMode, |
| 5 | WORKBENCH_SORT_CREATED_DEFAULT_MIGRATION_KEY, |
| 6 | WORKBENCH_SORT_KEY, |
| 7 | } from "../lib/projectTreeTopic"; |
| 8 | |
| 9 | function installLocalStorage(seed: Record<string, string> = {}): Storage { |
| 10 | const dom = new JSDOM("<!doctype html><html><body></body></html>", { url: "http://localhost/" }); |
| 11 | globalThis.localStorage = dom.window.localStorage; |
| 12 | for (const [key, value] of Object.entries(seed)) localStorage.setItem(key, value); |
| 13 | return localStorage; |
| 14 | } |
| 15 | |
| 16 | { |
| 17 | const storage = installLocalStorage(); |
| 18 | assert.equal(loadWorkbenchSortMode(), "created", "a fresh install defaults to creation time"); |
| 19 | assert.equal(storage.getItem(WORKBENCH_SORT_KEY), "created", "the new default is persisted"); |
| 20 | assert.equal(storage.getItem(WORKBENCH_SORT_CREATED_DEFAULT_MIGRATION_KEY), "1", "the reset runs only once"); |
| 21 | } |
| 22 | |
| 23 | { |
| 24 | const storage = installLocalStorage({ [WORKBENCH_SORT_KEY]: "updated" }); |
| 25 | assert.equal(loadWorkbenchSortMode(), "created", "an existing updated-time choice is reset on upgrade"); |
| 26 | assert.equal(storage.getItem(WORKBENCH_SORT_KEY), "created", "the legacy choice is overwritten for older readers too"); |
| 27 | } |
| 28 | |
| 29 | { |
| 30 | const storage = installLocalStorage({ [WORKBENCH_SORT_KEY]: "updated" }); |
| 31 | assert.equal(loadWorkbenchSortMode(), "created"); |
| 32 | storage.setItem(WORKBENCH_SORT_KEY, "updated"); |
| 33 | assert.equal(loadWorkbenchSortMode(), "updated", "a manual choice made after migration remains authoritative"); |
| 34 | } |
| 35 | |
| 36 | { |
| 37 | const storage = installLocalStorage({ [WORKBENCH_SORT_KEY]: "updated" }); |
| 38 | const interruptedStorage = { |
| 39 | get length() { return storage.length; }, |
| 40 | clear: () => storage.clear(), |
| 41 | getItem: (key: string) => storage.getItem(key), |
| 42 | key: (index: number) => storage.key(index), |
| 43 | removeItem: (key: string) => storage.removeItem(key), |
| 44 | setItem: (key: string, value: string) => { |
| 45 | if (key === WORKBENCH_SORT_CREATED_DEFAULT_MIGRATION_KEY) throw new Error("interrupted migration"); |
| 46 | storage.setItem(key, value); |
| 47 | }, |
| 48 | } satisfies Storage; |
| 49 | globalThis.localStorage = interruptedStorage; |
| 50 | assert.equal(loadWorkbenchSortMode(), "created", "an interrupted migration still uses creation time"); |
| 51 | assert.equal(storage.getItem(WORKBENCH_SORT_CREATED_DEFAULT_MIGRATION_KEY), null, "an interrupted migration remains retryable"); |
| 52 | globalThis.localStorage = storage; |
| 53 | assert.equal(loadWorkbenchSortMode(), "created", "the next launch completes an interrupted migration"); |
| 54 | assert.equal(storage.getItem(WORKBENCH_SORT_CREATED_DEFAULT_MIGRATION_KEY), "1"); |
| 55 | } |
| 56 | |
| 57 | { |
| 58 | installLocalStorage({ |
| 59 | [WORKBENCH_SORT_CREATED_DEFAULT_MIGRATION_KEY]: "1", |
| 60 | [WORKBENCH_SORT_KEY]: "created", |
| 61 | }); |
| 62 | assert.equal(loadWorkbenchSortMode(), "created", "a migrated creation-time choice remains authoritative"); |
| 63 | } |
| 64 | |
| 65 | console.log(" PASS project tree sort preference migration"); |
| 66 |