Skip to content
File

Blob: src/wpt/harness/utils.ts

typescript197 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4// Copyright © web-platform-tests contributors. BSD license
5// Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a
8// copy of this software and associated documentation files (the
9// "Software"), to deal in the Software without restriction, including
10// without limitation the rights to use, copy, modify, merge, publish,
11// distribute, sublicense, and/or sell copies of the Software, and to permit
12// persons to whom the Software is furnished to do so, subject to the
13// following conditions:
14//
15// The above copyright notice and this permission notice shall be included
16// in all copies or substantial portions of the Software.
17//
18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
21// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24// USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26import crypto from 'node:crypto';
27import {
28 type UnknownFunc,
29 type TestFn,
30 type PromiseTestFn,
31 type HostInfo,
32 getHostInfo,
33} from './common';
34 
35declare global {
36 var GLOBAL: {
37 isWindow(): boolean;
38 isWorker(): boolean;
39 isShadowRealm(): boolean;
40 };
41 
42 function done(): undefined;
43 function subsetTestByKey<T>(
44 _key: string,
45 testType: (
46 testCallback: TestFn | PromiseTestFn | string,
47 testMessage?: string
48 ) => T,
49 testCallback: TestFn | PromiseTestFn | string,
50 testMessage?: string
51 ): T;
52 function subsetTest(
53 testType: TestRunnerFn,
54 testCallback: TestFn | PromiseTestFn,
55 testMessage: string
56 ): void;
57 // Used by idlharness.js to determine if a subtest should be run
58 function shouldRunSubTest(name?: string): boolean;
59 
60 function step_timeout(
61 func: UnknownFunc,
62 timeout: number,
63 ...rest: unknown[]
64 ): ReturnType<typeof setTimeout>;
65 
66 function get_host_info(): HostInfo;
67 function token(): string;
68 function setup(func: UnknownFunc | Record<string, unknown>): void;
69 function add_completion_callback(func: UnknownFunc): void;
70 // Provided by /common/gc.js
71 function garbageCollect(): Promise<void>;
72 function format_value(val: unknown): string;
73 function createBuffer(
74 type: 'ArrayBuffer' | 'SharedArrayBuffer',
75 length: number,
76 opts: { maxByteLength?: number } | undefined
77 ): ArrayBuffer | SharedArrayBuffer;
78 // Used by idlharness.js to fetch IDL files
79 function fetch_spec(spec: string): Promise<{ spec: string; idl: string }>;
80}
81 
82type TestRunnerFn = (callback: TestFn | PromiseTestFn, message: string) => void;
83 
84globalThis.get_host_info = (): HostInfo => {
85 return getHostInfo();
86};
87 
88globalThis.GLOBAL = {
89 isWindow(): boolean {
90 return false;
91 },
92 isWorker(): boolean {
93 return false;
94 },
95 isShadowRealm(): boolean {
96 return false;
97 },
98};
99 
100globalThis.done = (): undefined => undefined;
101 
102globalThis.subsetTestByKey = <T>(
103 _key: string,
104 testType: (testCallback: TestFn | PromiseTestFn, testMessage: string) => T,
105 testCallback: TestFn | PromiseTestFn | string,
106 testMessage?: string
107): T => {
108 // This function is designed to allow selecting only certain tests when
109 // running in a browser, by changing the query string. We'll always run
110 // all the tests.
111 return testType(
112 testCallback as TestFn | PromiseTestFn,
113 testMessage as string
114 );
115};
116 
117// Used by idlharness.js to determine if a subtest should be run.
118// We always run all subtests.
119globalThis.shouldRunSubTest = (): boolean => true;
120 
121globalThis.subsetTest = (testType, testCallback, testMessage): void => {
122 // This function is designed to allow selecting only certain tests when
123 // running in a browser, by changing the query string. We'll always run
124 // all the tests.
125 
126 // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression -- We are emulating WPT's existing interface which always passes through the returned value
127 return testType(testCallback, testMessage);
128};
129 
130/**
131 * Global version of :js:func:`Test.step_timeout` for use in single page tests.
132 *
133 * @param func - Function to run after the timeout
134 * @param timeout - Time in ms to wait before running the
135 * test step. The actual wait time is ``timeout`` x
136 * ``timeout_multiplier``.
137 */
138globalThis.step_timeout = (
139 func: UnknownFunc,
140 timeout: number,
141 ...rest: unknown[]
142): ReturnType<typeof setTimeout> => {
143 return setTimeout(() => func(...rest), timeout);
144};
145 
146globalThis.token = (): string => {
147 return crypto.randomUUID();
148};
149 
150globalThis.setup = (func): void => {
151 if (typeof func === 'object') {
152 return;
153 }
154 
155 func();
156};
157 
158globalThis.add_completion_callback = (func: UnknownFunc): void => {
159 globalThis.state.completionCallbacks.push(func);
160};
161 
162globalThis.format_value = (val): string => {
163 return JSON.stringify(val, null, 2);
164};
165 
166globalThis.createBuffer = (
167 type,
168 length,
169 _opts
170): ArrayBuffer | SharedArrayBuffer => {
171 switch (type) {
172 case 'ArrayBuffer':
173 return new ArrayBuffer(length);
174 case 'SharedArrayBuffer':
175 return new SharedArrayBuffer(length);
176 default:
177 throw new TypeError(`Unsupported buffer type: ${type}`);
178 }
179};
180 
181/**
182 * fetch_spec is used by idlharness.js to fetch IDL files.
183 * This implementation reads from the embedded bindings instead of using fetch().
184 */
185globalThis.fetch_spec = (
186 spec: string
187): Promise<{ spec: string; idl: string }> => {
188 const path = `/interfaces/${spec}.idl`;
189 const idl = globalThis.state.env[path];
190 if (typeof idl !== 'string') {
191 return Promise.reject(
192 new Error(`Error fetching ${path}: IDL file not found in bindings`)
193 );
194 }
195 return Promise.resolve({ spec, idl });
196};