forked from mykmelez/gecko
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1600851 [wpt PR 20574] - [Import Maps] Migrate Jest-based resolut…
…ion tests into JSON-based tests, a=testonly Automatic update from web-platform-tests [Import Maps] Migrate Jest-based resolution tests into JSON-based tests This CL - Defines JSON test object format (see README.md) that describes the configurations and specifiers to be tested, - Implements the WPT test helper for executing the tests based on the JSON test objects (common-test-helper.js), - Converts Jest-based resolution tests into JSONs (with some refinement, and removing test cases depending on interoperability issues of underlying URL parsers), and - Removes imported resolution tests. The dependency to Blink internals remains after this CL. Removing this dependency is planned and discussed at WICG/import-maps#170. Bug: 1026809, WICG/import-maps#170 Change-Id: I993cc9cd7746d7175142f8296ac434571f5d7157 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1927852 Commit-Queue: Hiroshige Hayashizaki <[email protected]> Reviewed-by: Domenic Denicola <[email protected]> Cr-Commit-Position: refs/heads/master@{#721239} -- wpt-commits: de73fe8cc89c55dea4fee1fc46d98d73dad2b21b wpt-pr: 20574
- Loading branch information
1 parent
df62d4e
commit be7d9eb
Showing
17 changed files
with
834 additions
and
476 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Import maps test JSON format | ||
|
||
In this directory, test inputs and expectations are expressed as JSON files. | ||
This is in order to share the same JSON files between WPT tests and Jest-based | ||
tests for the reference JavaScript implementation at [WICG repository](https://github.com/WICG/import-maps/tree/master/reference-implementation). | ||
|
||
## Basics | ||
|
||
A **test object** describes a set of parameters (import maps and base URLs) and specifiers to be tested. | ||
Each JSON file under [resources/](resources/) directory consists of a test object. | ||
A minimum test object would be: | ||
|
||
```json | ||
{ | ||
"name": "Main test name", | ||
"importMapBaseURL": "https://example.com/import-map-base-url/index.html", | ||
"importMap": { | ||
"imports": { | ||
"a": "/mapped-a.mjs" | ||
} | ||
}, | ||
"baseURL": "https://example.com/base-url/app.mjs", | ||
"expectedResults": { | ||
"a": "https://example.com/mapped-a.mjs", | ||
"b": null | ||
} | ||
} | ||
``` | ||
|
||
Required fields: | ||
|
||
- `name`: Test name. | ||
- In WPT tests, this is used for the test name of `promise_test()` together with specifier to be resolved, like `"Main test name: a"`. | ||
- `importMap` (object or string): the import map to be attached. | ||
- `importMapBaseURL` (string): the base URL used for [parsing the import map](https://wicg.github.io/import-maps/#parse-an-import-map-string). | ||
- `baseURL` (string): the base URL used in [resolving a specifier](https://wicg.github.io/import-maps/#resolve-a-module-specifier) for each specifiers. | ||
- `expectedResults` (object; string to (string or null)): test cases. | ||
- The keys are specifiers to be resolved. | ||
- The values are expected resolved URLs. If `null`, resolution should fail. | ||
|
||
Optional fields: | ||
|
||
- `link` and `details` can be used for e.g. linking to specs or adding more detailed descriptions. | ||
- Currently they are simply ignored by the WPT test helper. | ||
|
||
## Nesting and inheritance | ||
|
||
We can organize tests by nesting test objects. | ||
A test object can contain child test objects (*subtests*) using `tests` field. | ||
The Keys of the `tests` value are the names of subtests, and values are test objects. | ||
|
||
For example: | ||
|
||
```json | ||
{ | ||
"name": "Main test name", | ||
"importMapBaseURL": "https://example.com/import-map-base-url/index.html", | ||
"importMap": { | ||
"imports": { | ||
"a": "/mapped-a.mjs" | ||
} | ||
}, | ||
"tests": { | ||
"Subtest1": { | ||
"baseURL": "https://example.com/base-url1/app.mjs", | ||
"expectedResults": { "a": "https://example.com/mapped-a.mjs" } | ||
}, | ||
"Subtest2": { | ||
"baseURL": "https://example.com/base-url2/app.mjs", | ||
"expectedResults": { "b": null } | ||
} | ||
} | ||
} | ||
``` | ||
|
||
The top-level test object contains two sub test objects, named as `Subtest1` and `Subtest2`, respectively. | ||
|
||
Child test objects inherit fields from their parent test object. | ||
In the example above, the child test objects specifies `baseURL` fields, while they inherits other fields (e.g. `importMapBaseURL`) from the top-level test object. |
23 changes: 23 additions & 0 deletions
23
testing/web-platform/tests/import-maps/common/resolving.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<!DOCTYPE html> | ||
<meta name="timeout" content="long"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<body> | ||
<script type="module"> | ||
import { runTestsFromJSON } from "./resources/common-test-helper.js"; | ||
|
||
for (const json of [ | ||
'resources/scopes.json', | ||
'resources/empty-import-map.json', | ||
'resources/packages-via-trailing-slashes.json', | ||
'resources/tricky-specifiers.json', | ||
'resources/url-specifiers.json', | ||
'resources/data-base-url.json', | ||
'resources/scopes-exact-vs-prefix.json', | ||
'resources/overlapping-entries.json', | ||
]) { | ||
promise_test(() => | ||
runTestsFromJSON(json), | ||
"Test helper: fetching and sanity checking test JSON: " + json); | ||
} | ||
</script> |
163 changes: 163 additions & 0 deletions
163
testing/web-platform/tests/import-maps/common/resources/common-test-helper.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
setup({allow_uncaught_exception : true}); | ||
|
||
// Creates a new Document (via <iframe>) and add an inline import map. | ||
function parse(importMap, importMapBaseURL) { | ||
return new Promise((resolve, reject) => { | ||
const importMapString = JSON.stringify(importMap); | ||
const iframe = document.createElement('iframe'); | ||
|
||
window.addEventListener('message', event => { | ||
if (event.data.type === 'Success') { | ||
resolve(iframe); | ||
} else { | ||
// Currently we don't distinguish fetch errors and parse errors. | ||
reject(event.data.error); | ||
} | ||
}, | ||
{once: true}); | ||
|
||
const testHTML = ` | ||
<script> | ||
// Handle errors around fetching, parsing and registering import maps. | ||
let registrationResult; | ||
const onScriptError = event => { | ||
registrationResult = {type: 'FetchError', error: event.error}; | ||
return false; | ||
}; | ||
const windowErrorHandler = event => { | ||
registrationResult = {type: 'ParseError', error: event.error}; | ||
return false; | ||
}; | ||
window.addEventListener('error', windowErrorHandler); | ||
window.addEventListener('load', event => { | ||
if (!registrationResult) { | ||
registrationResult = {type: 'Success'}; | ||
} | ||
window.removeEventListener('error', windowErrorHandler); | ||
parent.postMessage(registrationResult, '*'); | ||
}); | ||
// Handle specifier resolution requests from the parent frame. | ||
window.addEventListener('message', event => { | ||
try { | ||
// URL resolution is tested using Chromium's internals. | ||
// TODO(hiroshige): Remove the Chromium-specific dependency. | ||
const result = internals.resolveModuleSpecifier( | ||
event.data.specifier, | ||
event.data.baseURL, | ||
document); | ||
parent.postMessage({type: 'ResolutionSuccess', result: result}, '*'); | ||
} catch (e) { | ||
// We post error names instead of error objects themselves and | ||
// re-create error objects later, to avoid issues around serializing | ||
// error objects which is a quite new feature. | ||
parent.postMessage({type: 'ResolutionFailure', result: e.name}, '*'); | ||
} | ||
}); | ||
</script> | ||
<script type="importmap" onerror="onScriptError(event)"> | ||
${importMapString} | ||
</script> | ||
`; | ||
|
||
if (new URL(importMapBaseURL).protocol === 'data:') { | ||
iframe.src = 'data:text/html;base64,' + btoa(testHTML); | ||
} else { | ||
iframe.srcdoc = `<base href="${importMapBaseURL}">` + testHTML; | ||
} | ||
|
||
document.body.appendChild(iframe); | ||
|
||
}); | ||
} | ||
|
||
// Returns a promise that is resolved with the resulting URL. | ||
function resolve(specifier, parsedImportMap, baseURL) { | ||
return new Promise((resolve, reject) => { | ||
window.addEventListener('message', event => { | ||
if (event.data.type === 'ResolutionSuccess') { | ||
resolve(event.data.result); | ||
} else if (event.data.type === 'ResolutionFailure') { | ||
if (event.data.result === 'TypeError') { | ||
reject(new TypeError()); | ||
} else { | ||
reject(new Error(event.data.result)); | ||
} | ||
} else { | ||
assert_unreached('Invalid message: ' + event.data.type); | ||
} | ||
}, | ||
{once: true}); | ||
|
||
parsedImportMap.contentWindow.postMessage( | ||
{specifier: specifier, baseURL: baseURL}, '*'); | ||
}); | ||
} | ||
|
||
function assert_no_extra_properties(object, expectedProperties, description) { | ||
for (const actualProperty in object) { | ||
assert_true(expectedProperties.indexOf(actualProperty) !== -1, | ||
description + ": unexpected property " + actualProperty); | ||
} | ||
} | ||
|
||
async function runTests(j) { | ||
const tests = j.tests; | ||
delete j.tests; | ||
|
||
if (j.importMap) { | ||
assert_own_property(j, 'importMap'); | ||
assert_own_property(j, 'importMapBaseURL'); | ||
j.parsedImportMap = await parse(j.importMap, j.importMapBaseURL); | ||
delete j.importMap; | ||
delete j.importMapBaseURL; | ||
} | ||
|
||
assert_no_extra_properties( | ||
j, | ||
['expectedResults', 'baseURL', 'name', 'parsedImportMap', | ||
'importMap', 'importMapBaseURL', | ||
'link', 'details'], | ||
j.name); | ||
|
||
if (tests) { | ||
// Nested node. | ||
for (const testName in tests) { | ||
let fullTestName = testName; | ||
if (j.name) { | ||
fullTestName = j.name + ': ' + testName; | ||
} | ||
tests[testName].name = fullTestName; | ||
const k = Object.assign(Object.assign({}, j), tests[testName]); | ||
await runTests(k); | ||
} | ||
} else { | ||
// Leaf node. | ||
for (const key of | ||
['expectedResults', 'parsedImportMap', 'baseURL', 'name']) { | ||
assert_own_property(j, key, j.name); | ||
} | ||
|
||
for (const specifier in j.expectedResults) { | ||
const expected = j.expectedResults[specifier]; | ||
promise_test(async t => { | ||
if (expected === null) { | ||
return promise_rejects(t, new TypeError(), | ||
resolve(specifier, j.parsedImportMap, j.baseURL)); | ||
} else { | ||
// Should be resolved to `expected`. | ||
const actual = await resolve( | ||
specifier, j.parsedImportMap, j.baseURL); | ||
assert_equals(actual, expected); | ||
} | ||
}, | ||
j.name + ': ' + specifier); | ||
} | ||
} | ||
} | ||
|
||
export async function runTestsFromJSON(jsonURL) { | ||
const response = await fetch(jsonURL); | ||
const json = await response.json(); | ||
await runTests(json); | ||
} |
17 changes: 17 additions & 0 deletions
17
testing/web-platform/tests/import-maps/common/resources/data-base-url.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"importMap": { | ||
"imports": { | ||
"foo/": "data:text/javascript,foo/" | ||
} | ||
}, | ||
"importMapBaseURL": "https://example.com/app/index.html", | ||
"baseURL": "https://example.com/js/app.mjs", | ||
"name": "data: base URL (?)", | ||
"tests": { | ||
"should favor the most-specific key": { | ||
"expectedResults": { | ||
"foo/bar": null | ||
} | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
testing/web-platform/tests/import-maps/common/resources/empty-import-map.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ | ||
"importMap": {}, | ||
"importMapBaseURL": "https://example.com/app/index.html", | ||
"baseURL": "https://example.com/js/app.mjs", | ||
"tests": { | ||
"valid relative specifiers": { | ||
"expectedResults": { | ||
"./foo": "https://example.com/js/foo", | ||
"./foo/bar": "https://example.com/js/foo/bar", | ||
"./foo/../bar": "https://example.com/js/bar", | ||
"./foo/../../bar": "https://example.com/bar", | ||
"../foo": "https://example.com/foo", | ||
"../foo/bar": "https://example.com/foo/bar", | ||
"../../../foo/bar": "https://example.com/foo/bar", | ||
"/foo": "https://example.com/foo", | ||
"/foo/bar": "https://example.com/foo/bar", | ||
"/../../foo/bar": "https://example.com/foo/bar", | ||
"/../foo/../bar": "https://example.com/bar" | ||
} | ||
}, | ||
"fetch scheme absolute URLs": { | ||
"expectedResults": { | ||
"about:fetch-scheme": "about:fetch-scheme", | ||
"https://fetch-scheme.net": "https://fetch-scheme.net/", | ||
"https:fetch-scheme.org": "https://fetch-scheme.org/", | ||
"https://fetch%2Dscheme.com/": "https://fetch-scheme.com/", | ||
"https://///fetch-scheme.com///": "https://fetch-scheme.com///" | ||
} | ||
}, | ||
"non-fetch scheme absolute URLs": { | ||
"expectedResults": { | ||
"mailto:non-fetch-scheme": "mailto:non-fetch-scheme", | ||
"import:non-fetch-scheme": "import:non-fetch-scheme", | ||
"javascript:non-fetch-scheme": "javascript:non-fetch-scheme", | ||
"wss:non-fetch-scheme": "wss://non-fetch-scheme/" | ||
} | ||
}, | ||
"valid relative URLs that are invalid as specifiers should fail": { | ||
"expectedResults": { | ||
"invalid-specifier": null, | ||
"\\invalid-specifier": null, | ||
":invalid-specifier": null, | ||
"@invalid-specifier": null, | ||
"%2E/invalid-specifier": null, | ||
"%2E%2E/invalid-specifier": null, | ||
".%2Finvalid-specifier": null | ||
} | ||
}, | ||
"invalid absolute URLs should fail": { | ||
"expectedResults": { | ||
"https://invalid-url.com:demo": null, | ||
"http://[invalid-url.com]/": null | ||
} | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
testing/web-platform/tests/import-maps/common/resources/overlapping-entries.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"importMapBaseURL": "https://example.com/app/index.html", | ||
"baseURL": "https://example.com/js/app.mjs", | ||
"name": "should favor the most-specific key", | ||
"tests": { | ||
"Overlapping entries with trailing slashes": { | ||
"importMap": { | ||
"imports": { | ||
"a": "/1", | ||
"a/": "/2/", | ||
"a/b": "/3", | ||
"a/b/": "/4/" | ||
} | ||
}, | ||
"expectedResults": { | ||
"a": "https://example.com/1", | ||
"a/": "https://example.com/2/", | ||
"a/x": "https://example.com/2/x", | ||
"a/b": "https://example.com/3", | ||
"a/b/": "https://example.com/4/", | ||
"a/b/c": "https://example.com/4/c" | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.