diff --git a/bin/setup.ts b/bin/setup.ts index 9fad0c1..8712e43 100755 --- a/bin/setup.ts +++ b/bin/setup.ts @@ -1,5 +1,5 @@ #!/usr/bin/env bun -import { existsSync, statSync } from "node:fs"; +import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; @@ -40,8 +40,10 @@ const SUITES: SuiteSetup[] = [ id: "wpt-wintertc", aliases: ["wpt", "wpt-wintertc"], path: "suites/wpt", - sparse: ["resources", "url", "encoding", "fetch"], - required: ["resources", "url", "encoding", "fetch"], + // `tools` carries wptserve (`wpt serve`) + its vendored deps, needed to serve fetch/ tests + // against a real WPT server (see harness/src/adapters/wpt-server.ts). + sparse: ["resources", "url", "encoding", "fetch", "tools"], + required: ["resources", "url", "encoding", "fetch", "tools/serve/serve.py"], filterBlobNone: true, }, { @@ -184,6 +186,9 @@ function assertSuiteReady(suite: SuiteSetup): void { if (missing.length) { throw new Error(`${suite.id}: missing required path(s): ${missing.join(", ")}`); } + if (suite.id === "wpt-wintertc") { + assertWptServePatched(checkout); + } } async function prepareSuite(suite: SuiteSetup): Promise { @@ -216,9 +221,87 @@ async function prepareSuite(suite: SuiteSetup): Promise { ], `populating sparse paths for ${suite.id}`); } + if (suite.id === "wpt-wintertc") { + patchWptServe(resolve(ROOT, suite.path)); + } + assertSuiteReady(suite); } +/** + * Make the vendored `wpt serve` runnable offline inside the harness container. Two in-place edits + * to the (submodule-local, uncommitted) checkout, mirroring cloudflare/workerd's WPT patch: + * 1. `tools/serve/commands.json`: `virtualenv: false` — run against the system Python + WPT's + * vendored `tools/third_party/` deps, with no per-invocation venv/pip step (needs network). + * 2. `tools/wpt/paths`: drop the `docs/` line so the CLI's command loader does not require + * `docs/commands.json`, which the sparse checkout deliberately omits. + * Idempotent: re-running leaves an already-patched checkout unchanged (the paths edit normalizes to + * a single trailing newline so a second pass is a no-op). `assertWptServePatched` verifies the + * result, so a re-vendored submodule that reset these files is caught by `setup --check`. + */ +interface ServeCommands { + serve?: { virtualenv?: boolean; conditional_requirements?: unknown }; +} + +/** Parse `tools/serve/commands.json`, or return null if absent. Throws a clear error on bad JSON. */ +function readServeCommands(commandsPath: string): ServeCommands | null { + if (!existsSync(commandsPath)) return null; + let parsed: unknown; + try { + parsed = JSON.parse(readFileSync(commandsPath, "utf8")); + } catch (err) { + const detail = err instanceof Error ? err.message : String(err); + throw new Error(`wpt serve patch: ${commandsPath} is not valid JSON (${detail})`); + } + if (typeof parsed !== "object" || parsed === null) { + throw new Error(`wpt serve patch: ${commandsPath} is not a JSON object`); + } + return parsed as ServeCommands; +} + +function patchWptServe(suitePath: string): void { + const commandsPath = resolve(suitePath, "tools/serve/commands.json"); + const commands = readServeCommands(commandsPath); + if (commands) { + const serve = commands.serve; + if (!serve) { + throw new Error(`wpt serve patch: ${commandsPath} has no "serve" command entry (WPT layout changed?)`); + } + if (serve.virtualenv !== false) { + serve.virtualenv = false; + delete serve.conditional_requirements; + writeFileSync(commandsPath, `${JSON.stringify(commands, null, 2)}\n`); + } + } + const pathsFile = resolve(suitePath, "tools/wpt/paths"); + if (existsSync(pathsFile)) { + const original = readFileSync(pathsFile, "utf8"); + const kept = original.split("\n").filter((l: string) => l.trim() !== "docs/"); + const next = `${kept.join("\n").replace(/\n+$/, "")}\n`; + if (next !== original) writeFileSync(pathsFile, next); + } +} + +/** + * Confirm the wpt serve checkout carries the offline patch (see {@link patchWptServe}). Content-based + * rather than a marker file, so a re-vendored/updated submodule that silently reset these files is + * caught here (by `setup --check`) instead of failing opaquely at server start; `prepareSuite` + * re-applies the patch unconditionally, so a plain `setup` self-heals. + */ +function assertWptServePatched(suitePath: string): void { + const commandsPath = resolve(suitePath, "tools/serve/commands.json"); + const commands = readServeCommands(commandsPath); + if (commands && commands.serve?.virtualenv !== false) { + throw new Error( + `wpt-wintertc: ${commandsPath} not patched for offline serve (serve.virtualenv must be false) — re-run setup`, + ); + } + const pathsFile = resolve(suitePath, "tools/wpt/paths"); + if (existsSync(pathsFile) && readFileSync(pathsFile, "utf8").split("\n").some((l) => l.trim() === "docs/")) { + throw new Error(`wpt-wintertc: ${pathsFile} still lists docs/ (unpatched) — re-run setup`); + } +} + async function main(): Promise { process.chdir(ROOT); const options = parseArgs(Bun.argv.slice(2)); diff --git a/expectations/wpt-wintertc.ratchet.toml b/expectations/wpt-wintertc.ratchet.toml index 6ebf69c..9a026a2 100644 --- a/expectations/wpt-wintertc.ratchet.toml +++ b/expectations/wpt-wintertc.ratchet.toml @@ -1,7 +1,230 @@ # AUTO-GENERATED by `run --ratchet`. Do not edit by hand. -# Generated for elide 1.4.2+8bf2c6fb1 (sha dce38dd7dc4c) on 2026-07-20T02:20:28.588Z. +# Union of 6 runs (threads 1 and 4) to absorb the fetch suite's run-to-run / +# concurrency flakiness: a flaky pass then reads as a new-pass, never a spurious regression. [fail] +"encoding/api-invalid-label.any.js :: Invalid label \"866\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ansi_x3.4-1968\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"arabic\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ascii\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"asmo-708\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"big5-hkscs\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"big5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"chinese\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cn-big5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1250\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1251\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1252\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1253\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1254\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1255\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1256\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1257\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp1258\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp819\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cp866\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csbig5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cseuckr\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cseucpkdfmtjapanese\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csgb2312\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csibm866\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csiso2022jp\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csiso58gb231280\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csiso88596e\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csiso88596i\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csiso88598e\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csiso88598i\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin1\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin3\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin4\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin6\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatin9\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatinarabic\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatincyrillic\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatingreek\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csisolatinhebrew\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cskoi8r\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csksc56011987\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csmacintosh\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csshiftjis\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"csunicode\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"cyrillic\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"dos-874\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ecma-114\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ecma-118\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"elot_928\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"euc-jp\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"euc-kr\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"gb18030\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"gb2312\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"gb_2312-80\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"gb_2312\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"gbk\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"greek8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"greek\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"hebrew\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ibm819\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ibm866\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-10646-ucs-2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-2022-jp\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-10\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-11\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-13\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-14\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-15\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-16\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-1\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-3\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-4\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-6-e\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-6-i\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-6\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-7\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-8-e\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-8-i\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-8859-9\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-100\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-101\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-109\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-110\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-126\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-127\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-138\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-144\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-148\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-149\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-157\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso-ir-58\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-10\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-11\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-13\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-14\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-15\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-1\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-3\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-4\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-6\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-7\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso8859-9\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso885910\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso885911\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso885913\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso885914\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso885915\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88591\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88592\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88593\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88594\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88595\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88596\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88597\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88598\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso88599\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-15\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-1:1987\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-1\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-2:1987\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-3:1988\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-3\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-4:1988\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-4\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-5:1988\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-6:1987\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-6\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-7:1987\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-7\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-8:1988\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-9:1989\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"iso_8859-9\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"koi8-r\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"koi8-ru\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"koi8-u\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"koi8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"koi8_r\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"koi\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"korean\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ks_c_5601-1987\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ks_c_5601-1989\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ksc5601\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ksc_5601\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l1\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l3\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l4\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l6\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"l9\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"latin1\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"latin2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"latin3\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"latin4\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"latin5\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"latin6\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"logical\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"mac\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"macintosh\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ms932\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ms_kanji\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"shift-jis\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"shift_jis\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"sjis\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"sun_eu_greek\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"tis-620\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"ucs-2\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"unicode-1-1-utf-8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"unicode11utf8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"unicode20utf8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"unicode\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"unicodefeff\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"unicodefffe\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"us-ascii\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"utf-16\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"utf-16be\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"utf-16le\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"utf-8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"utf8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"visual\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1250\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1251\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1252\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1253\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1254\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1255\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1256\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1257\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-1258\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-31j\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-874\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"windows-949\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1250\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1251\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1252\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1253\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1254\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1255\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1256\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1257\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-cp1258\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-euc-jp\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-gbk\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-mac-cyrillic\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-mac-roman\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-mac-ukrainian\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-sjis\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-unicode20utf8\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-user-defined\\0\" should be rejected by TextDecoder." = "" +"encoding/api-invalid-label.any.js :: Invalid label \"x-x-big5\\0\" should be rejected by TextDecoder." = "" "encoding/encodeInto.any.js :: Invalid encodeInto() destination: BigInt64Array, backed by: ArrayBuffer" = "" "encoding/encodeInto.any.js :: Invalid encodeInto() destination: BigInt64Array, backed by: SharedArrayBuffer" = "" "encoding/encodeInto.any.js :: Invalid encodeInto() destination: BigUint64Array, backed by: ArrayBuffer" = "" @@ -69,47 +292,12 @@ "encoding/encodeInto.any.js :: encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 4, filler 128" = "" "encoding/encodeInto.any.js :: encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 4, filler random" = "" "encoding/idlharness.any.js :: idl_test setup" = "" -"encoding/replacement-encodings.any.js :: csiso2022kr - empty input decodes to empty output." = "" -"encoding/replacement-encodings.any.js :: csiso2022kr - non-empty input decodes to one replacement character." = "" -"encoding/replacement-encodings.any.js :: hz-gb-2312 - empty input decodes to empty output." = "" -"encoding/replacement-encodings.any.js :: hz-gb-2312 - non-empty input decodes to one replacement character." = "" -"encoding/replacement-encodings.any.js :: iso-2022-cn - empty input decodes to empty output." = "" -"encoding/replacement-encodings.any.js :: iso-2022-cn - non-empty input decodes to one replacement character." = "" -"encoding/replacement-encodings.any.js :: iso-2022-cn-ext - empty input decodes to empty output." = "" -"encoding/replacement-encodings.any.js :: iso-2022-cn-ext - non-empty input decodes to one replacement character." = "" -"encoding/replacement-encodings.any.js :: iso-2022-kr - empty input decodes to empty output." = "" -"encoding/replacement-encodings.any.js :: iso-2022-kr - non-empty input decodes to one replacement character." = "" -"encoding/replacement-encodings.any.js :: replacement - empty input decodes to empty output." = "" -"encoding/replacement-encodings.any.js :: replacement - non-empty input decodes to one replacement character." = "" "encoding/single-byte-decoder.window.js :: IBM866: 866 (XMLHttpRequest)" = "" "encoding/single-byte-decoder.window.js :: IBM866: 866 (document.characterSet and document.inputEncoding)" = "" "encoding/streams/decode-bad-chunks.any.js :: chunk of type array should error the stream" = "" "encoding/streams/decode-bad-chunks.any.js :: chunk of type undefined should error the stream" = "" -"encoding/streams/decode-ignore-bom.any.js :: ignoreBOM should work for encoding utf-16be, split at character 1" = "" -"encoding/streams/decode-ignore-bom.any.js :: ignoreBOM should work for encoding utf-16le, split at character 1" = "" -"encoding/streams/decode-ignore-bom.any.js :: ignoreBOM should work for encoding utf-8, split at character 1" = "" -"encoding/streams/decode-ignore-bom.any.js :: ignoreBOM should work for encoding utf-8, split at character 2" = "" "encoding/streams/decode-utf8.any.js :: " = "" -"encoding/streams/invalid-realm.window.js :: TextDecoderStream: close in detached realm should succeed" = "" -"encoding/streams/invalid-realm.window.js :: TextDecoderStream: write in detached realm should succeed" = "" -"encoding/streams/invalid-realm.window.js :: TextEncoderStream: close in detached realm should succeed" = "" -"encoding/streams/invalid-realm.window.js :: TextEncoderStream: write in detached realm should succeed" = "" -"encoding/streams/realms.window.js :: " = "" -"encoding/textdecoder-arguments.any.js :: TextDecoder decode() with array buffer detached during arg conversion" = "" -"encoding/textdecoder-copy.any.js :: Modify buffer after passing it in (ArrayBuffer)" = "" "encoding/textdecoder-copy.any.js :: Modify buffer after passing it in (SharedArrayBuffer)" = "" -"encoding/textdecoder-fatal-streaming.any.js :: " = "" -"encoding/textdecoder-mistakes.any.js :: BOM splitting / repeats: utf-16be" = "" -"encoding/textdecoder-mistakes.any.js :: BOM splitting / repeats: utf-16le" = "" -"encoding/textdecoder-mistakes.any.js :: BOM splitting / repeats: utf-8" = "" -"encoding/textdecoder-mistakes.any.js :: Invalid Unicode input is replaced: utf-16be" = "" -"encoding/textdecoder-mistakes.any.js :: Invalid Unicode input is replaced: utf-16le" = "" -"encoding/textdecoder-mistakes.any.js :: Sticky fatal BOM: utf-16be" = "" -"encoding/textdecoder-mistakes.any.js :: Sticky fatal BOM: utf-16le" = "" -"encoding/textdecoder-mistakes.any.js :: Sticky fatal BOM: utf-8" = "" -"encoding/textdecoder-mistakes.any.js :: labels: invalid non-ascii" = "" -"encoding/textdecoder-mistakes.any.js :: stream: utf-8" = "" -"encoding/textdecoder-streaming.any.js :: Streaming decode: UTF-8 chunk tests (ArrayBuffer)" = "" "encoding/textdecoder-streaming.any.js :: Streaming decode: UTF-8 chunk tests (SharedArrayBuffer)" = "" "encoding/textdecoder-streaming.any.js :: Streaming decode: utf-16be, 1 byte window (SharedArrayBuffer)" = "" "encoding/textdecoder-streaming.any.js :: Streaming decode: utf-16be, 2 byte window (SharedArrayBuffer)" = "" @@ -126,26 +314,6 @@ "encoding/textdecoder-streaming.any.js :: Streaming decode: utf-8, 3 byte window (SharedArrayBuffer)" = "" "encoding/textdecoder-streaming.any.js :: Streaming decode: utf-8, 4 byte window (SharedArrayBuffer)" = "" "encoding/textdecoder-streaming.any.js :: Streaming decode: utf-8, 5 byte window (SharedArrayBuffer)" = "" -"encoding/textdecoder-utf16-surrogates.any.js :: utf-16le - unmatched surrogate lead" = "" -"encoding/unsupported-encodings.any.js :: UTF-32 with BOM should decode as UTF-16LE" = "" -"encoding/unsupported-encodings.any.js :: UTF-32 with no BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: UTF-32LE with BOM should decode as UTF-16LE" = "" -"encoding/unsupported-encodings.any.js :: UTF-32LE with no BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: UTF-32be with BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: UTF-32be with no BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: UTF-7 should not be supported" = "" -"encoding/unsupported-encodings.any.js :: utf-32 with BOM should decode as UTF-16LE" = "" -"encoding/unsupported-encodings.any.js :: utf-32 with no BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: utf-32be with BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: utf-32be with no BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: utf-32le with BOM should decode as UTF-16LE" = "" -"encoding/unsupported-encodings.any.js :: utf-32le with no BOM should decode as UTF-8" = "" -"encoding/unsupported-encodings.any.js :: utf-7 should not be supported" = "" -"encoding/unsupported-labels.window.js :: 437 is not supported by the Encoding Standard" = "" -"fetch/api/abort/cache.https.any.js :: Signals are not stored in the cache API" = "" -"fetch/api/abort/cache.https.any.js :: Signals are not stored in the cache API, even if they're already aborted" = "" -"fetch/api/abort/general.any.js :: Aborting rejects with AbortError" = "" -"fetch/api/abort/general.any.js :: Aborting rejects with abort reason" = "" "fetch/api/abort/general.any.js :: Already aborted signal can be used for many fetches" = "" "fetch/api/abort/general.any.js :: Already aborted signal does not make request" = "" "fetch/api/abort/general.any.js :: Call text() twice on aborted response" = "" @@ -163,6 +331,16 @@ "fetch/api/abort/general.any.js :: Stream errors once aborted, after reading. Underlying connection closed." = "" "fetch/api/abort/general.any.js :: Stream errors once aborted. Underlying connection closed." = "" "fetch/api/abort/general.any.js :: Stream will not error if body is empty. It's closed with an empty queue before it errors." = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - Bad cache init parameter value" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - Bad credentials init parameter value" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - Bad mode init parameter value" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - Bad referrerPolicy init parameter value" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - RequestInit's mode is navigate" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - RequestInit's referrer is invalid" = "" +"fetch/api/abort/general.any.js :: TypeError from request constructor takes priority - RequestInit's window is not null" = "" "fetch/api/abort/general.any.js :: Underlying connection is closed when aborting after receiving response" = "" "fetch/api/abort/general.any.js :: Underlying connection is closed when aborting after receiving response - no-cors" = "" "fetch/api/abort/general.any.js :: response.arrayBuffer() rejects if already aborted" = "" @@ -190,6 +368,7 @@ "fetch/api/basic/header-value-combining.any.js :: response.headers.get('foo-test') expects 1, 2, 3" = "" "fetch/api/basic/header-value-combining.any.js :: response.headers.get('heya') expects , \u000b\f, 1, , , 2" = "" "fetch/api/basic/header-value-combining.any.js :: response.headers.get('www-authenticate') expects 1, 2, 3, 4" = "" +"fetch/api/basic/header-value-null-byte.any.js :: Ensure fetch() rejects null bytes in headers" = "" "fetch/api/basic/http-response-code.any.js :: Fetch on 425 response should not be retried for non TLS early data." = "" "fetch/api/basic/integrity.sub.any.js :: CORS SHA-512 integrity" = "" "fetch/api/basic/integrity.sub.any.js :: CORS empty integrity" = "" @@ -211,15 +390,14 @@ "fetch/api/basic/keepalive.any.js :: [keepalive] simple POST request on 'pagehide' [no payload]; setting up" = "" "fetch/api/basic/keepalive.any.js :: [keepalive] simple POST request on 'unload' [no payload]; setting up" = "" "fetch/api/basic/keepalive.any.js :: simple keepalive test for web workers;" = "" -"fetch/api/basic/mediasource.window.js :: Cannot fetch blob: URL from a MediaSource" = "" "fetch/api/basic/mode-no-cors.sub.any.js :: Fetch ../resources/top.txt with no-cors mode" = "" "fetch/api/basic/mode-no-cors.sub.any.js :: Fetch http://{{host}}:{{ports[http][0]}}/fetch/api/resources/top.txt with no-cors mode" = "" "fetch/api/basic/mode-no-cors.sub.any.js :: Fetch http://{{host}}:{{ports[http][1]}}/fetch/api/resources/top.txt with no-cors mode" = "" "fetch/api/basic/mode-no-cors.sub.any.js :: Fetch https://{{host}}:{{ports[https][0]}}/fetch/api/resources/top.txt with no-cors mode" = "" "fetch/api/basic/mode-same-origin.any.js :: Fetch ../resources/top.txt with same-origin mode" = "" "fetch/api/basic/mode-same-origin.any.js :: Fetch /fetch/api/basic/../resources/redirect.py?location=../resources/top.txt with same-origin mode" = "" -"fetch/api/basic/mode-same-origin.any.js :: Fetch /fetch/api/basic/../resources/redirect.py?location=http://web-platform.test/fetch/api/resources/top.txt with same-origin mode" = "" -"fetch/api/basic/mode-same-origin.any.js :: Fetch http://web-platform.test/fetch/api/resources/top.txt with same-origin mode" = "" +"fetch/api/basic/mode-same-origin.any.js :: Fetch /fetch/api/basic/../resources/redirect.py?location=http://127.0.0.1:/fetch/api/resources/top.txt with same-origin mode" = "" +"fetch/api/basic/mode-same-origin.any.js :: Fetch http://127.0.0.1:/fetch/api/resources/top.txt with same-origin mode" = "" "fetch/api/basic/referrer.any.js :: Referrer with credentials should be stripped" = "" "fetch/api/basic/referrer.any.js :: Referrer with fragment ID should be stripped" = "" "fetch/api/basic/referrer.any.js :: origin-when-cross-origin policy on a cross-origin URL" = "" @@ -322,6 +500,7 @@ "fetch/api/basic/request-forbidden-headers.any.js :: header x-method-override is forbidden to use value trace" = "" "fetch/api/basic/request-forbidden-headers.any.js :: header x-method-override is forbidden to use value trace," = "" "fetch/api/basic/request-forbidden-headers.any.js :: header x-method-override is forbidden to use value track" = "" +"fetch/api/basic/request-head.any.js :: Fetch with HEAD with body" = "" "fetch/api/basic/request-headers-case.any.js :: Multiple headers with the same name, different case (THIS-IS-A-TEST first)" = "" "fetch/api/basic/request-headers-case.any.js :: Multiple headers with the same name, different case (THIS-is-A-test first)" = "" "fetch/api/basic/request-headers-nonascii.any.js :: Non-ascii bytes in request headers" = "" @@ -387,13 +566,6 @@ "fetch/api/basic/scheme-data.any.js :: Fetching data:,response%27s%20body is OK (same-origin)" = "" "fetch/api/basic/scheme-data.any.js :: Fetching data:image/png;base64,cmVzcG9uc2UncyBib2[...] is OK" = "" "fetch/api/basic/scheme-data.any.js :: Fetching data:text/plain;base64,cmVzcG9uc2UncyBib[...] is OK" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 200 should be the empty string" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 210 should be the empty string" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 400 should be the empty string" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 404 should be the empty string" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 410 should be the empty string" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 500 should be the empty string" = "" -"fetch/api/basic/status.h2.any.js :: statusText over H2 for status 502 should be the empty string" = "" "fetch/api/basic/stream-response.any.js :: Stream response's body when content-type is not present" = "" "fetch/api/basic/stream-response.any.js :: Stream response's body when content-type is present" = "" "fetch/api/basic/stream-safe-creation.any.js :: Object.prototype.highWaterMark accessor returning invalid value should not affect stream creation by 'fetch'" = "" @@ -808,9 +980,7 @@ "fetch/api/headers/headers-record.any.js :: Correct operation ordering with two properties one of which has an invalid value" = "" "fetch/api/headers/headers-record.any.js :: Correct operation ordering with undefined descriptors" = "" "fetch/api/headers/headers-record.any.js :: Operation with non-enumerable Symbol keys" = "" -"fetch/api/idlharness.https.any.js :: idl_test setup" = "" -"fetch/api/redirect/redirect-back-to-original-origin.any.js :: original => remote => original with mode: \"cors\"" = "" -"fetch/api/redirect/redirect-back-to-original-origin.any.js :: original => remote => original with mode: \"no-cors\"" = "" +"fetch/api/redirect/redirect-back-to-original-origin.any.js :: " = "" "fetch/api/redirect/redirect-count.any.js :: Redirect 301 20 times" = "" "fetch/api/redirect/redirect-count.any.js :: Redirect 301 21 times" = "" "fetch/api/redirect/redirect-count.any.js :: Redirect 302 20 times" = "" @@ -828,7 +998,6 @@ "fetch/api/redirect/redirect-keepalive.any.js :: [keepalive][new window][unload] redirect to file URL; setting up" = "" "fetch/api/redirect/redirect-keepalive.any.js :: [keepalive][new window][unload] same-origin redirect + preflight; setting up" = "" "fetch/api/redirect/redirect-keepalive.any.js :: [keepalive][new window][unload] same-origin redirect; setting up" = "" -"fetch/api/redirect/redirect-keepalive.https.any.js :: [keepalive][iframe][load] mixed content redirect; setting up" = "" "fetch/api/redirect/redirect-location-escape.tentative.any.js :: Escaping produces double-percent" = "" "fetch/api/redirect/redirect-location-escape.tentative.any.js :: Redirect to escaped UTF-8" = "" "fetch/api/redirect/redirect-location-escape.tentative.any.js :: Redirect to escaped and unescaped UTF-8" = "" @@ -1114,8 +1283,6 @@ "fetch/api/redirect/redirect-referrer.any.js :: Same origin redirection, empty redirect header, strict-origin init " = "" "fetch/api/redirect/redirect-referrer.any.js :: Same origin redirection, empty redirect header, strict-origin-when-cross-origin init " = "" "fetch/api/redirect/redirect-referrer.any.js :: Same origin redirection, empty redirect header, unsafe-url init " = "" -"fetch/api/redirect/redirect-upload.h2.any.js :: Fetch upload streaming should be accepted on 303" = "" -"fetch/api/request/multi-globals/construct-in-detached-frame.window.js :: creating a request from another request in a detached realm should work" = "" "fetch/api/request/request-cache-default-conditional.any.js :: RequestCache \"default\" mode with an If-Match header (following a request without additional headers) is treated similarly to \"no-store\" with Etag and fresh response" = "" "fetch/api/request/request-cache-default-conditional.any.js :: RequestCache \"default\" mode with an If-Match header (following a request without additional headers) is treated similarly to \"no-store\" with Etag and stale response" = "" "fetch/api/request/request-cache-default-conditional.any.js :: RequestCache \"default\" mode with an If-Match header (following a request without additional headers) is treated similarly to \"no-store\" with Last-Modified and fresh response" = "" @@ -1300,17 +1467,6 @@ "fetch/api/response/response-stream-disturbed-5.any.js :: Getting a body reader after consuming as text (body source: string)" = "" "fetch/api/response/response-stream-disturbed-by-pipe.any.js :: using pipeThrough on Response body should disturb it synchronously" = "" "fetch/api/response/response-stream-disturbed-by-pipe.any.js :: using pipeTo on Response body should disturb it synchronously" = "" -"fetch/content-encoding/br/bad-br-body.https.any.js :: Consuming the body of a resource with bad br content with arrayBuffer() should reject" = "" -"fetch/content-encoding/br/bad-br-body.https.any.js :: Consuming the body of a resource with bad br content with blob() should reject" = "" -"fetch/content-encoding/br/bad-br-body.https.any.js :: Consuming the body of a resource with bad br content with bytes() should reject" = "" -"fetch/content-encoding/br/bad-br-body.https.any.js :: Consuming the body of a resource with bad br content with formData() should reject" = "" -"fetch/content-encoding/br/bad-br-body.https.any.js :: Consuming the body of a resource with bad br content with json() should reject" = "" -"fetch/content-encoding/br/bad-br-body.https.any.js :: Consuming the body of a resource with bad br content with text() should reject" = "" -"fetch/content-encoding/br/big-br-body.https.any.js :: large br data should be decompressed successfully" = "" -"fetch/content-encoding/br/big-br-body.https.any.js :: large br data should be decompressed successfully with byte stream" = "" -"fetch/content-encoding/br/br-body.https.any.js :: fetched br data with content type octetstream should be decompressed." = "" -"fetch/content-encoding/br/br-body.https.any.js :: fetched br data with content type text should be decompressed." = "" -"fetch/content-encoding/br/br-navigation.https.window.js :: Naigation to br encoded page" = "" "fetch/content-encoding/gzip/bad-gzip-body.any.js :: Consuming the body of a resource with bad gzip content with arrayBuffer() should reject" = "" "fetch/content-encoding/gzip/bad-gzip-body.any.js :: Consuming the body of a resource with bad gzip content with blob() should reject" = "" "fetch/content-encoding/gzip/bad-gzip-body.any.js :: Consuming the body of a resource with bad gzip content with bytes() should reject" = "" @@ -1318,30 +1474,8 @@ "fetch/content-encoding/gzip/bad-gzip-body.any.js :: Consuming the body of a resource with bad gzip content with json() should reject" = "" "fetch/content-encoding/gzip/bad-gzip-body.any.js :: Consuming the body of a resource with bad gzip content with text() should reject" = "" "fetch/content-encoding/gzip/bad-gzip-body.any.js :: Fetching a resource with bad gzip content should still resolve" = "" -"fetch/content-encoding/gzip/big-gzip-body.https.any.js :: large gzip data should be decompressed successfully" = "" -"fetch/content-encoding/gzip/big-gzip-body.https.any.js :: large gzip data should be decompressed successfully with byte stream" = "" "fetch/content-encoding/gzip/gzip-body.any.js :: fetched gzip data with content type octetstream should be decompressed." = "" "fetch/content-encoding/gzip/gzip-body.any.js :: fetched gzip data with content type text should be decompressed." = "" -"fetch/content-encoding/gzip/gzip-navigation.https.window.js :: Naigation to gzip encoded page" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Consuming the body of a resource with bad zstd content with arrayBuffer() should reject" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Consuming the body of a resource with bad zstd content with blob() should reject" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Consuming the body of a resource with bad zstd content with bytes() should reject" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Consuming the body of a resource with bad zstd content with formData() should reject" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Consuming the body of a resource with bad zstd content with json() should reject" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Consuming the body of a resource with bad zstd content with text() should reject" = "" -"fetch/content-encoding/zstd/bad-zstd-body.https.any.js :: Fetching a resource with bad zstd content should still resolve" = "" -"fetch/content-encoding/zstd/big-window-zstd-body.tentative.https.any.js :: Consuming the body of a resource with too large of a zstd window size should reject" = "" -"fetch/content-encoding/zstd/big-zstd-body.https.any.js :: large zstd data should be decompressed successfully" = "" -"fetch/content-encoding/zstd/big-zstd-body.https.any.js :: large zstd data should be decompressed successfully with byte stream" = "" -"fetch/content-encoding/zstd/zstd-body.https.any.js :: fetched zstd data with content type octetstream should be decompressed." = "" -"fetch/content-encoding/zstd/zstd-body.https.any.js :: fetched zstd data with content type text should be decompressed." = "" -"fetch/content-encoding/zstd/zstd-navigation.https.window.js :: Naigation to zstd encoded page" = "" -"fetch/content-length/api-and-duplicate-headers.any.js :: XMLHttpRequest and duplicate Content-Length/Content-Type headers" = "" -"fetch/content-length/api-and-duplicate-headers.any.js :: fetch() and duplicate Content-Length/Content-Type headers" = "" -"fetch/content-length/parsing.window.js :: Loading JSON…" = "" -"fetch/content-length/too-long.window.js :: Content-Length header value of network response exceeds response body" = "" -"fetch/content-type/response.window.js :: Loading JSON…" = "" -"fetch/content-type/script.window.js :: Loading JSON…" = "" "fetch/cross-origin-resource-policy/fetch.any.js :: Cross-origin cors fetch with a 'Cross-Origin-Resource-Policy: same-origin' response header." = "" "fetch/cross-origin-resource-policy/fetch.any.js :: Cross-origin cors fetch with a 'Cross-Origin-Resource-Policy: same-site' response header." = "" "fetch/cross-origin-resource-policy/fetch.any.js :: Cross-origin no-cors fetch with a 'Cross-Origin-Resource-Policy: same-origin' redirect response header." = "" @@ -1349,13 +1483,6 @@ "fetch/cross-origin-resource-policy/fetch.any.js :: Same-origin fetch with a 'Cross-Origin-Resource-Policy: same-origin' response header." = "" "fetch/cross-origin-resource-policy/fetch.any.js :: Same-origin fetch with a 'Cross-Origin-Resource-Policy: same-site' response header." = "" "fetch/cross-origin-resource-policy/fetch.any.js :: Valid cross-origin no-cors fetch with a 'Cross-Origin-Resource-Policy: same-site' response header." = "" -"fetch/cross-origin-resource-policy/fetch.https.any.js :: Cross-origin cors fetch with a 'Cross-Origin-Resource-Policy: same-origin' response header." = "" -"fetch/cross-origin-resource-policy/fetch.https.any.js :: Cross-origin cors fetch with a 'Cross-Origin-Resource-Policy: same-site' response header." = "" -"fetch/cross-origin-resource-policy/fetch.https.any.js :: Cross-origin no-cors fetch with a 'Cross-Origin-Resource-Policy: same-origin' redirect response header." = "" -"fetch/cross-origin-resource-policy/fetch.https.any.js :: Cross-origin no-cors fetch with a 'Cross-Origin-Resource-Policy: same-origin' response header after a cross-origin redirection." = "" -"fetch/cross-origin-resource-policy/fetch.https.any.js :: Same-origin fetch with a 'Cross-Origin-Resource-Policy: same-origin' response header." = "" -"fetch/cross-origin-resource-policy/fetch.https.any.js :: Same-origin fetch with a 'Cross-Origin-Resource-Policy: same-site' response header." = "" -"fetch/cross-origin-resource-policy/scheme-restriction.https.window.js :: Cross-Origin-Resource-Policy does not block Mixed Content " = "" "fetch/cross-origin-resource-policy/syntax.any.js :: Parsing Cross-Origin-Resource-Policy: SAME-ORIGIN" = "" "fetch/cross-origin-resource-policy/syntax.any.js :: Parsing Cross-Origin-Resource-Policy: Same-Origin" = "" "fetch/cross-origin-resource-policy/syntax.any.js :: Parsing Cross-Origin-Resource-Policy: https://www.example.com" = "" @@ -1364,151 +1491,7 @@ "fetch/cross-origin-resource-policy/syntax.any.js :: Parsing Cross-Origin-Resource-Policy: same-origin, <>" = "" "fetch/cross-origin-resource-policy/syntax.any.js :: Parsing Cross-Origin-Resource-Policy: same-origin, same-origin" = "" "fetch/data-urls/base64.any.js :: Setup." = "" -"fetch/data-urls/navigate.window.js :: ASCII whitespace in the input is removed" = "" -"fetch/data-urls/navigate.window.js :: Nothing fancy" = "" -"fetch/data-urls/navigate.window.js :: Vertical tab in the input leads to an error" = "" -"fetch/data-urls/navigate.window.js :: base64" = "" -"fetch/data-urls/navigate.window.js :: base64 with code points that differ from base64url" = "" -"fetch/data-urls/navigate.window.js :: base64 with incorrect padding" = "" -"fetch/data-urls/navigate.window.js :: base64url is not supported" = "" "fetch/data-urls/processing.any.js :: Setup." = "" -"fetch/fetch-later/activate-after.https.window.js :: fetchLater() sends out based on activateAfter, even if document is in BFCache." = "" -"fetch/fetch-later/activate-after.https.window.js :: fetchLater() sends out based on activateAfter." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() cannot be called without request." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() does not throw error when it is aborted before sending." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws AbortError when its initial abort signal is aborted." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws RangeError on negative activateAfter." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on about: scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on blob: scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on data: scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on file:// scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on ftp:// scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on javascript: scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on non-trustworthy http URL." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on ssh:// scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError on wss:// scheme." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() throws TypeError when mutating its returned state." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with http://127.0.0.1 URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with http://[::1] URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with http://localhost URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with https://127.0.0.1 URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with https://[::1] URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with https://example.com URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with https://localhost URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater() with same-origin (https) URL does not throw." = "" -"fetch/fetch-later/basic.https.window.js :: fetchLater()'s return tells the deferred request is not yet sent." = "" -"fetch/fetch-later/basic.https.worker.js :: " = "" -"fetch/fetch-later/iframe.https.window.js :: A blank iframe can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A blank window[target=''][features=''] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A blank window[target=''][features='popup'] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A blank window[target='_blank'][features=''] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A blank window[target='_blank'][features='popup'] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A cross-origin window[target=''][features=''] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A cross-origin window[target=''][features='popup'] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A cross-origin window[target='_blank'][features=''] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A cross-origin window[target='_blank'][features='popup'] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A same-origin window[target=''][features=''] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A same-origin window[target=''][features='popup'] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A same-origin window[target='_blank'][features=''] can trigger fetchLater." = "" -"fetch/fetch-later/new-window.https.window.js :: A same-origin window[target='_blank'][features='popup'] can trigger fetchLater." = "" -"fetch/fetch-later/non-secure.window.js :: fetchLater() is not supported in non-secure context." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy-attribute-redirect.https.window.js :: Permissions policy allow=\"deferred-fetch\" allows fetchLater() from a redirected same-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy-attribute-redirect.https.window.js :: Permissions policy allow=\"deferred-fetch\" disallows fetchLater() from a redirected cross-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy-attribute.https.window.js :: Permissions policy \"deferred-fetch\" can be enabled in the cross-origin iframe using allow=\"deferred-fetch\" attribute." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy-attribute.https.window.js :: Permissions policy \"deferred-fetch\" can be enabled in the same-origin iframe using allow=\"deferred-fetch\" attribute." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy.https.window.js :: Permissions policy header: \"deferred-fetch=*\" allow=\"deferred-fetch\" allows fetchLater() in the cross-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy.https.window.js :: Permissions policy header: \"deferred-fetch=*\" allows fetchLater() in the cross-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy.https.window.js :: Permissions policy header: \"deferred-fetch=*\" allows fetchLater() in the same-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-allowed-by-permissions-policy.https.window.js :: Permissions policy header: \"deferred-fetch=*\" allows fetchLater() in the top-level document." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-default-permissions-policy.https.window.js :: Default \"deferred-fetch\" permissions policy [\"self\"] allows fetchLater() in the same-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-default-permissions-policy.https.window.js :: Default \"deferred-fetch\" permissions policy [\"self\"] allows fetchLater() in the top-level document." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-default-permissions-policy.https.window.js :: Default \"deferred-fetch-minimal\" permissions policy [\"*\"] allows fetchLater() in the cross-origin iframe." = "" -"fetch/fetch-later/permissions-policy/deferred-fetch-supported-by-permissions-policy.window.js :: document.permissionsPolicy.features should advertise deferred-fetch." = "" -"fetch/fetch-later/policies/csp-allowed.https.window.js :: " = "" -"fetch/fetch-later/policies/csp-blocked.https.window.js :: " = "" -"fetch/fetch-later/policies/csp-redirect-to-blocked.https.window.js :: " = "" -"fetch/fetch-later/quota/accumulated-oversized-payload.https.window.js :: The 2nd fetchLater(same-origin) call in the top-level document is not allowed to exceed per-origin quota for its POST body of String." = "" -"fetch/fetch-later/quota/cross-origin-iframe/accumulated-oversized-payload.https.window.js :: The 2nd fetchLater(same-origin) call in a default cross-origin child iframe has its owned per-origin quota for a request POST body of String." = "" -"fetch/fetch-later/quota/cross-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of ArrayBuffer in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of Blob in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of File in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of FormData in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of URLSearchParams in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/max-payload.https.window.js :: fetchLater() accepts max payload in a parent-frame-origin POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/max-payload.https.window.js :: fetchLater() accepts max payload in a self-frame-origin POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/max-payload.https.window.js :: fetchLater() rejects max+1 payload in a parent-frame-origin POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/max-payload.https.window.js :: fetchLater() rejects max+1 payload in a self-frame-origin POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/multiple-iframes.https.window.js :: fetchLater() request quota are delegated to cross-origin iframes and not shared, even if they are same origin." = "" -"fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=8193] exceeding per-origin quota in a POST request body of ArrayBuffer in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=8193] exceeding per-origin quota in a POST request body of Blob in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=8193] exceeding per-origin quota in a POST request body of File in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=8193] exceeding per-origin quota in a POST request body of FormData in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=8193] exceeding per-origin quota in a POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=8193] exceeding per-origin quota in a POST request body of URLSearchParams in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/sandboxed-iframe.https.window.js :: A sandboxed iframe (without allow-same-origin) should be treated as cross-origin and have its own minimal quota." = "" -"fetch/fetch-later/quota/cross-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of ArrayBuffer in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of Blob in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of File in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of FormData in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of String in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/cross-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of URLSearchParams in a default cross-origin iframe." = "" -"fetch/fetch-later/quota/empty-payload.https.window.js :: fetchLater() accept a DELETE request." = "" -"fetch/fetch-later/quota/empty-payload.https.window.js :: fetchLater() accept a GET request." = "" -"fetch/fetch-later/quota/empty-payload.https.window.js :: fetchLater() accept a PUT request." = "" -"fetch/fetch-later/quota/max-payload.https.window.js :: fetchLater() accepts max payload in a POST request body of String." = "" -"fetch/fetch-later/quota/max-payload.https.window.js :: fetchLater() rejects max+1 payload in a POST request body of String." = "" -"fetch/fetch-later/quota/multiple-origins.https.window.js :: fetchLater() has per-request-origin quota for its POST body of ArrayBuffer." = "" -"fetch/fetch-later/quota/multiple-origins.https.window.js :: fetchLater() has per-request-origin quota for its POST body of Blob." = "" -"fetch/fetch-later/quota/multiple-origins.https.window.js :: fetchLater() has per-request-origin quota for its POST body of File." = "" -"fetch/fetch-later/quota/multiple-origins.https.window.js :: fetchLater() has per-request-origin quota for its POST body of FormData." = "" -"fetch/fetch-later/quota/multiple-origins.https.window.js :: fetchLater() has per-request-origin quota for its POST body of String." = "" -"fetch/fetch-later/quota/multiple-origins.https.window.js :: fetchLater() has per-request-origin quota for its POST body of URLSearchParams." = "" -"fetch/fetch-later/quota/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of ArrayBuffer." = "" -"fetch/fetch-later/quota/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of Blob." = "" -"fetch/fetch-later/quota/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of File." = "" -"fetch/fetch-later/quota/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of FormData." = "" -"fetch/fetch-later/quota/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of String." = "" -"fetch/fetch-later/quota/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of URLSearchParams." = "" -"fetch/fetch-later/quota/same-origin-iframe/accumulated-oversized-payload.https.window.js :: The 2nd fetchLater(same-origin) call in a same-origin child iframe is not allowed to exceed per-origin quota for its POST body of String." = "" -"fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of ArrayBuffer in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of Blob in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of File in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of FormData in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of String in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/empty-payload.https.window.js :: fetchLater() accepts an empty POST request body of URLSearchParams in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/max-payload.https.window.js :: fetchLater() accepts max payload in a POST request body of String in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/max-payload.https.window.js :: fetchLater() rejects max+1 payload in a POST request body of String in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/multiple-iframes.https.window.js :: fetchLater() request quota are shared by same-origin iframes and root." = "" -"fetch/fetch-later/quota/same-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of ArrayBuffer in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of Blob in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of File in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of FormData in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of String in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/oversized-payload.https.window.js :: fetchLater() does not accept payload[size=65537] exceeding per-origin quota in a POST request body of URLSearchParams in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/sandboxed-iframe.https.window.js :: A sandboxed iframe with 'allow-same-origin' should be treated as same-origin and share the parent's quota." = "" -"fetch/fetch-later/quota/same-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of ArrayBuffer in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of Blob in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of File in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of FormData in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of String in same-origin iframe." = "" -"fetch/fetch-later/quota/same-origin-iframe/small-payload.https.window.js :: fetchLater() accepts payload[size=20] in a POST request body of URLSearchParams in same-origin iframe." = "" -"fetch/fetch-later/quota/small-payload.https.window.js :: fetchLater() accepts small payload in a POST request body of ArrayBuffer." = "" -"fetch/fetch-later/quota/small-payload.https.window.js :: fetchLater() accepts small payload in a POST request body of Blob." = "" -"fetch/fetch-later/quota/small-payload.https.window.js :: fetchLater() accepts small payload in a POST request body of File." = "" -"fetch/fetch-later/quota/small-payload.https.window.js :: fetchLater() accepts small payload in a POST request body of FormData." = "" -"fetch/fetch-later/quota/small-payload.https.window.js :: fetchLater() accepts small payload in a POST request body of String." = "" -"fetch/fetch-later/quota/small-payload.https.window.js :: fetchLater() accepts small payload in a POST request body of URLSearchParams." = "" -"fetch/fetch-later/send-on-deactivate-with-background-sync.https.window.js :: " = "" -"fetch/fetch-later/send-on-deactivate.https.window.js :: Call fetchLater() when BFCached with activateAfter=0 sends immediately." = "" -"fetch/fetch-later/send-on-deactivate.https.window.js :: fetchLater() does not send aborted request on navigating away a page w/o BFCache." = "" -"fetch/fetch-later/send-on-deactivate.https.window.js :: fetchLater() sends on navigating away a page w/o BFCache." = "" -"fetch/fetch-later/send-on-deactivate.https.window.js :: fetchLater() sends on page entering BFCache if BackgroundSync is off." = "" -"fetch/fetch-later/send-on-deactivate.https.window.js :: fetchLater() with activateAfter=1m sends on page entering BFCache if BackgroundSync is off." = "" -"fetch/fetch-later/send-on-discard/not-send-after-abort.https.window.js :: A discarded document does not send an already aborted fetchLater request." = "" -"fetch/fetch-later/send-on-discard/send-multiple-with-activate-after.https.window.js :: A discarded document sends all its fetchLater requests, no matter how much their activateAfter timeout remain." = "" -"fetch/fetch-later/send-on-discard/send-multiple.https.window.js :: A discarded document sends all its fetchLater requests." = "" -"fetch/h1-parsing/resources-with-0x00-in-header.window.js :: Expect network error for script with 0x00 in a header" = "" "fetch/h1-parsing/status-code.window.js :: HTTP/1.1 0 OK " = "" "fetch/h1-parsing/status-code.window.js :: HTTP/1.1 077 77 " = "" "fetch/h1-parsing/status-code.window.js :: HTTP/1.1 099 HELLO " = "" @@ -1652,21 +1635,6 @@ "fetch/http-cache/vary.any.js :: HTTP cache reuses three-way Vary response when request matches" = "" "fetch/http-cache/vary.any.js :: HTTP cache reuses two-way Vary response when request matches" = "" "fetch/http-cache/vary.any.js :: HTTP cache uses three-way Vary response when both request and the original request omited a variant header" = "" -"fetch/local-network-access/iframe.tentative.https.window.js :: " = "" -"fetch/local-network-access/navigate.tentative.https.window.js :: " = "" -"fetch/local-network-access/navigate.tentative.window.js :: " = "" -"fetch/metadata/fetch-preflight.https.sub.any.js :: Cross-site fetch with preflight" = "" -"fetch/metadata/fetch-preflight.https.sub.any.js :: Same-site fetch with preflight" = "" -"fetch/metadata/fetch.https.sub.any.js :: CORS mode" = "" -"fetch/metadata/fetch.https.sub.any.js :: Cross-site fetch" = "" -"fetch/metadata/fetch.https.sub.any.js :: Same-origin fetch" = "" -"fetch/metadata/fetch.https.sub.any.js :: Same-origin mode" = "" -"fetch/metadata/fetch.https.sub.any.js :: Same-site fetch" = "" -"fetch/metadata/fetch.https.sub.any.js :: no-CORS mode" = "" -"fetch/metadata/trailing-dot.https.sub.any.js :: Fetching a resource from a cross-site host, spelled with a trailing dot." = "" -"fetch/metadata/trailing-dot.https.sub.any.js :: Fetching a resource from the same origin, but spelled with a trailing dot." = "" -"fetch/metadata/trailing-dot.https.sub.any.js :: Fetching a resource from the same site, but spelled with a trailing dot." = "" -"fetch/nosniff/parsing-nosniff.window.js :: Loading JSON…" = "" "fetch/orb/tentative/content-range.sub.any.js :: ORB shouldn't block opaque range of image/png starting at zero: fetch(..., {mode: \"no-cors\"})" = "" "fetch/orb/tentative/known-mime-type.sub.any.js :: ORB shouldn't block opaque image/png: fetch(..., {mode: \"no-cors\"})" = "" "fetch/orb/tentative/known-mime-type.sub.any.js :: ORB shouldn't block opaque text/javascript (iso-8559-1 encoded): fetch(..., {mode: \"no-cors\"})" = "" @@ -1681,49 +1649,6 @@ "fetch/orb/tentative/unknown-mime-type.sub.any.js :: ORB shouldn't block opaque failed missing MIME type (image/png): fetch(..., {mode: \"no-cors\"})" = "" "fetch/orb/tentative/unknown-mime-type.sub.any.js :: ORB shouldn't block opaque failed missing MIME type (text/javascript): fetch(..., {mode: \"no-cors\"})" = "" "fetch/orb/tentative/unknown-mime-type.sub.any.js :: ORB shouldn't block opaque failed missing MIME type (text/plain): fetch(..., {mode: \"no-cors\"})" = "" -"fetch/origin/assorted.window.js :: Origin header and 308 redirect" = "" -"fetch/origin/assorted.window.js :: Origin header and GET cross-origin fetch cors mode with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and GET cross-origin fetch cors mode with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and GET cross-origin fetch cors mode with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and GET cross-origin fetch cors mode with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and GET cross-origin fetch cors mode with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and GET navigation" = "" -"fetch/origin/assorted.window.js :: Origin header and GET same-origin fetch cors mode with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and GET same-origin fetch cors mode with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and GET same-origin fetch cors mode with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and GET same-origin fetch cors mode with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and GET same-origin fetch cors mode with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch cors mode with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch cors mode with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch cors mode with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch cors mode with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch cors mode with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch no-cors mode with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch no-cors mode with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch no-cors mode with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch no-cors mode with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin fetch no-cors mode with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin navigation with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin navigation with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin navigation with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin navigation with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST cross-origin navigation with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and POST navigation" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch cors mode with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch cors mode with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch cors mode with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch cors mode with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch cors mode with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch no-cors mode with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch no-cors mode with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch no-cors mode with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch no-cors mode with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin fetch no-cors mode with Referrer-Policy unsafe-url" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin navigation with Referrer-Policy no-referrer" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin navigation with Referrer-Policy no-referrer-when-downgrade" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin navigation with Referrer-Policy origin-when-cross-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin navigation with Referrer-Policy same-origin" = "" -"fetch/origin/assorted.window.js :: Origin header and POST same-origin navigation with Referrer-Policy unsafe-url" = "" "fetch/range/blob.any.js :: A blob range request with no end." = "" "fetch/range/blob.any.js :: A blob range request with no start." = "" "fetch/range/blob.any.js :: A blob range request with no type." = "" @@ -1753,141 +1678,17 @@ "fetch/range/blob.any.js :: Blob range with whitespace before and after hyphen" = "" "fetch/range/data.any.js :: data: URL and Range header" = "" "fetch/range/data.any.js :: data: URL and Range header with multiple ranges" = "" +"fetch/range/general.any.js :: Cross Origin Fetch with non safe range header" = "" "fetch/range/general.any.js :: Cross Origin Fetch with safe range header" = "" "fetch/range/general.any.js :: Fetch with range header will be sent with Accept-Encoding: identity" = "" -"fetch/range/general.window.js :: Fetch with range header will be sent with Accept-Encoding: identity" = "" -"fetch/range/general.window.js :: Script executed from partial response" = "" -"fetch/range/sw-416.https.window.js :: 416 response not allowed following no-cors ranged request" = "" -"fetch/range/sw-intercept-range.https.window.js :: Cross-origin CORS range request must be intercepted by the service worker" = "" -"fetch/range/sw-intercept-range.https.window.js :: Same-origin range request must be intercepted by the service worker" = "" -"fetch/range/sw.https.window.js :: Accept-Encoding should not appear in a service worker" = "" -"fetch/range/sw.https.window.js :: Defer range header filter tests to service worker" = "" -"fetch/range/sw.https.window.js :: Defer range header passthrough tests to service worker" = "" -"fetch/range/sw.https.window.js :: Non-opaque ranged response executed" = "" -"fetch/range/sw.https.window.js :: Opaque range preload successes and failures should be indistinguishable" = "" -"fetch/range/sw.https.window.js :: Ranged response not allowed following no-cors ranged request" = "" "fetch/security/1xx-response.any.js :: Status(101) should be accepted, with removing body." = "" "fetch/stale-while-revalidate/fetch.any.js :: Second fetch returns same response" = "" "url/IdnaTestV2-removed.any.js :: Loading data…" = "" "url/IdnaTestV2.any.js :: Loading data…" = "" "url/idlharness.any.js :: idl_test setup" = "" -"url/javascript-urls.window.js :: javascript: URL containing a JavaScript string split over path and query" = "" -"url/javascript-urls.window.js :: javascript: URL containing a JavaScript string split over path and query and has a U+000A in scheme" = "" -"url/javascript-urls.window.js :: javascript: URL that fails to parse due to invalid host" = "" -"url/javascript-urls.window.js :: javascript: URL that fails to parse due to invalid host and has a U+0009 in scheme" = "" -"url/javascript-urls.window.js :: javascript: URL with extra slashes at the start" = "" -"url/javascript-urls.window.js :: javascript: URL without an opaque path" = "" -"url/percent-encoding.window.js :: Loading data…" = "" -"url/toascii.window.js :: Loading data…" = "" "url/url-constructor.any.js :: Loading data…" = "" "url/url-origin.any.js :: Loading data…" = "" "url/url-searchparams.any.js :: URL.searchParams and URL.search setters, update propagation" = "" -"url/url-setters-a-area.window.js :: Loading data…" = "" -"url/url-setters-stripping.any.js :: Setting hash with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hash with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hash with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hash with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hash with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hash with trailing U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with leading U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with middle U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting host with trailing U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with leading U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with middle U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting hostname with trailing U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting password with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting password with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting password with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting password with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting password with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting password with trailing U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting pathname with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting pathname with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting pathname with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting pathname with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting pathname with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting pathname with trailing U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+001F (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with leading U+001F (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+001F (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with middle U+001F (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+0009 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+0009 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+000A (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+000A (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+000D (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+000D (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+001F (https:)" = "" -"url/url-setters-stripping.any.js :: Setting port with trailing U+001F (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting protocol with U+0000 before inserted colon (https:)" = "" -"url/url-setters-stripping.any.js :: Setting protocol with U+0000 before inserted colon (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting search with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting search with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting search with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting search with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting search with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting search with trailing U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting username with leading U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting username with leading U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting username with middle U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting username with middle U+0000 (wpt++:)" = "" -"url/url-setters-stripping.any.js :: Setting username with trailing U+0000 (https:)" = "" -"url/url-setters-stripping.any.js :: Setting username with trailing U+0000 (wpt++:)" = "" "url/url-setters.any.js :: Loading data…" = "" "url/url-statics-canparse.any.js :: URL.canParse(undefined, aaa:/b)" = "" "url/url-statics-parse.any.js :: URL.parse(undefined, aaa:/b)" = "" diff --git a/expectations/wpt-wintertc.toml b/expectations/wpt-wintertc.toml index 3d3453c..40993f3 100644 --- a/expectations/wpt-wintertc.toml +++ b/expectations/wpt-wintertc.toml @@ -1,6 +1,50 @@ # WinterTC / WPT expectations baseline. -# Keys are picomatch globs over WPT-relative test paths, without the subtest suffix. +# Keys are picomatch globs over WPT-relative test paths (no subtest suffix). Skipped tests leave the +# pass-rate denominator (rate over run, not selection); ratcheted per-subtest failures are counted +# but expected. Skip only what is structurally unreachable -- never a file with passing subtests. [skip] +# TLS / HTTP-2 -- unreachable transport. The wptserve sidecar is plain HTTP on loopback (no WPT-CA +# trust, HTTP/2 off), so .https / .h2 tests can't run on their required transport; the few that pass +# over plain HTTP are not valid signals for it. Skipped wholesale rather than counted. +# The `.https.` / `.h2.` infix marks the required transport in WPT (also in `.https.sub.any.js`, +# `.tentative.https.any.js`, `.https.window.js`, ...), so match it anywhere in the filename. +"**/*.https.*" = "no TLS: HTTP-only server cut, no WPT-CA trust" +"**/*.h2.*" = "no HTTP/2: server started with --no-h2" + +# Browser-only `.window.js` (no document / window / navigation). Only window-scoped files with ZERO +# headless passes are skipped; those that DO pass headless (encoding/single-byte-decoder, +# fetch/content-type/multipart, fetch/h1-parsing/{lone-cr,status-code}) stay in so their passes +# count and failures ratchet -- same rule as encodeInto. On a re-vendor, a new `.window.js` runs +# (failures show as regressions) until triaged here. +"fetch/fetch-later/**" = "browser-only: fetchLater needs window / iframe / bfcache" +"encoding/streams/invalid-realm.window.js" = "browser-only: window-scoped, no headless pass" +"encoding/streams/realms.window.js" = "browser-only: window-scoped, no headless pass" +"encoding/unsupported-labels.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/api/basic/mediasource.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/api/request/multi-globals/construct-in-detached-frame.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/content-length/parsing.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/content-length/too-long.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/content-type/response.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/content-type/script.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/data-urls/navigate.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/h1-parsing/resources-with-0x00-in-header.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/local-network-access/navigate.tentative.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/nosniff/parsing-nosniff.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/origin/assorted.window.js" = "browser-only: window-scoped, no headless pass" +"fetch/range/general.window.js" = "browser-only: window-scoped, no headless pass" +"url/javascript-urls.window.js" = "browser-only: window-scoped, no headless pass" +"url/percent-encoding.window.js" = "browser-only: window-scoped, no headless pass" +"url/toascii.window.js" = "browser-only: window-scoped, no headless pass" +"url/url-setters-a-area.window.js" = "browser-only: window-scoped, no headless pass" + +# encoding/encodeInto.any.js is NOT skipped: its valid-destination subtests pass. Known failures +# (ratcheted): the SharedArrayBuffer subtests (need WebAssembly.Memory) plus 12 non-SAB -- the +# invalid-destination checks for non-Uint8Array typed arrays over ArrayBuffer, and the detached +# buffer. Skipping the file would drop its passes, so it stays scored. + +# Cross-origin fetch subtests (CORS, CORP, cross-origin redirects) aren't file-globbable -- they sit +# among same-origin subtests in otherwise-passing files and need the web-platform.test subdomain +# aliases this loopback cut lacks. They stay ratcheted: structurally plateaued, not regressions. [fail] diff --git a/harness/src/adapters/wpt-server.test.ts b/harness/src/adapters/wpt-server.test.ts new file mode 100644 index 0000000..e4dc15e --- /dev/null +++ b/harness/src/adapters/wpt-server.test.ts @@ -0,0 +1,80 @@ +import { test, expect } from "bun:test"; +import { mkdtempSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { parseMainHttpPort, startWptServer } from "./wpt-server"; + +test("parseMainHttpPort reads the primary http listener, not http-local/http-public/https", () => { + const log = [ + "[2026-07-19 10:00:00,000 http-local on port 5001] INFO - Starting http server on http://127.0.0.1:5001", + "[2026-07-19 10:00:00,001 http-public on port 5002] INFO - Starting http server on http://127.0.0.1:5002", + "[2026-07-19 10:00:00,002 http on port 5003] INFO - Starting http server on http://127.0.0.1:5003", + "[2026-07-19 10:00:00,003 https on port 5004] INFO - Starting https server on https://127.0.0.1:5004", + ].join("\n"); + expect(parseMainHttpPort(log)).toBe(5003); +}); + +test("parseMainHttpPort ignores everything until the primary listener logs its bind", () => { + expect(parseMainHttpPort("")).toBeNull(); + // http-local / http-public / the http:// URL in the message must never be mistaken for the primary. + expect( + parseMainHttpPort( + "[.. http-local on port 5001] INFO - Starting http server on http://127.0.0.1:5001\n" + + "[.. http-public on port 5002] INFO - Starting http server on http://127.0.0.1:5002", + ), + ).toBeNull(); +}); + +// Fake `wpt` that binds an OS-assigned loopback port, logs it in wptserve's format, and serves +// testharness.js — exercising the real spawn → drain → port-parse → readiness → stop path without a +// WPT checkout or Python wptserve deps. +const FAKE_WPT = `import http.server, socketserver, signal, sys +class H(http.server.BaseHTTPRequestHandler): + def do_GET(self): + if self.path == "/resources/testharness.js": + self.send_response(200); self.end_headers(); self.wfile.write(b"// ok") + else: + self.send_response(404); self.end_headers() + def log_message(self, *a): pass +srv = socketserver.TCPServer(("127.0.0.1", 0), H) +port = srv.server_address[1] +print("[2026-07-19 10:00:00,000 http on port %d] INFO - Starting http server on http://127.0.0.1:%d" % (port, port), flush=True) +signal.signal(signal.SIGINT, lambda *a: sys.exit(0)) +srv.serve_forever() +`; + +const python = Bun.which("python3"); + +test.skipIf(!python)("startWptServer parses the bound port, becomes ready, and stop() is idempotent", async () => { + const suitePath = mkdtempSync(join(tmpdir(), "wpt-fake-")); + writeFileSync(join(suitePath, "wpt"), FAKE_WPT); + + const server = await startWptServer(suitePath, { readyTimeoutMs: 10_000 }); + try { + expect(server.host).toBe("127.0.0.1"); + expect(server.httpPort).toBeGreaterThan(0); + expect(server.origin).toBe(`http://127.0.0.1:${server.httpPort}`); + + // The server the parsed port points at genuinely serves testharness.js. + const resp = await fetch(`${server.origin}/resources/testharness.js`); + expect(resp.status).toBe(200); + await resp.body?.cancel(); + } finally { + server.stop(); + server.stop(); // idempotent — must not throw + } +}); + +test.skipIf(!python)("startWptServer throws (not hangs) when the server never reports a port", async () => { + const suitePath = mkdtempSync(join(tmpdir(), "wpt-fake-")); + // A `wpt` that exits immediately without ever logging a port. + writeFileSync(join(suitePath, "wpt"), "import sys; sys.exit(0)\n"); + + let error: unknown; + try { + await startWptServer(suitePath, { readyTimeoutMs: 2_000 }); + } catch (e) { + error = e; + } + expect(String(error)).toContain("did not report a bound HTTP port"); +}); diff --git a/harness/src/adapters/wpt-server.ts b/harness/src/adapters/wpt-server.ts new file mode 100644 index 0000000..a55f3b7 --- /dev/null +++ b/harness/src/adapters/wpt-server.ts @@ -0,0 +1,177 @@ +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +/** + * A running WPT server (wptserve) sidecar. `.any.js` fetch tests resolve relative URLs against the + * document location and fetch WPT resources / stateful handlers; without a real server they die in + * setup ("Failed to parse URL"). The two runtimes that actually run `fetch/api` — Deno and workerd + * — both run upstream Python wptserve as a sidecar; this mirrors that. + * + * Scope of this cut: HTTP only, bound to `127.0.0.1`, subdomain checks off. That un-gates the + * same-origin fetch tests (the majority) with no `/etc/hosts` dependency, so it runs identically + * locally and in the container. Cross-origin (subdomain) and `.https` / `.h2` tests still fail — + * they need the `web-platform.test` subdomain aliases and a client that trusts WPT's CA (an Elide + * TLS-trust concern), and are gated in `expectations/wpt-wintertc.toml`. + */ +export interface WptServer { + /** Same-origin base, e.g. `http://127.0.0.1:8123`. */ + origin: string; + host: string; + httpPort: number; + /** Terminate the server (and its child listeners) and clean up. Idempotent. */ + stop(): void; +} + +const HOST = "127.0.0.1"; + +// wptserve tags each listener line "[ on port ] ...". Reading the bound port +// from the log (rather than pre-allocating one) removes the bind-then-hope-it's-free TOCTOU race. +const MAIN_HTTP_PORT_RE = /\bhttp on port (\d+)\]/; +const CAPTURE_CAP = 8192; + +/** + * Port of the primary HTTP listener from wptserve's log output. The regex matches only the `http` + * scheme tag — never `http-local`/`http-public`/`https` nor the `http://…` message text. Null until + * that line appears. + */ +export function parseMainHttpPort(logText: string): number | null { + const m = MAIN_HTTP_PORT_RE.exec(logText); + return m ? Number(m[1]) : null; +} + +/** Poll `origin` until it serves testharness.js or the deadline passes. */ +async function waitReady(origin: string, deadlineMs: number): Promise { + const probeUrl = `${origin}/resources/testharness.js`; + while (Date.now() < deadlineMs) { + try { + // Loopback is never routed through an HTTP proxy by Bun's fetch, so no proxy bypass is needed. + const resp = await fetch(probeUrl, { signal: AbortSignal.timeout(1000) }); + await resp.body?.cancel(); + if (resp.status === 200) return true; + } catch { + // not up yet + } + await new Promise((r) => setTimeout(r, 200)); + } + return false; +} + +/** + * Start wptserve against `suitePath` (the WPT checkout) and wait until it serves. Throws if the + * server does not come up within `readyTimeoutMs`. `bin/setup.ts` has already patched the checkout + * to run `wpt serve` without a virtualenv. + */ +export async function startWptServer( + suitePath: string, + opts: { readyTimeoutMs?: number; log?: (msg: string) => void } = {}, +): Promise { + const log = opts.log ?? (() => {}); + + // Override merged over wptserve's `_default` config: bind loopback explicitly (bind_address + + // browser_host → 127.0.0.1, not 0.0.0.0), skip the subdomain check, auto-pick every port, and + // disable TLS (the pregenerated cert is for web-platform.test). The ssl-"none" https listeners + // fail to start and are logged-and-skipped; the http listener serves regardless. + const configDir = mkdtempSync(join(tmpdir(), "wpt-serve-")); + const configPath = join(configDir, "config.json"); + const cleanupConfig = (): void => { + try { + rmSync(configDir, { recursive: true, force: true }); + } catch { + // best effort + } + }; + writeFileSync( + configPath, + JSON.stringify({ + browser_host: HOST, + bind_address: true, + alternate_hosts: {}, + check_subdomains: false, + ports: { http: ["auto", "auto"], https: ["auto", "auto"] }, + ssl: { type: "none" }, + }), + ); + + const proc = Bun.spawn( + ["python3", "./wpt", "serve", "--config", configPath, "--no-h2", "--doc_root", suitePath], + { cwd: suitePath, stdout: "pipe", stderr: "pipe", stdin: "ignore" }, + ); + + let stopped = false; + const stop = (): void => { + if (stopped) return; + stopped = true; + try { + // wptserve forks multiprocessing child listeners and reaps them on its KeyboardInterrupt + // (SIGINT) handler; a plain SIGTERM/SIGKILL of the parent would orphan them (ports stay + // bound). SIGINT first for a clean reap; if it does not exit in time, SIGKILL the parent AND + // pkill anything still holding this server's unique --config path (the forked children + // inherit the parent's argv, so they carry it too) — no orphaned listeners survive. + proc.kill("SIGINT"); + } catch { + // already gone + } + const grace = setTimeout(() => { + try { + proc.kill("SIGKILL"); + } catch { + // gone + } + try { + Bun.spawn(["pkill", "-9", "-f", configPath], { stdout: "ignore", stderr: "ignore" }); + } catch { + // pkill unavailable / nothing to kill + } + cleanupConfig(); + }, 5000); + void proc.exited.finally(() => { + clearTimeout(grace); + cleanupConfig(); + }); + }; + + const deadline = Date.now() + (opts.readyTimeoutMs ?? 30_000); + + // Drain both streams (so wptserve never blocks on a full pipe), capturing a bounded tail for + // diagnostics and resolving the port as soon as the primary HTTP listener logs it. + let capture = ""; + let resolvePort: (p: number | null) => void = () => {}; + const portFound = new Promise((r) => { + resolvePort = r; + }); + const drain = async (stream: ReadableStream | undefined): Promise => { + if (!stream) return; + const dec = new TextDecoder(); + try { + for await (const chunk of stream) { + const text = capture + dec.decode(chunk, { stream: true }); + const port = parseMainHttpPort(text); + if (port !== null) resolvePort(port); + capture = text.length > CAPTURE_CAP ? text.slice(-CAPTURE_CAP) : text; + } + } catch { + // stream closed + } + }; + void drain(proc.stdout as ReadableStream); + void drain(proc.stderr as ReadableStream); + + const port = await Promise.race([ + portFound, + new Promise((r) => setTimeout(() => r(null), Math.max(0, deadline - Date.now()))), + ]); + if (port === null) { + stop(); + throw new Error(`wptserve did not report a bound HTTP port\n${capture.slice(-2000)}`); + } + + const origin = `http://${HOST}:${port}`; + const ready = await waitReady(origin, deadline); + if (!ready) { + stop(); + throw new Error(`wptserve did not become ready at ${origin}\n${capture.slice(-2000)}`); + } + log(`wptserve ready at ${origin}`); + return { origin, host: HOST, httpPort: port, stop }; +} diff --git a/harness/src/adapters/wpt-wintertc.test.ts b/harness/src/adapters/wpt-wintertc.test.ts index 3938758..eb31ea8 100644 --- a/harness/src/adapters/wpt-wintertc.test.ts +++ b/harness/src/adapters/wpt-wintertc.test.ts @@ -3,7 +3,7 @@ import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import type { AdapterContext } from "./types"; -import { filterIncludedPaths, parseWptLine, parseWptLines, runWptWintertc } from "./wpt-wintertc"; +import { filterIncludedPaths, isFetchTask, parseWptLine, parseWptLines, runWptWintertc } from "./wpt-wintertc"; const fixture = await Bun.file(`${import.meta.dir}/../../fixtures/wpt-wintertc.ndjson`).text(); @@ -113,6 +113,27 @@ test("META preamble inlines existing scripts, shims virtual ones, and marks miss expect(preamble).toContain("missing META script /no/such/helper.js"); }); +test("buildEnvPreamble roots location at WPT_SERVER_ORIGIN when set, else the synthetic origin", async () => { + const runner = await import("../../../suites/drivers/wpt/wintertc-runner.js"); + const prev = process.env.WPT_SERVER_ORIGIN; + try { + process.env.WPT_SERVER_ORIGIN = "http://127.0.0.1:8123"; + const withServer = runner.buildEnvPreamble("fetch/api/basic/a.any.js"); + expect(withServer).toContain('"origin":"http://127.0.0.1:8123"'); + expect(withServer).toContain('"href":"http://127.0.0.1:8123/fetch/api/basic/"'); + expect(withServer).toContain('"host":"127.0.0.1:8123"'); + expect(withServer).toContain('"port":"8123"'); + + delete process.env.WPT_SERVER_ORIGIN; + const noServer = runner.buildEnvPreamble("fetch/api/basic/a.any.js"); + expect(noServer).toContain('"origin":"http://web-platform.test"'); + expect(noServer).not.toContain("127.0.0.1"); + } finally { + if (prev === undefined) delete process.env.WPT_SERVER_ORIGIN; + else process.env.WPT_SERVER_ORIGIN = prev; + } +}); + function collect(items: AsyncIterable): Promise { return Array.fromAsync(items); } @@ -212,3 +233,53 @@ setTimeout(() => { expect(writes).toContain("progress: start url/a.any.js"); expect(writes).toContain("progress: still running url/a.any.js"); }); + +test("isFetchTask gates the server on fetch/ paths only", () => { + expect(isFetchTask({ category: "fetch", rel: "fetch/api/basic/a.any.js" })).toBe(true); + expect(isFetchTask({ category: "url", rel: "url/a.any.js" })).toBe(false); + expect(isFetchTask({ category: "encoding", rel: "encoding/textdecoder.any.js" })).toBe(false); +}); + +test("a failed server fails fetch tasks explicitly but leaves serverless tasks running", async () => { + const root = mkdtempSync(join(tmpdir(), "wpt-wintertc-")); + const manifest = join(root, "manifest.toml"); + const suitePath = join(root, "wpt"); // no ./wpt entrypoint -> startWptServer fails fast + const runnerDir = join(root, "suites/drivers/wpt"); + mkdirSync(suitePath, { recursive: true }); + mkdirSync(runnerDir, { recursive: true }); + writeFileSync( + manifest, + ['[[group]]', 'id = "fetch"', 'include = ["fetch/api/basic/a.any.js"]', "", '[[group]]', 'id = "url"', 'include = ["url/b.any.js"]', ""].join("\n"), + ); + writeFileSync( + join(runnerDir, "wintertc-runner.js"), + `function arg(name) { const i = process.argv.indexOf(name); return i >= 0 ? process.argv[i + 1] : ""; } +console.log(JSON.stringify({ path: arg("--test"), subtest: "file", status: "PASS", category: arg("--category") })); +`, + ); + const ctx: AdapterContext = { + elide: { semver: "test", digest: "deadbeef" }, + elidePath: "/fake/elide", + repoRoot: root, + suitePath, + include: [], + skipGlobs: [], + threads: 2, + settings: { manifest, timeoutMs: 5_000, serverReadyTimeoutMs: 500 }, + workspacePath: join(root, "workspace"), + }; + const stderr = spyOn(process.stderr, "write").mockImplementation(() => true); + let results; + try { + results = await collect(runWptWintertc(ctx)); + } finally { + stderr.mockRestore(); + } + const byId = new Map(results.map((r) => [r.id, r])); + // Serverless url task ran normally through the fake runner. + expect(byId.get("url/b.any.js :: file")?.status).toBe("pass"); + // Fetch task is an explicit, attributed error — not a silent pass and not an opaque runner failure. + const fetchResult = byId.get("fetch/api/basic/a.any.js :: "); + expect(fetchResult?.status).toBe("error"); + expect(fetchResult?.message).toContain("wpt-server unavailable"); +}); diff --git a/harness/src/adapters/wpt-wintertc.ts b/harness/src/adapters/wpt-wintertc.ts index f164981..bd66f0a 100644 --- a/harness/src/adapters/wpt-wintertc.ts +++ b/harness/src/adapters/wpt-wintertc.ts @@ -5,6 +5,7 @@ import type { TestResult } from "../results/schema"; import { loadManifest } from "../manifest"; import { runProcess } from "./process"; import { runTaskPool } from "./pool"; +import { type WptServer, startWptServer } from "./wpt-server"; interface WptBridgeRecord { path: string; @@ -82,34 +83,67 @@ export function parseWptLines(text: string): TestResult[] { return text.split(/\r?\n/).map(parseWptLine).filter((r): r is TestResult => r !== null); } +/** WPT `fetch/` tests hit the network sidecar; every other group runs serverless. */ +export function isFetchTask(task: WptTask): boolean { + return task.rel.startsWith("fetch/"); +} + +// Some fetch tests (e.g. fetch/api/basic/mode-same-origin) build subtest names from the server's +// absolute URL, which carries the sidecar's ephemeral port. That port changes every run, so the +// test id would change every run and never match the ratchet -- a permanent false regression. +// Replace the live loopback authority with a stable placeholder before the id is recorded/compared. +const PORT_PLACEHOLDER = "127.0.0.1:"; + +function normalizeServerPort(text: string, origin: string | undefined): string { + if (!origin || !text) return text; + let host: string; + try { + host = new URL(origin).host; // e.g. "127.0.0.1:54321" + } catch { + return text; + } + return host ? text.split(host).join(PORT_PLACEHOLDER) : text; +} + +/** A file-level `error` result (the runner never ran, or ran and failed before per-test output). */ +function fileErrorResult(task: WptTask, message: string, durationMs = 0): TestResult { + return { + kind: "test", + id: `${task.rel} :: `, + status: "error", + message, + durationMs, + meta: { suite: "wpt-wintertc", upstreamPath: task.rel, category: task.category, runner: "wpt", subtest: "" }, + }; +} + async function runWptTask( ctx: AdapterContext, runner: string, skip: Array<(path: string) => boolean>, task: WptTask, + serverEnv?: Record, ): Promise { const stopProgress = startProgress(ctx, task.rel); let result; try { result = await runProcess( ["node", runner, "--suite", ctx.suitePath, "--test", task.rel, "--category", task.category, "--elide", ctx.elidePath], - { cwd: ctx.repoRoot, timeoutMs: Number(ctx.settings.timeoutMs ?? 60_000) }, + { cwd: ctx.repoRoot, timeoutMs: Number(ctx.settings.timeoutMs ?? 60_000), env: serverEnv }, ); } finally { stopProgress(); } if (result.timedOut || result.exitCode !== 0) { - return [{ - kind: "test", - id: `${task.rel} :: `, - status: "error", - message: result.timedOut ? "WPT bridge timed out" : result.stderr || result.stdout, - durationMs: result.durationMs, - meta: { suite: "wpt-wintertc", upstreamPath: task.rel, category: task.category, runner: "wpt", subtest: "" }, - }]; + const message = result.timedOut ? "WPT bridge timed out" : result.stderr || result.stdout; + return [fileErrorResult(task, message, result.durationMs)]; } + const origin = serverEnv?.WPT_SERVER_ORIGIN; return parseWptLines(result.stdout).map((r) => { - return skip.some((m) => m(String(r.meta?.upstreamPath))) ? { ...r, status: "skip" } : r; + const id = normalizeServerPort(r.id, origin); + const subtest = typeof r.meta?.subtest === "string" ? normalizeServerPort(r.meta.subtest, origin) : r.meta?.subtest; + const nr: TestResult = { ...r, id, meta: { ...r.meta, subtest } }; + return skip.some((m) => m(String(nr.meta?.upstreamPath))) ? { ...nr, status: "skip" } : nr; }); } @@ -123,7 +157,46 @@ export async function* runWptWintertc(ctx: AdapterContext): AsyncIterable ({ category: group.id, rel })); }); - yield* runTaskPool(tasks, ctx.threads, (task) => runWptTask(ctx, runner, skip, task)); + // The fetch tests resolve relative URLs against the document location and fetch WPT resources / + // handlers; they need a real WPT server (the `fetch/` group — equivalently the `fetch/` path + // prefix; the manifest groups them one-to-one). Start one only when fetch tasks are in scope, and + // never let a server failure sink the encoding/url tests — those run serverless. + const needsServer = tasks.some(isFetchTask); + let server: WptServer | undefined; + let serverError: string | undefined; + if (needsServer) { + try { + server = await startWptServer(ctx.suitePath, { + readyTimeoutMs: Number(ctx.settings.serverReadyTimeoutMs ?? 30_000), + log: (m) => { + if (progressEnabled(ctx)) process.stderr.write(`${ctx.logPrefix ?? ""}${m}\n`); + }, + }); + } catch (err) { + serverError = err instanceof Error ? err.message : String(err); + // Loud, unmissable banner: without it a broken server (missing python, port issue) silently + // turns every fetch pass into an opaque error, and a ratchet regen taken in that state would + // bake the collapse into the baseline. Below, each fetch task is failed explicitly instead. + process.stderr.write( + `${ctx.logPrefix ?? ""}wpt-server: FAILED TO START — all fetch tests will be reported as errors, ` + + `fetch conformance for this run is INVALID (${serverError})\n`, + ); + } + } + const serverEnv = server ? { WPT_SERVER_ORIGIN: server.origin } : undefined; + + try { + yield* runTaskPool(tasks, ctx.threads, (task) => { + // Server needed but down: attribute the failure to the server rather than spawning a runner + // that would time out and emit an opaque error, so the collapse is explicit in the results. + if (serverError && isFetchTask(task)) { + return Promise.resolve([fileErrorResult(task, `wpt-server unavailable: ${serverError}`)]); + } + return runWptTask(ctx, runner, skip, task, serverEnv); + }); + } finally { + server?.stop(); + } } export const wptWintertcAdapter: Adapter = { diff --git a/harness/src/expectations/compare.test.ts b/harness/src/expectations/compare.test.ts index 30a2a0b..cf933d9 100644 --- a/harness/src/expectations/compare.test.ts +++ b/harness/src/expectations/compare.test.ts @@ -1,4 +1,6 @@ import { test, expect } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; import { parseExpectations } from "./load"; import { compare, passRate, scoredTotal } from "./compare"; import type { TestResult } from "../results/schema"; @@ -115,3 +117,34 @@ test("CPython module-level skip expectations match upstreamPath metadata", () => expect(c.regressions).toHaveLength(0); expect(c.counts.skip).toBe(1); }); + +test("wpt-wintertc baseline skips unreachable tests but keeps window.js files that pass headless", () => { + const wpt = parseExpectations( + readFileSync(join(import.meta.dir, "../../../expectations/wpt-wintertc.toml"), "utf8"), + ); + const mkWpt = (path: string, status: TestResult["status"]): TestResult => + mk(`${path} :: t`, status, { + suite: "wpt-wintertc", + upstreamPath: path, + runner: "wpt", + subtest: "t", + }); + const c = compare( + [ + mkWpt("url/toascii.window.js", "fail"), // browser-only, explicitly listed -> skip + mkWpt("fetch/api/cors/cors-basic.https.any.js", "fail"), // no TLS -> skip + mkWpt("fetch/api/redirect/redirect-upload.h2.any.js", "fail"), // no HTTP/2 -> skip + mkWpt("fetch/fetch-later/basic.any.js", "fail"), // browser-only -> skip + // A .window.js file that passes headless is deliberately NOT skipped, so its pass counts. + mkWpt("encoding/single-byte-decoder.window.js", "pass"), + mkWpt("url/urlsearchparams-constructor.any.js", "pass"), + // encodeInto is deliberately NOT skipped: its valid-destination branch passes, so it stays scored. + mkWpt("encoding/encodeInto.any.js", "fail"), + ], + wpt, + ); + expect(c.counts.skip).toBe(4); // listed .window.js + .https + .h2 + fetch-later + expect(c.counts.pass).toBe(2); // the headless-passing .window.js keeper and the url test are scored + expect(c.counts.fail).toBe(1); // encodeInto stays a scored failure, not skipped + expect(scoredTotal(c.counts)).toBe(3); // only the four unreachable tests leave the denominator +}); diff --git a/suites/drivers/wpt/wintertc-runner.js b/suites/drivers/wpt/wintertc-runner.js index e784ec2..b32aff1 100644 --- a/suites/drivers/wpt/wintertc-runner.js +++ b/suites/drivers/wpt/wintertc-runner.js @@ -94,25 +94,28 @@ function token() { return uuid; } `, - // Upstream common/get-host-info.sub.js with static substitutions - // (host: web-platform.test, ports: 80/81/443/444). + // Upstream common/get-host-info.sub.js. Same-origin host + port derive from self.location, so + // they track a running WPT server (WPT_SERVER_ORIGIN); cross-origin subdomains and the second + // port have no server here and stay gated. "/common/get-host-info.sub.js": ` function get_host_info() { - var HTTP_PORT = '80'; - var HTTP_PORT2 = '81'; - var HTTPS_PORT = '443'; - var HTTPS_PORT2 = '444'; var PROTOCOL = self.location.protocol; var IS_HTTPS = (PROTOCOL == "https:"); + // Host + primary port track the running server via location; the "second port" and cross-origin + // hosts below have no server here (subdomain / multi-port tests stay gated, failing honestly). + var ORIGINAL_HOST = self.location.hostname; + var HTTP_PORT = (!IS_HTTPS && self.location.port) ? self.location.port : '80'; + var HTTPS_PORT = (IS_HTTPS && self.location.port) ? self.location.port : '443'; + var HTTP_PORT2 = '81'; + var HTTPS_PORT2 = '444'; var PORT = IS_HTTPS ? HTTPS_PORT : HTTP_PORT; var PORT2 = IS_HTTPS ? HTTPS_PORT2 : HTTP_PORT2; var HTTP_PORT_ELIDED = HTTP_PORT == "80" ? "" : (":" + HTTP_PORT); var HTTP_PORT2_ELIDED = HTTP_PORT2 == "80" ? "" : (":" + HTTP_PORT2); var HTTPS_PORT_ELIDED = HTTPS_PORT == "443" ? "" : (":" + HTTPS_PORT); var PORT_ELIDED = IS_HTTPS ? HTTPS_PORT_ELIDED : HTTP_PORT_ELIDED; - var ORIGINAL_HOST = 'web-platform.test'; var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST); - var OTHER_HOST = 'www2.web-platform.test'; + var OTHER_HOST = 'www2.' + ORIGINAL_HOST; var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('not-' + ORIGINAL_HOST); return { HTTP_PORT: HTTP_PORT, @@ -210,13 +213,18 @@ export function buildMetaPreamble(suiteRoot, testRel, source) { export function buildEnvPreamble(testRel) { const dir = posix.dirname(testRel); const pathname = dir === "." ? "/" : `/${dir}/`; - const origin = "http://web-platform.test"; + // When a WPT server is running (fetch tests, WPT_SERVER_ORIGIN set by the adapter), root the + // document location at it so relative fetches resolve to real served resources. Otherwise use a + // static synthetic origin — enough for tests that only read location, never fetch. + const serverOrigin = process.env.WPT_SERVER_ORIGIN; + const u = serverOrigin ? new URL(serverOrigin) : null; + const origin = u ? u.origin : "http://web-platform.test"; const location = { href: origin + pathname, - protocol: "http:", - host: "web-platform.test", - hostname: "web-platform.test", - port: "", + protocol: u ? u.protocol : "http:", + host: u ? u.host : "web-platform.test", + hostname: u ? u.hostname : "web-platform.test", + port: u ? u.port : "", pathname, origin, search: "",