|
1 | 1 | --- |
| 2 | +import { fileURLToPath } from 'node:url' |
| 3 | +
|
| 4 | +// Read the source-mode chunk list at SSR time so the HTML ships |
| 5 | +// with <link rel="modulepreload"> for every shared chunk already |
| 6 | +// in <head>. The browser starts warming the HTTP cache during |
| 7 | +// initial parse — well before any JS runs — which side-steps the |
| 8 | +// concurrent-fetch race that makes WebKit occasionally fail spec |
| 9 | +// iframes with the opaque "Importing a module script failed." |
| 10 | +// error. `prebuild` always runs bundle-tests.mjs before Astro |
| 11 | +// builds the site, so manifest.json is guaranteed to exist. |
| 12 | +const manifestPath = fileURLToPath(new URL('../../public/tests/source/manifest.json', import.meta.url)) |
| 13 | +const sourceChunks: string[] = (await Bun.file(manifestPath).json()).chunks ?? [] |
| 14 | +
|
2 | 15 | // TKO Browser Test Runner — written in TKO itself. |
3 | 16 | // |
4 | 17 | // Two modes: |
|
32 | 45 | <title>TKO · Browser Tests</title> |
33 | 46 | <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Lobster&display=swap" /> |
34 | 47 | <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/mocha@10/mocha.css" /> |
| 48 | + {sourceChunks.map(name => <link rel="modulepreload" href={`/tests/source/${name}`} />)} |
| 49 | + <link rel="preload" as="script" href="/tests/source/setup.js" /> |
35 | 50 | <style> |
36 | 51 | :root { |
37 | 52 | --bg: #0b0d11; |
|
362 | 377 | self.pkg = ko.observable(safePkg) |
363 | 378 | self.ver = ko.observable(safeVer) |
364 | 379 | self.grep = ko.observable(qs.get('grep') || '') |
365 | | - // Pool for the parallel (non-focus) phase. Focus-needing |
| 380 | + // Pool for the parallel-hidden run. Focus-needing |
366 | 381 | // specs — flagged at bundle time via `manifest.specs[].needsFocus` |
367 | 382 | // — always run serially in the visible #workarea so each |
368 | 383 | // has sole system focus; Chromium only grants |
|
520 | 535 | const res = await fetch('/tests/source/manifest.json') |
521 | 536 | const manifest = await res.json() |
522 | 537 | let specs = manifest.specs |
| 538 | + |
523 | 539 | const grep = page.grep().trim() |
524 | 540 | if (grep) { |
525 | 541 | // Invalid regex patterns (e.g. bare `(`) throw from the |
|
632 | 648 | }) |
633 | 649 | } |
634 | 650 |
|
635 | | - // Phase 1: parallel hidden specs. |
| 651 | + // Parallel-hidden run: non-focus specs, `pool`-at-a-time |
| 652 | + // inside the offscreen `hiddenHost`. The <link rel=modulepreload> |
| 653 | + // tags in <head> warmed the HTTP cache, so iframes can |
| 654 | + // race on dynamic import() without tripping WebKit's |
| 655 | + // dependency-tree fetcher. |
636 | 656 | async function hiddenWorker() { |
637 | 657 | while (hiddenQueue.length) { |
638 | 658 | const spec = hiddenQueue.shift() |
|
642 | 662 | } |
643 | 663 | await Promise.all(Array.from({ length: page.pool }, hiddenWorker)) |
644 | 664 |
|
645 | | - // Phase 2: serial focus specs in the visible workarea. |
| 665 | + // Serial-focus run: one focus-needing spec at a time in |
| 666 | + // the visible #workarea so each has sole system focus. |
646 | 667 | for (const spec of focusQueue) { |
647 | 668 | await runOne(spec, { host: workarea, label: workareaLabel, grantFocus: true }) |
648 | 669 | } |
|
0 commit comments