Add selectable fullscreen orientation and an iPhone landscape overlay

This commit is contained in:
Jonathan Sykes
2026-10-04 02:19:44 +08:00
parent d43cce441b
commit 536555e12d
8 changed files with 205 additions and 50 deletions

View File

@@ -0,0 +1,56 @@
const { test, expect } = require('@playwright/test');
const { openClassic, showPlayingFixture } = require('./helpers/classic-fixture');
for (const layout of ['classic', 'glass-stage']) test(`${layout}: portrait forced landscape controls and restore`, async ({ page }, testInfo) => {
await page.setViewportSize({ width: 390, height: 844 });
await openClassic(page, { populated: true }); await showPlayingFixture(page);
await page.evaluate(layout => {
data.settings.layout = layout; data.settings.fullscreenOrientation = 'landscape'; applyAppearance();
els.video.parentElement.requestFullscreen = undefined;
}, layout);
await page.locator('#fsBtn').click();
const stage = page.locator('.orientation-overlay');
await expect(stage).toHaveAttribute('data-fullscreen-rotation', '90');
await expect.poll(async () => Math.round((await stage.boundingBox()).height)).toBe(844);
const rect = await stage.boundingBox();
expect(Math.abs(rect.width - 390)).toBeLessThan(2); expect(Math.abs(rect.height - 844)).toBeLessThan(2);
for (const button of await stage.locator('.fullscreen-hud button').all()) {
const r = await button.boundingBox(); expect(r.x).toBeGreaterThanOrEqual(0); expect(r.y).toBeGreaterThanOrEqual(0); expect(r.x + r.width).toBeLessThanOrEqual(391); expect(r.y + r.height).toBeLessThanOrEqual(845);
}
await page.screenshot({ path: testInfo.outputPath(`${layout}-landscape.png`) });
await stage.getByRole('button', { name: 'Change fullscreen orientation' }).click();
await expect(stage).toHaveAttribute('data-fullscreen-rotation', '0');
await stage.getByRole('button', { name: 'Exit fullscreen' }).click();
await expect(page.locator('.orientation-overlay')).toHaveCount(0);
await expect(page.locator('.fullscreen-hud')).toBeHidden();
});
test('standard fullscreen requests the selected orientation and releases it', async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await openClassic(page, { populated: true }); await showPlayingFixture(page);
await page.evaluate(() => {
data.settings.fullscreenOrientation = 'landscape';
window.orientationCalls = [];
const stage = els.video.parentElement;
stage.requestFullscreen = async () => { Object.defineProperty(document, 'fullscreenElement', { configurable: true, value: stage }); };
document.exitFullscreen = async () => { Object.defineProperty(document, 'fullscreenElement', { configurable: true, value: null }); };
Object.defineProperty(screen, 'orientation', { configurable: true, value: { lock: async value => orientationCalls.push(value), unlock: () => orientationCalls.push('unlock') } });
});
await page.locator('#fsBtn').click();
await expect.poll(() => page.evaluate(() => orientationCalls)).toEqual(['landscape']);
await page.locator('.fullscreen-hud').getByRole('button', { name: 'Exit fullscreen' }).click();
expect(await page.evaluate(() => orientationCalls)).toEqual(['landscape', 'unlock']);
});
test('browser fullscreen exit restores a CSS fallback after orientation lock rejects', async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await openClassic(page, { populated: true }); await showPlayingFixture(page);
await page.evaluate(() => {
data.settings.fullscreenOrientation = 'landscape';
const stage = els.video.parentElement;
stage.requestFullscreen = async () => { Object.defineProperty(document, 'fullscreenElement', { configurable: true, value: stage }); };
Object.defineProperty(screen, 'orientation', { configurable: true, value: { lock: async () => { throw new Error('Unsupported'); } } });
});
await page.locator('#fsBtn').click();
await expect(page.locator('.orientation-overlay')).toHaveAttribute('data-fullscreen-rotation', '90');
await page.evaluate(() => { Object.defineProperty(document, 'fullscreenElement', { configurable: true, value: null }); document.dispatchEvent(new Event('fullscreenchange')); });
await expect(page.locator('.orientation-overlay')).toHaveCount(0);
await expect(page.locator('.fullscreen-hud')).toBeHidden();
});