| <!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> |