Files
ytplayer/tests/classic-layout.spec.js
2026-10-03 06:44:22 +08:00

104 lines
6.2 KiB
JavaScript

const { test, expect } = require('@playwright/test');
const { openClassic, showPlayingFixture } = require('./helpers/classic-fixture');
for (const width of [320, 390, 768, 1024, 1280, 1440]) {
test(`empty home is unclipped at ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 });
await openClassic(page);
const result = await page.evaluate(() => {
const stage = document.querySelector('.player-stage').getBoundingClientRect();
const hero = document.querySelector('.hero').getBoundingClientRect();
const chips = [...document.querySelectorAll('.hero .chip')].map(el => el.getBoundingClientRect());
return { stageBottom: stage.bottom, heroBottom: hero.bottom, stageTop: stage.top, heroTop: hero.top,
chipsFit: chips.every(r => r.right <= innerWidth && r.left >= 0 && r.bottom <= stage.bottom),
overflow: document.querySelector('.main').scrollWidth > document.querySelector('.main').clientWidth + 1 };
});
expect(result.heroTop).toBeGreaterThanOrEqual(result.stageTop);
expect(result.heroBottom).toBeLessThanOrEqual(result.stageBottom + 1);
expect(result.chipsFit).toBe(true);
expect(result.overflow).toBe(false);
await expect(page.locator('#bottomNav')).toBeVisible({ visible: width <= 860 });
});
}
for (const standalone of [false, true]) {
test(`navigation during playback and mini-player return (${standalone ? 'PWA' : 'browser'})`, async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await openClassic(page, { populated: true, standalone });
await showPlayingFixture(page);
await expect(page.locator('#back10Btn')).toBeVisible();
await expect(page.locator('#fwd10Btn')).toBeVisible();
await page.locator('#bottomNav [data-view="settings"]').click();
await expect(page.locator('.settings')).toBeVisible();
await expect.poll(() => page.locator('.list-pane').evaluate(el => el.getBoundingClientRect().top)).toBeLessThan(130);
await expect(page.locator('#miniBar')).toBeVisible();
const boxes = await page.evaluate(() => ({
mini: document.getElementById('miniBar').getBoundingClientRect().bottom,
nav: document.getElementById('bottomNav').getBoundingClientRect().top,
}));
expect(boxes.mini).toBeLessThanOrEqual(boxes.nav + 1);
await page.locator('.body').evaluate(el => { el.scrollTop = el.scrollHeight; });
const last = page.locator('.settings .set-group').last();
await expect(last).toBeInViewport();
expect(await last.evaluate(el => el.getBoundingClientRect().bottom)).toBeLessThanOrEqual(boxes.nav);
await page.locator('#miniTitle').click();
await expect.poll(() => page.locator('.body').evaluate(el => el.scrollTop)).toBe(0);
expect(await page.evaluate(() => window.scrollY)).toBe(0);
await page.locator('#ctlMoreBtn').click();
await expect(page.locator('#modal')).toBeVisible();
});
}
test('playlist, appearance settings, rotation, and layout switching preserve data', async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 960 });
await openClassic(page, { populated: true });
await expect(page.locator('#homePlGrid')).toContainText('Studio sessions');
await showPlayingFixture(page);
expect(await page.locator('.list-pane').evaluate(el => el.getBoundingClientRect().width)).toBeGreaterThanOrEqual(340);
expect(await page.locator('.card-info').first().evaluate(el => el.getBoundingClientRect().width)).toBeGreaterThan(120);
const original = await page.evaluate(() => JSON.stringify(data.playlists));
for (const theme of ['light', 'contrast', 'dark']) {
await page.evaluate(theme => { data.settings.theme = theme; applyAppearance(); }, theme);
expect(await page.locator('.hero-title').evaluate(el => getComputedStyle(el).webkitTextFillColor)).not.toBe('rgba(0, 0, 0, 0)');
}
for (const layout of ['glass-stage', 'sanctuary-stage', 'classic']) {
await page.evaluate(layout => { data.settings.layout = layout; applyAppearance(); }, layout);
await expect(page.locator('html')).toHaveAttribute('data-layout', layout);
expect(await page.evaluate(() => JSON.stringify(data.playlists))).toBe(original);
}
await page.setViewportSize({ width: 844, height: 390 });
await page.locator('#bottomNav [data-view="history"]').click();
await expect(page.locator('#listTitle')).toHaveText('History');
await page.setViewportSize({ width: 390, height: 844 });
await page.evaluate(() => { data.settings.fontScale = 'xl'; data.settings.density = 'compact'; applyAppearance(); });
await expect(page.locator('#bottomNav [data-view="settings"]')).toBeInViewport();
expect(await page.evaluate(() => document.querySelector('.main').scrollWidth <= document.querySelector('.main').clientWidth + 1)).toBe(true);
});
test('320px with extra-large text keeps navigation and controls reachable', async ({ page }) => {
await page.setViewportSize({ width: 320, height: 844 });
await openClassic(page, { populated: true, settings: { fontScale: 'xl' } });
await showPlayingFixture(page);
await expect(page.locator('#bottomNav [data-view="settings"]')).toBeInViewport();
expect(await page.locator('#controls').evaluate(el => el.scrollWidth <= el.clientWidth + 1)).toBe(true);
expect(await page.locator('.app').evaluate(el => Math.abs(el.getBoundingClientRect().height - innerHeight))).toBeLessThan(2);
expect(await page.locator('#bottomNav').evaluate(el => el.scrollWidth <= el.clientWidth + 1)).toBe(true);
await page.locator('#bottomNav [data-view="settings"]').click();
await expect(page.locator('.settings')).toBeVisible();
});
test.describe('Classic offline shell', () => {
test.use({ serviceWorkers: 'allow' });
test('caches the Classic stylesheet and restores it offline', async ({ page, context }) => {
await openClassic(page);
await page.evaluate(() => navigator.serviceWorker.ready);
await page.reload();
await page.waitForFunction(() => !!navigator.serviceWorker.controller);
expect(await page.evaluate(async () => !!(await caches.match('/theme-classic.css')))).toBe(true);
await context.setOffline(true);
await page.reload();
await expect(page.locator('html')).toHaveAttribute('data-layout', 'classic');
expect(await page.locator('html').evaluate(el => getComputedStyle(el).getPropertyValue('--bg').trim())).toBe('#121315');
});
});