mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
- Refactored `tests/auth-service.test.mjs` to use `node:test` API so it is detected by the runner. - Removed console noise from `tests/watchHistory/watch-history-telemetry.test.mjs`. - Generated daily audit report `test-audit-report-2026-02-12.md`. - Updated test logs and tracking artifacts. Co-authored-by: PR0M3TH3AN <[email protected]>
224 lines
5.9 KiB
JavaScript
224 lines
5.9 KiB
JavaScript
import "../test-helpers/setup-localstorage.mjs";
|
|
import assert from "node:assert/strict";
|
|
|
|
import WatchHistoryTelemetry from "../../js/services/watchHistoryTelemetry.js";
|
|
|
|
const hexPubkey = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789";
|
|
|
|
function createTelemetry({
|
|
serviceOverrides = {},
|
|
controllerOverrides = {},
|
|
options = {},
|
|
} = {}) {
|
|
const watchHistoryService = {
|
|
isEnabled: () => true,
|
|
getSettings: () => ({ metadata: { storeLocally: true } }),
|
|
setLocalMetadata: () => {},
|
|
removeLocalMetadata: () => {},
|
|
clearLocalMetadata: () => {},
|
|
publishView: async () => ({ ok: true }),
|
|
subscribe: () => () => {},
|
|
...serviceOverrides,
|
|
};
|
|
|
|
const watchHistoryController = {
|
|
handleWatchHistoryRemoval: async () => ({}),
|
|
flush: async () => {},
|
|
...controllerOverrides,
|
|
};
|
|
|
|
const telemetry = new WatchHistoryTelemetry({
|
|
watchHistoryService,
|
|
watchHistoryController,
|
|
nostrClient: options.nostrClient || { pubkey: hexPubkey },
|
|
log: options.log || (() => {}),
|
|
normalizeHexPubkey:
|
|
options.normalizeHexPubkey || ((value) => (typeof value === "string" ? value.toLowerCase() : null)),
|
|
getActiveUserPubkey: options.getActiveUserPubkey || (() => hexPubkey),
|
|
ingestLocalViewEvent: options.ingestLocalViewEvent || (() => {}),
|
|
viewThresholdSeconds: options.viewThresholdSeconds,
|
|
});
|
|
|
|
return { telemetry, watchHistoryService, watchHistoryController };
|
|
}
|
|
|
|
class FakeVideoElement {
|
|
constructor() {
|
|
this.listeners = new Map();
|
|
this.paused = true;
|
|
this.currentTime = 0;
|
|
}
|
|
|
|
addEventListener(eventName, handler) {
|
|
if (!this.listeners.has(eventName)) {
|
|
this.listeners.set(eventName, new Set());
|
|
}
|
|
this.listeners.get(eventName).add(handler);
|
|
}
|
|
|
|
removeEventListener(eventName, handler) {
|
|
const set = this.listeners.get(eventName);
|
|
if (!set) {
|
|
return;
|
|
}
|
|
set.delete(handler);
|
|
if (set.size === 0) {
|
|
this.listeners.delete(eventName);
|
|
}
|
|
}
|
|
|
|
emit(eventName) {
|
|
const set = this.listeners.get(eventName);
|
|
if (!set) {
|
|
return;
|
|
}
|
|
for (const handler of set) {
|
|
handler({ type: eventName });
|
|
}
|
|
}
|
|
}
|
|
|
|
async function flushAsyncOperations() {
|
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
}
|
|
|
|
async function testMetadataPreferenceSync() {
|
|
const { telemetry } = createTelemetry();
|
|
const unsubscribe = await telemetry.initPreferenceSync();
|
|
assert.equal(unsubscribe, null, "initPreferenceSync should no-op");
|
|
assert.equal(telemetry.isMetadataPreferenceEnabled(), false);
|
|
}
|
|
|
|
async function testPreparePlaybackLoggingPublishesOnce() {
|
|
const ingestEvents = [];
|
|
const publishCalls = [];
|
|
|
|
const pointer = { type: "e", value: "event-id" };
|
|
const pointerKey = "event-id::relay";
|
|
|
|
const { telemetry } = createTelemetry({
|
|
serviceOverrides: {
|
|
publishView: async (ptr, _relay) => {
|
|
publishCalls.push({ ptr });
|
|
return {
|
|
ok: true,
|
|
event: { pubkey: hexPubkey },
|
|
};
|
|
},
|
|
},
|
|
options: {
|
|
ingestLocalViewEvent: (payload) => ingestEvents.push(payload),
|
|
},
|
|
});
|
|
|
|
const videoA = new FakeVideoElement();
|
|
videoA.paused = false;
|
|
videoA.currentTime = telemetry.viewThresholdSeconds;
|
|
|
|
telemetry.preparePlaybackLogging({
|
|
videoElement: videoA,
|
|
pointer,
|
|
pointerKey,
|
|
});
|
|
await flushAsyncOperations();
|
|
|
|
assert.equal(publishCalls.length, 1, "publishView should be called once");
|
|
assert.equal(ingestEvents.length, 1, "ingestLocalViewEvent should run once");
|
|
assert.deepEqual(publishCalls[0].ptr, pointer);
|
|
assert.deepEqual(ingestEvents[0].pointer, pointer);
|
|
|
|
const videoB = new FakeVideoElement();
|
|
videoB.paused = false;
|
|
videoB.currentTime = telemetry.viewThresholdSeconds;
|
|
|
|
telemetry.preparePlaybackLogging({
|
|
videoElement: videoB,
|
|
pointer,
|
|
pointerKey,
|
|
});
|
|
await flushAsyncOperations();
|
|
|
|
assert.equal(
|
|
publishCalls.length,
|
|
1,
|
|
"Repeated preparePlaybackLogging should reuse cooldown cache"
|
|
);
|
|
}
|
|
|
|
async function testPreparePlaybackLoggingIgnoresMetadata() {
|
|
const publishCalls = [];
|
|
|
|
const pointer = { type: "e", value: "event-id" };
|
|
const pointerKey = "event-id";
|
|
|
|
const { telemetry } = createTelemetry({
|
|
serviceOverrides: {
|
|
publishView: async (ptr, _relay) => {
|
|
publishCalls.push({ ptr });
|
|
return {
|
|
ok: true,
|
|
event: { pubkey: hexPubkey },
|
|
};
|
|
},
|
|
},
|
|
});
|
|
|
|
const videoElement = new FakeVideoElement();
|
|
videoElement.paused = false;
|
|
videoElement.currentTime = telemetry.viewThresholdSeconds;
|
|
|
|
const videoMetadata = {
|
|
id: "evt1",
|
|
title: "Example Video",
|
|
thumbnail: "https://example.com/thumb.jpg",
|
|
pubkey: hexPubkey,
|
|
rootCreatedAt: 1_700_000_000,
|
|
url: "https://example.com/video.mp4",
|
|
};
|
|
|
|
telemetry.preparePlaybackLogging({
|
|
videoElement,
|
|
pointer,
|
|
pointerKey,
|
|
video: videoMetadata,
|
|
});
|
|
|
|
await flushAsyncOperations();
|
|
|
|
assert.equal(publishCalls.length, 1, "publishView should be invoked once");
|
|
assert.equal(publishCalls[0].ptr, pointer);
|
|
assert.equal(publishCalls[0].metadata, undefined, "metadata should NOT be passed");
|
|
}
|
|
|
|
async function testCancelPlaybackLoggingFlushes() {
|
|
let flushArgs = null;
|
|
const video = new FakeVideoElement();
|
|
const { telemetry } = createTelemetry({
|
|
controllerOverrides: {
|
|
flush: async (reason, context) => {
|
|
flushArgs = { reason, context };
|
|
},
|
|
},
|
|
});
|
|
|
|
video.paused = true;
|
|
video.currentTime = 0;
|
|
|
|
telemetry.preparePlaybackLogging({
|
|
videoElement: video,
|
|
pointer: { type: "e", value: "event" },
|
|
pointerKey: "event",
|
|
});
|
|
|
|
telemetry.cancelPlaybackLogging({ reason: "unit", context: "test" });
|
|
await flushAsyncOperations();
|
|
|
|
assert.deepEqual(flushArgs, { reason: "unit", context: "test" });
|
|
}
|
|
|
|
await testMetadataPreferenceSync();
|
|
await testPreparePlaybackLoggingPublishesOnce();
|
|
await testPreparePlaybackLoggingIgnoresMetadata();
|
|
await testCancelPlaybackLoggingFlushes();
|
|
|