Commit 2f10bef5 authored by Hiroshige Hayashizaki's avatar Hiroshige Hayashizaki Committed by Commit Bot

[Import Maps] Drop WPTs for fallback/built-in modules support

Bug: 829084, 848607
Change-Id: I903141366d7fbda98f795840264f1c58c911d230
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2094383Reviewed-by: default avatarDomenic Denicola <domenic@chromium.org>
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749562}
parent 507f170d
......@@ -4329,7 +4329,6 @@ crbug.com/927477 external/wpt/import-maps/acquire-import-maps-flag/worker-reques
crbug.com/927477 virtual/import-maps-without-builtin-modules/external/wpt/import-maps/acquire-import-maps-flag/worker-request/* [ Skip ]
# Excludes tests that require built-in module supports.
crbug.com/1010751 virtual/import-maps-without-builtin-modules/external/wpt/import-maps/builtin-support.tentative/* [ Skip ]
crbug.com/1010751 external/wpt/import-maps/imported/* [ Skip ]
# Disabled temporarliy until eager evaluation is fixed/re-baselined in DevTools.
......
......@@ -47,9 +47,6 @@ external/wpt/html/interaction/focus/the-autofocus-attribute/update-the-rendering
external/wpt/html/rendering/widgets/baseline-alignment-and-overflow.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_anchor_download_block_downloads.sub.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigation_download_block_downloads.sub.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/import-maps/builtin-support.tentative/imported/parsing-schema.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/import-maps/builtin-support.tentative/imported/resolving-not-yet-implemented.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/import-maps/builtin-support.tentative/imported/resolving-scopes.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/import-maps/common/resolving.tentative.html [ Pass ] # wpt_subtest_failure
external/wpt/navigation-timing/test_performance_attributes.sub.html [ Pass ] # wpt_subtest_failure
external/wpt/offscreen-canvas/text/2d.text.measure.actualBoundingBox.html [ Pass ] # wpt_subtest_failure
......
<!DOCTYPE html>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
// "bare/..." (i.e. without leading "./") are bare specifiers
// (not relative paths).
//
// Discussions about notations for builtin modules are ongoing, e.g.
// https://github.com/tc39/proposal-javascript-standard-library/issues/12
// Currently the tests expects two notations are accepted.
// TODO: Once the discussions converge, update the tests.
const importMap = `
{
"imports": {
"bare/std-blank": "std:blank",
"bare/blank": "@std/blank",
"bare/std-none": "std:none",
"bare/none": "@std/none"
}
}
`;
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Currently, Chromium's implementation resolves import maps as a part of
// specifier resolution, and thus failure in import map resolution causes
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
// below. https://crbug.com/928435
// Bare to built-in.
"bare/std-blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"bare/blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"bare/std-none":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
"bare/none":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
};
doTests(importMap, null, tests);
</script>
<body>
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
const importMap = `
{
"imports": {
"../resources/log.js?pipe=sub&name=empty": [ "@std/" ],
"../resources/log.js?pipe=sub&name=empty-fallback": [
"@std/",
"../resources/log.js?pipe=sub&name=empty-fallback"
]
}
}
`;
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Discussions about notations are ongoing, e.g.
// https://github.com/tc39/proposal-javascript-standard-library/issues/12
// Currently the tests expects two notations are accepted.
// TODO: Once the discussions converge, update this and related tests.
"std:":
[Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
"@std/":
[Result.FETCH_ERROR, Result.PARSE_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
"../resources/log.js?pipe=sub&name=empty":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
"../resources/log.js?pipe=sub&name=empty-fallback":
[Result.URL, Result.URL, Result.URL, Result.URL],
};
doTests(importMap, null, tests);
</script>
<body>
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Currently direct use of import: URLs are disabled.
"import:std:blank":
[Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
"import:@std/blank":
[Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
"import:std:none":
[Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
"import:@std/none":
[Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
};
doTests(null, null, tests);
</script>
<body>
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Discussions about notations are ongoing, e.g.
// https://github.com/tc39/proposal-javascript-standard-library/issues/12
// Currently the tests expects two notations are accepted.
// TODO: Once the discussions converge, update this and related tests.
"std:blank":
[Result.BUILTIN, Result.FETCH_ERROR, Result.BUILTIN, Result.BUILTIN],
"@std/blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"std:none":
[Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
"@std/none":
[Result.URL, Result.URL, Result.FETCH_ERROR, Result.FETCH_ERROR],
};
doTests(null, null, tests);
</script>
<body>
<!DOCTYPE html>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
// "bare/..." (i.e. without leading "./") are bare specifiers
// (not relative paths).
//
// Discussions about notations for builtin modules are ongoing, e.g.
// https://github.com/tc39/proposal-javascript-standard-library/issues/12
// Currently the tests expects two notations are accepted.
// TODO: Once the discussions converge, update the tests.
const importMap = `
{
"imports": {
"data:text/javascript,log.push('data:std-blank')": "std:blank",
"data:text/javascript,log.push('data:blank')": "@std/blank",
"data:text/javascript,log.push('data:std-none')": "std:none",
"data:text/javascript,log.push('data:none')": "@std/none"
}
}
`;
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Currently, Chromium's implementation resolves import maps as a part of
// specifier resolution, and thus failure in import map resolution causes
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
// below. https://crbug.com/928435
// data: to built-in.
"data:text/javascript,log.push('data:std-blank')":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"data:text/javascript,log.push('data:blank')":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"data:text/javascript,log.push('data:std-none')":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
"data:text/javascript,log.push('data:none')":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
};
doTests(importMap, null, tests);
</script>
<body>
<!DOCTYPE html>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
// Fallbacks from external URLs (such as HTTPS URLs) are
// blocked by ongoing spec discussions, for example
// https://github.com/WICG/import-maps/issues/76.
// https://crbug.com/928435
//
// This test, as well as Chromium's implementation, rejects broader range of
// fallbacks (not only those from HTTPS), to avoid potential spec and
// interoperability issues.
// The only allowed fallback pattern is fallbacks from bare specifiers with
// two elements, which are listed in fallback.sub.tentative.html.
const importMap = `
{
"imports": {
"bare": "../resources/log.js?pipe=sub&name=bare",
"../resources/log.js?pipe=sub&name=http-to-builtin": [
"../resources/log.js?pipe=sub&name=http-to-builtin",
"@std/blank"
],
"../resources/log.js?pipe=sub&name=fallback-to-different-url-1": [
"@std/blank",
"../resources/log.js?pipe=sub&name=something-different"
],
"../resources/log.js?pipe=sub&name=fallback-to-different-url-2": [
"@std/none",
"../resources/log.js?pipe=sub&name=something-different2"
],
"../resources/log.js?pipe=sub&name=fallback-to-different-origin-1": [
"@std/blank",
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=fallback-to-different-origin-1"
],
"../resources/log.js?pipe=sub&name=fallback-to-different-origin-2": [
"@std/none",
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=fallback-to-different-origin-2"
],
"../resources/log.js?pipe=sub&name=more-than-two-values-1": [
"@std/none",
"@std/blank",
"../resources/log.js?pipe=sub&name=more-than-two-values-1"
],
"../resources/log.js?pipe=sub&name=more-than-two-values-2": [
"@std/none",
"../resources/log.js?pipe=sub&name=more-than-two-values-2",
"@std/blank"
],
"../resources/log.js?pipe=sub&name=fallback-from-http": [
"../resources/log.js?pipe=sub&name=non-built-in",
"../resources/log.js?pipe=sub&name=fallback-from-http"
],
"../resources/log.js?pipe=sub&name=fallback-from-data-1": [
"data:text/plain,",
"../resources/log.js?pipe=sub&name=fallback-from-http"
],
"../resources/log.js?pipe=sub&name=fallback-from-data-2": [
"data:text/javascript,log.push('dataURL')",
"../resources/log.js?pipe=sub&name=fallback-from-http"
]
}
}
`;
const tests = {};
for (const key in JSON.parse(importMap).imports) {
if (key === "bare") {
continue;
}
tests[key] =
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR];
}
doTests(importMap, null, tests);
</script>
<body>
<!DOCTYPE html>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
// This tests is for fallbacks with the pattern of
// `"https://some.external/url": ["@std/x", "https://some.external/url"]`
// which maps "https://some.external/url" to "@std/x" if "@std/x" is
// implemented, or leaves it unmodified otherwise.
//
// This is the primary use case where fallback should work.
// Some other patterns of fallbacks are intentionally blocked due to ongoing
// spec issues. See fallback-disallowed.sub.tentative.html.
const importMap = `
{
"imports": {
"../resources/log.js?pipe=sub&name=blank": [
"@std/blank",
"../resources/log.js?pipe=sub&name=blank"
],
"../resources/log.js?pipe=sub&name=none": [
"@std/none",
"../resources/log.js?pipe=sub&name=none"
],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank": [
"@std/blank",
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank"
],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none": [
"@std/none",
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none"
],
"../resources/log.js?pipe=sub&name=std-blank": [
"std:blank",
"../resources/log.js?pipe=sub&name=std-blank"
],
"../resources/log.js?pipe=sub&name=std-none": [
"std:none",
"../resources/log.js?pipe=sub&name=std-none"
],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank": [
"std:blank",
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank"
],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-none": [
"std:none",
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-none"
]
}
}
`;
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Result.URL indicates that the specifier was not re-mapped by import maps,
// i.e. either considered as a relative path, or fallback occured.
"../resources/log.js?pipe=sub&name=blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"../resources/log.js?pipe=sub&name=none":
[Result.URL, Result.URL, Result.URL, Result.URL],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-none":
[Result.URL, Result.URL, Result.URL, Result.URL],
"../resources/log.js?pipe=sub&name=std-blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"../resources/log.js?pipe=sub&name=std-none":
[Result.URL, Result.URL, Result.URL, Result.URL],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=std-cross-origin-none":
[Result.URL, Result.URL, Result.URL, Result.URL],
};
doTests(importMap, null, tests);
</script>
<body>
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helper.js"></script>
<script>
// "bare/..." (i.e. without leading "./") are bare specifiers
// (not relative paths).
//
// Discussions about notations for builtin modules are ongoing, e.g.
// https://github.com/tc39/proposal-javascript-standard-library/issues/12
// Currently the tests expects two notations are accepted.
// TODO: Once the discussions converge, update the tests.
const importMap = `
{
"imports": {
"../resources/log.js?pipe=sub&name=std-blank": "std:blank",
"../resources/log.js?pipe=sub&name=blank": "@std/blank",
"../resources/log.js?pipe=sub&name=std-none": "std:none",
"../resources/log.js?pipe=sub&name=none": "@std/none"
}
}
`;
const tests = {
// Arrays of expected results for:
// - <script src type="module">,
// - <script src> (classic script),
// - static import, and
// - dynamic import.
// Currently, Chromium's implementation resolves import maps as a part of
// specifier resolution, and thus failure in import map resolution causes
// a parse error, not fetch error. Therefore, we use Result.PARSE_ERROR
// below. https://crbug.com/928435
// HTTP(S) to built-in.
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=std-blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=blank":
[Result.URL, Result.URL, Result.BUILTIN, Result.BUILTIN],
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=std-none":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=none":
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
};
doTests(importMap, null, tests);
</script>
<body>
This is a testharness.js-based test.
PASS Relative URL-like addresses / should accept strings prefixed with ./, ../, or /
FAIL Relative URL-like addresses / should not accept strings prefixed with ./, ../, or / for data: base URLs test helper does not support data: base URLs
PASS Relative URL-like addresses / should accept the literal strings ./, ../, or / with no suffix
PASS Relative URL-like addresses / should ignore percent-encoded variants of ./, ../, or /
PASS Built-in module addresses / should accept URLs using the built-in module scheme
PASS Built-in module addresses / should ignore percent-encoded variants of the built-in module scheme
PASS Built-in module addresses / should allow built-in module URLs that contain "/" or "\"
FAIL Absolute URL addresses / should only accept absolute URL addresses with fetch schemes assert_equals: expected "{\"imports\":{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[\"filesystem:good\"],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[],\"javascript\":[],\"mailto\":[],\"wss\":[]},\"scopes\":{}}" but got "{\"imports\":{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[\"import:bad\"],\"javascript\":[\"javascript:bad\"],\"mailto\":[\"mailto:bad\"],\"wss\":[\"wss://bad/\"]},\"scopes\":{}}"
FAIL Absolute URL addresses / should only accept absolute URL addresses with fetch schemes inside arrays assert_equals: expected "{\"imports\":{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[\"filesystem:good\"],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[],\"javascript\":[],\"mailto\":[],\"wss\":[]},\"scopes\":{}}" but got "{\"imports\":{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[\"import:bad\"],\"javascript\":[\"javascript:bad\"],\"mailto\":[\"mailto:bad\"],\"wss\":[\"wss://bad/\"]},\"scopes\":{}}"
FAIL Absolute URL addresses / should parse absolute URLs, ignoring unparseable ones assert_equals: expected "{\"imports\":{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/%41\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[],\"unparseable2\":[],\"unparseable3\":[]},\"scopes\":{}}" but got "{\"imports\":{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/A\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[\"https://ex%20ample.org/\"],\"unparseable2\":[],\"unparseable3\":[]},\"scopes\":{}}"
FAIL Absolute URL addresses / should parse absolute URLs, ignoring unparseable ones inside arrays assert_equals: expected "{\"imports\":{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/%41\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[],\"unparseable2\":[],\"unparseable3\":[]},\"scopes\":{}}" but got "{\"imports\":{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/A\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[\"https://ex%20ample.org/\"],\"unparseable2\":[],\"unparseable3\":[]},\"scopes\":{}}"
PASS Failing addresses: mismatched trailing slashes / should warn for the simple case
PASS Failing addresses: mismatched trailing slashes / should warn for a mismatch alone in an array
PASS Failing addresses: mismatched trailing slashes / should warn for a mismatch alongside non-mismatches in an array
PASS Other invalid addresses / should ignore unprefixed strings that are not absolute URLs
Harness: the test ran to completion.
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-addresses.js
-->
<script type="module" src="resources/parsing-addresses.js"></script>
This is a testharness.js-based test.
PASS Invalid JSON
PASS Mismatching the top-level schema / should throw for top-level non-objects
PASS Mismatching the top-level schema / should throw if imports is a non-object
PASS Mismatching the top-level schema / should throw if scopes is a non-object
PASS Mismatching the top-level schema / should ignore unspecified top-level entries
FAIL Mismatching the specifier map schema / should ignore entries where the address is not a string, array, or null assert_equals: expected "{\"imports\":{\"bar\":[\"https://example.com/\"]},\"scopes\":{}}" but got "{\"imports\":{\"bar\":[\"https://example.com/\"],\"foo\":[]},\"scopes\":{}}"
PASS Mismatching the specifier map schema / should ignore entries where the specifier key is an empty string
PASS Mismatching the specifier map schema / should ignore members of an address array that are not strings
PASS Mismatching the specifier map schema / should throw if a scope's value is not an object
PASS Normalization / should normalize empty import maps to have imports and scopes keys
PASS Normalization / should normalize an import map without imports to have imports
PASS Normalization / should normalize an import map without scopes to have scopes
PASS Normalization / should normalize addresses to arrays
Harness: the test ran to completion.
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-schema.js
-->
<script type="module" src="resources/parsing-schema.js"></script>
This is a testharness.js-based test.
PASS Relative URL scope keys / should work with no prefix
PASS Relative URL scope keys / should work with ./, ../, and / prefixes
PASS Relative URL scope keys / should work with /s, ?s, and #s
PASS Relative URL scope keys / should work with an empty string scope key
PASS Relative URL scope keys / should work with / suffixes
PASS Relative URL scope keys / should deduplicate based on URL parsing rules
PASS Absolute URL scope keys / should accept all absolute URL scope keys, with or without fetch schemes
FAIL Absolute URL scope keys / should parse absolute URL scope keys, ignoring unparseable ones assert_equals: expected "{\"imports\":{},\"scopes\":{\"https://base.example/path1/path2/example.org\":{},\"https://example.com/%41\":{},\"https://example.com///\":{},\"https://example.com/foo/\":{},\"https://example.net/\":{}}}" but got "{\"imports\":{},\"scopes\":{\"https://base.example/path1/path2/example.org\":{},\"https://ex%20ample.org/\":{},\"https://example.com///\":{},\"https://example.com/A\":{},\"https://example.com/foo/\":{},\"https://example.net/\":{}}}"
FAIL Absolute URL scope keys / should ignore relative URL scope keys when the base URL is a data: URL test helper does not support data: base URLs
Harness: the test ran to completion.
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-scope-keys.js
-->
<script type="module" src="resources/parsing-scope-keys.js"></script>
This is a testharness.js-based test.
PASS Relative URL-like specifier keys / should absolutize strings prefixed with ./, ../, or / into the corresponding URLs
FAIL Relative URL-like specifier keys / should not absolutize strings prefixed with ./, ../, or / with a data: URL base test helper does not support data: base URLs
PASS Relative URL-like specifier keys / should absolutize the literal strings ./, ../, or / with no suffix
PASS Relative URL-like specifier keys / should treat percent-encoded variants of ./, ../, or / as bare specifiers
FAIL Absolute URL specifier keys / should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers assert_equals: expected "{\"imports\":{\"about:good\":[\"https://base.example/about\"],\"blob:good\":[\"https://base.example/blob\"],\"data:good\":[\"https://base.example/data\"],\"file:///good\":[\"https://base.example/file\"],\"filesystem:good\":[\"https://base.example/filesystem\"],\"ftp://good/\":[\"https://base.example/ftp/\"],\"http://good/\":[\"https://base.example/http/\"],\"https://good/\":[\"https://base.example/https/\"],\"import:bad\":[\"https://base.example/import\"],\"javascript:bad\":[\"https://base.example/javascript\"],\"mailto:bad\":[\"https://base.example/mailto\"],\"wss:bad\":[\"https://base.example/wss\"]},\"scopes\":{}}" but got "{\"imports\":{\"about:good\":[\"https://base.example/about\"],\"blob:good\":[\"https://base.example/blob\"],\"data:good\":[\"https://base.example/data\"],\"file:///good\":[\"https://base.example/file\"],\"filesystem:good\":[\"https://base.example/filesystem\"],\"ftp://good/\":[\"https://base.example/ftp/\"],\"http://good/\":[\"https://base.example/http/\"],\"https://good/\":[\"https://base.example/https/\"],\"import:bad\":[\"https://base.example/import\"],\"javascript:bad\":[\"https://base.example/javascript\"],\"mailto:bad\":[\"https://base.example/mailto\"],\"wss://bad/\":[\"https://base.example/wss\"]},\"scopes\":{}}"
FAIL Absolute URL specifier keys / should parse absolute URLs, treating unparseable ones as bare specifiers assert_equals: expected "{\"imports\":{\"http://[www.example.com]/\":[\"https://base.example/unparseable3/\"],\"https://ex ample.org/\":[\"https://base.example/unparseable1/\"],\"https://example.com/\":[\"https://base.example/percentDecoding/\"],\"https://example.com/%41\":[\"https://base.example/noPercentDecoding\"],\"https://example.com///\":[\"https://base.example/invalidButParseable2/\"],\"https://example.com:demo\":[\"https://base.example/unparseable2\"],\"https://example.net/\":[\"https://base.example/prettyNormal/\"],\"https://example.org/\":[\"https://base.example/invalidButParseable1/\"]},\"scopes\":{}}" but got "{\"imports\":{\"http://[www.example.com]/\":[\"https://base.example/unparseable3/\"],\"https://ex%20ample.org/\":[\"https://base.example/unparseable1/\"],\"https://example.com/\":[\"https://base.example/percentDecoding/\"],\"https://example.com///\":[\"https://base.example/invalidButParseable2/\"],\"https://example.com/A\":[\"https://base.example/noPercentDecoding\"],\"https://example.com:demo\":[\"https://base.example/unparseable2\"],\"https://example.net/\":[\"https://base.example/prettyNormal/\"],\"https://example.org/\":[\"https://base.example/invalidButParseable1/\"]},\"scopes\":{}}"
PASS Absolute URL specifier keys / should parse built-in module specifier keys, including with a "/"
Harness: the test ran to completion.
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-specifier-keys.js
-->
<script type="module" src="resources/parsing-specifier-keys.js"></script>
This is a testharness.js-based test.
PASS Unmapped built-in module specifiers / should resolve "std:blank" to "std:blank"
FAIL Unmapped built-in module specifiers / should error resolving "std:none" assert_throws_js: function "() => resolveUnderTest(NONE)" did not throw
PASS Remapping built-in module specifiers / should remap built-in modules
PASS Remapping built-in module specifiers / should remap built-in modules with slashes
FAIL Remapping built-in module specifiers / should remap built-in modules with fallbacks Failed to resolve module specifier std:blank: Import Map: "std:blank" matches with "std:blank" but fails to be mapped (no viable URLs)
FAIL Remapping built-in module specifiers / should remap built-in modules with slashes and fallbacks Failed to resolve module specifier std:blank/: Import Map: "std:blank/" matches with "std:blank/" but fails to be mapped (no viable URLs)
PASS Remapping to built-in modules / should remap to "std:blank"
PASS Remapping to built-in modules / should fail when remapping to "std:blank/"
FAIL Remapping to built-in modules / should remap to "std:blank/for-testing" Failed to resolve module specifier /blank/for-testing: Import Map: "https://example.com/blank/for-testing" matches with "https://example.com/blank/" but fails to be mapped (no viable URLs)
PASS Remapping to built-in modules / should remap to "std:blank" for URL-like specifiers
PASS Remapping to built-in modules / should fail when remapping to "std:none"
FAIL Fallbacks with built-in module addresses / should resolve to "std:blank" Failed to resolve module specifier blank: Import Map: "blank" matches with "blank" but fails to be mapped (no viable URLs)
FAIL Fallbacks with built-in module addresses / should fall back past "std:none" Failed to resolve module specifier none: Import Map: "none" matches with "none" but fails to be mapped (no viable URLs)
Harness: the test ran to completion.
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-builtins.js
-->
<script type="module" src="resources/resolving-builtins.js"></script>
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-not-yet-implemented.js
-->
<script type="module" src="resources/resolving-not-yet-implemented.js"></script>
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-scopes.js
-->
<script type="module" src="resources/resolving-scopes.js"></script>
This is a testharness.js-based test.
PASS Unmapped / should resolve ./ specifiers as URLs
PASS Unmapped / should resolve ../ specifiers as URLs
PASS Unmapped / should resolve / specifiers as URLs
PASS Unmapped / should parse absolute fetch-scheme URLs
FAIL Unmapped / should fail for absolute non-fetch-scheme URLs assert_throws_js: function "() => resolveUnderTest('mailto:bad')" did not throw
FAIL Unmapped / should fail for strings not parseable as absolute URLs and not starting with ./ ../ or / assert_throws_js: function "() => resolveUnderTest('https://ex ample.org/')" did not throw
PASS Mapped using the "imports" key only (no scopes) / should fail when the mapping is to an empty array
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package main modules
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package submodules
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package names that end in a slash by just passing through
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should still fail for package modules that are not declared
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should fail for package submodules that map to nowhere
PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work for explicitly-mapped specifiers that happen to have a slash
PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work when the specifier has punctuation
PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should fail for attempting to get a submodule of something not declared with a trailing slash
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap to other URLs
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should fail for URLs that remap to empty arrays
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are just composed from / and .
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are prefix-matched by keys with trailing slashes
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should use the last entry's address when URL-like specifiers parse to the same absolute URL
PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key (no empty arrays)
PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key when empty arrays are involved for less-specific keys
PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key when empty arrays are involved for more-specific keys
Harness: the test ran to completion.
<!DOCTYPE html>
<html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../resources/jest-test-helper.js"></script>
<script type="module" src="resources/helpers/parsing.js"></script>
<!--
Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js
-->
<script type="module" src="resources/resolving.js"></script>
'use strict';
const { parseFromString } = require('../../lib/parser.js');
// Local modifications from upstream:
// Currently warnings and scopes are not checked in expectSpecifierMap().
exports.expectSpecifierMap = (input, baseURL, output, warnings = []) => {
expect(parseFromString(`{ "imports": ${input} }`, baseURL))
.toEqual({ imports: output, scopes: {} });
};
exports.expectScopes = (inputArray, baseURL, outputArray, warnings = []) => {
const checkWarnings = testWarningHandler(warnings);
const inputScopesAsStrings = inputArray.map(scopePrefix => `${JSON.stringify(scopePrefix)}: {}`);
const inputString = `{ "scopes": { ${inputScopesAsStrings.join(', ')} } }`;
const outputScopesObject = {};
for (const outputScopePrefix of outputArray) {
outputScopesObject[outputScopePrefix] = {};
}
expect(parseFromString(inputString, baseURL)).toEqual({ imports: {}, scopes: outputScopesObject });
checkWarnings();
};
exports.expectBad = (input, baseURL, warnings = []) => {
const checkWarnings = testWarningHandler(warnings);
expect(parseFromString(input, baseURL)).toThrow('TypeError');
checkWarnings();
};
exports.expectWarnings = (input, baseURL, output, warnings = []) => {
const checkWarnings = testWarningHandler(warnings);
expect(parseFromString(input, baseURL)).toEqual(output);
checkWarnings();
};
function testWarningHandler(expectedWarnings) {
// We don't check warnings on WPT tests, because there are no
// ways to catch console warnings from JavaScript.
return () => {};
}
'use strict';
const { parseFromString } = require('../lib/parser.js');
const { expectBad, expectWarnings, expectSpecifierMap } = require('./helpers/parsing.js');
const nonObjectStrings = ['null', 'true', '1', '"foo"', '[]'];
test('Invalid JSON', () => {
expect(parseFromString('{ imports: {} }', 'https://base.example/')).toThrow('SyntaxError');
});
describe('Mismatching the top-level schema', () => {
it('should throw for top-level non-objects', () => {
for (const nonObject of nonObjectStrings) {
expectBad(nonObject, 'https://base.example/');
}
});
it('should throw if imports is a non-object', () => {
for (const nonObject of nonObjectStrings) {
expectBad(`{ "imports": ${nonObject} }`, 'https://base.example/');
}
});
it('should throw if scopes is a non-object', () => {
for (const nonObject of nonObjectStrings) {
expectBad(`{ "scopes": ${nonObject} }`, 'https://base.example/');
}
});
it('should ignore unspecified top-level entries', () => {
expectWarnings(
`{
"imports": {},
"new-feature": {},
"scops": {}
}`,
'https://base.example/',
{ imports: {}, scopes: {} },
[
`Invalid top-level key "new-feature". Only "imports" and "scopes" can be present.`,
`Invalid top-level key "scops". Only "imports" and "scopes" can be present.`
]
);
});
});
describe('Mismatching the specifier map schema', () => {
const invalidAddressStrings = ['true', '1', '{}'];
const invalidInsideArrayStrings = ['null', 'true', '1', '{}', '[]'];
it('should ignore entries where the address is not a string, array, or null', () => {
for (const invalid of invalidAddressStrings) {
expectSpecifierMap(
`{
"foo": ${invalid},
"bar": ["https://example.com/"]
}`,
'https://base.example/',
{
bar: [expect.toMatchURL('https://example.com/')]
},
[
`Invalid address ${invalid} for the specifier key "foo". ` +
`Addresses must be strings, arrays, or null.`
]
);
}
});
it('should ignore entries where the specifier key is an empty string', () => {
expectSpecifierMap(
`{
"": ["https://example.com/"]
}`,
'https://base.example/',
{},
[`Invalid empty string specifier key.`]
);
});
it('should ignore members of an address array that are not strings', () => {
for (const invalid of invalidInsideArrayStrings) {
expectSpecifierMap(
`{
"foo": ["https://example.com/", ${invalid}],
"bar": ["https://example.com/"]
}`,
'https://base.example/',
{
foo: [expect.toMatchURL('https://example.com/')],
bar: [expect.toMatchURL('https://example.com/')]
},
[
`Invalid address ${invalid} inside the address array for the specifier key "foo". ` +
`Address arrays must only contain strings.`
]
);
}
});
it('should throw if a scope\'s value is not an object', () => {
for (const invalid of nonObjectStrings) {
expectBad(`{ "scopes": { "https://scope.example/": ${invalid} } }`, 'https://base.example/');
}
});
});
describe('Normalization', () => {
it('should normalize empty import maps to have imports and scopes keys', () => {
expect(parseFromString(`{}`, 'https://base.example/'))
.toEqual({ imports: {}, scopes: {} });
});
it('should normalize an import map without imports to have imports', () => {
expect(parseFromString(`{ "scopes": {} }`, 'https://base.example/'))
.toEqual({ imports: {}, scopes: {} });
});
it('should normalize an import map without scopes to have scopes', () => {
expect(parseFromString(`{ "imports": {} }`, 'https://base.example/'))
.toEqual({ imports: {}, scopes: {} });
});
it('should normalize addresses to arrays', () => {
expectSpecifierMap(
`{
"foo": "https://example.com/1",
"bar": ["https://example.com/2"],
"baz": null
}`,
'https://base.example/',
{
foo: [expect.toMatchURL('https://example.com/1')],
bar: [expect.toMatchURL('https://example.com/2')],
baz: []
}
);
});
});
'use strict';
const { expectScopes } = require('./helpers/parsing.js');
describe('Relative URL scope keys', () => {
it('should work with no prefix', () => {
expectScopes(
['foo'],
'https://base.example/path1/path2/path3',
['https://base.example/path1/path2/foo']
);
});
it('should work with ./, ../, and / prefixes', () => {
expectScopes(
['./foo', '../foo', '/foo'],
'https://base.example/path1/path2/path3',
[
'https://base.example/path1/path2/foo',
'https://base.example/path1/foo',
'https://base.example/foo'
]
);
});
it('should work with /s, ?s, and #s', () => {
expectScopes(
['foo/bar?baz#qux'],
'https://base.example/path1/path2/path3',
['https://base.example/path1/path2/foo/bar?baz#qux']
);
});
it('should work with an empty string scope key', () => {
expectScopes(
[''],
'https://base.example/path1/path2/path3',
['https://base.example/path1/path2/path3']
);
});
it('should work with / suffixes', () => {
expectScopes(
['foo/', './foo/', '../foo/', '/foo/', '/foo//'],
'https://base.example/path1/path2/path3',
[
'https://base.example/path1/path2/foo/',
'https://base.example/path1/path2/foo/',
'https://base.example/path1/foo/',
'https://base.example/foo/',
'https://base.example/foo//'
]
);
});
it('should deduplicate based on URL parsing rules', () => {
expectScopes(
['foo/\\', 'foo//', 'foo\\\\'],
'https://base.example/path1/path2/path3',
['https://base.example/path1/path2/foo//']
);
});
});
describe('Absolute URL scope keys', () => {
it('should accept all absolute URL scope keys, with or without fetch schemes', () => {
expectScopes(
[
'about:good',
'blob:good',
'data:good',
'file:///good',
'filesystem:http://example.com/good/',
'http://good/',
'https://good/',
'ftp://good/',
'import:bad',
'mailto:bad',
'javascript:bad',
'wss:ba'
],
'https://base.example/path1/path2/path3',
[
'about:good',
'blob:good',
'data:good',
'file:///good',
'filesystem:http://example.com/good/',
'http://good/',
'https://good/',
'ftp://good/',
'import:bad',
'mailto:bad',
'javascript:bad',
'wss://ba/'
],
[]
);
});
it('should parse absolute URL scope keys, ignoring unparseable ones', () => {
expectScopes(
[
'https://ex ample.org/',
'https://example.com:demo',
'http://[www.example.com]/',
'https:example.org',
'https://///example.com///',
'https://example.net',
'https://ex%41mple.com/foo/',
'https://example.com/%41'
],
'https://base.example/path1/path2/path3',
[
'https://base.example/path1/path2/example.org', // tricky case! remember we have a base URL
'https://example.com///',
'https://example.net/',
'https://example.com/foo/',
'https://example.com/%41'
],
[
'Invalid scope "https://ex ample.org/" (parsed against base URL "https://base.example/path1/path2/path3").',
'Invalid scope "https://example.com:demo" (parsed against base URL "https://base.example/path1/path2/path3").',
'Invalid scope "http://[www.example.com]/" (parsed against base URL "https://base.example/path1/path2/path3").'
]
);
});
it('should ignore relative URL scope keys when the base URL is a data: URL', () => {
expectScopes(
[
'./foo',
'../foo',
'/foo'
],
'data:text/html,test',
[],
[
'Invalid scope "./foo" (parsed against base URL "data:text/html,test").',
'Invalid scope "../foo" (parsed against base URL "data:text/html,test").',
'Invalid scope "/foo" (parsed against base URL "data:text/html,test").'
]
);
});
});
'use strict';
const { expectSpecifierMap } = require('./helpers/parsing.js');
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`;
describe('Relative URL-like specifier keys', () => {
it('should absolutize strings prefixed with ./, ../, or / into the corresponding URLs', () => {
expectSpecifierMap(
`{
"./foo": "/dotslash",
"../foo": "/dotdotslash",
"/foo": "/slash"
}`,
'https://base.example/path1/path2/path3',
{
'https://base.example/path1/path2/foo': [expect.toMatchURL('https://base.example/dotslash')],
'https://base.example/path1/foo': [expect.toMatchURL('https://base.example/dotdotslash')],
'https://base.example/foo': [expect.toMatchURL('https://base.example/slash')]
}
);
});
it('should not absolutize strings prefixed with ./, ../, or / with a data: URL base', () => {
expectSpecifierMap(
`{
"./foo": "https://example.com/dotslash",
"../foo": "https://example.com/dotdotslash",
"/foo": "https://example.com/slash"
}`,
'data:text/html,test',
{
'./foo': [expect.toMatchURL('https://example.com/dotslash')],
'../foo': [expect.toMatchURL('https://example.com/dotdotslash')],
'/foo': [expect.toMatchURL('https://example.com/slash')]
}
);
});
it('should absolutize the literal strings ./, ../, or / with no suffix', () => {
expectSpecifierMap(
`{
"./": "/dotslash/",
"../": "/dotdotslash/",
"/": "/slash/"
}`,
'https://base.example/path1/path2/path3',
{
'https://base.example/path1/path2/': [expect.toMatchURL('https://base.example/dotslash/')],
'https://base.example/path1/': [expect.toMatchURL('https://base.example/dotdotslash/')],
'https://base.example/': [expect.toMatchURL('https://base.example/slash/')]
}
);
});
it('should treat percent-encoded variants of ./, ../, or / as bare specifiers', () => {
expectSpecifierMap(
`{
"%2E/": "/dotSlash1/",
"%2E%2E/": "/dotDotSlash1/",
".%2F": "/dotSlash2",
"..%2F": "/dotDotSlash2",
"%2F": "/slash2",
"%2E%2F": "/dotSlash3",
"%2E%2E%2F": "/dotDotSlash3"
}`,
'https://base.example/path1/path2/path3',
{
'%2E/': [expect.toMatchURL('https://base.example/dotSlash1/')],
'%2E%2E/': [expect.toMatchURL('https://base.example/dotDotSlash1/')],
'.%2F': [expect.toMatchURL('https://base.example/dotSlash2')],
'..%2F': [expect.toMatchURL('https://base.example/dotDotSlash2')],
'%2F': [expect.toMatchURL('https://base.example/slash2')],
'%2E%2F': [expect.toMatchURL('https://base.example/dotSlash3')],
'%2E%2E%2F': [expect.toMatchURL('https://base.example/dotDotSlash3')]
}
);
});
});
describe('Absolute URL specifier keys', () => {
it('should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers', () => {
expectSpecifierMap(
`{
"about:good": "/about",
"blob:good": "/blob",
"data:good": "/data",
"file:///good": "/file",
"filesystem:good": "/filesystem",
"http://good/": "/http/",
"https://good/": "/https/",
"ftp://good/": "/ftp/",
"import:bad": "/import",
"mailto:bad": "/mailto",
"javascript:bad": "/javascript",
"wss:bad": "/wss"
}`,
'https://base.example/path1/path2/path3',
{
'about:good': [expect.toMatchURL('https://base.example/about')],
'blob:good': [expect.toMatchURL('https://base.example/blob')],
'data:good': [expect.toMatchURL('https://base.example/data')],
'file:///good': [expect.toMatchURL('https://base.example/file')],
'filesystem:good': [expect.toMatchURL('https://base.example/filesystem')],
'http://good/': [expect.toMatchURL('https://base.example/http/')],
'https://good/': [expect.toMatchURL('https://base.example/https/')],
'ftp://good/': [expect.toMatchURL('https://base.example/ftp/')],
'import:bad': [expect.toMatchURL('https://base.example/import')],
'mailto:bad': [expect.toMatchURL('https://base.example/mailto')],
'javascript:bad': [expect.toMatchURL('https://base.example/javascript')],
'wss:bad': [expect.toMatchURL('https://base.example/wss')]
}
);
});
it('should parse absolute URLs, treating unparseable ones as bare specifiers', () => {
expectSpecifierMap(
`{
"https://ex ample.org/": "/unparseable1/",
"https://example.com:demo": "/unparseable2",
"http://[www.example.com]/": "/unparseable3/",
"https:example.org": "/invalidButParseable1/",
"https://///example.com///": "/invalidButParseable2/",
"https://example.net": "/prettyNormal/",
"https://ex%41mple.com/": "/percentDecoding/",
"https://example.com/%41": "/noPercentDecoding"
}`,
'https://base.example/path1/path2/path3',
{
'https://ex ample.org/': [expect.toMatchURL('https://base.example/unparseable1/')],
'https://example.com:demo': [expect.toMatchURL('https://base.example/unparseable2')],
'http://[www.example.com]/': [expect.toMatchURL('https://base.example/unparseable3/')],
'https://example.org/': [expect.toMatchURL('https://base.example/invalidButParseable1/')],
'https://example.com///': [expect.toMatchURL('https://base.example/invalidButParseable2/')],
'https://example.net/': [expect.toMatchURL('https://base.example/prettyNormal/')],
'https://example.com/': [expect.toMatchURL('https://base.example/percentDecoding/')],
'https://example.com/%41': [expect.toMatchURL('https://base.example/noPercentDecoding')]
}
);
});
it('should parse built-in module specifier keys, including with a "/"', () => {
expectSpecifierMap(
`{
"${BLANK}": "/blank",
"${BLANK}/": "/blank/",
"${BLANK}/foo": "/blank/foo",
"${BLANK}\\\\foo": "/blank/backslashfoo"
}`,
'https://base.example/path1/path2/path3',
{
[BLANK]: [expect.toMatchURL('https://base.example/blank')],
[`${BLANK}/`]: [expect.toMatchURL('https://base.example/blank/')],
[`${BLANK}/foo`]: [expect.toMatchURL('https://base.example/blank/foo')],
[`${BLANK}\\foo`]: [expect.toMatchURL('https://base.example/blank/backslashfoo')]
}
);
});
});
'use strict';
const { URL } = require('url');
const { parseFromString } = require('../lib/parser.js');
const { resolve } = require('../lib/resolver.js');
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
const mapBaseURL = new URL('https://example.com/app/index.html');
const scriptURL = new URL('https://example.com/js/app.mjs');
const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`;
const NONE = `${BUILT_IN_MODULE_SCHEME}:none`;
function makeResolveUnderTest(mapString) {
const map = parseFromString(mapString, mapBaseURL);
return specifier => resolve(specifier, map, scriptURL);
}
describe('Unmapped built-in module specifiers', () => {
const resolveUnderTest = makeResolveUnderTest(`{}`);
it(`should resolve "${BLANK}" to "${BLANK}"`, () => {
expect(resolveUnderTest(BLANK)).toMatchURL(BLANK);
});
it(`should error resolving "${NONE}"`, () => {
expect(() => resolveUnderTest(NONE)).toThrow(TypeError);
});
});
describe('Remapping built-in module specifiers', () => {
it('should remap built-in modules', () => {
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"${BLANK}": "./blank.mjs",
"${NONE}": "./none.mjs"
}
}`);
expect(resolveUnderTest(BLANK)).toMatchURL('https://example.com/app/blank.mjs');
expect(resolveUnderTest(NONE)).toMatchURL('https://example.com/app/none.mjs');
});
it('should remap built-in modules with slashes', () => {
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"${BLANK}/": "./blank-slash/",
"${BLANK}/foo": "./blank-foo.mjs",
"${NONE}/": "./none-slash/",
"${NONE}/foo": "./none-foo.mjs"
}
}`);
expect(resolveUnderTest(`${BLANK}/`)).toMatchURL('https://example.com/app/blank-slash/');
expect(resolveUnderTest(`${BLANK}/foo`)).toMatchURL('https://example.com/app/blank-foo.mjs');
expect(resolveUnderTest(`${BLANK}/bar`)).toMatchURL('https://example.com/app/blank-slash/bar');
expect(resolveUnderTest(`${NONE}/`)).toMatchURL('https://example.com/app/none-slash/');
expect(resolveUnderTest(`${NONE}/foo`)).toMatchURL('https://example.com/app/none-foo.mjs');
expect(resolveUnderTest(`${NONE}/bar`)).toMatchURL('https://example.com/app/none-slash/bar');
});
it('should remap built-in modules with fallbacks', () => {
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"${BLANK}": ["${BLANK}", "./blank.mjs"],
"${NONE}": ["${NONE}", "./none.mjs"]
}
}`);
expect(resolveUnderTest(BLANK)).toMatchURL(BLANK);
expect(resolveUnderTest(NONE)).toMatchURL('https://example.com/app/none.mjs');
});
it('should remap built-in modules with slashes and fallbacks', () => {
// NOTE: `${BLANK}/for-testing` is not per spec, just for these tests.
// See resolver.js.
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"${BLANK}/": ["${BLANK}/", "./blank/"],
"${BLANK}/for-testing": ["${BLANK}/for-testing", "./blank-for-testing-special"],
"${NONE}/": ["${NONE}/", "./none/"],
"${NONE}/foo": ["${NONE}/foo", "./none-foo-special"]
}
}`);
// Built-in modules only resolve for exact matches, so this will trigger the fallback.
expect(resolveUnderTest(`${BLANK}/`)).toMatchURL('https://example.com/app/blank/');
expect(resolveUnderTest(`${BLANK}/foo`)).toMatchURL('https://example.com/app/blank/foo');
// This would fall back in a real implementation; it's only because we've gone against
// spec in the reference implementation (to make this testable) that this maps.
expect(resolveUnderTest(`${BLANK}/for-testing`)).toMatchURL(`${BLANK}/for-testing`);
expect(resolveUnderTest(`${NONE}/`)).toMatchURL('https://example.com/app/none/');
expect(resolveUnderTest(`${NONE}/bar`)).toMatchURL('https://example.com/app/none/bar');
expect(resolveUnderTest(`${NONE}/foo`)).toMatchURL('https://example.com/app/none-foo-special');
});
});
describe('Remapping to built-in modules', () => {
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"blank": "${BLANK}",
"/blank": "${BLANK}",
"/blank/": "${BLANK}/",
"/blank-for-testing": "${BLANK}/for-testing",
"none": "${NONE}",
"/none": "${NONE}"
}
}`);
it(`should remap to "${BLANK}"`, () => {
expect(resolveUnderTest('blank')).toMatchURL(BLANK);
expect(resolveUnderTest('/blank')).toMatchURL(BLANK);
});
it(`should fail when remapping to "${BLANK}/"`, () => {
expect(() => resolveUnderTest('/blank/')).toThrow(TypeError);
});
it(`should remap to "${BLANK}/for-testing"`, () => {
expect(resolveUnderTest('/blank/for-testing')).toMatchURL(`${BLANK}/for-testing`);
expect(resolveUnderTest('/blank-for-testing')).toMatchURL(`${BLANK}/for-testing`);
});
it(`should remap to "${BLANK}" for URL-like specifiers`, () => {
expect(resolveUnderTest('/blank')).toMatchURL(BLANK);
expect(resolveUnderTest('https://example.com/blank')).toMatchURL(BLANK);
expect(resolveUnderTest('https://///example.com/blank')).toMatchURL(BLANK);
});
it(`should fail when remapping to "${NONE}"`, () => {
expect(() => resolveUnderTest('none')).toThrow(TypeError);
expect(() => resolveUnderTest('/none')).toThrow(TypeError);
});
});
describe('Fallbacks with built-in module addresses', () => {
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"blank": [
"${BLANK}",
"./blank-fallback.mjs"
],
"none": [
"${NONE}",
"./none-fallback.mjs"
]
}
}`);
it(`should resolve to "${BLANK}"`, () => {
expect(resolveUnderTest('blank')).toMatchURL(BLANK);
});
it(`should fall back past "${NONE}"`, () => {
expect(resolveUnderTest('none')).toMatchURL('https://example.com/app/none-fallback.mjs');
});
});
'use strict';
const { URL } = require('url');
const { parseFromString } = require('../lib/parser.js');
const { resolve } = require('../lib/resolver.js');
const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js');
const mapBaseURL = new URL('https://example.com/app/index.html');
const scriptURL = new URL('https://example.com/js/app.mjs');
const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`;
function makeResolveUnderTest(mapString) {
const map = parseFromString(mapString, mapBaseURL);
return specifier => resolve(specifier, map, scriptURL);
}
describe('Fallbacks that are not [built-in, fetch scheme]', () => {
const resolveUnderTest = makeResolveUnderTest(`{
"imports": {
"bad1": [
"${BLANK}",
"${BLANK}"
],
"bad2": [
"${BLANK}",
"/bad2-1.mjs",
"/bad2-2.mjs"
],
"bad3": [
"/bad3-1.mjs",
"/bad3-2.mjs"
]
}
}`);
it('should fail for [built-in, built-in]', () => {
expect(() => resolveUnderTest('bad1')).toThrow(/not yet implemented/);
});
it('should fail for [built-in, fetch scheme, fetch scheme]', () => {
expect(() => resolveUnderTest('bad2')).toThrow(/not yet implemented/);
});
it('should fail for [fetch scheme, fetch scheme]', () => {
expect(() => resolveUnderTest('bad3')).toThrow(/not yet implemented/);
});
});
def main(request, response):
return (
(('Content-Type', 'text/javascript'),),
'import "{}";\n'.format(request.GET.first('url'))
)
// Hacky glue code to run Jest-based tests as WPT tests.
// TODO(https://github.com/WICG/import-maps/issues/170): Consider better ways
// to write and run tests.
setup({allow_uncaught_exception : true});
const exports = {};
function require(name) {
return Object.assign({
'URL': URL,
'parseFromString': parseFromString,
'resolve': resolve,
'BUILT_IN_MODULE_SCHEME': 'std'
}, exports);
}
// Sort keys and then stringify for comparison.
function stringifyImportMap(importMap) {
function getKeys(m) {
if (typeof m !== 'object')
return [];
let keys = [];
for (const key in m) {
keys.push(key);
keys = keys.concat(getKeys(m[key]));
}
return keys;
}
return JSON.stringify(importMap, getKeys(importMap).sort());
}
function expect(v) {
return {
toMatchURL: expected => assert_equals(v, expected),
toThrow: expected => {
if (v.localName === 'iframe') {
// `v` is the result of parseFromString(), and thus toThrow()
// should be examining the error in that iframe.
assert_throws_js(v.contentWindow[expected], () => { throw v.contentWindow.windowError });
} else if (expected.test && expected.test('not yet implemented')) {
// We override /not yet implemented/ expectation.
assert_throws_js(TypeError, v);
} else {
assert_throws_js(expected, v);
}
},
toEqual: expected => {
if (v.localName === 'iframe') {
// `v` is the result of parseFromString(), and thus toEqual() is
// expected to compare parsed import maps.
// We sort keys when stringifying for normalization.
const actualParsedImportMap = JSON.parse(
internals.getParsedImportMap(v.contentDocument));
assert_equals(
stringifyImportMap(actualParsedImportMap),
stringifyImportMap(expected)
);
} else {
assert_object_equals(v, expected);
}
}
};
}
expect.toMatchURL = expected => expected;
const test_harness_test = test;
test = it;
let current_message = '';
function describe(message, f) {
const old = current_message;
if (current_message !== '') {
current_message += ' / ';
}
current_message += message;
f();
current_message = old;
}
function it(message, f) {
const old = current_message;
if (current_message !== '') {
current_message += ' / ';
}
current_message += message;
test_harness_test(t => t.step_func(f)(), current_message);
current_message = old;
}
// Creates a new Document (via <iframe>) and add an inline import map.
// Currently document.write() is used to make everything synchronous, which
// is just needed for running the existing Jest-based tests easily.
function parseFromString(mapString, mapBaseURL) {
// We can't test data: base URLs because <base> rejects data: URLs.
if (new URL(mapBaseURL).protocol === 'data:') {
throw Error('test helper does not support data: base URLs');
}
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.contentDocument.write(`
<base href="${mapBaseURL}">
<script>
var scriptError;
var windowError;
function onScriptError(event) {
scriptError = event.error;
}
function onWindowError(event) {
windowError = event.error;
return false;
}
window.addEventListener('error', onWindowError);
</sc` + `ript>
<script type="importmap" onerror="onScriptError(event)">
${mapString}
</sc` + `ript>
`);
iframe.contentDocument.close();
return iframe;
}
// URL resolution is tested using Chromium's `internals`.
// TODO(hiroshige): Remove the Chromium-specific dependency.
function resolve(specifier, map, baseURL) {
return internals.resolveModuleSpecifier(specifier,
baseURL,
map.contentDocument);
}
This is a testharness.js-based test.
PASS Relative URL-like addresses / should accept strings prefixed with ./, ../, or /
FAIL Relative URL-like addresses / should not accept strings prefixed with ./, ../, or / for data: base URLs assert_equals: expected "{\"dotDotSlash\":[],\"dotSlash\":[],\"slash\":[]}" but got "{\"dotDotSlash\":[\"http://web-platform.test:8001/import-maps/foo\"],\"dotSlash\":[\"http://web-platform.test:8001/import-maps/imported/foo\"],\"slash\":[\"http://web-platform.test:8001/foo\"]}"
PASS Relative URL-like addresses / should accept the literal strings ./, ../, or / with no suffix
PASS Relative URL-like addresses / should ignore percent-encoded variants of ./, ../, or /
PASS Built-in module addresses / should accept URLs using the built-in module scheme
PASS Built-in module addresses / should ignore percent-encoded variants of the built-in module scheme
FAIL Built-in module addresses / should allow built-in module URLs that contain "/" or "\" assert_equals: expected "{\"backslash\":[\"std:foo\\\baz\"],\"slashEnd\":[\"std:foo/\"],\"slashMiddle\":[\"std:foo/bar\"]}" but got "{\"backslash\":[\"std:foo\\baz\"],\"slashEnd\":[\"std:foo/\"],\"slashMiddle\":[\"std:foo/bar\"]}"
FAIL Absolute URL addresses / should only accept absolute URL addresses with fetch schemes assert_equals: expected "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[\"filesystem:good\"],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[],\"javascript\":[],\"mailto\":[],\"wss\":[]}" but got "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[\"import:bad\"],\"javascript\":[\"javascript:bad\"],\"mailto\":[\"mailto:bad\"],\"wss\":[\"wss://bad/\"]}"
FAIL Absolute URL addresses / should only accept absolute URL addresses with fetch schemes inside arrays assert_equals: expected "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[\"filesystem:good\"],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[],\"javascript\":[],\"mailto\":[],\"wss\":[]}" but got "{}"
FAIL Absolute URL addresses / should parse absolute URLs, ignoring unparseable ones assert_equals: expected "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/%41\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[],\"unparseable2\":[],\"unparseable3\":[]}" but got "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/A\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[\"https://ex%20ample.org/\"],\"unparseable2\":[],\"unparseable3\":[]}"
FAIL Absolute URL addresses / should parse absolute URLs, ignoring unparseable ones inside arrays assert_equals: expected "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/%41\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[],\"unparseable2\":[],\"unparseable3\":[]}" but got "{}"
PASS Failing addresses: mismatched trailing slashes / should warn for the simple case
FAIL Failing addresses: mismatched trailing slashes / should warn for a mismatch alone in an array assert_equals: expected "{\"std:trailer/\":[],\"trailer/\":[]}" but got "{}"
FAIL Failing addresses: mismatched trailing slashes / should warn for a mismatch alongside non-mismatches in an array assert_equals: expected "{\"std:trailer/\":[\"https://base.example/bim-atrailer/\"],\"trailer/\":[\"https://base.example/atrailer/\"]}" but got "{}"
PASS Other invalid addresses / should ignore unprefixed strings that are not absolute URLs
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS Invalid JSON
PASS Mismatching the top-level schema / should throw for top-level non-objects
PASS Mismatching the top-level schema / should throw if imports is a non-object
PASS Mismatching the top-level schema / should throw if scopes is a non-object
PASS Mismatching the top-level schema / should ignore unspecified top-level entries
FAIL Mismatching the specifier map schema / should ignore entries where the address is not a string, array, or null assert_equals: expected "{\"bar\":[\"https://example.com/\"]}" but got "{}"
PASS Mismatching the specifier map schema / should ignore entries where the specifier key is an empty string
FAIL Mismatching the specifier map schema / should ignore members of an address array that are not strings assert_equals: expected "{\"bar\":[\"https://example.com/\"],\"foo\":[\"https://example.com/\"]}" but got "{}"
PASS Mismatching the specifier map schema / should throw if a scope's value is not an object
PASS Normalization / should normalize empty import maps to have imports and scopes keys
PASS Normalization / should normalize an import map without imports to have imports
PASS Normalization / should normalize an import map without scopes to have scopes
FAIL Normalization / should normalize addresses to arrays assert_equals: expected "{\"bar\":[\"https://example.com/2\"],\"baz\":[],\"foo\":[\"https://example.com/1\"]}" but got "{\"foo\":[\"https://example.com/1\"]}"
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS Unmapped built-in module specifiers / should resolve "std:blank" to "std:blank"
FAIL Unmapped built-in module specifiers / should error resolving "std:none" assert_throws: function "() => resolveUnderTest(NONE)" did not throw
PASS Remapping built-in module specifiers / should remap built-in modules
PASS Remapping built-in module specifiers / should remap built-in modules with slashes
FAIL Remapping built-in module specifiers / should remap built-in modules with fallbacks assert_equals: expected "https://example.com/app/none.mjs" but got "std:none"
FAIL Remapping built-in module specifiers / should remap built-in modules with slashes and fallbacks assert_equals: expected "https://example.com/app/blank/" but got "std:blank/"
PASS Remapping to built-in modules / should remap to "std:blank"
FAIL Remapping to built-in modules / should fail when remapping to "std:blank/" assert_throws: function "() => resolveUnderTest('/blank/')" did not throw
FAIL Remapping to built-in modules / should remap to "std:blank/for-testing" Failed to resolve module specifier /blank/for-testing: Import Map: "https://example.com/blank/for-testing" matches with "https://example.com/blank/" and is mapped to
PASS Remapping to built-in modules / should remap to "std:blank" for URL-like specifiers
FAIL Remapping to built-in modules / should fail when remapping to "std:none" assert_throws: function "() => resolveUnderTest('none')" did not throw
FAIL Fallbacks with built-in module addresses / should resolve to "std:blank" Failed to resolve module specifier blank: Relative references must start with either "/", "./", or "../".
FAIL Fallbacks with built-in module addresses / should fall back past "std:none" Failed to resolve module specifier none: Relative references must start with either "/", "./", or "../".
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS Unmapped / should resolve ./ specifiers as URLs
PASS Unmapped / should resolve ../ specifiers as URLs
PASS Unmapped / should resolve / specifiers as URLs
PASS Unmapped / should parse absolute fetch-scheme URLs
FAIL Unmapped / should fail for absolute non-fetch-scheme URLs assert_throws: function "() => resolveUnderTest('mailto:bad')" did not throw
FAIL Unmapped / should fail for strings not parseable as absolute URLs and not starting with ./ ../ or / assert_throws: function "() => resolveUnderTest('https://ex ample.org/')" did not throw
PASS Mapped using the "imports" key only (no scopes) / should fail when the mapping is to an empty array
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package main modules
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package submodules
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package names that end in a slash by just passing through
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should still fail for package modules that are not declared
PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should fail for package submodules that map to nowhere
PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work for explicitly-mapped specifiers that happen to have a slash
PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work when the specifier has punctuation
PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should fail for attempting to get a submodule of something not declared with a trailing slash
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap to other URLs
FAIL Mapped using the "imports" key only (no scopes) / URL-like specifiers / should fail for URLs that remap to empty arrays assert_throws: function "() => resolveUnderTest('https://example.com/lib/no.mjs')" did not throw
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are just composed from / and .
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are prefix-matched by keys with trailing slashes
PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should use the last entry's address when URL-like specifiers parse to the same absolute URL
PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key (no empty arrays)
PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key when empty arrays are involved for less-specific keys
FAIL Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key when empty arrays are involved for more-specific keys assert_throws: function "() => resolveUnderTest('a/b')" did not throw
Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment