test(player): pin the native-video default and the opt-out that must survive it
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.
This commit is contained in:
@@ -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<string, string>();
|
||||||
|
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");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user