Files
bitvid/tests/bitlogin-modal-integration.test.mjs
T
thePR0M3TH3AN f0a3ede3e5 Preserve autoplay preference on fallback; reload open comment thread after login
### Motivation

- Prevent a browser-policy muted-autoplay retry from overwriting a viewer's explicit mute/unmute preference and ensure fallback mutes are transient.
- Ensure that when a user logs in while a video comment modal is open, the open thread is reloaded (not just refreshed) so comments continue to display correctly after relay-backed services are reconfigured.

### Description

- Add `js/utils/autoplayPreference.js` with `muteForAutoplayFallback` and `consumeAutoplayFallbackMute` helpers to mark and consume transient fallback mutes.
- Update `js/services/playbackService.js` to treat sound as default unless the viewer explicitly chose mute, persist explicit choices via `localStorage`, ignore fallback-generated volume changes using `consumeAutoplayFallbackMute`, and expose `muteForAutoplayFallback` delegating to the new util.
- Replace direct `videoElement.muted = true` calls with `playbackService.muteForAutoplayFallback` in `js/app/playbackCoordinator.js` and `js/webtorrent.js` so fallback mutes are marked as transient.
- Change `js/app/authSessionCoordinator.js` to reload the currently open video comment thread with `commentController.load(activeModalVideo)` after login if a modal video is active, instead of only calling `refreshAuthState`.
- Update tests in `tests/services/playbackService.test.mjs` and add a test in `tests/app/login-defers-dms.test.mjs` to cover the login behavior that reloads an open comment thread.

### Testing

- Ran the `PlaybackService` unit tests (`tests/services/playbackService.test.mjs`) which assert `prepareVideoElement` behavior, explicit mute persistence, and the transient nature of fallback mute, and they passed.
- Ran the auth login unit tests including `tests/app/login-defers-dms.test.mjs` which verifies DM deferral and reload of an open comment thread, and they passed.

(cherry picked from commit ce14004725)
2026-07-26 12:33:57 -04:00

44 lines
1.6 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import {
resolveVerifiedBitloginPubkey,
wireBitloginLogin,
} from "../js/ui/bitloginModalIntegration.js";
const PUBKEY = "a".repeat(64);
test("BitLogin accepts a login identity only when the event and widget worker agree", async () => {
const widget = { getPublicKey: async () => PUBKEY.toUpperCase() };
assert.equal(await resolveVerifiedBitloginPubkey(widget, PUBKEY), PUBKEY);
});
test("BitLogin rejects a forged event pubkey even when its claimed account has access", async () => {
const widget = { getPublicKey: async () => "b".repeat(64) };
assert.equal(await resolveVerifiedBitloginPubkey(widget, PUBKEY), "");
});
test("BitLogin rejects malformed claims and widgets without a worker-backed public key", async () => {
assert.equal(await resolveVerifiedBitloginPubkey({}, PUBKEY), "");
assert.equal(await resolveVerifiedBitloginPubkey({ getPublicKey: async () => PUBKEY }, "npub1nope"), "");
});
test("BitLogin bootstrap safely defers when MutationObserver is unavailable", () => {
const originalDocument = globalThis.document;
const originalObserver = globalThis.MutationObserver;
globalThis.document = {
body: {},
defaultView: {},
getElementById: () => null,
};
try {
delete globalThis.MutationObserver;
assert.doesNotThrow(() => wireBitloginLogin({ authService: {} }));
} finally {
if (originalDocument === undefined) delete globalThis.document;
else globalThis.document = originalDocument;
if (originalObserver === undefined) delete globalThis.MutationObserver;
else globalThis.MutationObserver = originalObserver;
}
});