Skip to content

Commit

Permalink
[Import Maps] Migrate Jest-based resolution tests into JSON-based tests
Browse files Browse the repository at this point in the history
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
- Removes imported resolution tests.

Bug: 1026809, WICG/import-maps#170
Change-Id: I993cc9cd7746d7175142f8296ac434571f5d7157
  • Loading branch information
hiroshige-g authored and chromium-wpt-export-bot committed Dec 3, 2019
1 parent 28b0967 commit ff1f5ba
Show file tree
Hide file tree
Showing 17 changed files with 848 additions and 476 deletions.
79 changes: 79 additions & 0 deletions import-maps/common/README.md
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",
"specifiers": {
"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.
- `specifiers` (object; string to (string or null)): Specifiers to be tested.
- 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",
"specifiers": { "a": "https://example.com/mapped-a.mjs" }
},
"Subtest2": {
"baseURL": "https://example.com/base-url2/app.mjs",
"specifiers": { "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 import-maps/common/resolving.tentative.html
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>
17 changes: 17 additions & 0 deletions import-maps/common/resources/data-base-url.json
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 import-maps/common/resources/empty-import-map.json
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 import-maps/common/resources/overlapping-entries.json
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"
}
}
}
}
43 changes: 43 additions & 0 deletions import-maps/common/resources/packages-via-trailing-slashes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"importMap": {
"imports": {
"moment": "/node_modules/moment/src/moment.js",
"moment/": "/node_modules/moment/src/",
"lodash-dot": "./node_modules/lodash-es/lodash.js",
"lodash-dot/": "./node_modules/lodash-es/",
"lodash-dotdot": "../node_modules/lodash-es/lodash.js",
"lodash-dotdot/": "../node_modules/lodash-es/"
}
},
"importMapBaseURL": "https://example.com/app/index.html",
"baseURL": "https://example.com/js/app.mjs",
"name": "Package-like scenarios",
"link": "https://github.com/WICG/import-maps#packages-via-trailing-slashes",
"tests": {
"package main modules": {
"expectedResults": {
"moment": "https://example.com/node_modules/moment/src/moment.js",
"lodash-dot": "https://example.com/app/node_modules/lodash-es/lodash.js",
"lodash-dotdot": "https://example.com/node_modules/lodash-es/lodash.js"
}
},
"package submodules": {
"expectedResults": {
"moment/foo": "https://example.com/node_modules/moment/src/foo",
"lodash-dot/foo": "https://example.com/app/node_modules/lodash-es/foo",
"lodash-dotdot/foo": "https://example.com/node_modules/lodash-es/foo"
}
},
"package names that end in a slash should just pass through": {
"expectedResults": {
"moment/": "https://example.com/node_modules/moment/src/"
}
},
"package modules that are not declared should fail": {
"expectedResults": {
"underscore/": null,
"underscore/foo": null
}
}
}
}
134 changes: 134 additions & 0 deletions import-maps/common/resources/scopes-exact-vs-prefix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{
"name": "Exact vs. prefix based matching",
"details": "Scopes are matched with base URLs that are exactly the same or subpaths under the scopes with trailing shashes",
"link": "https://wicg.github.io/import-maps/#resolve-a-module-specifier Step 8.1",
"tests": {
"Scope without trailing slash only": {
"importMap": {
"scopes": {
"/js": {
"moment": "/only-triggered-by-exact/moment",
"moment/": "/only-triggered-by-exact/moment/"
}
}
},
"importMapBaseURL": "https://example.com/app/index.html",
"tests": {
"Non-trailing-slash base URL (exact match)": {
"baseURL": "https://example.com/js",
"expectedResults": {
"moment": "https://example.com/only-triggered-by-exact/moment",
"moment/foo": "https://example.com/only-triggered-by-exact/moment/foo"
}
},
"Trailing-slash base URL (fail)": {
"baseURL": "https://example.com/js/",
"expectedResults": {
"moment": null,
"moment/foo": null
}
},
"Subpath base URL (fail)": {
"baseURL": "https://example.com/js/app.mjs",
"expectedResults": {
"moment": null,
"moment/foo": null
}
},
"Non-subpath base URL (fail)": {
"baseURL": "https://example.com/jsiscool",
"expectedResults": {
"moment": null,
"moment/foo": null
}
}
}
},
"Scope with trailing slash only": {
"importMap": {
"scopes": {
"/js/": {
"moment": "/triggered-by-any-subpath/moment",
"moment/": "/triggered-by-any-subpath/moment/"
}
}
},
"importMapBaseURL": "https://example.com/app/index.html",
"tests": {
"Non-trailing-slash base URL (fail)": {
"baseURL": "https://example.com/js",
"expectedResults": {
"moment": null,
"moment/foo": null
}
},
"Trailing-slash base URL (exact match)": {
"baseURL": "https://example.com/js/",
"expectedResults": {
"moment": "https://example.com/triggered-by-any-subpath/moment",
"moment/foo": "https://example.com/triggered-by-any-subpath/moment/foo"
}
},
"Subpath base URL (prefix match)": {
"baseURL": "https://example.com/js/app.mjs",
"expectedResults": {
"moment": "https://example.com/triggered-by-any-subpath/moment",
"moment/foo": "https://example.com/triggered-by-any-subpath/moment/foo"
}
},
"Non-subpath base URL (fail)": {
"baseURL": "https://example.com/jsiscool",
"expectedResults": {
"moment": null,
"moment/foo": null
}
}
}
},
"Scopes with and without trailing slash": {
"importMap": {
"scopes": {
"/js": {
"moment": "/only-triggered-by-exact/moment",
"moment/": "/only-triggered-by-exact/moment/"
},
"/js/": {
"moment": "/triggered-by-any-subpath/moment",
"moment/": "/triggered-by-any-subpath/moment/"
}
}
},
"importMapBaseURL": "https://example.com/app/index.html",
"tests": {
"Non-trailing-slash base URL (exact match)": {
"baseURL": "https://example.com/js",
"expectedResults": {
"moment": "https://example.com/only-triggered-by-exact/moment",
"moment/foo": "https://example.com/only-triggered-by-exact/moment/foo"
}
},
"Trailing-slash base URL (exact match)": {
"baseURL": "https://example.com/js/",
"expectedResults": {
"moment": "https://example.com/triggered-by-any-subpath/moment",
"moment/foo": "https://example.com/triggered-by-any-subpath/moment/foo"
}
},
"Subpath base URL (prefix match)": {
"baseURL": "https://example.com/js/app.mjs",
"expectedResults": {
"moment": "https://example.com/triggered-by-any-subpath/moment",
"moment/foo": "https://example.com/triggered-by-any-subpath/moment/foo"
}
},
"Non-subpath base URL (fail)": {
"baseURL": "https://example.com/jsiscool",
"expectedResults": {
"moment": null,
"moment/foo": null
}
}
}
}
}
}
Loading

0 comments on commit ff1f5ba

Please sign in to comment.