blob: 09c6687b014db89f9ea6c1233bc5396b0590f85a [file] [edit]
<!DOCTYPE html>
<meta charset="utf-8">
<title>URLPattern regexp groups work without a script context (detached frame)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
// These tests exercise URLPattern objects whose associated document/global
// object has gone away (the owning frame is detached). This means URLPattern
// is being used without a valid JavaScript context.
function withDetachedPatternConstructor(t) {
return new Promise(resolve => {
const frame = document.createElement("iframe");
frame.srcdoc = "";
frame.onload = () => {
const FrameURLPattern = frame.contentWindow.URLPattern;
frame.remove();
resolve(FrameURLPattern);
};
document.body.appendChild(frame);
t.add_cleanup(() => frame.remove());
});
}
promise_test(async t => {
const FrameURLPattern = await withDetachedPatternConstructor(t);
const pattern = new FrameURLPattern({ pathname: "/books/:id(\\d+)" });
assert_true(pattern.hasRegExpGroups, "pattern should report regexp groups");
const result = pattern.exec("https://example.com/books/123");
assert_not_equals(result, null, "regexp pattern should match");
assert_equals(result.pathname.input, "/books/123");
assert_equals(result.pathname.groups.id, "123");
}, "Named regexp group matches after the owning frame is detached");
promise_test(async t => {
const FrameURLPattern = await withDetachedPatternConstructor(t);
const pattern = new FrameURLPattern({ pathname: "/books/:id(\\d+)" });
assert_equals(pattern.exec("https://example.com/books/abc"), null,
"input that violates the regexp constraint should not match");
}, "Non-matching regexp input returns null after the owning frame is detached");
promise_test(async t => {
const FrameURLPattern = await withDetachedPatternConstructor(t);
// Anonymous regexp group, exercised through test() rather than exec().
const pattern = new FrameURLPattern({ pathname: "/(foo|bar)" });
assert_true(pattern.test("https://example.com/foo"),
"anonymous regexp alternation should match after detach");
assert_false(pattern.test("https://example.com/baz"),
"anonymous regexp alternation should reject non-matching input after detach");
}, "Anonymous regexp group via test() after the owning frame is detached");
promise_test(async t => {
const FrameURLPattern = await withDetachedPatternConstructor(t);
// Regexp groups across several components at once.
const pattern = new FrameURLPattern({
hostname: ":sub(.*)\\.example\\.com",
pathname: "/v:version(\\d+)/:rest*",
});
const result = pattern.exec("https://api.example.com/v2/users/42");
assert_not_equals(result, null, "multi-component regexp pattern should match after detach");
assert_equals(result.hostname.groups.sub, "api");
assert_equals(result.pathname.groups.version, "2");
assert_equals(result.pathname.groups.rest, "users/42");
}, "Regexp groups across multiple components after the owning frame is detached");
</script>
</body>