const { test, expect } = require('@playwright/test'); const { openClassic } = require('./helpers/classic-fixture'); const { mkdirSync } = require('node:fs'); const before = process.env.CAPTURE_BEFORE === '1'; for (const layout of ['classic', 'glass-stage']) for (const width of [390, 1440]) for (const screen of ['downloads', 'settings']) test(`${layout} ${width} ${screen}: failed download actions`, async ({ page }, info) => { await page.setViewportSize({ width, height: 844 }); await openClassic(page); await page.evaluate(({ layout, screen }) => { data.settings.layout = layout; applyAppearance(); window.actionCalls = []; Downloads.configure({ slots: () => 4, files: async () => [], playlists: () => [], jobs: () => [{ id: 'aaaaaaaaaaa', title: 'A long worship recording with piano, strings and choir — evening session', channel: 'Studio', thumbnail: '/fixture-cover.svg', status: 'failed', error: 'ERROR: [youtube] Video unavailable' }], action: (id, action) => actionCalls.push([id, action]) }); API.cacheList = async () => ({ ok: true, items: [], total: 0 }); view = { type: screen }; render(); }, { layout, screen }); if (screen === 'settings') await page.getByRole('button', { name: /Downloads & storage/ }).click(); const retry = page.getByRole('button', { name: /^Retry A long/ }); const cancel = page.getByRole('button', { name: /^Cancel A long/ }); await expect(retry).toBeVisible(); await expect(cancel).toBeVisible(); await retry.scrollIntoViewIfNeeded(); if (before) { mkdirSync('/home/josh/deliverables/ytplayer-done12', { recursive: true }); await page.screenshot({ path: `/home/josh/deliverables/ytplayer-done12/before-${layout}-${width}-${screen}-${info.project.name}.png` }); return; } for (const button of [retry, cancel]) { await expect(button.locator('svg')).toHaveAttribute('aria-hidden', 'true'); const rect = await button.boundingBox(); expect(rect.height).toBeGreaterThanOrEqual(44); expect(rect.width).toBeGreaterThanOrEqual(44); await expect(button.locator('span')).toHaveText(button === retry ? 'Retry' : 'Cancel'); } const a = await retry.boundingBox(), b = await cancel.boundingBox(); expect(a.x + a.width <= b.x || a.y + a.height <= b.y).toBe(true); const visual = await retry.evaluate(el => { const s = getComputedStyle(el), probe = document.createElement('span'); probe.style.backgroundColor = getComputedStyle(document.documentElement).getPropertyValue(document.documentElement.dataset.layout === 'glass-stage' ? '--tile' : '--bg-2').trim(); document.body.append(probe); const expected = getComputedStyle(probe).backgroundColor; probe.remove(); return { radius: s.borderRadius, background: s.backgroundColor, expected }; }); expect(visual.radius).toBe(layout === 'glass-stage' ? '18px' : '8px'); expect(visual.background).toBe(visual.expected); await page.keyboard.press('Tab'); await retry.focus(); expect(await retry.evaluate(el => getComputedStyle(el).outlineStyle)).not.toBe('none'); mkdirSync('/home/josh/deliverables/ytplayer-done12', { recursive: true }); await page.screenshot({ path: `/home/josh/deliverables/ytplayer-done12/after-${layout}-${width}-${screen}-${info.project.name}.png` }); await retry.click(); expect(await page.evaluate(() => actionCalls)).toContainEqual(['aaaaaaaaaaa', 'retry']); await cancel.click(); if (screen === 'downloads') await page.locator('.modal').getByRole('button', { name: 'Cancel save', exact: true }).click(); expect(await page.evaluate(() => actionCalls)).toContainEqual(['aaaaaaaaaaa', 'cancel']); });