Skip to content
Merged
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
17 changes: 17 additions & 0 deletions .github/scripts/test-autoplay.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ async function waitFor(page, predicate, { timeout = 5000, interval = 100 } = {})
throw new Error(`expected the cookie banner to be visible alongside ${overlayType}, but it wasn't`);
}

// Let the muted autoplay run for a few seconds before clicking, so
// currentTime has clearly moved past the intro - this is the whole
// point of the check below: a real visitor rarely clicks instantly,
// and the payoff should still start from the beginning regardless of
// how long the decoy held their attention.
await page.waitForTimeout(3000);
const beforeClickTime = await page.evaluate(() => document.getElementById('video').currentTime);
if (beforeClickTime < 1) {
throw new Error(`expected currentTime to have advanced past 1s after 3s of muted autoplay, got ${beforeClickTime}`);
}

await page.click(clickSelector);

const unmuted = await waitFor(page, () => {
Expand All @@ -88,6 +99,7 @@ async function waitFor(page, predicate, { timeout = 5000, interval = 100 } = {})
const cookie = document.querySelector(cookieSel);
return {
paused: v.paused,
currentTime: v.currentTime,
title: document.title,
overlayVisible: overlay ? !overlay.classList.contains('hidden') : null,
cookieVisible: cookie ? !cookie.classList.contains('hidden') : null
Expand All @@ -97,6 +109,11 @@ async function waitFor(page, predicate, { timeout = 5000, interval = 100 } = {})
if (after.paused) {
throw new Error('expected video to still be playing after unmuting');
}
// The whole point of a rickroll is the intro - a visitor who takes a
// while to click shouldn't hear the song mid-way through instead.
if (after.currentTime >= 1) {
throw new Error(`expected video to restart from the beginning on reveal, but currentTime was ${after.currentTime}s right after clicking (was ${beforeClickTime}s before)`);
}
if (after.title !== 'Rickroll') {
throw new Error(`expected title "Rickroll" after interaction, got "${after.title}"`);
}
Expand Down
36 changes: 29 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ jobs:
file: ./Dockerfile
load: true
tags: rickroll:test
# Same video-fetch stage as ghcr-publish.yml, and this
# workflow always builds the same default VIDEO_URL - caching
# it means CI stops re-downloading the video on every run.
cache-from: type=gha,scope=test
cache-to: type=gha,mode=max,scope=test

- name: Start container with default env vars
run: docker run -d --name rickroll-default -p 8080:8080 rickroll:test
Expand Down Expand Up @@ -157,15 +162,32 @@ jobs:
with:
node-version: 24

- name: Install Playwright
- name: Install Playwright package
run: |
npm init -y >/dev/null
npm install --no-save playwright@1
# Firefox gets its own engine check alongside Chromium - it's
# historically the most divergent on autoplay/gesture policy
# enforcement of the mainstream browsers, so a bug that's fine
# under one can still be broken under the other.
npx playwright install --with-deps chromium firefox
# Pinned exact version, not a floating "playwright@1" - the
# cache key below is keyed on this version, and an unpinned
# install could silently resolve a newer release whose browser
# binaries no longer match a stale cache.
npm install --no-save playwright@1.61.1

- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-1.61.1

- name: Install Playwright OS dependencies
run: npx playwright install-deps chromium firefox

- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
# Firefox gets its own engine check alongside Chromium - it's
# historically the most divergent on autoplay/gesture policy
# enforcement of the mainstream browsers, so a bug that's fine
# under one can still be broken under the other.
run: npx playwright install chromium firefox

- name: Start container with OVERLAY=error
run: docker run -d --name rickroll-error -p 8080:8080 -e OVERLAY=error rickroll:test
Expand Down
7 changes: 7 additions & 0 deletions scripts/index/80-index.sh
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,13 @@ tee /usr/share/nginx/html/index.html << EOF >/dev/null
var events = ['click', 'keydown'];

function reveal() {
// The video's been playing muted since page load, so by
// the time the decoy actually gets clicked - anywhere
// from a second to minutes later - it's already well
// past the intro. Jump back to the start so the payoff
// always lands on the actual song opening, not wherever
// playback happened to be.
video.currentTime = 0;
video.muted = false;
video.play().catch(function () {});
document.title = title;
Expand Down
Loading