Skip to content

Commit

Permalink
Convert WPT test harness to TS
Browse files Browse the repository at this point in the history
  • Loading branch information
npaun committed Jan 10, 2025
1 parent 5055345 commit 19f55a3
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 26 deletions.
2 changes: 1 addition & 1 deletion build/wpt_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const unitTests :Workerd.Config = (
worker = (
modules = [
(name = "worker", esModule = embed "{test_js}"),
(name = "harness", esModule = embed "../../../../../workerd/src/wpt/harness.js"),
(name = "wpt:harness", esModule = embed "../../../../../workerd/src/wpt/harness.js"),
{modules}
],
bindings = [
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/api/wpt/url-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0

import { run } from 'harness';
import { run } from 'wpt:harness';

export const idnaTestV2Window = run('IdnaTestV2.window.js');
export const historical = run('historical.any.js', {
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/api/wpt/urlpattern-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0

import { run } from 'harness';
import { run } from 'wpt:harness';

export const urlpatternCompareTests = run(
'urlpattern-compare-tests.tentative.js',
Expand Down
16 changes: 13 additions & 3 deletions src/wpt/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
filegroup(
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "wpt-test-harness",
testonly = False,
srcs = glob(
include = ["**/*"],
allow_empty = True,
[
"*.ts",
],
),
allow_js = True,
declaration = True,
tsconfig = "tsconfig.json",
visibility = ["//visibility:public"],
deps = [
"//:node_modules/@types",
],
)
3 changes: 3 additions & 0 deletions src/wpt/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { baseConfig } from '../../tools/base.eslint.config.mjs';

export default [...baseConfig({ tsconfigRootDir: import.meta.dirname })];
91 changes: 71 additions & 20 deletions src/wpt/harness.js → src/wpt/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,68 @@ import {
throws,
} from 'node:assert';

function OptionalFeatureUnsupportedError(message) {
AssertionError.call(this, message);
type Options = {
expectedFailures?: string[];
verbose?: boolean;
skippedTests?: string[];
};

type TestRunnerFn = (callback: TestFn | PromiseTestFn, message: string) => void;
type TestFn = () => void;
type PromiseTestFn = () => Promise<void>;
type ThrowingFn = () => any;

declare namespace globalThis {
var errors: Error[];
var testOptions: Options;
var Window: typeof globalThis;
var self: typeof globalThis;
var GLOBAL: { isWindow(): boolean };
function fetch(url: string): Promise<{ json(): Promise<any> }>;
function test(func: TestFn, name: string): void;
function done(): undefined;
function subsetTestByKey(
_key: any,
testType: TestRunnerFn,
testCallback: TestFn | PromiseTestFn,
testMessage: string
): void;
function promise_test(
func: PromiseTestFn,
name: string,
properties?: any
): void;
function assert_equals(a: any, b: any, message?: string): void;
function assert_not_equals(a: any, b: any, message?: string): void;
function assert_true(val: any, message?: string): void;
function assert_false(val: any, message?: string): void;
function assert_array_equals(a: any, b: any, message?: string): void;
function assert_object_equals(a: any, b: any, message?: string): void;
function assert_implements(condition: any, description?: string): void;
function assert_implements_optional(
condition: any,
description?: string
): void;
function assert_unreached(description?: string): void;
function assert_throws_js(
constructor: any,
func: ThrowingFn,
description?: string
): void;
function assert_throws_exactly(
exception: any,
fn: ThrowingFn,
description?: string
): void;
function assert_throws_dom(
type: any,
funcOrConstructor: any,
descriptionOrFunc: any,
maybeDescription: any
): void;
}
OptionalFeatureUnsupportedError.prototype = Object.create(
AssertionError.prototype
);

class OptionalFeatureUnsupportedError extends AssertionError {}

globalThis.Window = Object.getPrototypeOf(globalThis).constructor;

Expand Down Expand Up @@ -67,13 +123,7 @@ globalThis.subsetTestByKey = (_key, testType, testCallback, testMessage) => {
return testType(testCallback, testMessage);
};

globalThis.promise_test = async (func, name, properties) => {
if (typeof func !== 'function') {
properties = name;
name = func;
func = null;
}

globalThis.promise_test = async (func, name, _properties) => {
if (!shouldRunTest(name)) {
return;
}
Expand Down Expand Up @@ -140,7 +190,7 @@ globalThis.assert_implements = (condition, description) => {
*/
globalThis.assert_implements_optional = (condition, description) => {
if (!condition) {
throw new OptionalFeatureUnsupportedError(description);
throw new OptionalFeatureUnsupportedError({ message: description });
}
};

Expand Down Expand Up @@ -219,7 +269,7 @@ globalThis.assert_throws_exactly = (exception, fn, description) => {
*
*/
globalThis.assert_throws_dom = (
type,
_type,
funcOrConstructor,
descriptionOrFunc,
maybeDescription
Expand All @@ -230,6 +280,7 @@ globalThis.assert_throws_dom = (
func = descriptionOrFunc;
description = maybeDescription;
} else {
// @ts-ignore
constructor = this.DOMException;
func = funcOrConstructor;
description = descriptionOrFunc;
Expand All @@ -251,7 +302,7 @@ globalThis.assert_throws_dom = (
/**
* Create a synchronous test
*
* @param {TestFunction} func - Test function. This is executed
* @param {TestFn} func - Test function. This is executed
* immediately. If it returns without error, the test status is
* set to ``PASS``. If it throws an :js:class:`AssertionError`, or
* any other exception, the test status is set to ``FAIL``
Expand All @@ -273,7 +324,7 @@ globalThis.test = (func, name) => {

globalThis.errors = [];

function shouldRunTest(message) {
function shouldRunTest(message: string) {
if ((globalThis.testOptions.skippedTests ?? []).includes(message)) {
return false;
}
Expand All @@ -285,12 +336,12 @@ function shouldRunTest(message) {
return true;
}

function prepare(options) {
function prepare(options: Options) {
globalThis.errors = [];
globalThis.testOptions = options;
}

function sanitizeMessage(message) {
function sanitizeMessage(message: string) {
// Test logs will be exported to XML, so we must escape any characters that
// are forbidden in an XML CDATA section, namely "[...] the surrogate blocks,
// FFFE, and FFFF".
Expand All @@ -308,7 +359,7 @@ function sanitizeMessage(message) {
);
}

function validate(testFileName, options) {
function validate(testFileName: string, options: Options) {
const expectedFailures = new Set(options.expectedFailures ?? []);

let failing = false;
Expand All @@ -332,7 +383,7 @@ function validate(testFileName, options) {
}
}

export function run(file, options = {}) {
export function run(file: string, options: Options = {}) {
return {
async test() {
prepare(options);
Expand Down
28 changes: 28 additions & 0 deletions src/wpt/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext", "dom"],
"alwaysStrict": true,
"strict": true,
"allowJs": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": false,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strictNullChecks": true,
"esModuleInterop": true,
"moduleResolution": "node",
"declaration": true,
"paths": {
"wpt:*": ["./*"]
}
},
"exclude": []
}

0 comments on commit 19f55a3

Please sign in to comment.