From 3b9a8ad695ec5f1eb4a604d290b476740a6a7280 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 16 Aug 2026 22:16:39 +0200 Subject: [PATCH] test(player): pin the native-video default and the opt-out that must survive it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default has moved four times, so the risk is not which way it points but that a flip silently overrides people who chose. The previous reader was getItem(KEY) === "true", which conflates "never chose" with "chose off" — under it, flipping the default re-enables the native path for everyone who had deliberately turned it off. The three cases are pinned separately so that conflation cannot come back. --- src/lib/stores/nativeVideo.default.test.ts | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/lib/stores/nativeVideo.default.test.ts diff --git a/src/lib/stores/nativeVideo.default.test.ts b/src/lib/stores/nativeVideo.default.test.ts new file mode 100644 index 00000000..77963912 --- /dev/null +++ b/src/lib/stores/nativeVideo.default.test.ts @@ -0,0 +1,75 @@ +import { describe, it, expect, beforeEach, beforeAll, afterAll, vi } from "vitest"; +import { get } from "svelte/store"; + +/** + * The stored value of the native-video preference, and what it means. + * + * The default has moved four times (see the history on `load()` in + * nativeVideo.ts), so the risk here is not "which way is it pointing" — it is + * that a flip silently overrides people who chose. The old reader was + * `getItem(KEY) === "true"`, which conflates "never chose" with "chose off"; + * flipping the default under that reader re-enables the native path for + * everyone who deliberately turned it off. So the three cases are pinned + * separately rather than through the default alone. + * + * TRACES: UR-003, UR-004 | DR-188 + */ + +const STORAGE_KEY = "jellytau-experimental-native-video"; + +// jsdom here doesn't expose localStorage; stand in a minimal implementation, +// matching the viewMode/searchGroupOrder store tests. +const backing = new Map(); +const localStorageShim = { + getItem: (key: string) => backing.get(key) ?? null, + setItem: (key: string, value: string) => void backing.set(key, value), + removeItem: (key: string) => void backing.delete(key), + clear: () => backing.clear(), +}; + +beforeAll(() => { + vi.stubGlobal("localStorage", localStorageShim); +}); + +afterAll(() => { + vi.unstubAllGlobals(); +}); + +async function freshStore() { + // The default is read at module init, so each case needs a fresh module. + vi.resetModules(); + return await import("./nativeVideo"); +} + +describe("experimentalNativeVideo default", () => { + beforeEach(() => { + localStorage.clear(); + }); + + it("defaults to ON when the user has never chosen", async () => { + const { experimentalNativeVideo } = await freshStore(); + expect(get(experimentalNativeVideo)).toBe(true); + }); + + it("stays OFF for someone who deliberately turned it off", async () => { + // The regression the null check exists for: an explicit opt-out must + // survive the default flip, not be re-enabled by it. + localStorage.setItem(STORAGE_KEY, "false"); + const { experimentalNativeVideo } = await freshStore(); + expect(get(experimentalNativeVideo)).toBe(false); + }); + + it("stays ON for someone who deliberately turned it on", async () => { + localStorage.setItem(STORAGE_KEY, "true"); + const { experimentalNativeVideo } = await freshStore(); + expect(get(experimentalNativeVideo)).toBe(true); + }); + + it("persists an explicit choice in both directions", async () => { + const { experimentalNativeVideo } = await freshStore(); + experimentalNativeVideo.set(false); + expect(localStorage.getItem(STORAGE_KEY)).toBe("false"); + experimentalNativeVideo.set(true); + expect(localStorage.getItem(STORAGE_KEY)).toBe("true"); + }); +});