47 lines
3.4 KiB
JavaScript
47 lines
3.4 KiB
JavaScript
const { test, expect } = require('@playwright/test');
|
|
const { execFileSync } = require('node:child_process');
|
|
const { openClassic } = require('./helpers/classic-fixture');
|
|
const { differentPixels } = require('./helpers/png-diff');
|
|
const { readFileSync } = require('node:fs');
|
|
const phoneCss = readFileSync('frontend/styles.css', 'utf8').replaceAll('(display-mode: standalone)', '(min-width: 0px)');
|
|
const beforeCss = execFileSync('git', ['show', '5e78374:frontend/theme-glass-controls.css'], { encoding: 'utf8' });
|
|
async function setup(page, layout) {
|
|
const phone = page.viewportSize().width === 390;
|
|
if (phone) await page.route('**/styles.css', route => route.fulfill({ contentType: 'text/css', body: phoneCss }));
|
|
await openClassic(page, { populated: true, standalone: phone, settings: { autoPreload: false } });
|
|
await page.addStyleTag({ content: '*,*::before,*::after{animation:none!important;transition:none!important;caret-color:transparent!important}#bottomNav{display:flex!important}' });
|
|
await page.evaluate(layout => { data.settings.layout = layout; applyAppearance(); view = { type: 'queue' }; render(); }, layout);
|
|
await page.evaluate(async () => { await document.fonts.ready; await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); });
|
|
}
|
|
for (const layout of ['glass-stage', 'classic']) for (const width of [390, 1440]) {
|
|
test(`${layout} bottom tabs at ${width}`, async ({ page, context }) => {
|
|
await page.setViewportSize({ width, height: 900 });
|
|
const before = await context.newPage(); await before.setViewportSize({ width, height: 900 });
|
|
await before.route('**/theme-glass-controls.css', route => route.fulfill({ contentType: 'text/css', body: beforeCss }));
|
|
await setup(before, layout);
|
|
const baseline = await before.screenshot({ path: `/tmp/ytplayer-done8-A-before-${layout}-${width}.png` });
|
|
await setup(page, layout);
|
|
const result = await page.screenshot({ path: `/tmp/ytplayer-done8-A-after-${layout}-${width}.png` });
|
|
if (layout === 'classic') {
|
|
const geometry = p => p.locator('.bottom-nav-btn,.bottom-nav-icon,.bottom-nav-label').evaluateAll(nodes => nodes.map(el => { const r = el.getBoundingClientRect(), s = getComputedStyle(el); return [r.x,r.y,r.width,r.height,s.padding,s.color,s.display]; }));
|
|
expect(await geometry(page)).toEqual(await geometry(before));
|
|
expect(differentPixels(baseline, result)).toBeLessThanOrEqual(32);
|
|
}
|
|
else {
|
|
const positions = await page.locator('.bottom-nav-btn').evaluateAll(buttons => buttons.map(button => {
|
|
const icon = button.querySelector('svg').getBoundingClientRect(), label = button.querySelector('.bottom-nav-label').getBoundingClientRect();
|
|
return { offset: Math.abs(icon.x + icon.width / 2 - label.x - label.width / 2), above: icon.bottom <= label.top, target: button.getBoundingClientRect().height };
|
|
}));
|
|
expect(positions.every(p => p.offset <= 1 && p.above && p.target >= 44)).toBe(true);
|
|
const badge = await page.locator('#bnQueueCount').evaluate(el => {
|
|
const icon = el.parentElement.querySelector('svg').getBoundingClientRect(), r = el.getBoundingClientRect();
|
|
return { x: r.left - icon.right, y: r.top - icon.top };
|
|
});
|
|
expect(Math.abs(badge.x)).toBeLessThanOrEqual(5);
|
|
expect(Math.abs(badge.y)).toBeLessThanOrEqual(5);
|
|
await expect(page.locator('.bottom-nav-btn.active')).toHaveAttribute('aria-label', 'Queue');
|
|
}
|
|
await before.close();
|
|
});
|
|
}
|