Repository navigation
test: CI without demo video sites, tests that check what they say, harness fixes - #314
Merged
Merged
Conversation
…y name The property "resolves null when the length prefix is 0 or past MaxMessageBytes" wrote a 0-length header before the generated one, so every run settled before the generated length was read, and its fc.assert was not awaited: a host that accepted an over-limit length passed it, and a failing run showed up only as an unnamed unhandled rejection. It now writes one header per run, leaves the input open (an end would settle an accepted length with null too) and is awaited. "reads a message right at the limit" read a body 13 bytes under it; it is now exactly MaxMessageBytes, with a companion one byte over through the same frame path. An ESLint rule flags an unawaited fc.assert of an fc.asyncProperty in tests/. Mutation-checked: a cap raised to MaxMessageBytes * 100 fails the property (counterexample 2097152) and the one-byte-over case; a '>=' at the host's length check fails the at-limit case. Both survived before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a scanner
contentMessages.test.mjs scanned content.js by hand for the arguments of
each chrome.runtime.sendMessage call. A quote that never closed (an
apostrophe in a comment, a quote in a regex) sent the scan back to the
start of the file: with `(r) => { /* don't */ }` next to a callback, the
file ran 23-54 s and ended in "no tests" or a RangeError instead of
naming the bare call after it.
It now parses content.js with acorn (already a devDependency, used by
tools/ast-compare.mjs and recut-patch) and checks the call nodes: each has
a function as its last of two or more arguments, or is the one call with a
.catch, inside notifyBackground and sending its own argument.
Checked: with the issue's two probe calls appended to content.js, the new
test fails in 0.2 s naming content.js:2000 (the bare PROBE2 call); the old
one ran 23 s and reported no tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Connection's gaps - HLSDecrypt "fails the segment when its key or IV is missing" only ever lacked the key, so HLSFragmentRequester's missing-IV branch was never taken. It is now one case each. - MpvBackend's "keeps Referer and Origin" and "keeps lowercase variants" asserted only a length of 2; they now assert the headers picked. - MpvBackend.testConnection (the options page's "Test mpv connection") had no test: the ping and its mpvPath, mpv found or not, the host unreachable (lastError) and a throw. - TabTracker's hasPlayer, getMainPlayer, add/removeChildFrame, getFrames, createFrame, removeFrame and the tracker's tab methods had none either. Mutation-checked, each failing the new test and passing before: the IV check reduced to `!key`; testConnection ignoring lastError, always reporting mpv, or dropping mpvPath; hasPlayer counting grandchildren; getMainPlayer without its player-URL check; removeTab keeping the saved state; removeChildFrame keeping the parent link. Part of #254 (items 1 and 6). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st's
URLUtils.get_url_extension took whatever followed the last dot of the
whole URL. For a URL with no extension that was the host's last label and
the path ("https://e.com/stream" gave "com/stream"), so DirectVideoPlayer's
`|| 'webm'` fallback never applied and a save of such a source was named
with ".com/stream" as its extension; and a bare host such as
https://example.mp4 was taken for an MP4 stream. A unit test pinned the
"com/stream" answer.
It now reads the extension of the last path segment only, after the
scheme and host (file names, which SaveManager passes, have neither).
Wherever the last segment has a dot, the answer is the same as before.
Tests: no extension gives '', the host gives nothing (a property over
fc.webUrl origins), a file name still works, and the extension never
holds '/' or '.'. With the old implementation 5 of them fail.
Part of #254 (item 2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…of it The migrateKeybinds tests built their input with mergedOver, a private re-implementation of what Utils.mergeOptions does with the keybinds. A change to mergeOptions (its null and array handling, say) went unseen there. They now call Utils.mergeOptions(DefaultOptions, saved), as Utils.getOptionsFromStorage does. Mutation-checked: with mergeOptions ignoring saved nested objects, 12 of these tests fail; the old file passed all 56. Part of #254 (item 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iled test Real time: - mpvIpcRequest's tests gave a real pipe 200-400 ms budgets, so a loaded runner could take longer than the connect budget just to connect. The pipe stays real; the budgets now run on fake timers, moved on by the test once its request has reached the server. - StreamLengths' "reads at most four at once" and vadModel's "waits for a run in progress" slept 10 ms where all they need is the promise work done: they wait one turn of the event loop (setImmediate) instead. Clean-up: - MpvNativeHost's pipeName() left an fs-ipc-* folder per test on Linux. - DownloadEntry restored console.error only when the test passed, and DashLoader and e2eHarness restored their spies (and a temp folder) after the asserts: a failure left them for the rest of the file. All now restore in afterEach. Mutation-checked: mpvIpcRequest keeping the connect budget after connecting, reporting a silent instance as a timeout, or ignoring a connect error each fail one IPC test; StreamLengths with MAX_ACTIVE 5 and the VAD release not waiting for a run fail theirs. Part of #254 (items 4 and 5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nge until watched hls-live and mp4-fragmented-end both served on 41887. That held only while specs never run at once and each closes its server; a worker killed at the mocha cap leaves one open. mp4-fragmented-end moves to 41889, and e2ePorts.test.mjs now fails when two servers share a port (it named 41887 and these two files before the move). The spec's server answered the second range 6 s after it was asked for, and the test only started watching once 7 s were buffered. Where the player's start takes long (the Windows runner), the 6 s were gone by then, the watch loop ran zero times and the test failed "expected 0 to be greater than 3" with the player doing the right thing. The server now holds that answer until the test has watched the stream ten times (about 2.5 s) and releases it; the test also waits for the request itself, with its own message if it never comes. `after` releases a held answer, so close() does not wait on it. e2e: not run here (it launches Firefox); the file parses and lints, CI runs it. Fixes #261. Part of #262 (item 1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fsaunpack/testserver.mjs called app.listen(port) with no host, so express listened on every interface, with Access-Control-Allow-Origin: * on each file. The archive it serves is a recording of a stream, manifests with the CDN's tokens included: a developer serving one on a shared network served it to everyone there. Every other test server here binds 127.0.0.1; this one now does too. verify-fsaunpack (pnpm run verify, CI) now also connects to the machine's first non-loopback IPv4 address and fails if the server answers there. Checked with a self-ending probe that runs the server in-process on a small archive: the old server answered on 192.168.0.41 (this PC's LAN address), the new one only on 127.0.0.1. verify-fsaunpack itself was not run here (its npm ci would write into the shared node_modules); CI runs it. Fixes #259. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…them streams.e2e.mjs cached the npm releases it serves to its pages in tests/e2e/live-specs/fixtures/live-libs, which no .gitignore entry covers (only tests/e2e/fixtures/ is ignored): after one `pnpm run test:live`, git status showed about 1.5 MB of third-party bundles, one `git add -A` away from the tree. The comment said "next to the suite's gitignored fixtures directory" and CLAUDE.md "in the OS temp dir"; neither was so. The cache is now tests/e2e/fixtures/live-libs, inside the ignored directory (git check-ignore: the old path is not ignored, the new one is), and the comment and CLAUDE.md say where it is. Fixes #260. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
playback.e2e.mjs played test-streams.mux.dev's HLS and dash.akamaized.net's DASH, and save-video.e2e.mjs saved both, in the web suite that ci.yml runs on Linux and Windows and auto-release waits for. Either host slow or down timed those cases out twice (spec retry), turned CI red and held back the release, though CLAUDE.md says third-party streams are never part of CI. They are gone. The local cases already cover the same paths: playback's hls-ts, hls-fmp4, hls-audio and the four dash-* fixtures; save-video's local MPEG-TS, fMP4 and separate-audio HLS saves (the chunkMeta regression is on the fMP4 path); and save-fmp4's DASH save, which decodes the file and counts its frames, a stronger check than the remote DASH case's "over 1 MB". Real streams stay in the live suite. A unit test now fails when a spec under specs/, ext-specs/, classic-specs/ or pbm-specs/ names a public host (it named both hosts with the old playback spec put back). e2e: not run here; the files parse and lint, CI runs them. Fixes #255. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every e2e fixture is made from sample.mp4, fetched from test-videos.co.uk, and the only check on the download was its ftyp box. The specs count on its frames (300 at 30 fps, 250 of them B-frames, fmp4-bframes, hls-fmp4-cut's -frames:v 298, the 96/300 frame expectations): a host that re-encoded the file would move them all at once, with nothing saying why. mp4Fixture.mjs now pins the file (991017 bytes, SHA-256 77145c94..., checked with ffprobe on 2026-10-03: H.264 High, 640x360, 300 frames, 250 B, no audio). A download that is another file fails with "the MP4 fixture changed upstream", naming both. A local copy is checked on each run too (1 MB, milliseconds): one that is another file is fetched again, and the fixtures made from it are removed for the suites to make again. Run here against the real host: a fresh download passes the pin; a garbage sample.mp4 beside a made-up dash-template and long-av.mp4 is fetched again and those two are removed (live-libs kept); a third run does nothing. mp4FixtureMismatch has unit tests; with its hash compare removed, the same-size case fails. The host being down still fails every e2e job; a cache or a committed copy is the owner's call (see #256). Part of #256. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fixtures made from sample.mp4 were rebuilt only when their marker (expected.json, .complete, or a non-empty file) was missing, never when the ffmpeg arguments that make them changed. CI starts from nothing and picked a change up; a developer's fixtures directory, or verify:linux's tree, kept the old fixture: "passes locally, fails on CI". The builders move from wdio.conf.mjs to tests/e2e/buildFixtures.mjs, unchanged but for how each decides it is built. Each now keeps a recipe (a hash of its builder's code, its own arguments, this machine's H.264 encoder and the MP4 fixture's pin) in <file>.recipe or <dir>/.recipe, written last, and is built again when the recipe differs. sample-av.mp4 (analyzer.e2e.mjs and video-delay.e2e.mjs) was made in both specs' before hooks straight to its final name; with +faststart, a run killed while ffmpeg wrote it left a file without a moov that both specs then trusted. It is now built with the others, through writeFixture. The extension config builds them as well, so test:ext alone works on a fresh clone (source-length needs long-av.mp4 and hls-ts). Run here in Node with the local ffmpeg (no browser): all fixtures built in 6.7 s; a second run 0.2 s with no file touched; after changing an argument in the WebM and HLS builders, exactly sample.webm and the three HLS directories were rebuilt. e2e: not run here; the files parse and lint, CI runs them. Fixes #263. Part of #262 (item 2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
importText dispatched the file picker's change, paused 300 ms and read the alerts. The page reads the file (FileReader) before it answers, so on a loaded runner the alert came later, importText returned [] and "says so when the file is no settings file" failed with the page doing the right thing. It now waits up to 10 s for the alert. The import that must say nothing waits for its value (seekStepSize 7) to be saved, then checks that nothing was alerted. e2e: not run here; the file parses and lints, CI runs it. Fixes #262 (item 3; items 1 and 2 in the commits before). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Five parts of #265: - save-flow's this.timeout(180000) did nothing under WebdriverIO (mocha's cap is the config's 120 s), and its wait was one executeAsync polling up to 120 s, past WebDriver's 30 s script timeout and the cap, so the "settled: false" outcome it was built to log never was. It now polls from the spec once a second for at most 75 s and logs the page state either way. The private-browsing spec's three dead this.timeout calls are gone. - storage.e2e.mjs: "falls through to the next backend" returned early, reported as passed, when OPFS was not in FSBlob's chain. It now skips visibly, and the first case asserts usedOPFS (true on both CI jobs' logs of 2026-10-02, run 37065133847). - The web config's traversal guard compared startsWith(base) without a separator, so /fixtures/../fixtures-other/x passed for any sibling named like it. It is serveFile.mjs's resolveInside now, which needs base + path.sep, with unit tests (a plain startsWith fails them). - mozLog.mjs kept a MOZ_LOG only when afterTest saw a failure, but a failed hook (loader-retry's server not starting in before: the case the log is for) reaches no afterTest, so that log was deleted as passed. afterHook now marks the attempt failed, and an attempt in which no test ran keeps its log. Unit tests; each half fails without its line. - example/embed.html says it must be served over http, and says so on the page when opened as a file: its target origin is then "null", which postMessage refuses. Left: the sound pin on CI (item 2, an owner decision) and the stall comments (item 7, low confidence; needs repeated e2e runs). e2e: not run here; the files parse and lint, CI runs them. Part of #265. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s past the first wdio.extension.conf.mjs served every /fixtures/ request whole, with 200 and Accept-Ranges: none, while the web config answers ranges and says why they matter. On the 1 MB sample.mp4, which fits MP4Player's first range, save-flow, save-dialog-regression, save-transport, embed-page-query and the private-window MP4 case all passed; nothing in the extension suites would show accelerated MP4 broken on a real multi-range file, and a fix for #139 (refusing a 200 for a Range request) could break them. The /fixtures/ route now answers Range with 206 or 416 through serveFile.byteRange, as the web config does; embed-page-query's /stream proxy passes the player's Range on and the answer back. save-flow has a new case: the embedded player on long-av.mp4 (17 MB, 160 s, now made by the extension config too) seeks to 100 s and must play on there, in MP4Player. Checked in Node by running the config's own onPrepare and onComplete (with a stand-in package so it loads): whole file 200; bytes=0-999999 of sample.mp4 206 "0-991016/991017"; past its end 416; long-av.mp4's second MB 206 with 1000000 bytes; bytes=-8 the last 8. The new case is not run here (it launches Firefox); CI runs it. Fixes #257. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unInPage extension.e2e, save-transport and vad still opened the extension page and switched to the newest window handle. A fresh temporary install opens welcome.html at no fixed moment, on the same origin, so a startsWith check passed on it: "serves its player page from the extension origin" could pass on the welcome page, and save-transport's probes ran there. All three now use extension-page.mjs's openExtensionPage, which finds the page by its URL, and the first test also asserts the page's path. runInPage had three copies. save-transport's cleared window.____err (four underscores) while its catch wrote window.__err, and it and extension.e2e reported a page-side throw by e.stack alone, which in Firefox holds only the frames. One shared tests/e2e/runInPage.mjs now has modules.e2e's format (message, then stack), and all three specs use it. e2e: not run here; the files parse and lint, CI runs them. Fixes #264. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…exists sources-browser-ui.e2e.mjs lives in specs/, which only the web config runs, so its isExt branch never ran: it only checked that nothing was sent from a page with no chrome.runtime. Nothing anywhere sent the clear and looked at the background afterwards; removing the CLEAR_SOURCES call from SourcesBrowser.mjs, or its handler from background.mjs, left every suite green. The web spec's dead case is gone (its header says where the extension half is). embed-page-query.e2e.mjs, which already opens the player over a page with a detected stream, has a new case: the player's list lists the page's file; Clear empties it; the player then asks the background for the page's sources (REQUEST_SOURCES, as it does when it loads) and the background's answer must be an empty list. It asks again until it is, for up to 15 s, so a request that overtakes the clear message, or a later re-detection, cannot fail it; without the handler it is never empty. e2e: not run here; the files parse and lint, CI runs them. Fixes #258. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h unit tests stryker.config.mjs mutated 15 modules, while about 25 more pure-logic modules with unit tests were left out of the weekly report: a gap like SpeedTracker's prune (#251) is exactly what the run would show. Counted with Stryker's own instrumenter (dry runs, 2026-10-03): the 15 are 3,833 mutants; ten small ones (SpeedTracker, OpQueue, StallWatchdog, SourceBufferWrapper, FrameStepper, LargeBuffer, TimestampRebaser, ptsNormalize, ManifestTypes, HLSDecrypter) are 441, and are added; the initial test run passes with them instrumented. The rest are 2,790 (the downloader, loaders, LevelManager, SyncedAudioPlayer and others) plus 3,084 (tools and e2e harness modules): over twice the run, past the job's 240-minute limit before the first weekly run has said how long it takes. The config comment lists them and says why they wait, and that the mpv host's Windows-only tests never run in the Linux job, so its PowerShell and WMI mutants can only survive. Part of #253. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t they waited for From the #266 proposals, the small ones: - source-length.e2e.mjs had its own range server: bytes=5-2 made createReadStream throw inside the request listener, which takes the worker down, and a read error went unhandled. It now uses the harness's byteRange and sendFile (serveFile.mjs), as both configs do: 416 for that range, a destroyed response for a failed read. - subtitle-search, hls-live and mp4-loading had waits with no timeout message (two of subtitle-search's on WebdriverIO's default 5 s, failing with its generic "waitUntil condition timed out"); each now names what never came, and those two get 15 s. - playback's expectEveryHlsSegmentListed swallowed its wait's timeout and went on to compare two lists; it now logs how many fragments were listed of how many, and that the playlist never arrived. e2e: not run here; the files parse and lint, CI runs them. Part of #266. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The case added for #257 opened the embed page with browser.url() while the driver was still in the player frame the save case before it left it in, and browser.url() navigates the frame the driver is in. It now switches to the top level first, as CLAUDE.md asks of every spec that switches into a frame. Found reviewing the e2e changes, which are not run here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ch the file For the Actions cache of sample.mp4 (#256, next commit): the e2e setup needs the SHA-256 the file is pinned to, as its cache key, and a way to check a restored file the way a fetched one is checked. tests/e2e/mp4FixtureCli.mjs: `pin` prints MP4_FIXTURE_PIN's SHA-256; `ensure` runs ensureMp4Fixture and says what it found, for the job's log. ensureMp4Fixture now returns that: kept (the pinned file was there), fetched (none was) or replaced (another file was, with how it differed). Its callers only awaited it. Run here: `pin` prints 77145c94...; `ensure` with the pinned file says kept; with a 3-byte file, replaced ("it had 3 bytes, expected 991017") and the file is the pinned one again; with none, fetched; another command exits 2 with its usage. Part of #256. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…refox on Linux #256: every e2e job fetched sample.mp4 from test-videos.co.uk, so that host being down failed every e2e job on both systems. The e2e setup now restores it from the Actions cache under the SHA-256 it is pinned to (actions/cache/restore and save, v6.1.0 by commit, as the repository's other cache steps), checks it with `node tests/e2e/mp4FixtureCli.mjs ensure` (a restored file that is not the pinned one is fetched again), and saves it only after that check, only when the cache had no entry. The host is needed once per cache entry, not once per job. #265: the specs that listen to the player (firefox.e2e's 8x pin, audio-tools) skipped on every CI job: the Linux runner has no sound server, so Firefox's AudioContext stayed "suspended" (CI run 37065133847 logged it on both jobs). On Linux the e2e setup now installs PulseAudio when it is missing (GitHub's Ubuntu 24.04 and 26.04 images list neither PulseAudio nor PipeWire), starts it with no idle exit, loads a null sink "faststream_e2e", makes it the default, exports PULSE_SERVER and E2E_SOUND_SINK, and logs `pactl info` and the sinks. A sound server already running is used as it is. The daemon belongs to the job; the runner ends it with the job's other processes. tests/e2e/soundCheck.mjs decides: no sound skips a case, as before, except on Linux CI, where it fails it, naming the sink and the server. The Windows runner has no audio endpoint (the same log: "suspended" there too) and keeps skipping. Tests: - tests/workflows/e2e-setup.test.sh runs the sound step against stub pactl, pulseaudio, sudo and apt-get (PATH holds only bash and sed besides): fresh runner, installed, already running, daemon failing, sink failing, apt failing three times; and the pin step's output. Eight mutations of the step each fail it (no default sink, no unix: prefix, no running-server check, an idle exit, no E2E_SOUND_SINK, one apt attempt, another output name, no install check). - tests/unit/e2eSetupAction.test.mjs checks the cache wiring: order, key, path (mp4Fixture's own), save only on a miss, pinned SHAs. Five mutations each fail it. - tests/unit/soundCheck.test.mjs: Linux CI only; skip elsewhere, fail there with the sink and server named. Four mutations each fail it. Not run here: the e2e jobs themselves; this pull request's CI is the proof. actionlint and the workflow suite pass (WSL). Fixes #256. Part of #265 (item 2; items 1, 3-6 in 827cc97; item 7 left). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rough (CodeQL js/path-injection) CodeQL flagged the test server's file reads (wdio.conf.mjs, and serveFile.mjs's createReadStream): the request path reaches them through resolveInside, whose check was `abs === base || abs.startsWith(base + path.sep) ? abs : null`, and CodeQL takes only the startsWith half as a check. It now returns abs where startsWith holds, and base itself (no request data) for the directory, so every path it returns is one CodeQL sees checked. What it returns is unchanged: the same as before for 14 paths, among them the unit test's cases, '/..', '/../fixtures-other/x.mp4' and '//x'. Checked with CodeQL 2.27.1, the suite and threat model this repository's code scanning uses (security-extended, local). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017JiuRmQkMrNTDSUbPnwKsn
…ting (CodeQL js/user-controlled-bypass) CodeQL counts process.exit() as a security decision, and the two command checks above it as a bypass of it. It is the script's last statement, so process.exitCode = 2 ends the run with the same status (checked: "bogus" and no argument exit 2 with the usage line, as before; pin prints the pin and exits 0). Checked with CodeQL 2.27.1, the suite and threat model this repository's code scanning uses (security-extended, local): no new alert left but mp4Fixture.mjs's http-to-file-access, main's own one moved down the file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017JiuRmQkMrNTDSUbPnwKsn
Brings in the other code-review PRs (#237, #300, #302-#313). Conflicts, each kept from both sides: - storage.e2e.mjs: main's per-identifier loop, plus this branch's usedOPFS check. - subtitle-search.e2e.mjs: main's OpenSubtitles DOWNLOAD_LINK, plus this branch's wait timeouts. - TabTracker.test.mjs: main's and this branch's new describe blocks. - MpvNativeHost.test.mjs: main's imports (a superset). - MpvNativeHostReadMessage.property.test.mjs: main's version of the over-size test, which matches #303's host (an over-size length now waits for the body and answers TooLarge, null only when the input ends). And one test that merged cleanly but no longer held: mpvHostSecurity's "refuses a message one byte over the limit" now expects TooLarge, the answer #303 gives once the message has been read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JzfFWJzzaUDto87UaqoJGy
Nawid3333
marked this pull request as ready for review
October 3, 2026 20:31
11 tasks
Owner
Author
|
The red Generated by Claude Code |
…ayer was handed #306 (#288) keeps what a page frame handed its player (handedTo), so a player that loads again in its frame gets its stream back. CLEAR_SOURCES emptied every frame's source list but not that record, so the player's next REQUEST_SOURCES sent the cleared stream again: embed-page-query.e2e.mjs's new Clear test (#258) got [1] on every ask on Firefox Beta, once this branch had #306 from main. CLEAR_SOURCES now also calls forgetHandedToPlayer() on every frame. Unit tests drive the real background: a player asking again still gets its stream, and gets nothing after a Clear (fails without the fix). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JzfFWJzzaUDto87UaqoJGy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Test suite fixes: CI no longer depends on demo video sites, tests check what their names say, harness fixes
What was wrong:
com/stream, andhttps://example.mp4was taken for an MP4 file.What changed:
How it's proven: lint, typecheck and 997 unit tests pass, and the new CI steps have their own tests (each checked to fail with its part taken out). The end-to-end changes weren't run locally (they launch Firefox, and the sound device exists only on CI); this PR's CI runs them.
Fixes #250
Fixes #252
Fixes #254
Fixes #255
Fixes #256
Fixes #257
Fixes #258
Fixes #259
Fixes #260
Fixes #261
Fixes #262
Fixes #263
Fixes #264
Not fixed here (your call):
🤖 Generated with Claude Code