mirror of
https://github.com/zoriya/v10.git
synced 2026-08-05 05:37:21 +00:00
122 lines
4.6 KiB
TypeScript
122 lines
4.6 KiB
TypeScript
import { expect, test } from '@playwright/test';
|
|
import { ALL_VIDEO_PAGES, type PageEntry } from '../fixtures/media';
|
|
import { DATA_ATTRS, SELECTORS } from '../fixtures/selectors';
|
|
import { PlayerPage } from '../page-objects/player';
|
|
|
|
for (const { name, path, media, skipBrowsers } of ALL_VIDEO_PAGES as readonly PageEntry[]) {
|
|
/** Packaged skins use an inline rate control; CDN + site-ejected previews only expose nested settings menus. */
|
|
const skipsInlinePlaybackRateMenuTest = path.includes('/cdn-video') || path.includes('/ejected');
|
|
test.describe(`Video Controls — ${name}`, () => {
|
|
test.skip(({ browserName }) => {
|
|
return skipBrowsers?.includes(browserName as 'chromium' | 'webkit' | 'firefox') ?? false;
|
|
}, 'Skipped on this browser');
|
|
let player: PlayerPage;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
player = new PlayerPage(page);
|
|
await page.goto(path);
|
|
await player.waitForMediaReady();
|
|
});
|
|
|
|
// --- Grouped: control presence & attributes (one navigation) ---
|
|
|
|
test('all controls are present with correct attributes', async () => {
|
|
await expect(player.seekForward).toBeAttached();
|
|
await expect(player.seekForward).toHaveAttribute(DATA_ATTRS.direction, 'forward');
|
|
await expect(player.seekBackward).toBeAttached();
|
|
await expect(player.seekBackward).toHaveAttribute(DATA_ATTRS.direction, 'backward');
|
|
await expect(player.muteButton).toHaveAttribute(DATA_ATTRS.volumeLevel);
|
|
await expect(player.fullscreenButton).toHaveAttribute(DATA_ATTRS.availability);
|
|
await expect(player.pipButton).toHaveAttribute(DATA_ATTRS.availability);
|
|
await expect(player.captionsButton).toHaveAttribute(DATA_ATTRS.availability);
|
|
await expect(player.duration).not.toHaveText('');
|
|
await player.showControls();
|
|
await expect(player.controls).toBeAttached();
|
|
});
|
|
|
|
// --- Play / Pause ---
|
|
|
|
test('play button starts playback', async () => {
|
|
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, '');
|
|
await player.play();
|
|
await expect(player.playButton).not.toHaveAttribute(DATA_ATTRS.paused);
|
|
});
|
|
|
|
test('play button pauses playback', async () => {
|
|
await player.play();
|
|
await player.pause();
|
|
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, '');
|
|
});
|
|
|
|
// --- Seek ---
|
|
|
|
test('seek forward advances playback', async () => {
|
|
test.skip(media === 'simple-hls-video' || media === 'native-hls-video', 'seek before playback not yet supported');
|
|
|
|
await player.seekForward.click();
|
|
await expect(player.playButton).toHaveAttribute(DATA_ATTRS.started, '');
|
|
});
|
|
|
|
// --- Time Slider ---
|
|
|
|
test('time slider allows seeking', async ({ page }) => {
|
|
await player.seekTo(50);
|
|
|
|
await expect
|
|
.poll(
|
|
async () => {
|
|
return page.evaluate((selector) => {
|
|
const el = document.querySelector(selector);
|
|
const media = (el?.querySelector?.('video') as HTMLMediaElement) ?? (el as HTMLMediaElement);
|
|
return media?.currentTime ?? 0;
|
|
}, SELECTORS.media);
|
|
},
|
|
{ timeout: 10_000 }
|
|
)
|
|
.toBeGreaterThan(0);
|
|
});
|
|
|
|
test('time slider shows interactive state on hover', async () => {
|
|
await player.hoverTimeSlider(50);
|
|
await expect(player.timeSlider).toHaveAttribute(DATA_ATTRS.pointing, '');
|
|
});
|
|
|
|
// --- Mute ---
|
|
|
|
test('mute button toggles mute', async () => {
|
|
await expect(player.muteButton).toHaveAttribute(DATA_ATTRS.muted, '');
|
|
await player.muteButton.click();
|
|
await expect(player.muteButton).not.toHaveAttribute(DATA_ATTRS.muted);
|
|
await player.muteButton.click();
|
|
await expect(player.muteButton).toHaveAttribute(DATA_ATTRS.muted, '');
|
|
});
|
|
|
|
// --- Playback Rate ---
|
|
|
|
(skipsInlinePlaybackRateMenuTest ? test.skip : test)('playback rate menu changes selected rate', async () => {
|
|
const rateBtn = player.playbackRateButton;
|
|
const initialRate = await rateBtn.getAttribute(DATA_ATTRS.rate);
|
|
|
|
await player.selectAlternativePlaybackRate();
|
|
|
|
await expect.poll(async () => rateBtn.getAttribute(DATA_ATTRS.rate)).not.toBe(initialRate);
|
|
});
|
|
|
|
// --- Poster ---
|
|
|
|
test('poster hides after playback starts', async ({ page }) => {
|
|
await player.play();
|
|
|
|
const posterVisible = await page.evaluate((attr) => {
|
|
const htmlPoster = document.querySelector('media-poster');
|
|
if (htmlPoster) return htmlPoster.hasAttribute(attr);
|
|
|
|
const reactPoster = document.querySelector(`img[${attr}]`);
|
|
return !!reactPoster;
|
|
}, DATA_ATTRS.visible);
|
|
|
|
expect(posterVisible).toBe(false);
|
|
});
|
|
});
|
|
}
|