From 115229b3bca742834dbd412af1e9722e2ed3dd5f Mon Sep 17 00:00:00 2001 From: Sam Potts Date: Fri, 31 Jul 2026 11:38:48 +1000 Subject: [PATCH] fix(test): remove seek tests, add missing tests (#1892) --- apps/e2e/fixtures/selectors.ts | 5 +- apps/e2e/page-objects/player.ts | 8 + apps/e2e/tests/captions.spec.ts | 20 ++ apps/e2e/tests/video-controls.spec.ts | 209 ++++++++++++++++-- .../audio-html-default-vite-chromium.png | Bin 4098 -> 3924 bytes .../audio-html-default-vite-webkit.png | Bin 4946 -> 4639 bytes .../audio-react-default-vite-chromium.png | Bin 4098 -> 3922 bytes .../audio-react-default-vite-webkit.png | Bin 4937 -> 4639 bytes apps/e2e/tests/visual/video-skin.spec.ts | 5 +- packages/html/src/define/shared.css | 12 - .../src/default/css/components/reset.css | 2 + .../src/minimal/css/components/reset.css | 2 + packages/skins/src/shared/css/sr-only.css | 11 + 13 files changed, 232 insertions(+), 42 deletions(-) create mode 100644 packages/skins/src/shared/css/sr-only.css diff --git a/apps/e2e/fixtures/selectors.ts b/apps/e2e/fixtures/selectors.ts index 02252fff..d64ac418 100644 --- a/apps/e2e/fixtures/selectors.ts +++ b/apps/e2e/fixtures/selectors.ts @@ -69,7 +69,7 @@ export const SELECTORS = { // Sliders // HTML: , React: horizontal .media-slider inside .media-time-controls timeSlider: 'media-time-slider, .media-time-controls .media-slider', - volumeSlider: 'media-volume-slider, .media-slider[data-orientation="vertical"]', + volumeSlider: 'media-volume-slider, .media-popover--volume .media-slider', sliderThumb: 'media-slider-thumb, .media-slider__thumb', // Display elements @@ -81,11 +81,10 @@ export const SELECTORS = { '[data-type="duration"].media-time', '[data-type="remaining"].media-time', ].join(', '), - poster: 'media-poster, img[data-visible]', + poster: 'media-poster, img[data-loaded]', bufferingIndicator: 'media-buffering-indicator, .media-buffering-indicator', thumbnail: 'media-slider-thumbnail, .media-thumbnail__image', - // Popover & tooltip tooltip: 'media-tooltip, .media-tooltip', popover: 'media-popover, .media-popover', errorDialog: 'media-error-dialog, .media-error', diff --git a/apps/e2e/page-objects/player.ts b/apps/e2e/page-objects/player.ts index 2170d041..c598d02f 100644 --- a/apps/e2e/page-objects/player.ts +++ b/apps/e2e/page-objects/player.ts @@ -98,6 +98,14 @@ export class PlayerPage { return this.page.locator(SELECTORS.thumbnail).first(); } + get tooltip(): Locator { + return this.page.locator(SELECTORS.tooltip); + } + + get playTooltip(): Locator { + return this.tooltip.filter({ hasText: 'Play' }).first(); + } + get popover(): Locator { return this.page.locator(SELECTORS.popover).first(); } diff --git a/apps/e2e/tests/captions.spec.ts b/apps/e2e/tests/captions.spec.ts index f9d16f1e..407136a9 100644 --- a/apps/e2e/tests/captions.spec.ts +++ b/apps/e2e/tests/captions.spec.ts @@ -37,4 +37,24 @@ test.describe('Captions', () => { const options = page.locator(SELECTORS.activeMenuOptions); await expect(options).toHaveCount(2, { timeout: 5_000 }); }); + + test('captions button toggles captions', async ({ page }) => { + await page.evaluate(() => { + const video = document.querySelector('video') as HTMLVideoElement; + if (!video) return; + + const track = document.createElement('track'); + track.kind = 'subtitles'; + track.label = 'English'; + track.srclang = 'en'; + track.src = `data:text/vtt,${encodeURIComponent('WEBVTT\n\n00:00:00.000 --> 00:00:30.000\nTest caption')}`; + video.appendChild(track); + }); + + await player.showControls(); + await player.captionsButton.click(); + await expect(player.captionsButton).toHaveAttribute(DATA_ATTRS.active, ''); + await player.captionsButton.click(); + await expect(player.captionsButton).not.toHaveAttribute(DATA_ATTRS.active); + }); }); diff --git a/apps/e2e/tests/video-controls.spec.ts b/apps/e2e/tests/video-controls.spec.ts index 705ddaf9..49a7bee3 100644 --- a/apps/e2e/tests/video-controls.spec.ts +++ b/apps/e2e/tests/video-controls.spec.ts @@ -1,9 +1,89 @@ -import { expect, test } from '@playwright/test'; -import { ALL_VIDEO_PAGES, type PageEntry } from '../fixtures/media'; +import { expect, type Page, test } from '@playwright/test'; +import { ALL_VIDEO_PAGES, type PageEntry, VIDEO_PAGES } 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[]) { +const UI_VIDEO_PAGES = VIDEO_PAGES.filter(({ media }) => media === 'video'); + +function getMediaVolume(page: Page): Promise { + return page.evaluate((selector) => { + const media = document.querySelector(selector) as HTMLMediaElement | null; + const actual = (media?.querySelector?.('video') as HTMLMediaElement) ?? media; + return actual?.volume ?? 1; + }, SELECTORS.media); +} + +async function mockPresentation(page: Page): Promise { + await page.addInitScript(() => { + let fullscreenElement: Element | null = null; + let pipElement: Element | null = null; + + Object.defineProperties(document, { + fullscreenElement: { configurable: true, get: () => fullscreenElement }, + fullscreenEnabled: { configurable: true, get: () => true }, + pictureInPictureElement: { configurable: true, get: () => pipElement }, + pictureInPictureEnabled: { configurable: true, get: () => true }, + }); + + Object.defineProperty(HTMLElement.prototype, 'requestFullscreen', { + configurable: true, + value: async function requestFullscreen(this: HTMLElement) { + fullscreenElement = this; + document.dispatchEvent(new Event('fullscreenchange')); + }, + }); + + Object.defineProperty(document, 'exitFullscreen', { + configurable: true, + value: async () => { + fullscreenElement = null; + document.dispatchEvent(new Event('fullscreenchange')); + }, + }); + + Object.defineProperty(HTMLVideoElement.prototype, 'requestPictureInPicture', { + configurable: true, + value: async function requestPictureInPicture(this: HTMLVideoElement) { + pipElement = this; + this.dispatchEvent(new Event('enterpictureinpicture')); + return {}; + }, + }); + + Object.defineProperties(HTMLVideoElement.prototype, { + webkitPresentationMode: { + configurable: true, + get: function webkitPresentationMode(this: HTMLVideoElement) { + return pipElement === this ? 'picture-in-picture' : 'inline'; + }, + }, + webkitSetPresentationMode: { + configurable: true, + value: function webkitSetPresentationMode(this: HTMLVideoElement, mode: string) { + const wasPip = pipElement === this; + pipElement = mode === 'picture-in-picture' ? this : null; + + if (!wasPip && pipElement === this) { + this.dispatchEvent(new Event('enterpictureinpicture')); + } else if (wasPip && pipElement !== this) { + this.dispatchEvent(new Event('leavepictureinpicture')); + } + }, + }, + }); + + Object.defineProperty(document, 'exitPictureInPicture', { + configurable: true, + value: async () => { + const video = pipElement; + pipElement = null; + video?.dispatchEvent(new Event('leavepictureinpicture')); + }, + }); + }); +} + +for (const { name, path, skipBrowsers } of ALL_VIDEO_PAGES as readonly PageEntry[]) { const rateMenu = !path.includes('/cdn-video') && !path.includes('/ejected'); test.describe(`Video Controls — ${name}`, () => { test.skip(({ browserName }) => { @@ -20,10 +100,6 @@ for (const { name, path, media, skipBrowsers } of ALL_VIDEO_PAGES as readonly Pa // --- 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); @@ -47,15 +123,6 @@ for (const { name, path, media, skipBrowsers } of ALL_VIDEO_PAGES as readonly Pa await expect(player.playButton).toHaveAttribute(DATA_ATTRS.paused, ''); }); - // --- Seek --- - - test('seek forward advances playback', async () => { - test.skip(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 }) => { @@ -102,18 +169,112 @@ for (const { name, path, media, skipBrowsers } of ALL_VIDEO_PAGES as readonly Pa // --- Poster --- - test('poster hides after playback starts', async ({ page }) => { + test('poster hides after playback starts', async () => { + await expect(player.poster).toBeAttached(); await player.play(); - const posterVisible = await page.evaluate((attr) => { - const htmlPoster = document.querySelector('media-poster'); - if (htmlPoster) return htmlPoster.hasAttribute(attr); + await expect(player.poster).not.toHaveAttribute(DATA_ATTRS.visible); + }); + }); +} - const reactPoster = document.querySelector(`img[${attr}]`); - return !!reactPoster; - }, DATA_ATTRS.visible); +for (const { name, path } of UI_VIDEO_PAGES) { + test.describe(`Video Controls — ${name} UI`, () => { + let player: PlayerPage; - expect(posterVisible).toBe(false); + test.beforeEach(async ({ page }) => { + await mockPresentation(page); + player = new PlayerPage(page); + await page.goto(path); + await player.waitForMediaReady(); + }); + + test('volume slider changes volume', async ({ page }) => { + await player.showControls(); + await player.muteButton.hover(); + + await expect(player.volumeSlider).toBeVisible(); + + const box = await player.volumeSlider.boundingBox(); + if (!box) throw new Error('Volume slider not visible'); + + await page.mouse.click(box.x + box.width / 2, box.y + box.height * 0.75); + + await expect.poll(() => getMediaVolume(page)).toBeLessThan(0.5); + }); + + test('buffering indicator follows waiting state', async ({ page }) => { + await player.play(); + await page.evaluate((selector) => { + const media = document.querySelector(selector) as HTMLMediaElement | null; + const actual = (media?.querySelector?.('video') as HTMLMediaElement) ?? media; + if (!actual) return; + + Object.defineProperties(actual, { + paused: { configurable: true, get: () => false }, + readyState: { configurable: true, get: () => HTMLMediaElement.HAVE_CURRENT_DATA }, + }); + actual.dispatchEvent(new Event('waiting')); + }, SELECTORS.media); + + await expect(player.bufferingIndicator).toHaveAttribute(DATA_ATTRS.visible, '', { timeout: 2_000 }); + + await page.evaluate((selector) => { + const media = document.querySelector(selector) as HTMLMediaElement | null; + const actual = (media?.querySelector?.('video') as HTMLMediaElement) ?? media; + if (!actual) return; + + Object.defineProperty(actual, 'readyState', { + configurable: true, + get: () => HTMLMediaElement.HAVE_ENOUGH_DATA, + }); + actual.dispatchEvent(new Event('playing')); + }, SELECTORS.media); + + await expect(player.bufferingIndicator).not.toHaveAttribute(DATA_ATTRS.visible); + }); + + test('play button shows its tooltip on hover', async ({ page }) => { + await player.showControls(); + await player.playButton.hover(); + + await expect(player.playTooltip).toHaveAttribute(DATA_ATTRS.open, '', { timeout: 2_000 }); + }); + + test('play button reflects ended playback', async ({ page }) => { + await page.evaluate((selector) => { + const media = document.querySelector(selector) as HTMLMediaElement | null; + const actual = (media?.querySelector?.('video') as HTMLMediaElement) ?? media; + if (!actual) return; + + Object.defineProperties(actual, { + ended: { configurable: true, get: () => true }, + paused: { configurable: true, get: () => true }, + }); + actual.dispatchEvent(new Event('ended')); + }, SELECTORS.media); + + await expect(player.playButton).toHaveAttribute(DATA_ATTRS.ended, ''); + }); + + test('fullscreen button toggles fullscreen', async () => { + await expect(player.fullscreenButton).toHaveAttribute(DATA_ATTRS.availability, 'available'); + + await player.fullscreenButton.click(); + await expect(player.fullscreenButton).toHaveAttribute(DATA_ATTRS.fullscreen, ''); + + await player.fullscreenButton.click(); + await expect(player.fullscreenButton).not.toHaveAttribute(DATA_ATTRS.fullscreen); + }); + + test('PiP button toggles picture-in-picture', async () => { + await expect(player.pipButton).toHaveAttribute(DATA_ATTRS.availability, 'available'); + + await player.pipButton.click(); + await expect(player.pipButton).toHaveAttribute(DATA_ATTRS.pip, ''); + + await player.pipButton.click(); + await expect(player.pipButton).not.toHaveAttribute(DATA_ATTRS.pip); }); }); } diff --git a/apps/e2e/tests/visual/audio-skin.spec.ts-snapshots/audio-html-default-vite-chromium.png b/apps/e2e/tests/visual/audio-skin.spec.ts-snapshots/audio-html-default-vite-chromium.png index 6d719708dd6d83baa5f9ac30c52e9d035b1da6a3..7a95b8d2e8059aa0056b9c3bd60d007eea1621bc 100644 GIT binary patch literal 3924 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 literal 4098 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
  • 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 literal 4946 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�_8|PY?wO41n{*Kz-6VD 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 literal 4098 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
  • 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 literal 4937 zcmYjV1zc2H6DMWq1zoy%fZ)=lz)E*Y2q;K*gOV<|NSC704breQyR?*`G)l8{cS*;$ zJ|FLWzu&p{&b{}<%$%7y^Pg}n4Mk!C8UhRq3}R&^Ic*FKECV#n2e^a2_r1VrLq9M* zv=wDA;Qe&#=odLF17&Mv4Zy$*wZp*q-35Kopf3yz>`Y7yZ1fZJ_qR-}+rL-_ znb@~92H)?FsuYZj7#QSL%5u`W-k95IxKZ?alwG@yh$g$a3bD9yYsrLY_}=Rr*`;8-FkMd$;;ox zbLFQ0(TUnZDU#-U6t&>=(fSXRQC1t`2ay3W|7mNa zI4Vx+VI=`KS7YiaBHUpm6E+zr5a?MQE=4qRNn!{I{RU7Uz!_e6?Yds@?%y@#0ZjFY zK*NBmUkS37{PPt(I_~&juHCIIqLs==D~YUOTr_dW?{5t*!rlP>v?E2VC!2d`C$j;e zA-Muv75EeU`hlmqqYdZi(p)i5IMRrXsYF<~tO zOoL>2&4Rc%Dy<`a%A~mgN4XYCb^o0SP1N5F<6j?|8iN*l2;!F@StHbVTD6UyQQWEv zh)F3#{*03*PbKN)U4y09OvJKLbzCUJp8ptU!n)yjV=W_|l~u_GGB_pUP)}Y8A!STQ z!F~QyI}pZ&GpJ#Ezgib8Z7P3AfnV*7iZ*&n_U^I#tz2@MXu_|8=v1a&m-2^#I;ZK1=N z$qHrINQWL9iuzxkTAm-RJGTYlfAbiCtU5v~r`>z%^k4X}9j&9ebJLXAmwQ4qX>zO1 z%%CrZHfhW82Ik>;ki#Ke+ss;pum|V<<7S~}CjMt^XJ@M!s3Aqhw33FM`s=2XnFo(b zN5SSvVpm5$P@Ypxt8nypOSGfyj9a{WRn~G{pCRE>X?jF@#r!F$l(R8+wqTWFD z?69=p)^pb&SRG3A0hjwbX#Flyr+zxdL8SZCH?Cvqmkr@M#U+mK?L)3>F)iT*{r_O`kDRml)5Uk}nYZ7oZ5>5ALnAukEkE?C4YAszy&1Y6s-PP2FMw1NY z^kpyYlc3ytxYw!UeJ6niE0BXQ-b4SoVt73l3eim@!-E9$K;|NKb)8It+LjYc(!nj4 z2RrD!*ai{y#)$72JTV&bG74hh6wmH=1oBr`Yx^w4Do(RRf&&dlxT|^vc1H9~)V<^lk~)XE>({cg zn$bqdgvz7-+kIgRI0rKs`RXYv#}hV;=H4i6Rc=ta-E6=ObaIX}Kb1V4Q$l~?Xznd( z-V`mQ{m^vG*o)W+dVRJU4R6jnH?2OI@oOkSet%lsFSdEgT|3_PGWLXG=MxdNK!>s4 zcFh`W%Q<+(4D~g`8V{L52%fOZPy3MOH8Ww=aw^lrU0#)@!}Xz;1+-9BL?6>FKxw0- z1M9X|;6Eu0Sj!4+H1q=M>v2C}Zj#Grna5ANsXYH3!k;z5dMX29mv?xH>4Q-H$NXkX5$j)@g&gJ2N*L2rnbvuc8 zM<4OkXGS9SMQZZ=5D~4+%1(;sV9+P_#74*f*JIhf$OMU-%foNfHmPLinp+}Q2wOEUA+oH@;Fmlqy*j}FN+fE9C!~^8Z1HjQgKAlPD`1(y3+`4>?Hex&PS>OY-?h@J& zQ$>h97?xPF2mip*G9671?M56y5~RFjOL&pN7kSgNaghf6AuYF9%luM z{>XH{xjG4jSzZD-iXUP3#2b4~4Dw+2@HA{y&T-1{?$OOl0OIC-hSxqQew3qRHh=Yv zE#c@G%GPpo-Qb5Fib{5XhaIVKI3rJN6YJS}W64aiT6Ek-u~(C^ zoO8O*igI!Ip+UI{;bys#6=6?FJ_8P=4)|xM@1MAc_RWatjH;Rp?}c#Y>Y!Nn3Z`

    ZGmAHUqzpLhJ;|c|G8agTqI1(0HL(|3F`St9Im&SJ=URcBdms9ZDcyn zQhljIEDlrItEiuQ*H6JyN%_K?8Sr+?cV*u}XKzX*r^DAmJlBa&jQ9L!)zpmth0_T- zc-!a;TQdA`e~Q!TGpcj?3q;tuZGfl@zA_xRPV{|pT~W?GdUtI3>a)h{F|ObF!e9oz z={`q}7k5rk!$hrd$ARq|NkA3eQmTt$&GNq9N=eyPbv>)6(4mIfe*EPR^_$|t z3P$V7nj1vNBBf$UFFFgAwp<_=->&}ACW-5&S>Q+DZ~A(bs80S1lQ&rDv1PW4+(1}M z;5TVJ`g=td=|e%&KqPxFBmMY(WLPXGk-mJUdsX5?H*>!2%JkT`OBZvew($!0v;(-U zPWR?xl>g3Zto5))b_S3W0BwX(%;$T6uyT#qvDj5b5u#u}5zIs6G7_N^7R^F0?Q*Z@ za7`(%uPQ<6wL-?!T2tQ3U?kl3;aVZ4>g-%!Q!=nPgii$Wrd)+eP0InFf}b{d*D0iT z^OgE2zL>6OC7xG8p}j+Pv&aFRi#aZttbnGAIS+(mSa>{vCZ5~EcP+ngwA>NX$v8d_ z_R5(3-mt|%wZ0`I;TGxkvvR-55Zp^YS`rmFp9?H{-IvyG4S`NAUM4N&c%feD*BgCC zxnCsPjZR6Xav*0FJbeQ%%qUNm16c#8daUt}JS##TC+B{D&ew=Ak!|efa72&=`?nK| z9*IQo(OCrcq;#unM!ednIvZ=DimZUct^sGk%1UdUKpZPef`+lh&L)oku;H(&na|iW`*Qvg`H^Ax#`za zm-yPjS?ePh=4%RUN_IczS4nr)xJK?*7)SE&R8p0|l|QokXbbai0N;k$y{*1+o0Z70 z<*JU$X|u)$53?omB6}1$v@HU^C8`Q=UV>U+HmTx4V z4A?!Au15oiNvo%fE-YowpNmA*rhJj<80Y;^-C_-89kQ*T4)dQZOLk@6hs0ucfUQ8A z9Pg;hWEQdo1FRVAu&*X=f6w1r7HlyOm>r_j%+1{jWY%j9|YR{!i- z`(ST%v5g=-tMm>g^*?fCE}-`i_Ay9&m$$a{IQdVa-mS^BdzB=Frxy1eo$T%aAG z%VeXTJdoi77>V)^m#Y4C$lhX63#9l_By*pzj&VqQB=E8i@L>+Zk{c9PG_Y0f9itFXHkC z5ni)UQB<4|X)dKreMJm)AafOF>`2kV1sJ41aTPwVP4+jIuqA@AoUEolEAiajSs#a0 zrrA(2KXUCHH_M$8WF$MCm8y2$ba)g%^l&|%P=+OJL(Bc#SQgmBtY$F0k}`o<24DxI zdRF`&LJ`Ghf`>s^8Iq7I9cqR|Wu*4SpjH>?-AG@yTNJ~D^^0r{S|6X?x^K@U_^c+F zX?1_GYvA556B9wPXSc9I3dfol%b;vf8)pcOcUTW1@Ow6GlJ zUI4@dZ$T#PE18sFR@$JJEvFDDH(C;$iR5#N4Ni&m{QK~^Egp>EXC|SMXn}3hLKstd zqO|3{SbW_|a?gY+Iej6m<+s47h<^Y)8ZW-&c%vZmAnTt2<^#H>!MKsWU5)Yr8Z(-T z=XY-5$?x(4YzJphX}_t}mP3KWTGgBY+$hNhw~WmSp%XG|3o_lI5wup*vNE)yI2p_T zZ-rh0^eDCCXHueQG`NT5^ujqB$u**cT8b@Yb!95jI{8w6- z@|zQ)?C?Pa+s`Ts5mg!A0zt8IsuZ%M;^N}62PIE(6oLuJOdWak9QF;M5w}H&FsT3z zV2y?vON0%nnY_Tz8b!(HU@n3ZK(NXaN1c2P;&3HpOi6Tl_r!{DSqBs5wr!?;t|F|nRVc8GEGziS0&WL@CvZMIRk71bl}$JS zrFi&XtzeK6km*s0yNl`wzx&oKymyOLAqs#+Xcnj5`5uz@@^QkK1tuCB^M@>VrT295 z)bQ_aii?TKkN`R;bhh4fJmqxfj=YuRNCZ~kz{kW~kT@v(kwcS&S!=1roTb00sR^QH do7`Bx62L7M%!E4KtovQYQkK_{gUgr({tvzq3i<#5 diff --git a/apps/e2e/tests/visual/video-skin.spec.ts b/apps/e2e/tests/visual/video-skin.spec.ts index d17100f3..5007cf95 100644 --- a/apps/e2e/tests/visual/video-skin.spec.ts +++ b/apps/e2e/tests/visual/video-skin.spec.ts @@ -41,9 +41,8 @@ for (const { name, path } of VISUAL_PAGES) { await player.hoverTimeSlider(50); // Wait for thumbnail to finish loading (deterministic, no fixed timeout) - const thumbnail = page.locator(SELECTORS.thumbnail).first(); - await expect(thumbnail).toBeAttached({ timeout: 10_000 }); - await expect(thumbnail).not.toHaveAttribute(DATA_ATTRS.loading, { timeout: 10_000 }); + await expect(player.thumbnail).toBeAttached({ timeout: 10_000 }); + await expect(player.thumbnail).not.toHaveAttribute(DATA_ATTRS.loading, { timeout: 10_000 }); await expect(player.playerRoot).toHaveScreenshot(`video-${name.toLowerCase()}-storyboard.png`); }); diff --git a/packages/html/src/define/shared.css b/packages/html/src/define/shared.css index 5a0524b7..ddbfa53b 100644 --- a/packages/html/src/define/shared.css +++ b/packages/html/src/define/shared.css @@ -6,18 +6,6 @@ media-tooltip-group { display: contents; } -.media-sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - white-space: nowrap; - border: 0; - clip: rect(0, 0, 0, 0); -} - :host { /* `display:grid` fixes a weird issue with Safari when setting aspect-ratio */ display: grid; diff --git a/packages/skins/src/default/css/components/reset.css b/packages/skins/src/default/css/components/reset.css index cb3fcbd6..14dd57a2 100644 --- a/packages/skins/src/default/css/components/reset.css +++ b/packages/skins/src/default/css/components/reset.css @@ -1,3 +1,5 @@ +@import "../../../shared/css/sr-only.css"; + /* ========================================================================== Reset ========================================================================== */ diff --git a/packages/skins/src/minimal/css/components/reset.css b/packages/skins/src/minimal/css/components/reset.css index 6773da60..44ff3eba 100644 --- a/packages/skins/src/minimal/css/components/reset.css +++ b/packages/skins/src/minimal/css/components/reset.css @@ -1,3 +1,5 @@ +@import "../../../shared/css/sr-only.css"; + /* ========================================================================== Reset ========================================================================== */ diff --git a/packages/skins/src/shared/css/sr-only.css b/packages/skins/src/shared/css/sr-only.css new file mode 100644 index 00000000..c1004de5 --- /dev/null +++ b/packages/skins/src/shared/css/sr-only.css @@ -0,0 +1,11 @@ +.media-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + white-space: nowrap; + border: 0; + clip: rect(0, 0, 0, 0); +}