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,112 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { startRelay } from '../../scripts/agent/simple-relay.mjs';
|
||||
import { WebSocket } from 'ws';
|
||||
import { finalizeEvent, getPublicKey, nip19 } from 'nostr-tools';
|
||||
|
||||
// Polyfill WebSocket for node environment
|
||||
if (!global.WebSocket) {
|
||||
global.WebSocket = WebSocket;
|
||||
}
|
||||
|
||||
const RELAY_PORT = 8899;
|
||||
const RELAY_URL = `ws://127.0.0.1:${RELAY_PORT}`;
|
||||
|
||||
test.describe('Embed Player', () => {
|
||||
let relayServer;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
relayServer = startRelay(RELAY_PORT);
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
if (relayServer) {
|
||||
await relayServer.close();
|
||||
}
|
||||
});
|
||||
|
||||
test('reproduce embed resetStats error', async ({ page }) => {
|
||||
// 1. Create a dummy video event
|
||||
const sk = Uint8Array.from(Buffer.from('7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b', 'hex'));
|
||||
const pk = getPublicKey(sk);
|
||||
|
||||
const event = finalizeEvent({
|
||||
kind: 30078,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [
|
||||
['d', 'test-video'],
|
||||
['title', 'Test Video'],
|
||||
['url', 'https://example.com/video.mp4'],
|
||||
],
|
||||
content: '',
|
||||
pubkey: pk,
|
||||
}, sk);
|
||||
|
||||
// 2. Publish event to local relay
|
||||
await new Promise((resolve, reject) => {
|
||||
const ws = new WebSocket(RELAY_URL);
|
||||
ws.on('open', () => {
|
||||
ws.send(JSON.stringify(['EVENT', event]));
|
||||
});
|
||||
ws.on('message', (msg) => {
|
||||
const data = JSON.parse(msg.toString());
|
||||
if (data[0] === 'OK') {
|
||||
ws.close();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
ws.on('error', (e) => {
|
||||
reject(e);
|
||||
});
|
||||
});
|
||||
|
||||
// 3. Construct nevent
|
||||
const nevent = nip19.neventEncode({
|
||||
id: event.id,
|
||||
relays: [RELAY_URL]
|
||||
});
|
||||
|
||||
// 4. Navigate
|
||||
const consoleMessages = [];
|
||||
page.on('console', msg => consoleMessages.push(msg.text()));
|
||||
|
||||
const errors = [];
|
||||
page.on('pageerror', err => {
|
||||
errors.push(err);
|
||||
console.log('PAGE ERROR:', err.message);
|
||||
});
|
||||
|
||||
// Force local storage cleanup or setup if needed
|
||||
// The memory said: "Frontend verification scripts using Playwright must inject localStorage.setItem('hasSeenDisclaimer', 'true')"
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem('hasSeenDisclaimer', 'true');
|
||||
});
|
||||
|
||||
const embedUrl = `/embed.html?pointer=${nevent}&playback=url`;
|
||||
await page.goto(embedUrl);
|
||||
|
||||
// 5. Wait for video attempt
|
||||
// We expect the status to change from "Loading video..."
|
||||
// If it crashes, it might not change, or it might change to "Resolving..." then crash.
|
||||
|
||||
// We wait for a bit to let the async playback logic run
|
||||
try {
|
||||
await expect(page.locator('#embedStatus')).not.toHaveText('Loading video…', { timeout: 5000 });
|
||||
await expect(page.locator('#embedStatus')).not.toHaveText('Resolving video…', { timeout: 5000 });
|
||||
} catch (e) {
|
||||
console.log('Timeout waiting for status change. Current status:', await page.locator('#embedStatus').textContent());
|
||||
}
|
||||
|
||||
// Check for the specific error
|
||||
const typeError = errors.find(e => e.message && e.message.includes('this.videoModal.resetStats is not a function'));
|
||||
if (typeError) {
|
||||
console.error('Reproduced TypeError:', typeError);
|
||||
// Fail the test
|
||||
expect(typeError).toBeUndefined();
|
||||
} else {
|
||||
console.log('No TypeError found.');
|
||||
}
|
||||
|
||||
// Log console for debugging
|
||||
console.log('Console output:', consoleMessages.join('\n'));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user