diff --git a/tests/data/groups.json b/tests/data/groups.json new file mode 100644 index 0000000000..871f1b9133 --- /dev/null +++ b/tests/data/groups.json @@ -0,0 +1,126 @@ +{ + "https://respec.org/w3c/groups/css/": { + "body": { + "shortname": "css", + "type": "wg", + "id": 32061, + "name": "Cascading Style Sheets (CSS) Working Group", + "URI": "https://www.w3.org/groups/wg/css/", + "patentURI": "https://www.w3.org/groups/wg/css/ipr", + "patentPolicy": "PP2020", + "wgURI": "https://www.w3.org/groups/wg/css" + } + }, + "https://respec.org/w3c/groups/maps4html/": { + "body": { + "shortname": "maps4html", + "type": "cg", + "id": 70543, + "name": "Maps For HTML Community Group", + "URI": "https://www.w3.org/community/maps4html/", + "wgURI": "https://www.w3.org/groups/cg/maps4html" + } + }, + "https://respec.org/w3c/groups/payments/": { + "body": { + "shortname": "payments", + "type": "wg", + "id": 83744, + "name": "Web Payments Working Group", + "URI": "https://www.w3.org/groups/wg/payments/", + "patentURI": "https://www.w3.org/groups/wg/payments/ipr", + "patentPolicy": "PP2020", + "wgURI": "https://www.w3.org/groups/wg/payments" + } + }, + "https://respec.org/w3c/groups/publishingbg/": { + "body": { + "shortname": "publishingbg", + "type": "bg", + "id": 97159, + "name": "Publishing Business Group", + "URI": "https://www.w3.org/community/publishingbg/", + "wgURI": "https://www.w3.org/groups/bg/publishingbg" + } + }, + "https://respec.org/w3c/groups/tag/": { + "body": { + "shortname": "tag", + "type": "other", + "id": 34270, + "name": "Technical Architecture Group", + "URI": "https://www.w3.org/2001/tag/", + "wgURI": "https://www.w3.org/groups/other/tag" + } + }, + "https://respec.org/w3c/groups/webapps/": { + "body": { + "shortname": "webapps", + "type": "wg", + "id": 114929, + "name": "Web Applications Working Group", + "URI": "https://www.w3.org/groups/wg/webapps/", + "patentURI": "https://www.w3.org/groups/wg/webapps/ipr", + "patentPolicy": "PP2020", + "wgURI": "https://www.w3.org/groups/wg/webapps" + } + }, + "https://respec.org/w3c/groups/webperf/": { + "body": { + "shortname": "webperf", + "type": "wg", + "id": 45211, + "name": "Web Performance Working Group", + "URI": "https://www.w3.org/groups/wg/webperf/", + "patentURI": "https://www.w3.org/groups/wg/webperf/ipr", + "patentPolicy": "PP2020", + "wgURI": "https://www.w3.org/groups/wg/webperf" + } + }, + "https://respec.org/w3c/groups/wicg/": { + "body": { + "shortname": "wicg", + "type": "cg", + "id": 80485, + "name": "Web Platform Incubator Community Group", + "URI": "https://www.w3.org/community/wicg/", + "wgURI": "https://www.w3.org/groups/cg/wicg" + } + }, + "https://respec.org/w3c/groups/wot/wg": { + "body": { + "shortname": "wot", + "type": "wg", + "id": 95969, + "name": "Web of Things Working Group", + "URI": "https://www.w3.org/WoT/wg/", + "patentURI": "https://www.w3.org/groups/wg/wot/ipr", + "patentPolicy": "PP2020", + "wgURI": "https://www.w3.org/groups/wg/wot" + } + }, + "https://respec.org/w3c/groups/json-ld/wg": { + "body": { + "shortname": "json-ld", + "type": "wg", + "id": 107714, + "name": "JSON-LD Working Group", + "URI": "https://www.w3.org/groups/wg/json-ld/", + "patentURI": "https://www.w3.org/groups/wg/json-ld/ipr", + "patentPolicy": "PP2020", + "wgURI": "https://www.w3.org/groups/wg/json-ld" + } + }, + "https://respec.org/w3c/groups/wot/": { + "status": 409, + "body": "Multiple groups with shortname: \"wot\".\nPlease use either: \"cg/wot\", \"ig/wot\", \"wg/wot\"." + }, + "https://respec.org/w3c/groups/404/": { + "status": 404, + "body": "No group with shortname: \"404\"." + }, + "https://respec.org/w3c/groups/not%20a%20real%20group/": { + "status": 404, + "body": "No group with shortname: \"not a real group\"." + } +} diff --git a/tests/spec/core/exporter-spec.js b/tests/spec/core/exporter-spec.js index c9c73c41ea..752f1de569 100644 --- a/tests/spec/core/exporter-spec.js +++ b/tests/spec/core/exporter-spec.js @@ -6,9 +6,11 @@ import { makeRSDoc, makeStandardOps, } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; describe("Core - exporter", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); it("removes .removeOnSave elements", async () => { const ops = makeStandardOps(); diff --git a/tests/spec/core/include-config-spec.js b/tests/spec/core/include-config-spec.js index 7acdeca629..9bd013677a 100644 --- a/tests/spec/core/include-config-spec.js +++ b/tests/spec/core/include-config-spec.js @@ -7,9 +7,11 @@ import { makeRSDoc, makeStandardOps, } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; describe("Core — Include config as JSON", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); let ops; beforeAll(() => { ops = { diff --git a/tests/spec/core/seo-spec.js b/tests/spec/core/seo-spec.js index b4abbf2eca..022f1279cf 100644 --- a/tests/spec/core/seo-spec.js +++ b/tests/spec/core/seo-spec.js @@ -7,9 +7,11 @@ import { makeRSDoc, makeStandardOps, } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; describe("Core — Seo", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); it("doesn't insert a meta description element if there is no abstract", async () => { const ops = { config: makeBasicConfig(), diff --git a/tests/spec/core/ui-spec.js b/tests/spec/core/ui-spec.js index 5a4f15811e..ee78fba2af 100644 --- a/tests/spec/core/ui-spec.js +++ b/tests/spec/core/ui-spec.js @@ -1,9 +1,11 @@ "use strict"; import { flushIframes, makeRSDoc, makeStandardOps } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; describe("Core - UI", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); it("shows and hides the UI", async () => { const doc = await makeRSDoc(makeStandardOps()); diff --git a/tests/spec/karma.conf.cjs b/tests/spec/karma.conf.cjs index a74be1fb7e..d82e1a2bae 100644 --- a/tests/spec/karma.conf.cjs +++ b/tests/spec/karma.conf.cjs @@ -9,6 +9,11 @@ const additionalFiles = [ type: "module", included: false, }, + { + pattern: "tests/spec/respec-cache-helper.js", + type: "module", + included: false, + }, { pattern: "tests/spec/**/*-spec.js", type: "module", diff --git a/tests/spec/respec-cache-helper.js b/tests/spec/respec-cache-helper.js new file mode 100644 index 0000000000..21d3e5d8b9 --- /dev/null +++ b/tests/spec/respec-cache-helper.js @@ -0,0 +1,58 @@ +"use strict"; + +const WEEK = 7 * 24 * 60 * 60 * 1000; + +/** + * Pre-seeds the browser Cache API so fetchAndCache() returns cached + * data without hitting the network. Works for any respec.org endpoint. + * + * @param {Record} entries + * Keys are full URLs, values have optional status (default 200) + * and a body (object for JSON, string for text). + */ +export async function seedCache(entries) { + const byOrigin = new Map(); + for (const [url, entry] of Object.entries(entries)) { + const origin = new URL(url).origin; + if (!byOrigin.has(origin)) byOrigin.set(origin, []); + byOrigin.get(origin).push([url, entry]); + } + const expires = new Date(Date.now() + WEEK).toISOString(); + for (const [origin, urls] of byOrigin) { + const cache = await caches.open(origin); + for (const [url, { status = 200, body }] of urls) { + const isJSON = body !== null && typeof body === "object"; + const headers = { + "Content-Type": isJSON ? "application/json" : "text/plain", + Expires: expires, + }; + const responseBody = isJSON ? JSON.stringify(body) : body; + await cache.put( + new Request(url), + new Response(responseBody, { status, headers }) + ); + } + } +} + +let groupsPromise; + +/** + * Seeds the cache with W3C group API responses from tests/data/groups.json. + * Call from beforeAll() in any test file that uses group: in its config. + */ +export async function seedGroupCache() { + if (!groupsPromise) { + groupsPromise = fetch("/tests/data/groups.json") + .then(r => { + if (!r.ok) + throw new Error(`Failed to load groups fixture: ${r.status}`); + return r.json(); + }) + .catch(err => { + groupsPromise = undefined; + throw err; + }); + } + await seedCache(await groupsPromise); +} diff --git a/tests/spec/w3c/defaults-spec.js b/tests/spec/w3c/defaults-spec.js index b9e2680ae6..0800da1246 100644 --- a/tests/spec/w3c/defaults-spec.js +++ b/tests/spec/w3c/defaults-spec.js @@ -9,10 +9,12 @@ import { makeRSDoc, makeStandardOps, } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; const errorsFilter = errorFilters.filter("w3c/defaults"); describe("W3C — Defaults", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); it("sets sensible defaults for w3c specs", async () => { const ops = { config: { editors: [{ name: "foo" }], specStatus: "base" }, diff --git a/tests/spec/w3c/group-spec.js b/tests/spec/w3c/group-spec.js index 9af5f63f6e..2ba57110da 100644 --- a/tests/spec/w3c/group-spec.js +++ b/tests/spec/w3c/group-spec.js @@ -1,9 +1,11 @@ "use strict"; import { flushIframes, makeRSDoc, makeStandardOps } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; describe("W3C — Group", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); async function getGroupConf(config) { const ops = makeStandardOps(config); diff --git a/tests/spec/w3c/headers-spec.js b/tests/spec/w3c/headers-spec.js index 19dd6197eb..ab981fd8ce 100644 --- a/tests/spec/w3c/headers-spec.js +++ b/tests/spec/w3c/headers-spec.js @@ -18,6 +18,8 @@ import { makeStandardOps, } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; + const headerErrors = errorFilters.filter("w3c/headers"); const defaultErrors = errorFilters.filter("w3c/defaults"); @@ -26,6 +28,7 @@ const findContent = string => { }; describe("W3C — Headers", () => { afterEach(flushIframes); + beforeAll(seedGroupCache); const simpleSpecURL = "spec/core/simple.html"; /** * @param {Node} node diff --git a/tests/spec/w3c/linter-rules/required-sections-spec.js b/tests/spec/w3c/linter-rules/required-sections-spec.js index c4a8d6757b..fd16512a94 100644 --- a/tests/spec/w3c/linter-rules/required-sections-spec.js +++ b/tests/spec/w3c/linter-rules/required-sections-spec.js @@ -9,11 +9,13 @@ import { warningFilters, } from "../../SpecHelper.js"; import { requiresSomeSectionStatus } from "../../../../src/w3c/linter-rules/required-sections.js"; +import { seedGroupCache } from "../../respec-cache-helper.js"; describe("w3c — required-sections", () => { afterAll(() => { flushIframes(); }); + beforeAll(seedGroupCache); const errorsFilter = errorFilters.filter( "w3c/linter-rules/required-sections" diff --git a/tests/spec/w3c/seo-spec.js b/tests/spec/w3c/seo-spec.js index d25db28cf8..42b58557a9 100644 --- a/tests/spec/w3c/seo-spec.js +++ b/tests/spec/w3c/seo-spec.js @@ -2,9 +2,11 @@ import { flushIframes, makeRSDoc, makeStandardOps } from "../SpecHelper.js"; import { requiresCanonicalLink } from "../../../src/w3c/seo.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; describe("W3C - SEO", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); it("defaults to TR as canonical URI", async () => { const doc = await makeRSDoc( diff --git a/tests/spec/w3c/style-spec.js b/tests/spec/w3c/style-spec.js index f4d9b833f7..7889b97620 100644 --- a/tests/spec/w3c/style-spec.js +++ b/tests/spec/w3c/style-spec.js @@ -7,6 +7,8 @@ import { makeStandardOps, } from "../SpecHelper.js"; +import { seedGroupCache } from "../respec-cache-helper.js"; + const statuses = [ { specStatus: undefined, @@ -163,6 +165,7 @@ const statuses = [ describe("W3C - Style", () => { afterAll(flushIframes); + beforeAll(seedGroupCache); it("should include 'fixup.js'", async () => { const ops = makeStandardOps();