diff --git a/build/wpt_test.bzl b/build/wpt_test.bzl index f99288dff2c..a1102680967 100644 --- a/build/wpt_test.bzl +++ b/build/wpt_test.bzl @@ -9,34 +9,88 @@ load("//:build/wd_test.bzl", "wd_test") -def wpt_test(name, wpt_directory, test_js): - test_gen_rule = "{}@_wpt_test_gen".format(name) - _wpt_test_gen( - name = test_gen_rule, +def wpt_test(name, wpt_directory, test_config): + js_test_gen_rule = "{}@_wpt_js_test_gen".format(name) + _wpt_js_test_gen( + name = js_test_gen_rule, test_name = name, wpt_directory = wpt_directory, - test_js = test_js, + test_config = test_config, + ) + + wd_test_gen_rule = "{}@_wpt_wd_test_gen".format(name) + _wpt_wd_test_gen( + name = wd_test_gen_rule, + test_name = name, + wpt_directory = wpt_directory, + test_config = test_config, + test_js_generated = js_test_gen_rule, ) wd_test( name = "{}".format(name), - src = test_gen_rule, + src = wd_test_gen_rule, args = ["--experimental"], data = [ "//src/wpt:wpt-test-harness", - test_js, + test_config, + js_test_gen_rule, wpt_directory, "//src/workerd/io:trimmed-supported-compatibility-date.txt", ], ) -def _wpt_test_gen_impl(ctx): +def _wpt_js_test_gen_impl(ctx): + src = ctx.actions.declare_file("{}-test.generated.js".format(ctx.attr.test_name)) + ctx.actions.write( + output = src, + content = WPT_JS_TEST_TEMPLATE.format( + test_config = ctx.file.test_config.basename, + cases = generate_external_cases(ctx.attr.wpt_directory.files), + ), + ) + + return DefaultInfo( + files = depset([src]), + ) + +def generate_external_cases(files): + result = [] + + for file in files.to_list(): + if file.extension == "js": + entry = """export const {} = run(config, '{}');""".format(test_case_name(file.basename), file.basename) + else: + continue + result.append(entry) + + return "\n".join(result) + +def test_case_name(filename): + words = (filename + .removesuffix(".js") + .removesuffix(".any") + .replace(".", "-") + .split("-")) + + return words[0] + "".join([word.capitalize() for word in words[1:]]) + +WPT_JS_TEST_TEMPLATE = """// This file is autogenerated by wpt_test.bzl +// DO NOT EDIT. +import {{ run }} from 'wpt:harness'; +import config from '{test_config}'; + +{cases} +""" + +def _wpt_wd_test_gen_impl(ctx): src = ctx.actions.declare_file("{}.wd-test".format(ctx.attr.test_name)) ctx.actions.write( output = src, - content = WPT_TEST_TEMPLATE.format( + content = WPT_WD_TEST_TEMPLATE.format( test_name = ctx.attr.test_name, - test_js = wd_relative_path(ctx.file.test_js), + test_config = ctx.file.test_config.basename, + test_js_generated = wd_relative_path(ctx.file.test_js_generated), modules = generate_external_modules(ctx.attr.wpt_directory.files), ), ) @@ -45,14 +99,15 @@ def _wpt_test_gen_impl(ctx): files = depset([src]), ) -WPT_TEST_TEMPLATE = """ +WPT_WD_TEST_TEMPLATE = """ using Workerd = import "/workerd/workerd.capnp"; const unitTests :Workerd.Config = ( services = [ ( name = "{test_name}", worker = ( modules = [ - (name = "worker", esModule = embed "{test_js}"), + (name = "worker", esModule = embed "{test_js_generated}"), + (name = "{test_config}", esModule = embed "{test_config}"), (name = "wpt:harness", esModule = embed "../../../../../workerd/src/wpt/harness.js"), {modules} ], @@ -102,14 +157,28 @@ def generate_external_modules(files): return ",\n".join(result) -_wpt_test_gen = rule( - implementation = _wpt_test_gen_impl, +_wpt_wd_test_gen = rule( + implementation = _wpt_wd_test_gen_impl, + attrs = { + # A string to use as the test name. Used in the wd-test filename and the worker's name + "test_name": attr.string(), + # A file group representing a directory of wpt tests. All files in the group will be embedded. + "wpt_directory": attr.label(), + # A JS file containing the test configuration. + "test_config": attr.label(allow_single_file = True), + # An auto-generated JS file containing the test logic. + "test_js_generated": attr.label(allow_single_file = True), + }, +) + +_wpt_js_test_gen = rule( + implementation = _wpt_js_test_gen_impl, attrs = { # A string to use as the test name. Used in the wd-test filename and the worker's name "test_name": attr.string(), # A file group representing a directory of wpt tests. All files in the group will be embedded. "wpt_directory": attr.label(), - # A JS file containing the actual test logic. - "test_js": attr.label(allow_single_file = True), + # A JS file containing the test configuration. + "test_config": attr.label(allow_single_file = True), }, ) diff --git a/src/workerd/api/wpt/BUILD.bazel b/src/workerd/api/wpt/BUILD.bazel index 22b83a5bc2f..5ceaa4cbd44 100644 --- a/src/workerd/api/wpt/BUILD.bazel +++ b/src/workerd/api/wpt/BUILD.bazel @@ -6,6 +6,6 @@ load("//:build/wpt_test.bzl", "wpt_test") [wpt_test( name = file.replace("-test.js", ""), - test_js = file, + test_config = file, wpt_directory = "@wpt//:{}".format(file.replace("-test.js", "")), ) for file in glob(["*-test.js"])] diff --git a/src/workerd/api/wpt/url-test.js b/src/workerd/api/wpt/url-test.js index d7d26a355f5..42a6785212b 100644 --- a/src/workerd/api/wpt/url-test.js +++ b/src/workerd/api/wpt/url-test.js @@ -2,140 +2,136 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { run } from 'wpt:harness'; - -export const idnaTestV2Window = run('IdnaTestV2.window.js'); -export const historical = run('historical.any.js', { - expectedFailures: [ - 'Constructor only takes strings', - 'URL: no structured serialize/deserialize support', - 'URLSearchParams: no structured serialize/deserialize support', - ], -}); -// TODO(soon): Implement `globalThis.document` -export const javascriptUrlsWindow = run('javascript-urls.window.js', { - expectedFailures: [ - 'javascript: URL that fails to parse due to invalid host', - 'javascript: URL that fails to parse due to invalid host and has a U+0009 in scheme', - 'javascript: URL without an opaque path', - 'javascript: URL containing a JavaScript string split over path and query', - 'javascript: URL containing a JavaScript string split over path and query and has a U+000A in scheme', - ], -}); -// TODO(soon): Implement `async_test` -// export const percentEncodingWindow = run('percent-encoding.window.js'); -// TODO(soon): Implement document. -// export const toAsciiWindow = run('toascii.window.js'); -export const urlConstructorAny = run('url-constructor.any.js', { - expectedFailures: [ - 'Parsing: without base', - ], -}); -export const urlOriginAny = run('url-origin.any.js'); -export const urlSearchParamsAny = run('url-searchparams.any.js'); -// TODO(soon): Implement promise_test -// export const urlSettersAAreaWindow = run('url-setters-a-area.window.js'); -export const urlSettersStripping = run('url-setters-stripping.any.js'); -export const urlSettersAny = run('url-setters.any.js'); -export const urlStaticsCanParse = run('url-statics-canparse.any.js'); -export const urlStaticsParse = run('url-statics-parse.any.js'); -export const urlToJson = run('url-tojson.any.js'); -export const urlencodedParser = run('urlencoded-parser.any.js', { - expectedFailures: [ - 'request.formData() with input: test', - 'response.formData() with input: test', - 'request.formData() with input: \uFEFFtest=\uFEFF', - 'response.formData() with input: \uFEFFtest=\uFEFF', - 'request.formData() with input: %EF%BB%BFtest=%EF%BB%BF', - 'response.formData() with input: %EF%BB%BFtest=%EF%BB%BF', - 'request.formData() with input: %EF%BF%BF=%EF%BF%BF', - 'response.formData() with input: %EF%BF%BF=%EF%BF%BF', - 'request.formData() with input: %FE%FF', - 'response.formData() with input: %FE%FF', - 'request.formData() with input: %FF%FE', - 'response.formData() with input: %FF%FE', - 'request.formData() with input: †&†=x', - 'response.formData() with input: †&†=x', - 'request.formData() with input: %C2', - 'response.formData() with input: %C2', - 'request.formData() with input: %C2x', - 'response.formData() with input: %C2x', - 'request.formData() with input: _charset_=windows-1252&test=%C2x', - 'response.formData() with input: _charset_=windows-1252&test=%C2x', - 'request.formData() with input: ', - 'response.formData() with input: ', - 'request.formData() with input: a', - 'response.formData() with input: a', - 'request.formData() with input: a=b', - 'response.formData() with input: a=b', - 'request.formData() with input: a=', - 'response.formData() with input: a=', - 'request.formData() with input: =b', - 'response.formData() with input: =b', - 'request.formData() with input: &', - 'response.formData() with input: &', - 'request.formData() with input: &a', - 'response.formData() with input: &a', - 'request.formData() with input: a&', - 'response.formData() with input: a&', - 'request.formData() with input: a&a', - 'response.formData() with input: a&a', - 'request.formData() with input: a&b&c', - 'response.formData() with input: a&b&c', - 'request.formData() with input: a=b&c=d', - 'response.formData() with input: a=b&c=d', - 'request.formData() with input: a=b&c=d&', - 'response.formData() with input: a=b&c=d&', - 'request.formData() with input: &&&a=b&&&&c=d&', - 'response.formData() with input: &&&a=b&&&&c=d&', - 'request.formData() with input: a=a&a=b&a=c', - 'response.formData() with input: a=a&a=b&a=c', - 'request.formData() with input: a==a', - 'response.formData() with input: a==a', - 'request.formData() with input: a=a+b+c+d', - 'response.formData() with input: a=a+b+c+d', - 'request.formData() with input: %=a', - 'response.formData() with input: %=a', - 'request.formData() with input: %a=a', - 'response.formData() with input: %a=a', - 'request.formData() with input: %a_=a', - 'response.formData() with input: %a_=a', - 'request.formData() with input: %61=a', - 'response.formData() with input: %61=a', - 'request.formData() with input: %61+%4d%4D=', - 'response.formData() with input: %61+%4d%4D=', - 'request.formData() with input: id=0&value=%', - 'response.formData() with input: id=0&value=%', - 'request.formData() with input: b=%2sf%2a', - 'response.formData() with input: b=%2sf%2a', - 'request.formData() with input: b=%2%2af%2a', - 'response.formData() with input: b=%2%2af%2a', - 'request.formData() with input: b=%%2a', - 'response.formData() with input: b=%%2a', - ], -}); -export const urlSearchParamsAppend = run('urlsearchparams-append.any.js'); -export const urlSearchParamsConstructor = run( - 'urlsearchparams-constructor.any.js', - { +export default { + 'historical.any.js': { + expectedFailures: [ + 'Constructor only takes strings', + 'URL: no structured serialize/deserialize support', + 'URLSearchParams: no structured serialize/deserialize support', + ], + }, + // TODO(soon): Implement `globalThis.document` + 'javascript-urls.window.js': { + expectedFailures: [ + 'javascript: URL that fails to parse due to invalid host', + 'javascript: URL that fails to parse due to invalid host and has a U+0009 in scheme', + 'javascript: URL without an opaque path', + 'javascript: URL containing a JavaScript string split over path and query', + 'javascript: URL containing a JavaScript string split over path and query and has a U+000A in scheme', + ], + }, + // TODO(soon): Implement `async_test` + 'percent-encoding.window.js': { + skipAllTests: true, + }, + // TODO(soon): Implement document. + 'toascii.window.js': { + skipAllTests: true, + }, + 'url-constructor.any.js': { + expectedFailures: [ + 'Parsing: without base', + ], + }, + // TODO(soon): Implement promise_test + 'url-setters-a-area.window.js': { + skipAllTests: true, + }, + // TODO(soon): Implement unsafeRequire + 'urlencoded-parser.any.js': { + expectedFailures: [ + 'request.formData() with input: test', + 'response.formData() with input: test', + 'request.formData() with input: \uFEFFtest=\uFEFF', + 'response.formData() with input: \uFEFFtest=\uFEFF', + 'request.formData() with input: %EF%BB%BFtest=%EF%BB%BF', + 'response.formData() with input: %EF%BB%BFtest=%EF%BB%BF', + 'request.formData() with input: %EF%BF%BF=%EF%BF%BF', + 'response.formData() with input: %EF%BF%BF=%EF%BF%BF', + 'request.formData() with input: %FE%FF', + 'response.formData() with input: %FE%FF', + 'request.formData() with input: %FF%FE', + 'response.formData() with input: %FF%FE', + 'request.formData() with input: †&†=x', + 'response.formData() with input: †&†=x', + 'request.formData() with input: %C2', + 'response.formData() with input: %C2', + 'request.formData() with input: %C2x', + 'response.formData() with input: %C2x', + 'request.formData() with input: _charset_=windows-1252&test=%C2x', + 'response.formData() with input: _charset_=windows-1252&test=%C2x', + 'request.formData() with input: ', + 'response.formData() with input: ', + 'request.formData() with input: a', + 'response.formData() with input: a', + 'request.formData() with input: a=b', + 'response.formData() with input: a=b', + 'request.formData() with input: a=', + 'response.formData() with input: a=', + 'request.formData() with input: =b', + 'response.formData() with input: =b', + 'request.formData() with input: &', + 'response.formData() with input: &', + 'request.formData() with input: &a', + 'response.formData() with input: &a', + 'request.formData() with input: a&', + 'response.formData() with input: a&', + 'request.formData() with input: a&a', + 'response.formData() with input: a&a', + 'request.formData() with input: a&b&c', + 'response.formData() with input: a&b&c', + 'request.formData() with input: a=b&c=d', + 'response.formData() with input: a=b&c=d', + 'request.formData() with input: a=b&c=d&', + 'response.formData() with input: a=b&c=d&', + 'request.formData() with input: &&&a=b&&&&c=d&', + 'response.formData() with input: &&&a=b&&&&c=d&', + 'request.formData() with input: a=a&a=b&a=c', + 'response.formData() with input: a=a&a=b&a=c', + 'request.formData() with input: a==a', + 'response.formData() with input: a==a', + 'request.formData() with input: a=a+b+c+d', + 'response.formData() with input: a=a+b+c+d', + 'request.formData() with input: %=a', + 'response.formData() with input: %=a', + 'request.formData() with input: %a=a', + 'response.formData() with input: %a=a', + 'request.formData() with input: %a_=a', + 'response.formData() with input: %a_=a', + 'request.formData() with input: %61=a', + 'response.formData() with input: %61=a', + 'request.formData() with input: %61+%4d%4D=', + 'response.formData() with input: %61+%4d%4D=', + 'request.formData() with input: id=0&value=%', + 'response.formData() with input: id=0&value=%', + 'request.formData() with input: b=%2sf%2a', + 'response.formData() with input: b=%2sf%2a', + 'request.formData() with input: b=%2%2af%2a', + 'response.formData() with input: b=%2%2af%2a', + 'request.formData() with input: b=%%2a', + 'response.formData() with input: b=%%2a', + ], + }, + 'urlsearchparams-constructor.any.js': { expectedFailures: [ 'URLSearchParams constructor, DOMException as argument', 'Construct with 2 unpaired surrogates (no trailing)', 'Construct with 3 unpaired surrogates (no leading)', 'Construct with object with NULL, non-ASCII, and surrogate keys', ], - } -); -export const urlSearchParamsDelete = run('urlsearchparams-delete.any.js'); -export const urlSearchParamsForEach = run('urlsearchparams-foreach.any.js'); -export const urlSearchParamsGetAny = run('urlsearchparams-get.any.js'); -export const urlSearchParamsGetAll = run('urlsearchparams-getall.any.js'); -export const urlSearchParamsHas = run('urlsearchparams-has.any.js'); -export const urlSearchParamsSet = run('urlsearchparams-set.any.js'); -export const urlSearchParamsSize = run('urlsearchparams-size.any.js'); -export const urlSearchParamsSort = run('urlsearchparams-sort.any.js', { - expectedFailures: ['Parse and sort: ffi&🌈', 'URL parse and sort: ffi&🌈'], -}); -export const urlSearchParamsStringifier = run( - 'urlsearchparams-stringifier.any.js' -); + }, + 'urlsearchparams-sort.any.js': { + expectedFailures: ['Parse and sort: ffi&🌈', 'URL parse and sort: ffi&🌈'], + }, + 'idlharness.any.js': { + skipAllTests: true, + }, + // TODO(soon): Implement globalThis.document + 'a-element-origin.js': { + skipAllTests: true, + }, + // TODO(soon): Implement globalThis.document + 'a-element.js': { + skipAllTests: true, + }, +}; diff --git a/src/workerd/api/wpt/urlpattern-test.js b/src/workerd/api/wpt/urlpattern-test.js index 6848924c8bb..880d825ab7e 100644 --- a/src/workerd/api/wpt/urlpattern-test.js +++ b/src/workerd/api/wpt/urlpattern-test.js @@ -2,11 +2,8 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 -import { run } from 'wpt:harness'; - -export const urlpatternCompareTests = run( - 'urlpattern-compare-tests.tentative.js', - { +export default { + 'urlpattern-compare-tests.tentative.js': { expectedFailures: [ // Each of these *ought* to pass. They are included here because we // know they currently do not. Each needs to be investigated. @@ -36,151 +33,148 @@ export const urlpatternCompareTests = run( 'Component: search Left: {"search":"a"} Right: {"search":"b"}', 'Component: hash Left: {"hash":"a"} Right: {"hash":"b"}', ], - } -); -export const urlpatternHasRegexGroups = run( - 'urlpattern-hasregexpgroups-tests.js', - { + }, + 'urlpattern-hasregexpgroups-tests.js': { expectedFailures: [ // Each of these *ought* to pass. They are included here because we // know they currently do not. Each needs to be investigated. '', // This file consists of one unnamed subtest ], - } -); -export const urlPatternTests = run('urlpatterntests.js', { - expectedFailures: [ - // Each of these *ought* to pass. They are included here because we - // know they currently do not. Each needs to be investigated. - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"hostname":"example.com","pathname":"/foo/bar"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar/baz"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar","search":"otherquery","hash":"otherhash"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar","search":"otherquery","hash":"otherhash"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?otherquery#otherhash"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar","search":"otherquery","hash":"otherhash"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar"]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar?otherquery#otherhash"]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar?query#hash"]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar/baz"]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://other.com/foo/bar"]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["http://other.com/foo/bar"]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"https://example.com"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar/baz","baseURL":"https://example.com"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"https://other.com"}]', - 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"http://example.com"}]', - 'Pattern: [{"pathname":"/foo/:bar?"}] Inputs: [{"pathname":"/foo"}]', - 'Pattern: [{"pathname":"/foo/:bar*"}] Inputs: [{"pathname":"/foo"}]', - 'Pattern: [{"pathname":"/foo/(.*)?"}] Inputs: [{"pathname":"/foo"}]', - 'Pattern: [{"pathname":"/foo/*?"}] Inputs: [{"pathname":"/foo"}]', - 'Pattern: [{"pathname":"/foo/(.*)*"}] Inputs: [{"pathname":"/foo"}]', - 'Pattern: [{"pathname":"/foo/**"}] Inputs: [{"pathname":"/foo"}]', - 'Pattern: [{"protocol":"(.*)"}] Inputs: [{"protocol":"café"}]', - 'Pattern: [{"hostname":"xn--caf-dma.com"}] Inputs: [{"hostname":"café.com"}]', - 'Pattern: [{"hostname":"café.com"}] Inputs: [{"hostname":"café.com"}]', - 'Pattern: [{"protocol":"http","port":"80"}] Inputs: [{"protocol":"http","port":"80"}]', - 'Pattern: [{"protocol":"http","port":"80 "}] Inputs: [{"protocol":"http","port":"80"}]', - 'Pattern: [{"port":"(.*)"}] Inputs: [{"port":"invalid80"}]', - 'Pattern: [{"pathname":"/foo/bar"}] Inputs: [{"pathname":"foo/bar"}]', - 'Pattern: [{"pathname":"./foo/bar","baseURL":"https://example.com"}] Inputs: [{"pathname":"foo/bar","baseURL":"https://example.com"}]', - 'Pattern: [{"pathname":"","baseURL":"https://example.com"}] Inputs: [{"pathname":"/","baseURL":"https://example.com"}]', - 'Pattern: [{"pathname":"{/bar}","baseURL":"https://example.com/foo/"}] Inputs: [{"pathname":"./bar","baseURL":"https://example.com/foo/"}]', - 'Pattern: [{"pathname":"\\\\/bar","baseURL":"https://example.com/foo/"}] Inputs: [{"pathname":"./bar","baseURL":"https://example.com/foo/"}]', - 'Pattern: [{"pathname":"b","baseURL":"https://example.com/foo/"}] Inputs: [{"pathname":"./b","baseURL":"https://example.com/foo/"}]', - 'Pattern: [{"pathname":"foo/bar","baseURL":"https://example.com"}] Inputs: ["https://example.com/foo/bar"]', - 'Pattern: [{"pathname":":name.html","baseURL":"https://example.com"}] Inputs: ["https://example.com/foo.html"]', - 'Pattern: [{"protocol":"javascript","pathname":"var x = 1;"}] Inputs: [{"protocol":"javascript","pathname":"var x = 1;"}]', - 'Pattern: [{"protocol":"(data|javascript)","pathname":"var x = 1;"}] Inputs: [{"protocol":"javascript","pathname":"var x = 1;"}]', - 'Pattern: [{"pathname":"var x = 1;"}] Inputs: [{"pathname":"var x = 1;"}]', - 'Pattern: ["https://example.com:8080/foo?bar#baz"] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}]', - 'Pattern: ["/foo?bar#baz","https://example.com:8080"] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}]', - 'Pattern: ["http{s}?://{*.}?example.com/:product/:endpoint"] Inputs: ["https://sub.example.com/foo/bar"]', - 'Pattern: ["https://example.com?foo"] Inputs: ["https://example.com/?foo"]', - 'Pattern: ["https://example.com#foo"] Inputs: ["https://example.com/#foo"]', - 'Pattern: ["https://example.com:8080?foo"] Inputs: ["https://example.com:8080/?foo"]', - 'Pattern: ["https://example.com:8080#foo"] Inputs: ["https://example.com:8080/#foo"]', - 'Pattern: ["https://example.com/?foo"] Inputs: ["https://example.com/?foo"]', - 'Pattern: ["https://example.com/#foo"] Inputs: ["https://example.com/#foo"]', - 'Pattern: ["https://example.com/*?foo"] Inputs: ["https://example.com/?foo"]', - 'Pattern: ["https://example.com/*\\\\?foo"] Inputs: ["https://example.com/?foo"]', - 'Pattern: ["https://example.com/:name?foo"] Inputs: ["https://example.com/bar?foo"]', - 'Pattern: ["https://example.com/:name\\\\?foo"] Inputs: ["https://example.com/bar?foo"]', - 'Pattern: ["https://example.com/(bar)?foo"] Inputs: ["https://example.com/bar?foo"]', - 'Pattern: ["https://example.com/(bar)\\\\?foo"] Inputs: ["https://example.com/bar?foo"]', - 'Pattern: ["https://example.com/{bar}?foo"] Inputs: ["https://example.com/bar?foo"]', - 'Pattern: ["https://example.com/{bar}\\\\?foo"] Inputs: ["https://example.com/bar?foo"]', - 'Pattern: ["https://example.com/"] Inputs: ["https://example.com:8080/"]', - 'Pattern: ["data\\\\:foobar"] Inputs: ["data:foobar"]', - 'Pattern: ["https://{sub.}?example.com/foo"] Inputs: ["https://example.com/foo"]', - 'Pattern: ["https://(sub.)?example.com/foo"] Inputs: ["https://example.com/foo"]', - 'Pattern: ["https://(sub.)?example(.com/)foo"] Inputs: ["https://example.com/foo"]', - 'Pattern: ["https://(sub(?:.))?example.com/foo"] Inputs: ["https://example.com/foo"]', - 'Pattern: ["file:///foo/bar"] Inputs: ["file:///foo/bar"]', - 'Pattern: ["data:"] Inputs: ["data:"]', - 'Pattern: ["foo://bar"] Inputs: ["foo://bad_url_browser_interop"]', - 'Pattern: ["https://example.com/foo?bar#baz"] Inputs: [{"protocol":"https:","search":"?bar","hash":"#baz","baseURL":"http://example.com/foo"}]', - 'Pattern: ["?bar#baz","https://example.com/foo"] Inputs: ["?bar#baz","https://example.com/foo"]', - 'Pattern: ["?bar","https://example.com/foo#baz"] Inputs: ["?bar","https://example.com/foo#snafu"]', - 'Pattern: ["#baz","https://example.com/foo?bar"] Inputs: ["#baz","https://example.com/foo?bar"]', - 'Pattern: ["#baz","https://example.com/foo"] Inputs: ["#baz","https://example.com/foo"]', - 'Pattern: ["https://foo\\\\:bar@example.com"] Inputs: ["https://foo:bar@example.com"]', - 'Pattern: ["https://foo@example.com"] Inputs: ["https://foo@example.com"]', - 'Pattern: ["https://\\\\:bar@example.com"] Inputs: ["https://:bar@example.com"]', - 'Pattern: ["https://:user::pass@example.com"] Inputs: ["https://foo:bar@example.com"]', - 'Pattern: ["https\\\\:foo\\\\:bar@example.com"] Inputs: ["https:foo:bar@example.com"]', - 'Pattern: ["data\\\\:foo\\\\:bar@example.com"] Inputs: ["data:foo:bar@example.com"]', - 'Pattern: ["https://foo{\\\\:}bar@example.com"] Inputs: ["https://foo:bar@example.com"]', - 'Pattern: ["data{\\\\:}channel.html","https://example.com"] Inputs: ["https://example.com/data:channel.html"]', - 'Pattern: ["http://[\\\\:\\\\:1]/"] Inputs: ["http://[::1]/"]', - 'Pattern: ["http://[\\\\:\\\\:1]:8080/"] Inputs: ["http://[::1]:8080/"]', - 'Pattern: ["http://[\\\\:\\\\:a]/"] Inputs: ["http://[::a]/"]', - 'Pattern: ["http://[:address]/"] Inputs: ["http://[::1]/"]', - 'Pattern: ["http://[\\\\:\\\\:AB\\\\::num]/"] Inputs: ["http://[::ab:1]/"]', - 'Pattern: [{"hostname":"[\\\\:\\\\:AB\\\\::num]"}] Inputs: [{"hostname":"[::ab:1]"}]', - 'Pattern: ["data\\\\:text/javascript,let x = 100/:tens?5;"] Inputs: ["data:text/javascript,let x = 100/5;"]', - 'Pattern: [{"pathname":"/foo"},"https://example.com"] Inputs: undefined', - 'Pattern: [{"pathname":":name*"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":name+"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":name"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":"(foo)(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{(foo)bar}(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"(foo)?(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo}(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo}(barbaz)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo}{(.*)}"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo}{bar(.*)}"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo}:bar(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo}?(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', - 'Pattern: [{"pathname":"{:foo\\\\bar}"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":"{:foo\\\\.bar}"}] Inputs: [{"pathname":"foo.bar"}]', - 'Pattern: [{"pathname":"{:foo(foo)bar}"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":"{:foo}bar"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":foo\\\\bar"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":foo{}(.*)"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":foo{}bar"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":foo{}?bar"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":"*{}**?"}] Inputs: [{"pathname":"foobar"}]', - 'Pattern: [{"pathname":":foo(baz)(.*)"}] Inputs: [{"pathname":"bazbar"}]', - 'Pattern: [{"pathname":":foo(baz)bar"}] Inputs: [{"pathname":"bazbar"}]', - 'Pattern: [{"pathname":"*/*"}] Inputs: [{"pathname":"foo/bar"}]', - 'Pattern: [{"pathname":"*\\\\/*"}] Inputs: [{"pathname":"foo/bar"}]', - 'Pattern: [{"pathname":"*/{*}"}] Inputs: [{"pathname":"foo/bar"}]', - 'Pattern: [{"pathname":"./foo"}] Inputs: [{"pathname":"./foo"}]', - 'Pattern: [{"pathname":"../foo"}] Inputs: [{"pathname":"../foo"}]', - 'Pattern: [{"pathname":":foo./"}] Inputs: [{"pathname":"bar./"}]', - 'Pattern: [{"pathname":":foo../"}] Inputs: [{"pathname":"bar../"}]', - 'Pattern: [{"pathname":"/:foo\\\\bar"}] Inputs: [{"pathname":"/bazbar"}]', - 'Pattern: [{"pathname":"/foo/bar"},{"ignoreCase":true}] Inputs: [{"pathname":"/FOO/BAR"}]', - 'Pattern: ["https://example.com:8080/foo?bar#baz",{"ignoreCase":true}] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}]', - 'Pattern: ["/foo?bar#baz","https://example.com:8080",{"ignoreCase":true}] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}]', - 'Pattern: [{"search":"foo","baseURL":"https://example.com/a/+/b"}] Inputs: [{"search":"foo","baseURL":"https://example.com/a/+/b"}]', - 'Pattern: [{"hash":"foo","baseURL":"https://example.com/?q=*&v=?&hmm={}&umm=()"}] Inputs: [{"hash":"foo","baseURL":"https://example.com/?q=*&v=?&hmm={}&umm=()"}]', - 'Pattern: ["#foo","https://example.com/?q=*&v=?&hmm={}&umm=()"] Inputs: ["https://example.com/?q=*&v=?&hmm={}&umm=()#foo"]', - 'Pattern: [{"pathname":"/([[a-z]--a])"}] Inputs: [{"pathname":"/a"}]', - 'Pattern: [{"pathname":"/([[a-z]--a])"}] Inputs: [{"pathname":"/z"}]', - 'Pattern: [{"pathname":"/([\\\\d&&[0-1]])"}] Inputs: [{"pathname":"/0"}]', - 'Pattern: [{"pathname":"/([\\\\d&&[0-1]])"}] Inputs: [{"pathname":"/3"}]', - ], -}); + }, + 'urlpatterntests.js': { + expectedFailures: [ + // Each of these *ought* to pass. They are included here because we + // know they currently do not. Each needs to be investigated. + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"hostname":"example.com","pathname":"/foo/bar"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar/baz"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar","search":"otherquery","hash":"otherhash"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar","search":"otherquery","hash":"otherhash"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?otherquery#otherhash"}] Inputs: [{"protocol":"https","hostname":"example.com","pathname":"/foo/bar","search":"otherquery","hash":"otherhash"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar"]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar?otherquery#otherhash"]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar?query#hash"]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://example.com/foo/bar/baz"]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["https://other.com/foo/bar"]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: ["http://other.com/foo/bar"]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"https://example.com"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar/baz","baseURL":"https://example.com"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"https://other.com"}]', + 'Pattern: [{"pathname":"/foo/bar","baseURL":"https://example.com?query#hash"}] Inputs: [{"pathname":"/foo/bar","baseURL":"http://example.com"}]', + 'Pattern: [{"pathname":"/foo/:bar?"}] Inputs: [{"pathname":"/foo"}]', + 'Pattern: [{"pathname":"/foo/:bar*"}] Inputs: [{"pathname":"/foo"}]', + 'Pattern: [{"pathname":"/foo/(.*)?"}] Inputs: [{"pathname":"/foo"}]', + 'Pattern: [{"pathname":"/foo/*?"}] Inputs: [{"pathname":"/foo"}]', + 'Pattern: [{"pathname":"/foo/(.*)*"}] Inputs: [{"pathname":"/foo"}]', + 'Pattern: [{"pathname":"/foo/**"}] Inputs: [{"pathname":"/foo"}]', + 'Pattern: [{"protocol":"(.*)"}] Inputs: [{"protocol":"café"}]', + 'Pattern: [{"hostname":"xn--caf-dma.com"}] Inputs: [{"hostname":"café.com"}]', + 'Pattern: [{"hostname":"café.com"}] Inputs: [{"hostname":"café.com"}]', + 'Pattern: [{"protocol":"http","port":"80"}] Inputs: [{"protocol":"http","port":"80"}]', + 'Pattern: [{"protocol":"http","port":"80 "}] Inputs: [{"protocol":"http","port":"80"}]', + 'Pattern: [{"port":"(.*)"}] Inputs: [{"port":"invalid80"}]', + 'Pattern: [{"pathname":"/foo/bar"}] Inputs: [{"pathname":"foo/bar"}]', + 'Pattern: [{"pathname":"./foo/bar","baseURL":"https://example.com"}] Inputs: [{"pathname":"foo/bar","baseURL":"https://example.com"}]', + 'Pattern: [{"pathname":"","baseURL":"https://example.com"}] Inputs: [{"pathname":"/","baseURL":"https://example.com"}]', + 'Pattern: [{"pathname":"{/bar}","baseURL":"https://example.com/foo/"}] Inputs: [{"pathname":"./bar","baseURL":"https://example.com/foo/"}]', + 'Pattern: [{"pathname":"\\\\/bar","baseURL":"https://example.com/foo/"}] Inputs: [{"pathname":"./bar","baseURL":"https://example.com/foo/"}]', + 'Pattern: [{"pathname":"b","baseURL":"https://example.com/foo/"}] Inputs: [{"pathname":"./b","baseURL":"https://example.com/foo/"}]', + 'Pattern: [{"pathname":"foo/bar","baseURL":"https://example.com"}] Inputs: ["https://example.com/foo/bar"]', + 'Pattern: [{"pathname":":name.html","baseURL":"https://example.com"}] Inputs: ["https://example.com/foo.html"]', + 'Pattern: [{"protocol":"javascript","pathname":"var x = 1;"}] Inputs: [{"protocol":"javascript","pathname":"var x = 1;"}]', + 'Pattern: [{"protocol":"(data|javascript)","pathname":"var x = 1;"}] Inputs: [{"protocol":"javascript","pathname":"var x = 1;"}]', + 'Pattern: [{"pathname":"var x = 1;"}] Inputs: [{"pathname":"var x = 1;"}]', + 'Pattern: ["https://example.com:8080/foo?bar#baz"] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}]', + 'Pattern: ["/foo?bar#baz","https://example.com:8080"] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}]', + 'Pattern: ["http{s}?://{*.}?example.com/:product/:endpoint"] Inputs: ["https://sub.example.com/foo/bar"]', + 'Pattern: ["https://example.com?foo"] Inputs: ["https://example.com/?foo"]', + 'Pattern: ["https://example.com#foo"] Inputs: ["https://example.com/#foo"]', + 'Pattern: ["https://example.com:8080?foo"] Inputs: ["https://example.com:8080/?foo"]', + 'Pattern: ["https://example.com:8080#foo"] Inputs: ["https://example.com:8080/#foo"]', + 'Pattern: ["https://example.com/?foo"] Inputs: ["https://example.com/?foo"]', + 'Pattern: ["https://example.com/#foo"] Inputs: ["https://example.com/#foo"]', + 'Pattern: ["https://example.com/*?foo"] Inputs: ["https://example.com/?foo"]', + 'Pattern: ["https://example.com/*\\\\?foo"] Inputs: ["https://example.com/?foo"]', + 'Pattern: ["https://example.com/:name?foo"] Inputs: ["https://example.com/bar?foo"]', + 'Pattern: ["https://example.com/:name\\\\?foo"] Inputs: ["https://example.com/bar?foo"]', + 'Pattern: ["https://example.com/(bar)?foo"] Inputs: ["https://example.com/bar?foo"]', + 'Pattern: ["https://example.com/(bar)\\\\?foo"] Inputs: ["https://example.com/bar?foo"]', + 'Pattern: ["https://example.com/{bar}?foo"] Inputs: ["https://example.com/bar?foo"]', + 'Pattern: ["https://example.com/{bar}\\\\?foo"] Inputs: ["https://example.com/bar?foo"]', + 'Pattern: ["https://example.com/"] Inputs: ["https://example.com:8080/"]', + 'Pattern: ["data\\\\:foobar"] Inputs: ["data:foobar"]', + 'Pattern: ["https://{sub.}?example.com/foo"] Inputs: ["https://example.com/foo"]', + 'Pattern: ["https://(sub.)?example.com/foo"] Inputs: ["https://example.com/foo"]', + 'Pattern: ["https://(sub.)?example(.com/)foo"] Inputs: ["https://example.com/foo"]', + 'Pattern: ["https://(sub(?:.))?example.com/foo"] Inputs: ["https://example.com/foo"]', + 'Pattern: ["file:///foo/bar"] Inputs: ["file:///foo/bar"]', + 'Pattern: ["data:"] Inputs: ["data:"]', + 'Pattern: ["foo://bar"] Inputs: ["foo://bad_url_browser_interop"]', + 'Pattern: ["https://example.com/foo?bar#baz"] Inputs: [{"protocol":"https:","search":"?bar","hash":"#baz","baseURL":"http://example.com/foo"}]', + 'Pattern: ["?bar#baz","https://example.com/foo"] Inputs: ["?bar#baz","https://example.com/foo"]', + 'Pattern: ["?bar","https://example.com/foo#baz"] Inputs: ["?bar","https://example.com/foo#snafu"]', + 'Pattern: ["#baz","https://example.com/foo?bar"] Inputs: ["#baz","https://example.com/foo?bar"]', + 'Pattern: ["#baz","https://example.com/foo"] Inputs: ["#baz","https://example.com/foo"]', + 'Pattern: ["https://foo\\\\:bar@example.com"] Inputs: ["https://foo:bar@example.com"]', + 'Pattern: ["https://foo@example.com"] Inputs: ["https://foo@example.com"]', + 'Pattern: ["https://\\\\:bar@example.com"] Inputs: ["https://:bar@example.com"]', + 'Pattern: ["https://:user::pass@example.com"] Inputs: ["https://foo:bar@example.com"]', + 'Pattern: ["https\\\\:foo\\\\:bar@example.com"] Inputs: ["https:foo:bar@example.com"]', + 'Pattern: ["data\\\\:foo\\\\:bar@example.com"] Inputs: ["data:foo:bar@example.com"]', + 'Pattern: ["https://foo{\\\\:}bar@example.com"] Inputs: ["https://foo:bar@example.com"]', + 'Pattern: ["data{\\\\:}channel.html","https://example.com"] Inputs: ["https://example.com/data:channel.html"]', + 'Pattern: ["http://[\\\\:\\\\:1]/"] Inputs: ["http://[::1]/"]', + 'Pattern: ["http://[\\\\:\\\\:1]:8080/"] Inputs: ["http://[::1]:8080/"]', + 'Pattern: ["http://[\\\\:\\\\:a]/"] Inputs: ["http://[::a]/"]', + 'Pattern: ["http://[:address]/"] Inputs: ["http://[::1]/"]', + 'Pattern: ["http://[\\\\:\\\\:AB\\\\::num]/"] Inputs: ["http://[::ab:1]/"]', + 'Pattern: [{"hostname":"[\\\\:\\\\:AB\\\\::num]"}] Inputs: [{"hostname":"[::ab:1]"}]', + 'Pattern: ["data\\\\:text/javascript,let x = 100/:tens?5;"] Inputs: ["data:text/javascript,let x = 100/5;"]', + 'Pattern: [{"pathname":"/foo"},"https://example.com"] Inputs: undefined', + 'Pattern: [{"pathname":":name*"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":name+"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":name"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":"(foo)(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{(foo)bar}(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"(foo)?(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo}(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo}(barbaz)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo}{(.*)}"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo}{bar(.*)}"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo}:bar(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo}?(.*)"}] Inputs: [{"pathname":"foobarbaz"}]', + 'Pattern: [{"pathname":"{:foo\\\\bar}"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":"{:foo\\\\.bar}"}] Inputs: [{"pathname":"foo.bar"}]', + 'Pattern: [{"pathname":"{:foo(foo)bar}"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":"{:foo}bar"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":foo\\\\bar"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":foo{}(.*)"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":foo{}bar"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":foo{}?bar"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":"*{}**?"}] Inputs: [{"pathname":"foobar"}]', + 'Pattern: [{"pathname":":foo(baz)(.*)"}] Inputs: [{"pathname":"bazbar"}]', + 'Pattern: [{"pathname":":foo(baz)bar"}] Inputs: [{"pathname":"bazbar"}]', + 'Pattern: [{"pathname":"*/*"}] Inputs: [{"pathname":"foo/bar"}]', + 'Pattern: [{"pathname":"*\\\\/*"}] Inputs: [{"pathname":"foo/bar"}]', + 'Pattern: [{"pathname":"*/{*}"}] Inputs: [{"pathname":"foo/bar"}]', + 'Pattern: [{"pathname":"./foo"}] Inputs: [{"pathname":"./foo"}]', + 'Pattern: [{"pathname":"../foo"}] Inputs: [{"pathname":"../foo"}]', + 'Pattern: [{"pathname":":foo./"}] Inputs: [{"pathname":"bar./"}]', + 'Pattern: [{"pathname":":foo../"}] Inputs: [{"pathname":"bar../"}]', + 'Pattern: [{"pathname":"/:foo\\\\bar"}] Inputs: [{"pathname":"/bazbar"}]', + 'Pattern: [{"pathname":"/foo/bar"},{"ignoreCase":true}] Inputs: [{"pathname":"/FOO/BAR"}]', + 'Pattern: ["https://example.com:8080/foo?bar#baz",{"ignoreCase":true}] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}]', + 'Pattern: ["/foo?bar#baz","https://example.com:8080",{"ignoreCase":true}] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}]', + 'Pattern: [{"search":"foo","baseURL":"https://example.com/a/+/b"}] Inputs: [{"search":"foo","baseURL":"https://example.com/a/+/b"}]', + 'Pattern: [{"hash":"foo","baseURL":"https://example.com/?q=*&v=?&hmm={}&umm=()"}] Inputs: [{"hash":"foo","baseURL":"https://example.com/?q=*&v=?&hmm={}&umm=()"}]', + 'Pattern: ["#foo","https://example.com/?q=*&v=?&hmm={}&umm=()"] Inputs: ["https://example.com/?q=*&v=?&hmm={}&umm=()#foo"]', + 'Pattern: [{"pathname":"/([[a-z]--a])"}] Inputs: [{"pathname":"/a"}]', + 'Pattern: [{"pathname":"/([[a-z]--a])"}] Inputs: [{"pathname":"/z"}]', + 'Pattern: [{"pathname":"/([\\\\d&&[0-1]])"}] Inputs: [{"pathname":"/0"}]', + 'Pattern: [{"pathname":"/([\\\\d&&[0-1]])"}] Inputs: [{"pathname":"/3"}]', + ], + }, +}; diff --git a/src/wpt/harness.ts b/src/wpt/harness.ts index 6f4978a4289..995fad4c4fd 100644 --- a/src/wpt/harness.ts +++ b/src/wpt/harness.ts @@ -36,6 +36,15 @@ type TestRunnerOptions = { expectedFailures?: string[]; verbose?: boolean; skippedTests?: string[]; + skipAllTests?: boolean; +}; + +type TestRunnerConfig = { + [key: string]: TestRunnerOptions; +}; + +type TestCase = { + test(): Promise; }; type TestRunnerFn = (callback: TestFn | PromiseTestFn, message: string) => void; @@ -444,12 +453,16 @@ function validate(testFileName: string, options: TestRunnerOptions): void { } } -export function run( - file: string, - options: TestRunnerOptions = {} -): { test(): Promise } { +export function run(config: TestRunnerConfig, file: string): TestCase { + const options = config[file] ?? {}; + return { async test(): Promise { + if (!!options.skipAllTests) { + console.warn(`All tests in ${file} have been skipped.`); + return; + } + prepare(options); await import(file); validate(file, options);