Files
bitvid/tests/app/hash-change-handler.test.mjs
T
thePR0M3TH3ANandClaude Fable 5 99d1b1dd36 tests: spec-correct four stale tests hidden by piped exit codes
A per-file sweep (local suite runs were reading the PIPE's exit code, not
npm's) surfaced four tests failing on HEAD:

- hash-change-handler: logged-out default is deliberately TRENDING since
  04621efc; test still expected most-recent-videos
- session-actor / sessionActor / nsec-login: encoded the pre-fix "no-arg
  clearStoredSessionActor wipes EVERY account" behavior that 2026-07-02
  deliberately removed (one account's logout must not destroy other saved
  accounts' keys). Replaced with stronger assertions: multi-account survival
  on no-arg clear, targeted forget, and the blocked-key security property
  asserted on the blocked account specifically.

Integrity notes in each file; TODO #11b addendum documents the pipe lesson.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 21:01:45 -04:00

150 lines
4.4 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { JSDOM } from "jsdom";
import { createHashChangeHandler } from "../../js/hashChangeHandler.js";
const setupDom = (url) => {
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", { url });
const { window } = dom;
const previousWindow = global.window;
const previousDocument = global.document;
const previousHTMLElement = global.HTMLElement;
global.window = window;
global.document = window.document;
global.HTMLElement = window.HTMLElement;
return () => {
global.window = previousWindow;
global.document = previousDocument;
if (previousHTMLElement === undefined) {
delete global.HTMLElement;
} else {
global.HTMLElement = previousHTMLElement;
}
};
};
const createLogger = () => ({
log() {},
warn() {},
error() {},
});
test("handleHashChange defaults to for-you when logged in", async () => {
const restore = setupDom("https://example.com");
try {
const loadViewCalls = [];
let initCalled = false;
const handleHashChange = createHashChangeHandler({
getApplication: () => ({ isUserLoggedIn: () => true }),
getApplicationReady: () => Promise.resolve(),
loadView: async (viewUrl) => {
loadViewCalls.push(viewUrl);
},
viewInitRegistry: {
"for-you": async () => {
initCalled = true;
},
},
devLogger: createLogger(),
userLogger: createLogger(),
});
await handleHashChange();
assert.deepEqual(loadViewCalls, ["views/for-you.html"]);
assert.equal(initCalled, true);
} finally {
restore();
}
});
// spec_correction: commit 04621efc (2026-06-24, "Trending defaults") made
// TRENDING the deliberate logged-out landing ("the best not-personalized
// landing", falling back to Recent only when FEATURE_TRENDING_FEED is off —
// see js/hashChangeHandler.js). This test still encoded the pre-change
// default (most-recent-videos) and has been failing since; the flag defaults
// to true, so the correct observable outcome is views/trending.html.
//
// test_integrity_note:
// change_type: ["spec_correction"]
// scenarios:
// - id: SCN-logged-out-default-view
// given: "no #view= hash and a logged-out user (FEATURE_TRENDING_FEED default-on)"
// when: "handleHashChange resolves the default view"
// then: "the Trending view loads and its init runs"
// observable_outcomes:
// - "loadView called with views/trending.html and the trending init fires"
// determinism_controls:
// - "JSDOM with fixed URL; injected logged-out application stub"
// anti_cheat_rationale:
// prevents: ["snapshot rubber-stamping"]
// relaxation:
// did_relax_any_assertion: false
// if_true_explain_spec_basis: "expectation moved to the newer intended default (equally strict)"
test("handleHashChange defaults to trending when logged out", async () => {
const restore = setupDom("https://example.com");
try {
const loadViewCalls = [];
let initCalled = false;
const handleHashChange = createHashChangeHandler({
getApplication: () => ({ isUserLoggedIn: () => false }),
getApplicationReady: () => Promise.resolve(),
loadView: async (viewUrl) => {
loadViewCalls.push(viewUrl);
},
viewInitRegistry: {
trending: async () => {
initCalled = true;
},
},
devLogger: createLogger(),
userLogger: createLogger(),
});
await handleHashChange();
assert.deepEqual(loadViewCalls, ["views/trending.html"]);
assert.equal(initCalled, true);
} finally {
restore();
}
});
test("handleHashChange respects explicit view regardless of login state", async () => {
const restore = setupDom("https://example.com/#view=subscriptions");
try {
const loadViewCalls = [];
let initCalled = false;
const handleHashChange = createHashChangeHandler({
getApplication: () => ({ isUserLoggedIn: () => true }),
getApplicationReady: () => Promise.resolve(),
loadView: async (viewUrl) => {
loadViewCalls.push(viewUrl);
},
viewInitRegistry: {
subscriptions: async () => {
initCalled = true;
},
},
devLogger: createLogger(),
userLogger: createLogger(),
});
await handleHashChange();
assert.deepEqual(loadViewCalls, ["views/subscriptions.html"]);
assert.equal(initCalled, true);
} finally {
restore();
}
});