Files
ytplayer/tests/settings-sections.spec.js

84 lines
7.9 KiB
JavaScript
Raw 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');
for (const layout of ['classic', 'glass-stage']) for (const width of [390, 1440]) {
test(`${layout} settings navigation at ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 }); await openClassic(page);
await page.evaluate(layout => { data.settings.layout = layout; applyAppearance(); view = { type: 'settings' }; render(); }, layout);
await expect(page.locator('.settings-section-row').first()).toBeVisible();
await expect(page.locator('#setQuality')).toHaveCount(1);
if (width === 390) await expect(page.locator('#setQuality')).toBeHidden();
await page.locator('.settings-search input').fill('default quality');
await page.locator('.settings-results button').first().click();
await expect(page.locator('#setQuality')).toBeVisible();
await page.locator('#setQuality').selectOption('720p');
expect(await page.evaluate(() => data.settings.quality)).toBe('720p');
if (width === 390) { await page.goBack(); await expect(page.locator('.settings-overview')).toBeVisible(); await expect(page.locator('#setQuality')).toBeHidden(); }
await page.locator('.settings-section-row[data-section="appearance"]').click();
await expect(page.locator('#setTheme')).toBeVisible();
await page.locator('#setTheme').selectOption('light');
expect(await page.evaluate(() => data.settings.theme)).toBe('light');
await expect(page.locator('#setQuality')).toHaveValue('720p');
expect(await page.evaluate(() => sessionStorage.getItem('ytpSettingsSection'))).toBe('appearance');
const overflow = await page.locator('.settings-browser').evaluate(el => el.scrollWidth > el.clientWidth + 1); expect(overflow).toBe(false);
});
}
test('floating lyrics move the real view and restore it on close', async ({ page }) => {
await page.addInitScript(() => { window.documentPictureInPicture = { requestWindow: async () => window.open('about:blank', 'lyrics-test', 'width=420,height=500') }; });
await openClassic(page);
const popupPromise = page.waitForEvent('popup');
await page.locator('#stageLyricsAuto').evaluate(el => el.nextElementSibling.click());
const popup = await popupPromise;
await expect(popup.locator('#stageLyrics')).toBeVisible();
await expect(popup.getByRole('button', { name: 'Play / Pause', exact: true })).toBeVisible();
await expect(page.locator('#stageLyrics')).toHaveCount(0);
await popup.close(); await expect(page.locator('#stageLyrics')).toHaveCount(1);
});
test('OBS lower third has a transparent background and renders two cues', async ({ page }) => {
await page.route('**/api/**', route => route.fulfill({ contentType: 'application/json', body: '{"ok":false}' }));
await page.goto('/?overlay=lowerthird&code=123456');
await page.evaluate(() => LowerThird.paint([{ kind: 'line', text: 'Current lyric' }, { kind: 'line', text: 'Next lyric' }], 0));
await expect(page.locator('.obs-current')).toHaveText('Current lyric'); await expect(page.locator('.obs-next')).toHaveText('Next lyric');
expect(await page.evaluate(() => getComputedStyle(document.body).backgroundColor)).toBe('rgba(0, 0, 0, 0)');
await expect(page.locator('#searchInput')).toBeHidden();
});
test('setlist import confirms library matches and retains key tags', async ({ page }) => {
await openClassic(page, { populated: true }); await page.evaluate(() => SetlistImport.open());
await page.getByLabel('Setlist text', { exact: true }).fill('1. A quiet morning — live studio session [E]');
await page.getByRole('button', { name: 'Find matches', exact: true }).click();
await expect(page.getByLabel('Match A quiet morning — live studio session', { exact: true })).toHaveValue('preview0000');
await page.getByRole('button', { name: 'Create setlist', exact: true }).click();
expect(await page.evaluate(() => data.playlists.at(-1).videos[0].tags)).toContain('Key E');
});
for (const layout of ['classic', 'glass-stage']) for (const width of [390, 1440]) test(`${layout} Car mode at ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 }); await openClassic(page); await page.evaluate(layout => { data.settings.layout = layout; applyAppearance(); CarMode.open(); }, layout);
await expect(page.getByRole('dialog', { name: 'Car mode' })).toBeVisible();
expect(await page.locator('.car-controls button').first().evaluate(el => el.getBoundingClientRect().height)).toBeGreaterThanOrEqual(100);
expect(await page.locator('.app').evaluate(el => el.inert)).toBe(true);
await page.getByRole('button', { name: 'Exit Car mode' }).click(); await expect(page.locator('.car-mode')).toHaveCount(0); expect(await page.locator('.app').evaluate(el => el.inert)).toBe(false);
});
for (const layout of ['classic', 'glass-stage']) for (const width of [390, 1440]) test(`${layout} ten-band EQ at ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 }); await openClassic(page, { settings: { eq: { preset: 'custom', g: [6,2,-2,4,0] } } });
await page.evaluate(layout => { data.settings.layout = layout; applyAppearance(); EQ.open(); }, layout);
await expect(page.locator('.eq-band input')).toHaveCount(10);
expect(await page.evaluate(() => data.settings.eq.g.length)).toBe(10);
await page.getByRole('button', { name: 'Vocal clarity', exact: true }).click();
expect(await page.evaluate(() => data.settings.eq.g[7])).toBe(4);
expect(await page.locator('.eq-panel').evaluate(el => el.scrollWidth <= el.clientWidth + 1)).toBe(true);
});
for (const layout of ['classic', 'glass-stage']) test(`${layout} secondary lyrics in stage and Service mode`, async ({ page }) => {
await openClassic(page); await page.route('**/api/notes/0gfX0dFLaBc', route => route.fulfill({ contentType: 'application/json', body: JSON.stringify({ ok:true, lyrics:{rev:1,data:{offset:0,lines:[{t:0,text:'主你的恩典',secondary:'Your grace is enough',phonetic:'zhǔ nǐ de ēndiǎn',kind:'line'}]}}, chapters:null }) }));
await page.evaluate(async layout => { data.settings.layout = layout; applyAppearance(); current = {meta:{id:'0gfX0dFLaBc',title:'Fixture'}}; await Notes.load(current.meta); Notes.stageLyrics.set(true); }, layout);
await expect(page.locator('#stageLyricsList .lyric-secondary').first()).toHaveText('Your grace is enough');
await page.evaluate(() => { $('serviceMode').classList.remove('hidden'); data.settings.serviceLyrics = true; Notes.serviceRefresh(); });
await expect(page.locator('#serviceLyricsList .lyric-phonetic')).toHaveText('zhǔ nǐ de ēndiǎn');
expect(await page.locator('#serviceLyricsList .lyric-secondary').first().evaluate(el => parseFloat(getComputedStyle(el).fontSize) < parseFloat(getComputedStyle(el.parentElement).fontSize))).toBe(true);
});
for (const layout of ['classic', 'glass-stage']) for (const width of [390,1440]) test(`${layout} piano settings stay lazy at ${width}px`, async ({ page }) => {
const models=[];page.on('request',req=>{if(/esm\.sh|jsdelivr.*basic-pitch/.test(req.url()))models.push(req.url());});
await page.setViewportSize({width,height:900});await openClassic(page);await page.evaluate(layout=>{data.settings.layout=layout;applyAppearance();current={meta:{id:'0gfX0dFLaBc',title:'Piano fixture',duration:200}};view={type:'settings'};render();},layout);
await page.locator('[data-section="piano"]').click();await expect(page.getByRole('button',{name:'Transcribe in browser',exact:true})).toBeDisabled();
await page.locator('#settings-section-piano input[type="checkbox"]').check();await expect(page.getByRole('button',{name:'Transcribe in browser',exact:true})).toBeEnabled();
await page.getByRole('button',{name:'Add current 8 s to practice',exact:true}).click();await expect(page.locator('.piano-practice button').first()).toHaveText('Loop 0.0–8.0 s');
expect(models).toEqual([]);expect(await page.locator('#settings-section-piano').evaluate(el=>el.scrollWidth<=el.clientWidth+1)).toBe(true);
});