Files
KoalaSync/tests/e2e/README.md
T
KoalaDev 36e1291d2c feat: rank player candidates by ordered signals, add browser E2E suite
The weighted score summed incomparable units, so size could outvote traits
that disqualify an element outright. Measured on a real page: a display:none
preload reports its full 1080p intrinsic size and scored 2073600, beating a
visible unmuted player at 509920.

Selection now compares an ordered list of signals, highest priority first:
has a source, is rendered, is not a silent background loop, rendered size
bucket, is playing, has controls, duration. Rendered size replaces intrinsic
resolution, and mute state is gone from the ranking entirely: it is a viewer
preference, not evidence about which element is the player.

It stays a ranking rather than a filter, so a page of only bad candidates
still yields one and findVideo never returns null where a video exists.

The new tests/e2e suite runs the shipped finder against real fixture pages
and drives the packed extension for injection, reinjection and remote
play/pause/seek into a first-party frame. All five scoring scenarios fail
against the previous implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 07:23:12 +02:00

2.8 KiB

Extension E2E smoke tests

Browser-level tests for the parts that unit tests cannot reach: which <video> the extension picks on a real page, and whether the packed extension gets far enough to control it.

npm run test:e2e:install   # once, downloads the browsers
npm run build:extension    # extension.spec.mjs loads dist/chrome
npm run test:e2e

Layout

Path Purpose
detection.spec.mjs Runs the shipped findVideo() against the fixture pages
extension.spec.mjs Loads dist/chrome, injects into a tab, applies remote play/pause/seek
fixture-server.mjs Static server for the fixtures, with byte-range support for media
fixtures/pages/ One page per scenario
fixtures/media/ Small generated clips (see below)
helpers/content-source.mjs Lifts the real finder out of extension/content.js

Two rules worth keeping

The specs run the shipped source, not a copy. helpers/content-source.mjs extracts findVideo and its ranking helpers straight out of extension/content.js. A fixture that passes against a reimplementation would prove nothing about the extension. If you split the finder into more functions, add them to VIDEO_FINDER_EXPORTS there and to VIDEO_FINDER_PARTS in scripts/test-content-video-finder.cjs, or the extraction fails loudly.

Each fixture marks its own answer. The element that must win carries data-expected; videos that have to be playing carry data-autoplay, and ready.js holds the page back until metadata and playback have settled. The specs assert those preconditions before judging the finder, so a broken fixture reads as a broken fixture instead of a scoring regression.

Scenarios

Fixture What it pins down
simple-player.html The ordinary case
iframe-player.html Player inside a same-origin frame, empty top document
late-frame.html Player frame attached after the page settled
shadow-player.html Player in a shadow root, tiny teaser in the light DOM
muted-player.html Mute must not disqualify the only player
hidden-preload.html A display:none preload still reports 1080p; it must lose
ad-frame.html 1080p asset in a 300x250 ad slot must lose to the real player
background-loop.html Silent looping hero must lose despite being the largest
multi-player.html Between equal players, the playing one wins
sourceless.html A large <video> with no source can never be the player

Regenerating the media

Solid-colour clips, a few KB each, committed so the suite needs no network:

ffmpeg -y -f lavfi -i "color=c=blue:s=1920x1080:d=30:r=10" -c:v libx264 -preset veryfast -crf 45 -pix_fmt yuv420p -movflags +faststart fixtures/media/player-1080p-30s.mp4

Same command with green/854x480/12, red/640x360/5 and gray/1280x720/3 for the other three.