wpt.ts (3581B)
1 // Implements the wpt-embedded test runner (see also: wpt/cts.https.html). 2 3 import { globalTestConfig } from '../framework/test_config.js'; 4 import { DefaultTestFileLoader } from '../internal/file_loader.js'; 5 import { prettyPrintLog } from '../internal/logging/log_message.js'; 6 import { Logger } from '../internal/logging/logger.js'; 7 import { parseQuery } from '../internal/query/parseQuery.js'; 8 import { parseExpectationsForTestQuery, relativeQueryString } from '../internal/query/query.js'; 9 import { assert } from '../util/util.js'; 10 11 import { optionEnabled, optionWorkerMode } from './helper/options.js'; 12 import { TestDedicatedWorker, TestServiceWorker, TestSharedWorker } from './helper/test_worker.js'; 13 14 // testharness.js API (https://web-platform-tests.org/writing-tests/testharness-api.html) 15 declare interface WptTestObject { 16 step(f: () => void): void; 17 done(): void; 18 } 19 declare function setup(properties: { explicit_done?: boolean }): void; 20 declare function promise_test(f: (t: WptTestObject) => Promise<void>, name: string): void; 21 declare function done(): void; 22 declare function assert_unreached(description: string): void; 23 24 declare const loadWebGPUExpectations: Promise<unknown> | undefined; 25 declare const shouldWebGPUCTSFailOnWarnings: Promise<boolean> | undefined; 26 27 setup({ 28 // It's convenient for us to asynchronously add tests to the page. Prevent done() from being 29 // called implicitly when the page is finished loading. 30 explicit_done: true, 31 }); 32 33 void (async () => { 34 const workerString = optionWorkerMode('worker'); 35 const dedicatedWorker = workerString === 'dedicated' ? new TestDedicatedWorker() : undefined; 36 const sharedWorker = workerString === 'shared' ? new TestSharedWorker() : undefined; 37 const serviceWorker = workerString === 'service' ? new TestServiceWorker() : undefined; 38 39 globalTestConfig.unrollConstEvalLoops = optionEnabled('unroll_const_eval_loops'); 40 41 const failOnWarnings = 42 typeof shouldWebGPUCTSFailOnWarnings !== 'undefined' && (await shouldWebGPUCTSFailOnWarnings); 43 44 const loader = new DefaultTestFileLoader(); 45 const qs = new URLSearchParams(window.location.search).getAll('q'); 46 assert(qs.length === 1, 'currently, there must be exactly one ?q='); 47 const filterQuery = parseQuery(qs[0]); 48 const testcases = await loader.loadCases(filterQuery); 49 50 const expectations = 51 typeof loadWebGPUExpectations !== 'undefined' 52 ? parseExpectationsForTestQuery( 53 await loadWebGPUExpectations, 54 filterQuery, 55 new URL(window.location.href) 56 ) 57 : []; 58 59 const log = new Logger(); 60 61 for (const testcase of testcases) { 62 const name = testcase.query.toString(); 63 // For brevity, display the case name "relative" to the ?q= path. 64 const shortName = relativeQueryString(filterQuery, testcase.query) || '(case)'; 65 66 const wpt_fn = async () => { 67 const [rec, res] = log.record(name); 68 if (dedicatedWorker) { 69 await dedicatedWorker.run(rec, name, expectations); 70 } else if (sharedWorker) { 71 await sharedWorker.run(rec, name, expectations); 72 } else if (serviceWorker) { 73 await serviceWorker.run(rec, name, expectations); 74 } else { 75 await testcase.run(rec, expectations); 76 } 77 78 // Unfortunately, it seems not possible to surface any logs for warn/skip. 79 if (res.status === 'fail' || (res.status === 'warn' && failOnWarnings)) { 80 const logs = (res.logs ?? []).map(prettyPrintLog); 81 assert_unreached('\n' + logs.join('\n') + '\n'); 82 } 83 }; 84 85 promise_test(wpt_fn, shortName); 86 } 87 88 done(); 89 })();