73 lines
3.2 KiB
JavaScript
73 lines
3.2 KiB
JavaScript
/**
|
||
* Smoke test for the "Edit & download" custom-video feature (Task #68).
|
||
*
|
||
* The editor lets a user cut parts out of a video and save the result as a
|
||
* custom offline video that can be added to playlists like any other. This
|
||
* spec runs against the static frontend (no backend), so it exercises the
|
||
* pieces that don't need the yt-dlp/ffmpeg server round-trip:
|
||
* • video-edit.js loads and exposes window.VideoEdit with correct maths.
|
||
* • The now-playing "Edit & download" button (#editBtn) is present.
|
||
* • The editor modal opens, accepts a cut, and reports the right final
|
||
* length via the shared keep-segment maths.
|
||
*/
|
||
const { test, expect } = require('@playwright/test');
|
||
|
||
test.describe('Video editor — Edit & download', () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await page.goto('/');
|
||
await page.waitForSelector('.app', { state: 'attached' });
|
||
});
|
||
|
||
test('exposes window.VideoEdit with correct cut/keep maths', async ({ page }) => {
|
||
const ok = await page.evaluate(() => typeof window.VideoEdit === 'object' && window.VideoEdit !== null);
|
||
expect(ok).toBe(true);
|
||
|
||
const keep = await page.evaluate(() =>
|
||
window.VideoEdit.invertCuts([{ start: 10, end: 20 }], 60));
|
||
expect(keep).toEqual([{ start: 0, end: 10 }, { start: 20, end: 60 }]);
|
||
|
||
const param = await page.evaluate(() =>
|
||
window.VideoEdit.keepToParam(window.VideoEdit.invertCuts([{ start: 10, end: 20 }], 60)));
|
||
expect(param).toBe('0-10,20-60');
|
||
|
||
const finalLen = await page.evaluate(() =>
|
||
window.VideoEdit.keepDuration(window.VideoEdit.invertCuts([{ start: 10, end: 20 }], 60)));
|
||
expect(finalLen).toBe(50);
|
||
});
|
||
|
||
test('renders the now-playing Edit & download button', async ({ page }) => {
|
||
const btn = page.locator('#editBtn');
|
||
await expect(btn).toHaveCount(1);
|
||
await expect(btn).toContainText('Edit');
|
||
});
|
||
|
||
test('editor modal opens for a source video and computes the final length', async ({ page }) => {
|
||
// Drive openVideoEditor directly with a fake source that has a known
|
||
// duration, so the test doesn't depend on network playback. OPFS may be
|
||
// absent in the test browser; if so the editor toasts and returns — assert
|
||
// whichever path this browser takes so the test is deterministic.
|
||
const supported = await page.evaluate(() =>
|
||
!!(window.OPFS && window.OPFS.isSupported && window.OPFS.isSupported()));
|
||
|
||
const opened = await page.evaluate(() => {
|
||
window.openVideoEditor({ id: 'testsource1', title: 'Sample', duration: 100, thumbnail: '' });
|
||
const modal = document.getElementById('modal');
|
||
return modal && !modal.classList.contains('hidden');
|
||
});
|
||
|
||
if (!supported) {
|
||
// Without OPFS the editor declines to open — that's the correct guard.
|
||
expect(opened).toBe(false);
|
||
return;
|
||
}
|
||
|
||
expect(opened).toBe(true);
|
||
// Add a cut 0:10–0:40 → final length should be 100 - 30 = 70s = "1:10".
|
||
await page.fill('.video-editor .ve-from', '0:10');
|
||
await page.fill('.video-editor .ve-to', '0:40');
|
||
await page.click('.video-editor .ve-add');
|
||
await expect(page.locator('.video-editor .ve-cut')).toHaveCount(1);
|
||
await expect(page.locator('.video-editor .ve-summary')).toContainText('1:10');
|
||
});
|
||
});
|