Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: E2E Tests

on:
push:
branches:
- main
pull_request:
branches-ignore:
- 'rfc/**'

jobs:
e2e:
name: E2E (${{ matrix.browser }})
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.59.1-noble
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
# PRs: Chromium only for fast feedback (~2 min).
# Push to main: Chromium + WebKit for full coverage.
browser: ${{ github.event_name == 'push' && fromJson('["chromium","webkit"]') || fromJson('["chromium"]') }}

steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version-file: '.nvmrc'
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Cache turbo build
uses: actions/cache@v5
with:
path: .turbo
key: ${{ runner.os }}-turbo-e2e-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-e2e-
${{ runner.os }}-turbo-

- name: Build packages
run: pnpm build:packages

- name: Build CDN bundles
run: pnpm build:cdn

- name: Build ejected skins
run: pnpm -F site ejected-skins

- name: Run E2E tests
run: pnpm --dir apps/e2e exec playwright test --project=vite-${{ matrix.browser }}

- name: Upload test report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ matrix.browser }}
path: apps/e2e/playwright-report/
retention-days: 14

- name: Upload test traces
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-traces-${{ matrix.browser }}
path: apps/e2e/test-results/
retention-days: 7
3 changes: 3 additions & 0 deletions apps/e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
playwright-report/
test-results/
blob-report/
9 changes: 9 additions & 0 deletions apps/e2e/apps/vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@videojs/e2e-vite",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --host"
}
}
12 changes: 12 additions & 0 deletions apps/e2e/apps/vite/src/cdn-video-hls.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CDN Video HLS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./cdn-video-hls.ts"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions apps/e2e/apps/vite/src/cdn-video-hls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* CDN bundle test page — HLS.
*
* Imports the CDN video bundle + HLS media plugin. Uses a different HLS
* source (Elephants Dream) for media variety.
*/

import '@videojs/html/cdn/video';
import '@videojs/html/cdn/media/hls-video';
import { MEDIA } from './shared';

const html = String.raw;

document.getElementById('root')!.innerHTML = html`
<video-player>
<video-skin style="max-width: 800px; aspect-ratio: 16/9">
<hls-video src="${MEDIA.hls2.url}" playsinline crossorigin="anonymous">
<track kind="metadata" label="thumbnails" src="${MEDIA.hls2.storyboard}" default />
</hls-video>
<img slot="poster" src="${MEDIA.hls2.poster}" alt="Video poster" />
</video-skin>
</video-player>
`;
12 changes: 12 additions & 0 deletions apps/e2e/apps/vite/src/cdn-video-mp4.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CDN Video MP4</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./cdn-video-mp4.ts"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions apps/e2e/apps/vite/src/cdn-video-mp4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* CDN bundle test page — MP4.
*
* Imports from `@videojs/html/cdn/video` which is the self-contained CDN
* bundle. This tests a completely different code path from the workspace
* package imports used in the other test pages.
*/

import '@videojs/html/cdn/video';
import { MEDIA } from './shared';

const html = String.raw;

document.getElementById('root')!.innerHTML = html`
<video-player>
<video-skin style="max-width: 800px; aspect-ratio: 16/9">
<video src="${MEDIA.mp4.url}" playsinline crossorigin="anonymous">
<track kind="metadata" label="thumbnails" src="${MEDIA.mp4.storyboard}" default />
</video>
<img slot="poster" src="${MEDIA.mp4.poster}" alt="Video poster" />
</video-skin>
</video-player>
`;
12 changes: 12 additions & 0 deletions apps/e2e/apps/vite/src/ejected-html-video-mp4.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ejected HTML Video MP4</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./ejected-html-video-mp4.ts"></script>
</body>
</html>
45 changes: 45 additions & 0 deletions apps/e2e/apps/vite/src/ejected-html-video-mp4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Ejected HTML skin test page.
*
* Reads the actual output of `build-ejected-skins.ts` and renders it.
* This validates that the generated ejected HTML works end-to-end.
*/

// Register all UI custom elements (without the skin wrapper)
import '@videojs/html/video/ui';

// Import the generated ejected skins JSON
import ejectedSkins from '../../../../../site/src/content/ejected-skins.json';

interface EjectedSkinEntry {
id: string;
html?: string;
css?: string;
}

const skin = (ejectedSkins as EjectedSkinEntry[]).find((s) => s.id === 'default-video');

if (!skin?.html || !skin?.css) {
throw new Error('Ejected skin "default-video" not found. Run `pnpm -F site ejected-skins` first.');
}

// Inject the ejected CSS into the document
const style = document.createElement('style');
style.textContent = skin.css;
document.head.appendChild(style);

// The ejected HTML contains:
// <script type="module" src="...cdn..."></script>
// <link rel="stylesheet" href="./player.css">
// <video-player>...</video-player>
//
// Strip the <script> and <link> tags — we import modules via Vite instead.
// Extract just the <video-player>...</video-player> block.
const playerMatch = skin.html.match(/<video-player>[\s\S]*<\/video-player>/);

if (!playerMatch) {
throw new Error('Could not find <video-player> in ejected HTML output.');
}

const root = document.getElementById('root')!;
root.innerHTML = `<div style="max-width: 800px; aspect-ratio: 16/9">${playerMatch[0]}</div>`;
12 changes: 12 additions & 0 deletions apps/e2e/apps/vite/src/ejected-react-video-mp4.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ejected React Video MP4</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./ejected-react-video-mp4.tsx"></script>
</body>
</html>
Loading
Loading