mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
fix(embed): implement robust EmbedPlayerModal and guard resetTorrentStats
- Add `js/ui/components/EmbedPlayerModal.js` to implement the `VideoModal` interface for embed contexts (including `resetStats`). - Update `js/ui/ModalManager.js` to detect embed mode and use `EmbedPlayerModal`. - Clean up `js/embed.js` to remove local modal definition and add `postMessage` diagnostic logging. - Update `js/app.js` `resetTorrentStats` log message and verify guard. - Add unit tests for `EmbedPlayerModal` and `resetTorrentStats` logic. - Add E2E reproduction script `tests/e2e/repro_issue.spec.ts`.
This commit is contained in:
1 parent
d71d2812f4
commit
981fac785a
7 files changed
+379
-117
No files matched your search
@@ -0,0 +1,51 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
|
||||
/**
|
||||
* Validates the logic used in Application.resetTorrentStats.
|
||||
* Note: We test the function logic in isolation because importing the full Application class
|
||||
* triggers side effects (network, webtorrent) that are difficult to mock in this unit test environment.
|
||||
*/
|
||||
function resetTorrentStats(context, logger) {
|
||||
// Exact logic from js/app.js
|
||||
if (context.videoModal) {
|
||||
if (typeof context.videoModal.resetStats === "function") {
|
||||
context.videoModal.resetStats();
|
||||
} else {
|
||||
logger.info(
|
||||
"[Application] resetTorrentStats: videoModal.resetStats not available — skipping."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('Application.resetTorrentStats logic', async (t) => {
|
||||
const logger = {
|
||||
info: () => {},
|
||||
warn: () => {}
|
||||
};
|
||||
|
||||
await t.test('does not throw when videoModal is null', () => {
|
||||
const context = { videoModal: null };
|
||||
assert.doesNotThrow(() => resetTorrentStats(context, logger));
|
||||
});
|
||||
|
||||
await t.test('does not throw when videoModal is undefined', () => {
|
||||
const context = { videoModal: undefined };
|
||||
assert.doesNotThrow(() => resetTorrentStats(context, logger));
|
||||
});
|
||||
|
||||
await t.test('does not throw when videoModal lacks resetStats', () => {
|
||||
const context = { videoModal: { other: 1 } };
|
||||
assert.doesNotThrow(() => resetTorrentStats(context, logger));
|
||||
});
|
||||
|
||||
await t.test('calls resetStats when available', () => {
|
||||
let called = false;
|
||||
const context = {
|
||||
videoModal: { resetStats: () => { called = true; } }
|
||||
};
|
||||
resetTorrentStats(context, logger);
|
||||
assert.strictEqual(called, true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
import { EmbedPlayerModal } from '../../js/ui/components/EmbedPlayerModal.js';
|
||||
|
||||
// Polyfill EventTarget for Node < 16 if needed, but likely available
|
||||
if (typeof EventTarget === 'undefined') {
|
||||
global.EventTarget = class EventTarget {
|
||||
constructor() { this.listeners = {}; }
|
||||
addEventListener() {}
|
||||
removeEventListener() {}
|
||||
dispatchEvent() { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
test('EmbedPlayerModal interface', async (t) => {
|
||||
const modal = new EmbedPlayerModal();
|
||||
|
||||
await t.test('has expected methods', () => {
|
||||
assert.strictEqual(typeof modal.load, 'function');
|
||||
assert.strictEqual(typeof modal.getRoot, 'function');
|
||||
assert.strictEqual(typeof modal.getVideoElement, 'function');
|
||||
assert.strictEqual(typeof modal.setVideoElement, 'function');
|
||||
assert.strictEqual(typeof modal.resetStats, 'function');
|
||||
assert.strictEqual(typeof modal.updateStatus, 'function');
|
||||
assert.strictEqual(typeof modal.setTorrentStatsVisibility, 'function');
|
||||
assert.strictEqual(typeof modal.addEventListener, 'function');
|
||||
assert.strictEqual(typeof modal.removeEventListener, 'function');
|
||||
assert.strictEqual(typeof modal.dispatch, 'function');
|
||||
});
|
||||
|
||||
await t.test('resetStats is no-op and does not throw', () => {
|
||||
assert.doesNotThrow(() => modal.resetStats());
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user