Files
ytplayer/tests/download-retry.spec.js

73 lines
4.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { test, expect } = require('@playwright/test');
const { openClassic } = require('./helpers/classic-fixture');
const id = 'wZzRoXymOUU';
for (const layout of ['classic', 'glass-stage']) for (const screen of ['downloads', 'settings']) {
test(`${layout} ${screen}: Retry starts a fresh server job before preparation`, async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await openClassic(page, { settings: { autoPreload: false } });
const requests = [];
await page.route(`**/api/download/${id}/retry`, route => {
requests.push('retry:' + route.request().method());
return route.fulfill({ status: 202, contentType: 'application/json', body: '{"ok":true,"state":"working"}' });
});
await page.route(`**/api/download/${id}/prepare*`, route => {
requests.push('prepare');
return route.fulfill({ contentType: 'application/json', body: '{"ok":true,"state":"ready","etag":"fixture","size":4096,"ext":"mp4"}' });
});
await page.evaluate(({ layout, screen, id }) => {
data.settings.layout = layout; applyAppearance();
window.OPFS.isSupported = () => true;
window.OPFS.downloadVideo = async () => ({ ok: true, size: 4096 });
SaveQueue.add({ id, title: 'Rock Medley', channel: 'Petra - Topic' });
SaveQueue.state(id, 'failed', `ERROR: [youtube] ${id}: Video unavailable`);
view = { type: screen }; render();
}, { layout, screen, id });
if (screen === 'settings') await page.locator('[data-section="downloads-storage"]').click();
await page.getByRole('button', { name: 'Retry Rock Medley', exact: true }).click();
await expect.poll(() => requests).toEqual(['retry:POST', 'prepare']);
await expect.poll(() => page.evaluate(id => cachedIds.has(id), id)).toBe(true);
expect(await page.evaluate(() => SaveQueue.pending().length)).toBe(0);
});
}
test('normal resumptions do not force the server to restart a cache job', async ({ page }) => {
await openClassic(page, { settings: { autoPreload: false } });
let retries = 0;
await page.route(`**/api/download/${id}/retry`, route => { retries++; return route.fulfill({ contentType: 'application/json', body: '{"ok":true}' }); });
await page.route(`**/api/download/${id}/prepare*`, route => route.fulfill({ contentType: 'application/json', body: '{"ok":true,"state":"ready","etag":"fixture","size":4096}' }));
await page.evaluate(async id => {
window.OPFS.isSupported = () => true;
window.OPFS.downloadVideo = async () => ({ ok: true, size: 4096 });
await preload({ id, title: 'Rock Medley' }, { quiet: true });
}, id);
expect(retries).toBe(0);
expect(await page.evaluate(id => cachedIds.has(id), id)).toBe(true);
});
for (const layout of ['classic', 'glass-stage']) for (const width of [390, 1440]) for (const screen of ['downloads', 'settings']) {
test(`${layout} ${width} ${screen}: friendly failure retains safe technical details`, async ({ page }) => {
await page.setViewportSize({ width, height: 844 });
await openClassic(page, { settings: { autoPreload: false } });
const raw = `ERROR: [youtube] ${id}: Video unavailable\nYouTube clients tried: default, web_embedded, web_safari\n<script>window.unsafeDetail=true</script>`;
await page.evaluate(({ layout, screen, id, raw }) => {
data.settings.layout = layout; applyAppearance();
SaveQueue.add({ id, title: 'Rock Medley', channel: 'Petra - Topic' });
SaveQueue.state(id, 'failed', raw);
view = { type: screen }; render();
}, { layout, screen, id, raw });
if (screen === 'settings') await page.locator('[data-section="downloads-storage"]').click();
const row = page.locator(screen === 'settings' ? '.download-job' : '.dl-failed').first();
await expect(row).toContainText('YouTube isn’t letting the server save this video.');
await expect(row.locator('pre')).toBeHidden();
const summary = row.locator('summary');
expect((await summary.boundingBox()).height).toBeGreaterThanOrEqual(44);
await summary.click();
await expect(row.locator('pre')).toHaveText(raw);
expect(await page.evaluate(() => window.unsafeDetail)).toBeUndefined();
const bounds = await row.evaluate(el => ({ width: el.clientWidth, content: el.scrollWidth, children: [...el.querySelectorAll('*')].filter(child => child.scrollWidth > child.clientWidth + 1).map(child => [child.tagName, child.className, child.clientWidth, child.scrollWidth]) }));
expect(bounds.content <= bounds.width + 1, JSON.stringify(bounds)).toBe(true);
await expect(row.getByRole('button', { name: 'Retry Rock Medley', exact: true })).toBeVisible();
});
}