mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Update web-platform-tests to revision ad219567030d1f99f7310f52a17546b57b70d29e
This commit is contained in:
parent
2c63d1296b
commit
a7e62acbe8
129 changed files with 4156 additions and 590 deletions
File diff suppressed because it is too large
Load diff
|
@ -3,3 +3,9 @@
|
|||
[scroll-behavior: smooth on DIV element]
|
||||
expected: FAIL
|
||||
|
||||
[Smooth scrolling while doing history navigation.]
|
||||
expected: FAIL
|
||||
|
||||
[Instant scrolling while doing history navigation.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[HTMLBaseElement.html]
|
||||
[target on HTMLBaseElement must enqueue an attributeChanged reaction when adding a new attribute]
|
||||
expected: FAIL
|
||||
|
||||
[target on HTMLBaseElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
||||
expected: FAIL
|
||||
|
|
@ -27,3 +27,24 @@
|
|||
[Check if attribute serialization takes into account of the same prefix declared in an ancestor element]
|
||||
expected: FAIL
|
||||
|
||||
[Check if the prefix of an attribute is replaced with another existing prefix mapped to the same namespace URI.]
|
||||
expected: FAIL
|
||||
|
||||
[Check if inconsistent xmlns="..." is dropped.]
|
||||
expected: FAIL
|
||||
|
||||
[Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix]
|
||||
expected: FAIL
|
||||
|
||||
[Check if no special handling for XLink namespace unlike HTML serializer.]
|
||||
expected: FAIL
|
||||
|
||||
[Check if the prefix of an attribute is NOT preserved in a case where neither its prefix nor its namespace URI is not already used.]
|
||||
expected: FAIL
|
||||
|
||||
[Check if the prefix of an attribute is replaced with a generated one in a case where the prefix is already mapped to a different namespace URI.]
|
||||
expected: FAIL
|
||||
|
||||
[Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix even if the prefix is assigned to another namespace.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -8,3 +8,12 @@
|
|||
[Cross-site fetch]
|
||||
expected: FAIL
|
||||
|
||||
[Same-origin mode]
|
||||
expected: FAIL
|
||||
|
||||
[no-CORS mode]
|
||||
expected: FAIL
|
||||
|
||||
[CORS mode]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -8,3 +8,6 @@
|
|||
[Cross-site script]
|
||||
expected: FAIL
|
||||
|
||||
[Same-origin CORS script]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -8,3 +8,6 @@
|
|||
[Same-Origin style]
|
||||
expected: FAIL
|
||||
|
||||
[Same-Origin, cors style]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -9,3 +9,6 @@
|
|||
[Cross-Site track]
|
||||
expected: NOTRUN
|
||||
|
||||
[Same-Origin, CORS track]
|
||||
expected: NOTRUN
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[javascript-url-abort-return-value-undefined.tentative.html]
|
||||
expected: TIMEOUT
|
||||
[Not aborting fetch for javascript:undefined navigation]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[traverse_the_history_5.html]
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
[document_domain_access_details.sub.html]
|
||||
[Access allowed if same-origin with no 'document.domain' modification. (Sanity check)]
|
||||
expected: FAIL
|
||||
|
||||
[Access is revoked to Window object when we stop being same effective script origin due to document.domain.]
|
||||
expected: FAIL
|
||||
|
||||
[Access allowed if different-origin but both set document.domain to parent domain.]
|
||||
expected: FAIL
|
||||
|
||||
[Access is not revoked to random object when we stop being same effective script origin due to document.domain.]
|
||||
expected: FAIL
|
||||
|
||||
[Access not allowed if different-origin with no 'document.domain' modification. (Sanity check)]
|
||||
expected: FAIL
|
||||
|
||||
[Access disallowed again if same-origin, both set document-domain to existing value, then one sets to parent.]
|
||||
expected: FAIL
|
||||
|
||||
[Access is revoked to Location object when we stop being same effective script origin due to document.domain.]
|
||||
expected: FAIL
|
||||
|
||||
[Access allowed if same-origin and both set document.domain to existing value.]
|
||||
expected: FAIL
|
||||
|
||||
[Access is not revoked to Document object when we stop being same effective script origin due to document.domain.]
|
||||
expected: FAIL
|
||||
|
||||
[Access disallowed if same-origin but only one sets document.domain.]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[name-attribute.window.html]
|
||||
[Window object's name IDL attribute]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[iframe_005.html]
|
||||
[document.write external script into iframe write back into parent]
|
||||
expected: FAIL
|
||||
|
|
@ -214,15 +214,11 @@ jobs:
|
|||
- job: all_post
|
||||
displayName: 'all tests (wpt.fyi hook)'
|
||||
dependsOn: all_macOS
|
||||
pool: server
|
||||
pool:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
steps:
|
||||
- task: InvokeRESTAPI@1
|
||||
- script: curl -s -S https://wpt.fyi/api/checks/azure/$(Build.BuildId)
|
||||
displayName: 'Invoke wpt.fyi hook'
|
||||
inputs:
|
||||
serviceConnection: wpt.fyi
|
||||
urlSuffix: /api/checks/azure/$(Build.BuildId)
|
||||
- task: InvokeRESTAPI@1
|
||||
- script: curl -s -S https://staging.wpt.fyi/api/checks/azure/$(Build.BuildId)
|
||||
displayName: 'Invoke staging.wpt.fyi hook'
|
||||
inputs:
|
||||
serviceConnection: staging.wpt.fyi
|
||||
urlSuffix: /api/checks/azure/$(Build.BuildId)
|
||||
condition: succeededOrFailed()
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Basic use of Worklet Animation</title>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="common.js"></script>
|
||||
|
||||
<div id="target"></div>
|
||||
|
||||
<script>
|
||||
promise_test(async t => {
|
||||
await registerConstantLocalTimeAnimator(500);
|
||||
const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 });
|
||||
const animation = new WorkletAnimation('constant_time', effect);
|
||||
animation.play();
|
||||
|
||||
await waitForAsyncAnimationFrames(1);
|
||||
assert_equals(getComputedStyle(target).opacity, "0.5");
|
||||
}, "Simple worklet animation should output values at specified local time");
|
||||
</script>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Worklet Animation with options</title>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-animationworklet/">
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/web-animations/testcommon.js"></script>
|
||||
<script src="common.js"></script>
|
||||
|
||||
<div id="target"></div>
|
||||
|
||||
<script id="animate_with_options" type="text/worklet">
|
||||
registerAnimator("test_animator", class {
|
||||
constructor(options) {
|
||||
this.time_ = options.time;
|
||||
}
|
||||
animate(currentTime, effect) {
|
||||
effect.localTime = this.time_;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
promise_test(async t => {
|
||||
await runInAnimationWorklet(document.getElementById('animate_with_options').textContent);
|
||||
const target = document.getElementById('target');
|
||||
const effect = new KeyframeEffect(target, [{ opacity: 0 }], { duration: 1000 });
|
||||
const options = {'time': 500};
|
||||
const animation = new WorkletAnimation('test_animator', effect, document.timeline, options);
|
||||
animation.play();
|
||||
|
||||
await waitForAsyncAnimationFrames(1);
|
||||
assert_equals(getComputedStyle(target).opacity, "0.5");
|
||||
}, "Animator should be able to use options to update the animation");
|
||||
</script>
|
|
@ -5,4 +5,8 @@ import time
|
|||
sleep_padding = 15.0
|
||||
|
||||
def sleep_at_least(sleep_in_ms):
|
||||
time.sleep((sleep_in_ms + sleep_padding) / 1E3);
|
||||
sleep_until = time.time() + (sleep_in_ms / 1E3)
|
||||
time.sleep((sleep_in_ms + sleep_padding) / 1E3)
|
||||
# Check if the padding was sufficient; if not, sleep again.
|
||||
while time.time() < sleep_until:
|
||||
time.sleep(sleep_padding / 1E3)
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
.then(t.step_func(e => {
|
||||
assert_equals(e.blockedURI, "inline");
|
||||
assert_equals(e.lineNumber, 118);
|
||||
assert_equals(e.columnNumber, 4);
|
||||
assert_in_array(e.columnNumber, [4, 6]);
|
||||
assert_equals(e.target, document, "Elements created in this document, but pushed into a same-origin frame trigger on that frame's document, not on this frame's document.");
|
||||
return watcher.wait_for('securitypolicyviolation');
|
||||
}))
|
||||
|
@ -50,7 +50,7 @@
|
|||
.then(t.step_func(e => {
|
||||
assert_equals(e.blockedURI, "inline");
|
||||
assert_equals(e.lineNumber, 139);
|
||||
assert_equals(e.columnNumber, 4);
|
||||
assert_in_array(e.columnNumber, [4, 6]);
|
||||
assert_equals(e.target, document, "Inline event handlers for disconnected elements target the document.");
|
||||
return watcher.wait_for('securitypolicyviolation');
|
||||
}))
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
<!DOCTYPE html>
|
||||
<title>CSS Position: position:absolute dynamic containing block</title>
|
||||
<link rel="author" title="mailto:atotic@google.com">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-position-3/#def-cb">
|
||||
<meta name="assert" content="Tests changes in containing block for out-of-flow positioned descendants.">
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
outline: black solid 1px;
|
||||
}
|
||||
#intermediate {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
outline: gray solid 1px;
|
||||
}
|
||||
#target {
|
||||
background: green;
|
||||
}
|
||||
.abs {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
.fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
.abs-container {
|
||||
position: relative;
|
||||
}
|
||||
.fixed-container {
|
||||
will-change: transform;
|
||||
}
|
||||
div {
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
<!-- This tests potential caching of out-of-flow positioned descendants. -->
|
||||
<div id="outer">
|
||||
<div>
|
||||
<div id="intermediate">
|
||||
<div>
|
||||
<div id="target">TTT</div>
|
||||
<div id="noLayout1"></div>
|
||||
</div>
|
||||
<div id="noLayout2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
let outer = document.querySelector("#outer");
|
||||
let intermediate = document.querySelector("#intermediate");
|
||||
let target = document.querySelector("#target");
|
||||
let padding = 5;
|
||||
|
||||
function cleanup() {
|
||||
outer.className = "";
|
||||
intermediate.className = "";
|
||||
target.className = "";
|
||||
document.body.offsetTop;
|
||||
}
|
||||
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
outer.classList.add("abs-container");
|
||||
target.classList.add("abs");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
intermediate.classList.add("abs-container");
|
||||
assert_equals(target.offsetHeight, intermediate.offsetHeight);
|
||||
}, "abs containing block moves from outer to intermediate" );
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
target.classList.add("abs");
|
||||
intermediate.classList.add("abs-container");
|
||||
assert_equals(target.offsetHeight, intermediate.offsetHeight);
|
||||
outer.classList.add("abs-container");
|
||||
assert_equals(target.offsetHeight, intermediate.offsetHeight);
|
||||
intermediate.classList.remove("abs-container");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
}, "abs containing block moves from intermediate to outer" );
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
target.classList.add("abs");
|
||||
outer.classList.add("abs-container");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
target.classList.remove("abs");
|
||||
assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
|
||||
}, "target is no longer absolute");
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
outer.classList.add("abs-container");
|
||||
assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
|
||||
target.classList.add("abs");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
}, "target becomes absolute");
|
||||
|
||||
// Repeat same tests with fixed
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
outer.classList.add("fixed-container");
|
||||
target.classList.add("fixed");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
intermediate.classList.add("fixed-container");
|
||||
assert_equals(target.offsetHeight, intermediate.offsetHeight);
|
||||
}, "fixed containing block moves from outer to intermediate" );
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
target.classList.add("fixed");
|
||||
intermediate.classList.add("fixed-container");
|
||||
assert_equals(target.offsetHeight, intermediate.offsetHeight);
|
||||
outer.classList.add("fixed-container");
|
||||
assert_equals(target.offsetHeight, intermediate.offsetHeight);
|
||||
intermediate.classList.remove("fixed-container");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
}, "fixed containing block moves from intermediate to outer" );
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
target.classList.add("fixed");
|
||||
outer.classList.add("fixed-container");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
target.classList.remove("fixed");
|
||||
assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
|
||||
}, "target is no longer fixed");
|
||||
test( t => {
|
||||
t.add_cleanup(cleanup);
|
||||
outer.classList.add("fixed-container");
|
||||
assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
|
||||
target.classList.add("fixed");
|
||||
assert_equals(target.offsetHeight, outer.offsetHeight);
|
||||
}, "target becomes fixed");
|
||||
</script>
|
54
tests/wpt/web-platform-tests/css/css-values/rgba-011.html
Normal file
54
tests/wpt/web-platform-tests/css/css-values/rgba-011.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<title>CSS Values and Units Test: rgba() function syntax (complex)</title>
|
||||
|
||||
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-color-3/#rgba-color">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-color-4/#rgb-functions">
|
||||
<link rel="help" href="https://www.w3.org/TR/css-values-4/#combine-integers">
|
||||
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="This test checks the syntax allowed by rgba() function. White space characters, instead of commas, are allowed between numerical values. <alpha-value> can be omitted for rgba() function, in which case it must defaults to 100%. Finally, rgba() function can take real numbers but their computed values will be rounded to the nearest integer, with values halfway between adjacent integers rounded towards positive infinity.">
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<div id="log"></div>
|
||||
|
||||
<div id="target"></div>
|
||||
|
||||
<script>
|
||||
function startTesting()
|
||||
{
|
||||
|
||||
var targetElement = document.getElementById("target");
|
||||
|
||||
function compareValue(property_name, calcValue, expectedValue, description)
|
||||
{
|
||||
|
||||
test(function()
|
||||
{
|
||||
|
||||
targetElement.style.setProperty(property_name, calcValue);
|
||||
|
||||
var computedCalcValue = getComputedStyle(targetElement)[property_name];
|
||||
|
||||
targetElement.style.setProperty(property_name, expectedValue);
|
||||
|
||||
var computedExpectedValue = getComputedStyle(targetElement)[property_name];
|
||||
|
||||
assert_equals(computedCalcValue, computedExpectedValue);
|
||||
|
||||
}, description);
|
||||
}
|
||||
|
||||
compareValue("background-color", "rgba(0.4 127.5 0.3)", "rgb(0, 128, 0)", "testing background-color: rgba(0.4 127.5 0.3)");
|
||||
|
||||
}
|
||||
|
||||
startTesting();
|
||||
|
||||
</script>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Custom Elements: CEReactions on HTMLBaseElement interface</title>
|
||||
<link rel="author" title="Intel" href="http://www.intel.com">
|
||||
<meta name="assert" content="href, target of HTMLBaseElement interface must have CEReactions">
|
||||
<meta name="help" content="https://html.spec.whatwg.org/#the-base-element">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/custom-elements-helpers.js"></script>
|
||||
<script src="./resources/reactions.js"></script>
|
||||
</head>
|
||||
<script>
|
||||
|
||||
function getParentElement() {
|
||||
return document.head;
|
||||
}
|
||||
|
||||
testReflectAttributeWithParentNode('href', 'href', '/', 'http://example.com/', 'href on HTMLBaseElement', 'base', getParentElement, HTMLBaseElement);
|
||||
testReflectAttributeWithParentNode('target', 'target', '_blank', '_self', 'target on HTMLBaseElement', 'base', getParentElement, HTMLBaseElement);
|
||||
|
||||
</script>
|
|
@ -10,55 +10,23 @@
|
|||
<body>
|
||||
<script>
|
||||
|
||||
function getParentElement(parentElementName) {
|
||||
let parentElement = document.createElement(parentElementName);
|
||||
document.body.appendChild(parentElement);
|
||||
return parentElement;
|
||||
}
|
||||
|
||||
testReflectAttributeWithContentValues('autofocus', 'autofocus', true, 'true', false, 'false', 'autofocus on HTMLButtonElement', 'button', HTMLButtonElement);
|
||||
testReflectAttributeWithContentValues('disabled', 'disabled', true, 'true', false, 'false', 'disabled on HTMLButtonElement', 'button', HTMLButtonElement);
|
||||
testReflectAttribute('name', 'name', 'intel', 'intel1', 'name on HTMLButtonElement', 'button', HTMLButtonElement);
|
||||
testReflectAttribute('value', 'value', 'HTML', 'CSS', 'value on HTMLButtonElement', 'button', HTMLButtonElement);
|
||||
testReflectAttrWithParentNode('type', 'type', 'submit', 'submit', 'reset', 'reset', 'type on HTMLButtonElement', 'button', 'form', HTMLButtonElement);
|
||||
testReflectAttributeWithParentNode('type', 'type', 'submit', 'reset', 'type on HTMLButtonElement', 'button', () => getParentElement('form'), HTMLButtonElement);
|
||||
testReflectAttrWithDepAttr('formAction', 'formaction', 'type', 'intel.asp', 'intel1.asp', 'submit', 'formAction on HTMLButtonElement', 'button', 'form', HTMLButtonElement);
|
||||
testReflectAttrWithDepAttr('formEnctype', 'formenctype', 'type', 'text/plain', 'multipart/form-data', 'submit', 'formEnctype on HTMLButtonElement', 'button', 'form', HTMLButtonElement);
|
||||
testReflectAttrWithDepAttr('formMethod', 'formmethod', 'type', 'get', 'post', 'submit', 'formMethod on HTMLButtonElement', 'button', 'form', HTMLButtonElement);
|
||||
testReflectAttrWithContentValuesAndDepAttr('formNoValidate', 'formnovalidate', 'type', true, 'true', false, 'false', 'submit', 'formNoValidate on HTMLButtonElement', 'button', 'form', HTMLButtonElement);
|
||||
testReflectAttrWithDepAttr('formTarget', 'formtarget', 'type', '_blank', '_self', 'submit', 'formTarget on HTMLButtonElement', 'button', 'form', HTMLButtonElement);
|
||||
|
||||
//In parent node, sub node's observeAttribute can enqueue by changing attribute value
|
||||
//Test reflect attribute with content values and parent node
|
||||
function testReflectAttrWithParentNode(jsAtName, coAtName, jsAtValue1, coAtValue1, jsAtValue2, coAtValue2, name, elementName, pElementName, interfaceName) {
|
||||
var parentElement = document.createElement(pElementName);
|
||||
document.body.appendChild(parentElement);
|
||||
|
||||
test(() => {
|
||||
var element = define_build_in_custom_element([coAtName], interfaceName, elementName);
|
||||
var instance = document.createElement(elementName, { is: element.name });
|
||||
|
||||
assert_array_equals(element.takeLog().types(), ['constructed']);
|
||||
parentElement.appendChild(instance);
|
||||
assert_array_equals(element.takeLog().types(), ['connected']);
|
||||
instance[jsAtName] = jsAtValue1;
|
||||
var logEntries = element.takeLog();
|
||||
assert_array_equals(logEntries.types(), ['attributeChanged']);
|
||||
assert_attribute_log_entry(logEntries.last(), { name: coAtName, oldValue: null, newValue: coAtValue1, namespace: null });
|
||||
|
||||
}, name + ' must enqueue an attributeChanged reaction when adding a new attribute');
|
||||
|
||||
test(() => {
|
||||
var element = define_build_in_custom_element([coAtName], interfaceName, elementName);
|
||||
var instance = document.createElement(elementName, { is: element.name });
|
||||
parentElement.appendChild(instance);
|
||||
|
||||
assert_array_equals(element.takeLog().types(), ['constructed', 'connected']);
|
||||
instance[jsAtName] = jsAtValue1;
|
||||
assert_array_equals(element.takeLog().types(), ['attributeChanged']);
|
||||
instance[jsAtName] = jsAtValue2;
|
||||
var logEntries = element.takeLog();
|
||||
assert_array_equals(logEntries.types(), ['attributeChanged']);
|
||||
assert_attribute_log_entry(logEntries.last(), { name: coAtName, oldValue: coAtValue1, newValue: coAtValue2, namespace: null });
|
||||
|
||||
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
|
||||
|
||||
parentElement.parentNode.removeChild(parentElement);
|
||||
}
|
||||
|
||||
//In parent node, sub node's observeAttribute which depends another attribute can enqueue by changing attribute value
|
||||
//Test reflect attribute with content values and dependent attribute
|
||||
function testReflectAttrWithContentValuesAndDepAttr(jsAtName, coAtName, deAtName, jsAtValue1, coAtValue1, jsAtValue2, coAtValue2, deAtValue, name, elementName, pElementName, interfaceName) {
|
||||
|
|
|
@ -168,6 +168,41 @@ function testReflectBooleanAttribute(jsAttributeName, contentAttributeName, name
|
|||
testReflectAttributeWithContentValues(jsAttributeName, contentAttributeName, true, '', false, null, name, elementName, interfaceName);
|
||||
}
|
||||
|
||||
function testReflectAttributeWithContentValuesAndParentNode(jsAttributeName, contentAttributeName, validValue1, contentValue1, validValue2, contentValue2, name, elementName, getParentElement, interfaceName) {
|
||||
let parentElement = getParentElement();
|
||||
|
||||
test(() => {
|
||||
let element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
|
||||
let instance = document.createElement(elementName, { is: element.name });
|
||||
|
||||
assert_array_equals(element.takeLog().types(), ['constructed']);
|
||||
parentElement.appendChild(instance);
|
||||
assert_array_equals(element.takeLog().types(), ['connected']);
|
||||
instance[jsAttributeName] = validValue1;
|
||||
let logEntries = element.takeLog();
|
||||
assert_array_equals(logEntries.types(), ['attributeChanged']);
|
||||
assert_attribute_log_entry(logEntries.last(), { name: contentAttributeName, oldValue: null, newValue: contentValue1, namespace: null });
|
||||
}, name + ' must enqueue an attributeChanged reaction when adding a new attribute');
|
||||
|
||||
test(() => {
|
||||
let element = define_build_in_custom_element([contentAttributeName], interfaceName, elementName);
|
||||
let instance = document.createElement(elementName, { is: element.name });
|
||||
parentElement.appendChild(instance);
|
||||
|
||||
assert_array_equals(element.takeLog().types(), ['constructed', 'connected']);
|
||||
instance[jsAttributeName] = validValue1;
|
||||
assert_array_equals(element.takeLog().types(), ['attributeChanged']);
|
||||
instance[jsAttributeName] = validValue2;
|
||||
let logEntries = element.takeLog();
|
||||
assert_array_equals(logEntries.types(), ['attributeChanged']);
|
||||
assert_attribute_log_entry(logEntries.last(), { name: contentAttributeName, oldValue: contentValue1, newValue: contentValue2, namespace: null });
|
||||
}, name + ' must enqueue an attributeChanged reaction when replacing an existing attribute');
|
||||
}
|
||||
|
||||
function testReflectAttributeWithParentNode(jsAttributeName, contentAttributeName, validValue1, validValue2, name, elementName, getParentElement, interfaceName) {
|
||||
testReflectAttributeWithContentValuesAndParentNode(jsAttributeName, contentAttributeName, validValue1, validValue1, validValue2, validValue2, name, elementName, getParentElement, interfaceName);
|
||||
}
|
||||
|
||||
function testAttributeAdder(testFunction, name) {
|
||||
test(function () {
|
||||
var element = define_new_custom_element(['id']);
|
||||
|
|
|
@ -9,12 +9,23 @@
|
|||
<body>
|
||||
<h1>domparsing_XMLSerializer_serializeToString</h1>
|
||||
<script>
|
||||
const XMLNS_URI = 'http://www.w3.org/2000/xmlns/';
|
||||
|
||||
function createXmlDoc(){
|
||||
var input = '<?xml version="1.0" encoding="UTF-8"?><root><child1>value1</child1></root>';
|
||||
var parser = new DOMParser();
|
||||
return parser.parseFromString(input, 'text/xml');
|
||||
}
|
||||
|
||||
// Returns the root element.
|
||||
function parse(xmlString) {
|
||||
return (new DOMParser()).parseFromString(xmlString, 'text/xml').documentElement;
|
||||
}
|
||||
|
||||
function serialize(node) {
|
||||
return (new XMLSerializer()).serializeToString(node);
|
||||
}
|
||||
|
||||
test(function() {
|
||||
var serializer = new XMLSerializer();
|
||||
var root = createXmlDoc().documentElement;
|
||||
|
@ -40,6 +51,78 @@ test(function() {
|
|||
assert_equals(xmlString, '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>');
|
||||
}, 'Check if there is no redundant empty namespace declaration.');
|
||||
|
||||
test(function() {
|
||||
const root = parse('<root xmlns="uri1"/>');
|
||||
const child = root.ownerDocument.createElement('child');
|
||||
child.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL1');
|
||||
root.appendChild(child);
|
||||
const child2 = root.ownerDocument.createElementNS('uri2', 'child2');
|
||||
child2.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL2');
|
||||
root.appendChild(child2);
|
||||
const child3 = root.ownerDocument.createElementNS('uri1', 'child3');
|
||||
child3.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL3');
|
||||
root.appendChild(child3);
|
||||
const child4 = root.ownerDocument.createElementNS('uri4', 'child4');
|
||||
child4.setAttributeNS(XMLNS_URI, 'xmlns', 'uri4');
|
||||
root.appendChild(child4);
|
||||
const child5 = root.ownerDocument.createElement('child5');
|
||||
child5.setAttributeNS(XMLNS_URI, 'xmlns', '');
|
||||
root.appendChild(child5);
|
||||
assert_equals(serialize(root), '<root xmlns="uri1"><child xmlns=""/><child2 xmlns="uri2"/><child3/><child4 xmlns="uri4"/><child5 xmlns=""/></root>');
|
||||
}, 'Check if inconsistent xmlns="..." is dropped.');
|
||||
|
||||
test(function() {
|
||||
let root = parse('<r xmlns:xx="uri"></r>');
|
||||
root.setAttributeNS('uri', 'name', 'v');
|
||||
assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>');
|
||||
|
||||
let root2 = parse('<r xmlns:xx="uri"><b/></r>');
|
||||
let child = root2.firstChild;
|
||||
child.setAttributeNS('uri', 'name', 'v');
|
||||
assert_equals(serialize(root2), '<r xmlns:xx="uri"><b xx:name="v"/></r>');
|
||||
|
||||
let root3 = parse('<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri"/></r>');
|
||||
let child3 = root3.firstChild;
|
||||
child3.setAttributeNS('uri', 'name', 'v');
|
||||
assert_equals(serialize(root3),
|
||||
'<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri" x1:name="v"/></r>',
|
||||
'Should choose the nearest prefix');
|
||||
}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix');
|
||||
|
||||
test(function() {
|
||||
let root = parse('<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2"/></el1>');
|
||||
root.firstChild.setAttributeNS('u1', 'name', 'v');
|
||||
assert_equals(serialize(root),
|
||||
'<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2" q:name="v"/></el1>');
|
||||
// Maybe this is a specification error.
|
||||
}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix even if the prefix is assigned to another namespace.');
|
||||
|
||||
test(function() {
|
||||
let root = parse('<r xmlns:xx="uri"></r>');
|
||||
root.setAttributeNS('uri', 'p:name', 'v');
|
||||
assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>');
|
||||
|
||||
let root2 = parse('<r xmlns:xx="uri"><b/></r>');
|
||||
let child = root2.firstChild;
|
||||
child.setAttributeNS('uri', 'p:name', 'value');
|
||||
assert_equals(serialize(root2),
|
||||
'<r xmlns:xx="uri"><b xx:name="value"/></r>');
|
||||
}, 'Check if the prefix of an attribute is replaced with another existing prefix mapped to the same namespace URI.');
|
||||
|
||||
test(function() {
|
||||
let root = parse('<r xmlns:xx="uri"></r>');
|
||||
root.setAttributeNS('uri2', 'p:name', 'value');
|
||||
assert_equals(serialize(root),
|
||||
'<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>');
|
||||
}, 'Check if the prefix of an attribute is NOT preserved in a case where neither its prefix nor its namespace URI is not already used.');
|
||||
|
||||
test(function() {
|
||||
let root = parse('<r xmlns:xx="uri"></r>');
|
||||
root.setAttributeNS('uri2', 'xx:name', 'value');
|
||||
assert_equals(serialize(root),
|
||||
'<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>');
|
||||
}, 'Check if the prefix of an attribute is replaced with a generated one in a case where the prefix is already mapped to a different namespace URI.');
|
||||
|
||||
test(function() {
|
||||
var serializer = new XMLSerializer();
|
||||
var parser = new DOMParser();
|
||||
|
@ -91,6 +174,16 @@ test(function() {
|
|||
assert_equals(xmlString, '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:ns1="uri3" ns1:attr1="value1"/></root>');
|
||||
}, 'Check if "ns1" is generated even if the element already has xmlns:ns1.');
|
||||
|
||||
test(function() {
|
||||
const root = (new Document()).createElement('root');
|
||||
root.setAttributeNS('http://www.w3.org/1999/xlink', 'href', 'v');
|
||||
assert_equals(serialize(root), '<root xmlns:ns1="http://www.w3.org/1999/xlink" ns1:href="v"/>');
|
||||
|
||||
const root2 = (new Document()).createElement('root');
|
||||
root2.setAttributeNS('http://www.w3.org/1999/xlink', 'xl:type', 'v');
|
||||
assert_equals(serialize(root2), '<root xmlns:xl="http://www.w3.org/1999/xlink" xl:type="v"/>');
|
||||
}, 'Check if no special handling for XLink namespace unlike HTML serializer.');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE HTML>
|
||||
<meta charset=utf-8>
|
||||
<title>Element Timing: observe image inside SVG</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/element-timing-helpers.js"></script>
|
||||
<script>
|
||||
let beforeRender;
|
||||
async_test(function (t) {
|
||||
const observer = new PerformanceObserver(
|
||||
t.step_func_done(function(entryList) {
|
||||
assert_equals(entryList.getEntries().length, 1);
|
||||
const entry = entryList.getEntries()[0];
|
||||
checkElement(entry, 'my_svg', beforeRender);
|
||||
// Assume viewport has size at least 200, so the element is fully visible.
|
||||
checkRect(entry, [0, 200, 0, 200]);
|
||||
})
|
||||
);
|
||||
observer.observe({entryTypes: ['element']});
|
||||
beforeRender = performance.now();
|
||||
}, "Able to observe svg image.");
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<svg>
|
||||
<image href='resources/circle.svg' elementtiming='my_svg'/>
|
||||
</svg>
|
|
@ -13,7 +13,7 @@
|
|||
let e = document.createElement('embed');
|
||||
e.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"embed", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"embed", "site":"same-origin", "user":"?F", "mode":"no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -32,7 +32,7 @@
|
|||
let e = document.createElement('embed');
|
||||
e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"embed", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"embed", "site":"same-site", "user":"?F", "mode":"no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -51,7 +51,7 @@
|
|||
let e = document.createElement('embed');
|
||||
e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"embed", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"embed", "site":"cross-site", "user":"?F", "mode":"no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/fetch/sec-metadata/resources/helper.js></script>
|
||||
<script>
|
||||
// Site
|
||||
promise_test(t => {
|
||||
return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
|
||||
.then(r => r.json())
|
||||
|
@ -10,7 +11,8 @@
|
|||
assert_header_equals(j, {
|
||||
"dest": "empty",
|
||||
"site": "same-origin",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "cors",
|
||||
});
|
||||
});
|
||||
}, "Same-origin fetch");
|
||||
|
@ -22,7 +24,8 @@
|
|||
assert_header_equals(j, {
|
||||
"dest": "empty",
|
||||
"site": "same-site",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "cors",
|
||||
});
|
||||
});
|
||||
}, "Same-site fetch");
|
||||
|
@ -34,8 +37,49 @@
|
|||
assert_header_equals(j, {
|
||||
"dest": "empty",
|
||||
"site": "cross-site",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "cors",
|
||||
});
|
||||
});
|
||||
}, "Cross-site fetch");
|
||||
|
||||
// Mode
|
||||
promise_test(t => {
|
||||
return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py", {mode: "same-origin"})
|
||||
.then(r => r.json())
|
||||
.then(j => {
|
||||
assert_header_equals(j, {
|
||||
"dest": "empty",
|
||||
"site": "same-origin",
|
||||
"user": "?F",
|
||||
"mode": "same-origin",
|
||||
});
|
||||
});
|
||||
}, "Same-origin mode");
|
||||
|
||||
promise_test(t => {
|
||||
return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py", {mode: "cors"})
|
||||
.then(r => r.json())
|
||||
.then(j => {
|
||||
assert_header_equals(j, {
|
||||
"dest": "empty",
|
||||
"site": "same-origin",
|
||||
"user": "?F",
|
||||
"mode": "cors",
|
||||
});
|
||||
});
|
||||
}, "CORS mode");
|
||||
|
||||
promise_test(t => {
|
||||
return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py", {mode: "no-cors"})
|
||||
.then(r => r.json())
|
||||
.then(j => {
|
||||
assert_header_equals(j, {
|
||||
"dest": "empty",
|
||||
"site": "same-origin",
|
||||
"user": "?F",
|
||||
"mode": "no-cors",
|
||||
});
|
||||
});
|
||||
}, "no-CORS mode");
|
||||
</script>
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = "font-same-origin";
|
||||
let expected = {"dest":"font", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"font", "site":"same-origin", "user":"?F", "mode": "cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -58,7 +58,7 @@
|
|||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = "font-same-site";
|
||||
let expected = {"dest":"font", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"font", "site":"same-site", "user":"?F", "mode": "cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -70,7 +70,7 @@
|
|||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = "font-cross-site";
|
||||
let expected = {"dest":"font", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"font", "site":"cross-site", "user":"?F", "mode": "cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "nested-document",
|
||||
"site": "same-origin",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "navigate"
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -32,7 +33,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "nested-document",
|
||||
"site": "same-site",
|
||||
"user": "?F"
|
||||
"user": "?F",
|
||||
"mode": "navigate"
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -50,7 +52,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "nested-document",
|
||||
"site": "cross-site",
|
||||
"user": "?F"
|
||||
"user": "?F",
|
||||
"mode": "navigate"
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "",
|
||||
"site": "",
|
||||
"user": ""
|
||||
"user": "",
|
||||
"mode": "",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -32,7 +33,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "",
|
||||
"site": "",
|
||||
"user": ""
|
||||
"user": "",
|
||||
"mode": "",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -50,7 +52,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "",
|
||||
"site": "",
|
||||
"user": ""
|
||||
"user": "",
|
||||
"mode": "",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
assert_header_equals(got, {
|
||||
"dest": "image",
|
||||
"site": "same-origin",
|
||||
"user": "?F"
|
||||
"user": "?F",
|
||||
"mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin`
|
||||
});
|
||||
}),
|
||||
[],
|
||||
|
@ -42,7 +43,8 @@
|
|||
assert_header_equals(got, {
|
||||
"dest": "image",
|
||||
"site": "same-site",
|
||||
"user": "?F"
|
||||
"user": "?F",
|
||||
"mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin`
|
||||
});
|
||||
}),
|
||||
[],
|
||||
|
@ -63,7 +65,8 @@
|
|||
assert_header_equals(got, {
|
||||
"dest": "image",
|
||||
"site": "cross-site",
|
||||
"user": "?F"
|
||||
"user": "?F",
|
||||
"mode": "cors", // Because `loadImageInWindow` tacks on `crossorigin`
|
||||
});
|
||||
}),
|
||||
[],
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
let e = document.createElement('object');
|
||||
e.data = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"object", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"object", "site":"same-origin", "user":"?F", "mode":"no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -32,7 +32,7 @@
|
|||
let e = document.createElement('object');
|
||||
e.data = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"object", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"object", "site":"same-site", "user":"?F", "mode":"no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -51,7 +51,7 @@
|
|||
let e = document.createElement('object');
|
||||
e.data = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"object", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"object", "site":"cross-site", "user":"?F", "mode":"no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
|
|
@ -12,7 +12,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
|
@ -38,7 +38,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
|
@ -64,7 +64,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
|
|
|
@ -14,7 +14,7 @@ promise_test(t => {
|
|||
e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin
|
||||
"https://{{hosts[alt][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// cross-site
|
||||
"https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;// same-origin
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
|
|
@ -14,7 +14,7 @@ promise_test(t => {
|
|||
e.src = "https://{{host}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-origin
|
||||
"https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=" +// same-site
|
||||
"https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;// same-origin
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
|
|
@ -12,7 +12,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"same-origin", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
@ -39,7 +39,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "/xhr/resources/redirect.py?location=https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
@ -66,7 +66,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
|
|
@ -12,7 +12,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
@ -39,7 +39,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"same-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
@ -66,7 +66,7 @@ promise_test(t => {
|
|||
|
||||
let e = document.createElement('img');
|
||||
e.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/xhr/resources/redirect.py?location=https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"image", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
|
||||
e.onload = e => {
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
document.addEventListener("securitypolicyviolation", (e) => {
|
||||
counter++;
|
||||
if (counter == 3) {
|
||||
generate_test({"dest":"report", "site":"same-origin", "user":"?F"}, "same-origin");
|
||||
generate_test({"dest":"report", "site":"same-site", "user":"?F"}, "same-site");
|
||||
generate_test({"dest":"report", "site":"cross-site", "user":"?F"}, "cross-site");
|
||||
generate_test({"dest":"report", "site":"same-origin", "user":"?F", "mode": "no-cors"}, "same-origin");
|
||||
generate_test({"dest":"report", "site":"same-site", "user":"?F", "mode": "no-cors"}, "same-site");
|
||||
generate_test({"dest":"report", "site":"cross-site", "user":"?F", "mode": "no-cors"}, "cross-site");
|
||||
}
|
||||
});
|
||||
}, "Initialization.");
|
||||
|
|
|
@ -4,8 +4,7 @@ function assert_header_equals(value, expected) {
|
|||
value = JSON.parse(value);
|
||||
}
|
||||
assert_equals(value.dest, expected.dest, "dest");
|
||||
// Mode is commented out as no test cases have been filled out yet
|
||||
// assert_equals(value.mode, expected.mode, "mode");
|
||||
assert_equals(value.mode, expected.mode, "mode");
|
||||
assert_equals(value.site, expected.site, "site");
|
||||
assert_equals(value.user, expected.user, "user");
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
assert_header_equals(header, {
|
||||
"dest": "script",
|
||||
"site": "same-origin",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "no-cors",
|
||||
});
|
||||
}, "Same-origin script");
|
||||
</script>
|
||||
|
@ -26,7 +27,8 @@
|
|||
assert_header_equals(header, {
|
||||
"dest": "script",
|
||||
"site": "same-site",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "no-cors",
|
||||
});
|
||||
}, "Same-site script");
|
||||
</script>
|
||||
|
@ -40,7 +42,23 @@
|
|||
assert_header_equals(header, {
|
||||
"dest": "script",
|
||||
"site": "cross-site",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "no-cors",
|
||||
});
|
||||
}, "Cross-site script");
|
||||
</script>
|
||||
|
||||
<!-- Same-origin script, CORS mode -->
|
||||
<script src="https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
test(t => {
|
||||
t.add_cleanup(_ => { header = null; });
|
||||
|
||||
assert_header_equals(header, {
|
||||
"dest": "script",
|
||||
"site": "same-origin",
|
||||
"user": "?F",
|
||||
"mode": "cors",
|
||||
});
|
||||
}, "Same-origin CORS script");
|
||||
</script>
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
assert_header_equals(header, {
|
||||
"dest": "",
|
||||
"site": "",
|
||||
"user": ""
|
||||
"user": "",
|
||||
"mode": "",
|
||||
});
|
||||
}, "Non-secure same-origin script => No headers");
|
||||
</script>
|
||||
|
@ -26,7 +27,8 @@
|
|||
assert_header_equals(header, {
|
||||
"dest": "",
|
||||
"site": "",
|
||||
"user": ""
|
||||
"user": "",
|
||||
"mode": "",
|
||||
});
|
||||
}, "Non-secure same-site script => No headers");
|
||||
</script>
|
||||
|
@ -40,7 +42,8 @@
|
|||
assert_header_equals(header, {
|
||||
"dest": "",
|
||||
"site": "",
|
||||
"user": ""
|
||||
"user": "",
|
||||
"mode": "",
|
||||
});
|
||||
}, "Non-secure cross-site script => No headers");
|
||||
</script>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = "serviceworker-same-origin";
|
||||
let expected = {"dest":"serviceworker", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"serviceworker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = "sharedworker-same-origin";
|
||||
let expected = {"dest":"sharedworker", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"sharedworker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
|
||||
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
e.rel = "stylesheet";
|
||||
e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"style", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"style", "site":"same-origin", "user":"?F", "mode": "no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -34,7 +34,7 @@
|
|||
e.rel = "stylesheet";
|
||||
e.href = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"style", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"style", "site":"same-site", "user":"?F", "mode": "no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -54,7 +54,7 @@
|
|||
e.rel = "stylesheet";
|
||||
e.href = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"style", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"style", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -65,6 +65,27 @@
|
|||
document.body.appendChild(e);
|
||||
})
|
||||
}, "Cross-Site style");
|
||||
|
||||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let key = "style-same-origin";
|
||||
|
||||
let e = document.createElement('link');
|
||||
e.rel = "stylesheet";
|
||||
e.href = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=" + key;
|
||||
e.crossOrigin = "anonymous";
|
||||
e.onload = e => {
|
||||
let expected = {"dest":"style", "site":"same-origin", "user":"?F", "mode": "cors"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
.then(_ => resolve())
|
||||
.catch(e => reject(e));
|
||||
};
|
||||
|
||||
document.body.appendChild(e);
|
||||
})
|
||||
}, "Same-Origin, cors style");
|
||||
</script>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -29,7 +29,12 @@
|
|||
let el = createTrack();
|
||||
el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-origin";
|
||||
el.onload = t.step_func(_ => {
|
||||
expected = {"dest":"track", "site":"same-origin", "user":"?F"};
|
||||
expected = {
|
||||
"dest": "track",
|
||||
"site": "same-origin",
|
||||
"user": "?F",
|
||||
"mode": "cors" // Because the `video` element has `crossorigin`
|
||||
};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-origin")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -46,7 +51,12 @@
|
|||
let el = createTrack();
|
||||
el.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-site";
|
||||
el.onload = t.step_func(_ => {
|
||||
expected = {"dest":"track", "site":"same-site", "user":"?F"};
|
||||
expected = {
|
||||
"dest": "track",
|
||||
"site": "same-site",
|
||||
"user": "?F",
|
||||
"mode": "cors" // Because the `video` element has `crossorigin`
|
||||
};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-site")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -65,7 +75,12 @@
|
|||
let el = createTrack();
|
||||
el.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-cross-site";
|
||||
el.onload = t.step_func(_ => {
|
||||
expected = {"dest":"track", "site":"cross-site", "user":"?F"};
|
||||
expected = {
|
||||
"dest": "track",
|
||||
"site": "cross-site",
|
||||
"user": "?F",
|
||||
"mode": "cors" // Because the `video` element has `crossorigin`
|
||||
};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-cross-site")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
@ -76,4 +91,30 @@
|
|||
document.body.appendChild(video);
|
||||
});
|
||||
}, "Cross-Site track");
|
||||
|
||||
promise_test(t => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let video = createVideoElement();
|
||||
|
||||
// Unset `crossorigin` to change the CORS mode:
|
||||
video.crossOrigin = undefined;
|
||||
|
||||
let el = createTrack();
|
||||
el.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/record-header.py?file=track-same-origin";
|
||||
el.onload = t.step_func(_ => {
|
||||
expected = {
|
||||
"dest":"track",
|
||||
"site":"same-origin",
|
||||
"user":"?F",
|
||||
"mode": "same-origin"
|
||||
};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=track-same-origin")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
.then(_ => resolve());
|
||||
});
|
||||
video.appendChild(el);
|
||||
document.body.appendChild(video);
|
||||
});
|
||||
}, "Same-Origin, CORS track");
|
||||
</script>
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "document",
|
||||
"site": "same-origin",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "navigate",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -33,7 +34,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "document",
|
||||
"site": "same-site",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "navigate",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -49,7 +51,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "document",
|
||||
"site": "cross-site",
|
||||
"user":"?F"
|
||||
"user": "?F",
|
||||
"mode": "navigate",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -68,7 +71,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "document",
|
||||
"site": "same-origin",
|
||||
"user": "?T"
|
||||
"user": "?T",
|
||||
"mode": "navigate",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -89,7 +93,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "document",
|
||||
"site": "same-site",
|
||||
"user": "?T"
|
||||
"user": "?T",
|
||||
"mode": "navigate",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
@ -110,7 +115,8 @@
|
|||
assert_header_equals(e.data, {
|
||||
"dest": "document",
|
||||
"site": "cross-site",
|
||||
"user": "?T"
|
||||
"user": "?T",
|
||||
"mode": "navigate",
|
||||
});
|
||||
t.done();
|
||||
}));
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
let key = "worker-same-origin";
|
||||
let w = new Worker("/fetch/sec-metadata/resources/record-header.py?file=" + key);
|
||||
w.onmessage = e => {
|
||||
let expected = {"dest":"worker", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"worker", "site":"same-origin", "user":"?F", "mode": "same-origin"};
|
||||
fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key)
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected))
|
||||
|
|
|
@ -12,21 +12,21 @@
|
|||
return;
|
||||
|
||||
promise_test(t => {
|
||||
let expected = {"dest":"xslt", "site":"same-origin", "user":"?F"};
|
||||
let expected = {"dest":"xslt", "site":"same-origin", "user":"?F", "mode": "same-origin"};
|
||||
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-origin")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected));
|
||||
}, "Same-Origin xslt");
|
||||
|
||||
promise_test(t => {
|
||||
let expected = {"dest":"xslt", "site":"same-site", "user":"?F"};
|
||||
let expected = {"dest":"xslt", "site":"same-site", "user":"?F", "mode": "no-cors"};
|
||||
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-same-site")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected));
|
||||
}, "Same-site xslt");
|
||||
|
||||
promise_test(t => {
|
||||
let expected = {"dest":"xslt", "site":"cross-site", "user":"?F"};
|
||||
let expected = {"dest":"xslt", "site":"cross-site", "user":"?F", "mode": "no-cors"};
|
||||
return fetch("/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=xslt-cross-site")
|
||||
.then(response => response.text())
|
||||
.then(text => assert_header_equals(text, expected));
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support/document_domain_frame.sub.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "control1-1", "{{domains[www1]}}");
|
||||
let frame2 = await createFrame(t, "control1-2", "{{domains[www1]}}");
|
||||
let result = await postMessageToFrame(frame1, { 'poke-at-sibling': "control1-2" });
|
||||
assert_equals(result.data, "omg!");
|
||||
}, "Access allowed if same-origin with no 'document.domain' modification. (Sanity check)");
|
||||
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "control2-1", "{{domains[www1]}}");
|
||||
let frame2 = await createFrame(t, "control2-2", "{{domains[www2]}}");
|
||||
let result = await postMessageToFrame(frame1, { 'poke-at-sibling': "control2-2" });
|
||||
assert_equals(result.data, "SecurityError");
|
||||
}, "Access not allowed if different-origin with no 'document.domain' modification. (Sanity check)");
|
||||
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "one-set-one-not-1", "{{domains[www1]}}");
|
||||
let frame2 = await createFrame(t, "one-set-one-not-2", "{{domains[www1]}}");
|
||||
await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
|
||||
let result = await postMessageToFrame(frame1, { 'poke-at-sibling': "one-set-one-not-2" });
|
||||
assert_equals(result.data, "SecurityError");
|
||||
|
||||
result = await postMessageToFrame(frame2, { 'poke-at-sibling': "one-set-one-not-1" });
|
||||
assert_equals(result.data, "SecurityError");
|
||||
}, "Access disallowed if same-origin but only one sets document.domain.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
var frame1 = await createFrame(t, "both-set-to-existing-1", "{{domains[www1]}}");
|
||||
var frame2 = await createFrame(t, "both-set-to-existing-2", "{{domains[www1]}}");
|
||||
let result = await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame2, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, { 'poke-at-sibling': "both-set-to-existing-2" });
|
||||
assert_equals(result.data, "omg!");
|
||||
|
||||
result = await postMessageToFrame(frame2, { 'poke-at-sibling': "both-set-to-existing-1" });
|
||||
assert_equals(result.data, "omg!");
|
||||
}, "Access allowed if same-origin and both set document.domain to existing value.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
var frame1 = await createFrame(t, "both-set-to-parent-1", "{{domains[www1]}}");
|
||||
var frame2 = await createFrame(t, "both-set-to-parent-2", "{{domains[www2]}}");
|
||||
let result = await postMessageToFrame(frame1, { domain: "{{domains[]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame2, { domain: "{{domains[]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, { 'poke-at-sibling': "both-set-to-parent-2" });
|
||||
assert_equals(result.data, "omg!");
|
||||
|
||||
result = await postMessageToFrame(frame2, { 'poke-at-sibling': "both-set-to-parent-1" });
|
||||
assert_equals(result.data, "omg!");
|
||||
}, "Access allowed if different-origin but both set document.domain to parent domain.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
var frame1 = await createFrame(t, "allow-then-revoke-1", "{{domains[www1]}}");
|
||||
var frame2 = await createFrame(t, "allow-then-revoke-2", "{{domains[www1]}}");
|
||||
let result = await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame2, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, { 'poke-at-sibling': "allow-then-revoke-2" });
|
||||
assert_equals(result.data, "omg!");
|
||||
|
||||
result = await postMessageToFrame(frame2, { 'poke-at-sibling': "allow-then-revoke-1" });
|
||||
assert_equals(result.data, "omg!");
|
||||
|
||||
result = await postMessageToFrame(frame1, { domain: "{{domains[]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, { 'poke-at-sibling': "allow-then-revoke-2" });
|
||||
assert_equals(result.data, "SecurityError");
|
||||
|
||||
result = await postMessageToFrame(frame2, { 'poke-at-sibling': "allow-then-revoke-1" });
|
||||
assert_equals(result.data, "SecurityError");
|
||||
}, "Access disallowed again if same-origin, both set document-domain to existing value, then one sets to parent.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "revoke-Window-1", "{{domains[www1]}}");
|
||||
let frame2 = await createFrame(t, "revoke-Window-2", "{{domains[www1]}}");
|
||||
|
||||
let result = await postMessageToFrame(frame1, { cache: ["parent", "revoke-Window-2"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 1");
|
||||
|
||||
result = await postMessageToFrame(frame2, { cache: ["parent", "revoke-Window-1"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 1");
|
||||
|
||||
result = await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "SecurityError");
|
||||
|
||||
result = await postMessageToFrame(frame2, 'touch-cached');
|
||||
assert_equals(result.data, "SecurityError");
|
||||
}, "Access is revoked to Window object when we stop being same effective script origin due to document.domain.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "revoke-Location-1", "{{hosts[][www1]}}");
|
||||
let frame2 = await createFrame(t, "revoke-Location-2", "{{domains[www1]}}");
|
||||
|
||||
let result = await postMessageToFrame(frame1, { cache: ["parent", "revoke-Location-2", "location"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 3");
|
||||
|
||||
result = await postMessageToFrame(frame2, { cache: ["parent", "revoke-Location-1", "location"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 3");
|
||||
|
||||
result = await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "SecurityError");
|
||||
|
||||
result = await postMessageToFrame(frame2, 'touch-cached');
|
||||
assert_equals(result.data, "SecurityError");
|
||||
}, "Access is revoked to Location object when we stop being same effective script origin due to document.domain.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "no-revoke-Document-1", "{{domains[www1]}}");
|
||||
let frame2 = await createFrame(t, "no-revoke-Document-2", "{{domains[www1]}}");
|
||||
|
||||
let result = await postMessageToFrame(frame1, { cache: ["parent", "no-revoke-Document-2", "document"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 4");
|
||||
|
||||
result = await postMessageToFrame(frame2, { cache: ["parent", "no-revoke-Document-1", "document"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 4");
|
||||
|
||||
result = await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 4");
|
||||
|
||||
result = await postMessageToFrame(frame2, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 4");
|
||||
}, "Access is not revoked to Document object when we stop being same effective script origin due to document.domain.");
|
||||
|
||||
promise_test(async (t) => {
|
||||
let frame1 = await createFrame(t, "no-revoke-object-1", "{{domains[www1]}}");
|
||||
let frame2 = await createFrame(t, "no-revoke-object-2", "{{domains[www1]}}");
|
||||
|
||||
let result = await postMessageToFrame(frame1, { cache: ["parent", "no-revoke-object-2", "bar"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 2");
|
||||
|
||||
result = await postMessageToFrame(frame2, { cache: ["parent", "no-revoke-object-1", "bar"] });
|
||||
assert_equals(result.data, "cached");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 2");
|
||||
|
||||
result = await postMessageToFrame(frame1, { domain: "{{domains[www1]}}" });
|
||||
assert_equals(result.data, "Done");
|
||||
|
||||
result = await postMessageToFrame(frame1, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 2");
|
||||
|
||||
result = await postMessageToFrame(frame2, 'touch-cached');
|
||||
assert_equals(result.data, "Reachable 2");
|
||||
}, "Access is not revoked to random object when we stop being same effective script origin due to document.domain.");
|
||||
</script>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<script>
|
||||
let cache = window;
|
||||
// "foo" needs to be a var so it's a property on the global.
|
||||
var foo = 'Reachable 1';
|
||||
// "bar" needs to be a var so it's a property on the global.
|
||||
var bar = { foo: 'Reachable 2' };
|
||||
location.foo = 'Reachable 3';
|
||||
document.foo = 'Reachable 4';
|
||||
window.addEventListener('message', e => {
|
||||
if (e.data.domain !== undefined) {
|
||||
try {
|
||||
document.domain = e.data.domain;
|
||||
e.ports[0].postMessage('Done');
|
||||
} catch(error) {
|
||||
e.ports[0].postMessage(error.name);
|
||||
}
|
||||
} else if (e.data['poke-at-sibling'] !== undefined) {
|
||||
try {
|
||||
var sekrit = parent[e.data['poke-at-sibling']].document.body.querySelector('#sekrit').value;
|
||||
e.ports[0].postMessage(sekrit);
|
||||
} catch(error) {
|
||||
e.ports[0].postMessage(error.name);
|
||||
}
|
||||
} else if (e.data.cache != undefined) {
|
||||
let path = e.data.cache;
|
||||
try {
|
||||
while (path.length != 0) {
|
||||
cache = cache[path.shift()];
|
||||
}
|
||||
e.ports[0].postMessage('cached');
|
||||
} catch (error) {
|
||||
e.ports[0].postMessage(error.name);
|
||||
}
|
||||
} else if (e.data == 'touch-cached') {
|
||||
try {
|
||||
e.ports[0].postMessage(cache.foo);
|
||||
} catch (error) {
|
||||
e.ports[0].postMessage(error.name);
|
||||
}
|
||||
} else if (e.data == 'poke-at-parent') {
|
||||
try {
|
||||
var sekrit = window.parent.document.body.querySelector('#sekrit').value;
|
||||
e.ports[0].postMessage(sekrit);
|
||||
} catch(error) {
|
||||
e.ports[0].postMessage(error.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
window.parent.postMessage('Hi!', '*');
|
||||
</script>
|
||||
<input id="sekrit" value="omg!">
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Utilities to be used with document_domain_frame.html.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send a message to the frame and resolve a promise when a response is received.
|
||||
*
|
||||
* Supported messages:
|
||||
*
|
||||
* 1) { domain: something }. Has the subframe try to set document.domain to the
|
||||
* given value, and message back 'Done' if that succeeds or an error name if it
|
||||
* fails.
|
||||
*
|
||||
* 2) 'poke-at-parent'. Has the subframe try to synchronously attempt to access
|
||||
* the parent's DOM, read out a string value, and message it back to the parent.
|
||||
* Again, sends back the error name if that fails.
|
||||
*
|
||||
* 3) { 'poke-at-sibling': name }. Has the subframe try to synchronously
|
||||
* attempt to access the DOM of the sibling with the given name, read out a
|
||||
* string value, and message it back to the parent.
|
||||
*/
|
||||
function postMessageToFrame(frame, message) {
|
||||
return new Promise(resolve => {
|
||||
var c = new MessageChannel();
|
||||
c.port1.onmessage = e => {
|
||||
resolve({ data: e.data, frame: frame })
|
||||
};
|
||||
frame.contentWindow.postMessage(message, '*', [c.port2]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a frame that loads document_domain_frame.html and resolves a promise
|
||||
* when the frame is loaded enough to be sending and receiving messages.
|
||||
*
|
||||
* If a "name" argument is provided, that name is used for the iframe, so
|
||||
*
|
||||
* If a "hostname" argument is provided, that hostname is used for the load, to
|
||||
* allow testing details of the behavior when different sorts of hostnames are
|
||||
* used.
|
||||
*/
|
||||
function createFrame(t, name, hostname) {
|
||||
return new Promise(resolve => {
|
||||
var i = document.createElement('iframe');
|
||||
if (hostname) {
|
||||
i.src = `//${hostname}:{{location[port]}}/html/browsers/origin/relaxing-the-same-origin-restriction/support/document_domain_frame.html`;
|
||||
} else {
|
||||
i.src = "support/document_domain_frame.html";
|
||||
}
|
||||
if (name) {
|
||||
i.name = name;
|
||||
}
|
||||
var listener = m => {
|
||||
if (m.source == i.contentWindow)
|
||||
resolve(i);
|
||||
}
|
||||
window.addEventListener('message', listener);
|
||||
t.add_cleanup(() => {
|
||||
i.remove();
|
||||
window.removeEventListener('message', listener);
|
||||
});
|
||||
document.body.appendChild(i);
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
test(() => {
|
||||
const frame = document.createElement("iframe"),
|
||||
name = "A",
|
||||
name2 = "B";
|
||||
frame.setAttribute("name", name);
|
||||
document.body.append(frame);
|
||||
const frameW = frame.contentWindow;
|
||||
assert_equals(frameW.name, name);
|
||||
frameW.name = name2;
|
||||
assert_equals(frame.getAttribute("name"), name);
|
||||
assert_equals(frameW.name, name2);
|
||||
frame.remove();
|
||||
assert_equals(frame.getAttribute("name"), name);
|
||||
assert_equals(frameW.name, "");
|
||||
frameW.name = name2;
|
||||
assert_equals(frame.getAttribute("name"), name);
|
||||
assert_equals(frameW.name, "");
|
||||
}, "Window object's name IDL attribute");
|
|
@ -13,8 +13,8 @@ test(function() {
|
|||
var a = document.getElementById("test");
|
||||
|
||||
test(function() {
|
||||
a.rel = "noreferrer"
|
||||
assert_equals(a.rel, "noreferrer");
|
||||
a.rel = "noreferrer";
|
||||
assert_equals(a.getAttribute("rel"), "noreferrer");
|
||||
}, "Test anchor's rel setter");
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
test(t => {
|
||||
assert_false("getUserAgent" in navigator);
|
||||
}, "navigator.getUserAgent() is not available in non-secure contexts.");
|
||||
</script>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/webrtc/dictionary-helper.js"></script>
|
||||
<script>
|
||||
test(t => {
|
||||
assert_true("getUserAgent" in navigator);
|
||||
}, "navigator.getUserAgent() is exposed.");
|
||||
|
||||
promise_test(t => {
|
||||
return navigator.getUserAgent()
|
||||
.then(ua => {
|
||||
// TODO(web-platform-tests/wpt#9106): Use `idlharness.js` once it supports dictionaries.
|
||||
assert_string_field(ua, "brand");
|
||||
assert_string_field(ua, "version");
|
||||
assert_string_field(ua, "platform");
|
||||
assert_string_field(ua, "architecture");
|
||||
assert_string_field(ua, "model");
|
||||
});
|
||||
}, "navigator.getUserAgent() returns a UserAgentMetadata object.");
|
||||
</script>
|
|
@ -0,0 +1 @@
|
|||
Content-Type: text/javascript
|
1
tests/wpt/web-platform-tests/import-maps/@std/blank
Normal file
1
tests/wpt/web-platform-tests/import-maps/@std/blank
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:@std/blank");
|
1
tests/wpt/web-platform-tests/import-maps/@std/none
Normal file
1
tests/wpt/web-platform-tests/import-maps/@std/none
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:@std/none");
|
9
tests/wpt/web-platform-tests/import-maps/README.md
Normal file
9
tests/wpt/web-platform-tests/import-maps/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
Tests for [Import Maps](https://github.com/WICG/import-maps).
|
||||
|
||||
Because the spec itself is still under development and there are ongoing spec
|
||||
discussions, the tests are all tentative.
|
||||
|
||||
Also, some tests are based on Chromium's behavior which reflects an older
|
||||
version of import maps spec ("package name maps" around May 2018), and have
|
||||
dependency to Chromium's implementation (internals.resolveModuleSpecifier).
|
||||
These dependencies should be removed, once the spec matures.
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
// https://github.com/WICG/import-maps/blob/master/spec.md#when-import-maps-can-be-encountered
|
||||
const t = async_test(
|
||||
'After dynamic imports, import maps should fire error events');
|
||||
const log = [];
|
||||
// To ensure we are testing that the flag is cleared at the beginning of module
|
||||
// script loading unconditionally, not at the end of loading or not at the
|
||||
// first attempt to resolve a module specifier, trickle(d1) is used to ensure
|
||||
// the following import map is added after module loading is triggered but
|
||||
// before the first module script is parsed.
|
||||
promise_test(() => import('../../resources/empty.js?pipe=trickle(d1)'),
|
||||
"A dynamic import succeeds");
|
||||
</script>
|
||||
<script type="importmap" onload="t.assert_unreached('onload')" onerror="t.done()">
|
||||
{
|
||||
"imports": {
|
||||
"../../resources/log.js?pipe=sub&name=A": "../../resources/log.js?pipe=sub&name=B"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
promise_test(() => {
|
||||
return import("../../resources/log.js?pipe=sub&name=A")
|
||||
.then(() => assert_array_equals(log, ["log:A"]))
|
||||
},
|
||||
'After a dynamic import(), import maps are not effective');
|
||||
</script>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
// https://github.com/WICG/import-maps/blob/master/spec.md#when-import-maps-can-be-encountered
|
||||
const t = async_test(
|
||||
'After <script type="module"> import maps should fire error events');
|
||||
const log = [];
|
||||
</script>
|
||||
<script type="module" src="../../resources/empty.js?pipe=trickle(d1)"></script>
|
||||
<script type="importmap" onerror="t.done()">
|
||||
{
|
||||
"imports": {
|
||||
"../../resources/log.js?pipe=sub&name=A": "../../resources/log.js?pipe=sub&name=B"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
promise_test(() => {
|
||||
return import("../../resources/log.js?pipe=sub&name=A")
|
||||
.then(() => assert_array_equals(log, ["log:A"]))
|
||||
},
|
||||
'After <script type="module"> import maps are not effective');
|
||||
</script>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
// https://github.com/WICG/import-maps/blob/master/spec.md#when-import-maps-can-be-encountered
|
||||
const t = async_test(
|
||||
'After module worker creation, import maps should fire error events');
|
||||
const log = [];
|
||||
new Worker('../../resources/empty.js?pipe=trickle(d1)', {type: "module"});
|
||||
</script>
|
||||
<script type="importmap" onerror="t.done()">
|
||||
{
|
||||
"imports": {
|
||||
"../../resources/log.js?pipe=sub&name=A": "../../resources/log.js?pipe=sub&name=B"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
promise_test(() => {
|
||||
return import("../../resources/log.js?pipe=sub&name=A")
|
||||
.then(() => assert_array_equals(log, ["A"]))
|
||||
},
|
||||
'After module worker creation import maps are not effective');
|
||||
</script>
|
|
@ -0,0 +1,70 @@
|
|||
<!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": {
|
||||
"bare/bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
"bare/cross-origin-bare": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bare",
|
||||
"bare/to-data": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"bare/std-blank": "std:blank",
|
||||
"bare/blank": "@std/blank",
|
||||
"bare/std-none": "std:none",
|
||||
"bare/none": "@std/none",
|
||||
|
||||
"bare/to-bare": "bare/bare"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
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 HTTP(S).
|
||||
"bare/bare":
|
||||
[Result.URL, Result.URL, "log:bare", "log:bare"],
|
||||
"bare/cross-origin-bare":
|
||||
[Result.URL, Result.URL, "log:cross-origin-bare", "log:cross-origin-bare"],
|
||||
|
||||
// Bare to data:
|
||||
"bare/to-data":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// 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],
|
||||
|
||||
// Bare to bare mapping is disabled.
|
||||
"bare/to-bare":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
||||
</script>
|
||||
<body>
|
|
@ -0,0 +1 @@
|
|||
Content-Type: text/javascript
|
1
tests/wpt/web-platform-tests/import-maps/bare/bare
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/bare
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/bare");
|
1
tests/wpt/web-platform-tests/import-maps/bare/blank
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/blank
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/blank");
|
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/cross-origin-bare");
|
1
tests/wpt/web-platform-tests/import-maps/bare/none
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/none
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/none");
|
1
tests/wpt/web-platform-tests/import-maps/bare/std-blank
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/std-blank
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/std-blank");
|
1
tests/wpt/web-platform-tests/import-maps/bare/std-none
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/std-none
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/std-none");
|
1
tests/wpt/web-platform-tests/import-maps/bare/to-bare
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/to-bare
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/to-bare");
|
1
tests/wpt/web-platform-tests/import-maps/bare/to-data
Normal file
1
tests/wpt/web-platform-tests/import-maps/bare/to-data
Normal file
|
@ -0,0 +1 @@
|
|||
log.push("relative:bare/to-data");
|
|
@ -0,0 +1,43 @@
|
|||
<!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>
|
|
@ -0,0 +1,27 @@
|
|||
<!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>
|
|
@ -0,0 +1,30 @@
|
|||
<!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>
|
|
@ -0,0 +1,72 @@
|
|||
<!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": {
|
||||
"bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"data:text/javascript,log.push('data:foo')": "./resources/log.js?pipe=sub&name=foo",
|
||||
"data:text/javascript,log.push('data:cross-origin-foo')": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo",
|
||||
"data:text/javascript,log.push('data:to-data')": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"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",
|
||||
|
||||
"data:text/javascript,log.push('data:to-bare')": "bare"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
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 HTTP(S).
|
||||
"data:text/javascript,log.push('data:foo')":
|
||||
[Result.URL, Result.URL, "log:foo", "log:foo"],
|
||||
"data:text/javascript,log.push('data:cross-origin-foo')":
|
||||
[Result.URL, Result.URL, "log:cross-origin-foo", "log:cross-origin-foo"],
|
||||
|
||||
// data: to data:
|
||||
"data:text/javascript,log.push('data:to-data')":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// 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],
|
||||
|
||||
// data: to bare mapping is disabled.
|
||||
"data:text/javascript,log.push('data:to-bare')":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
||||
</script>
|
||||
<body>
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<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>
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<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>
|
|
@ -0,0 +1,72 @@
|
|||
<!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": {
|
||||
"bare": "./resources/log.js?pipe=sub&name=bare",
|
||||
|
||||
"./resources/log.js?pipe=sub&name=foo": "./resources/log.js?pipe=sub&name=bar",
|
||||
"./resources/log.js?pipe=sub&name=cross-origin-foo": "https://{{domains[www1]}}:{{ports[https][0]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-bar",
|
||||
"./resources/log.js?pipe=sub&name=to-data": "data:text/javascript,log.push('dataURL')",
|
||||
|
||||
"./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",
|
||||
|
||||
"./resources/log.js?pipe=sub&name=to-bare": "bare"
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
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 HTTP(S).
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=foo":
|
||||
[Result.URL, Result.URL, "log:bar", "log:bar"],
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=cross-origin-foo":
|
||||
[Result.URL, Result.URL, "log:cross-origin-bar", "log:cross-origin-bar"],
|
||||
|
||||
// HTTP(S) to data:
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-data":
|
||||
[Result.URL, Result.URL, "dataURL", "dataURL"],
|
||||
|
||||
// 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],
|
||||
|
||||
// HTTP(S) to bare mapping is disabled.
|
||||
"{{location[server]}}/import-maps/resources/log.js?pipe=sub&name=to-bare":
|
||||
[Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
|
||||
};
|
||||
|
||||
doTests(importMap, null, tests);
|
||||
</script>
|
||||
<body>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"./resources/log.js?pipe=sub&name=A": "./resources/log.js?pipe=sub&name=B"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
const log = [];
|
||||
|
||||
// This test reflects the Chromium's current implementation.
|
||||
// If the import map resolution is moved into the fetch spec, the module map's
|
||||
// key will become the URL/specifier BEFORE import map resolution.
|
||||
// https://crbug.com/928435
|
||||
promise_test(() => {
|
||||
return import("./resources/log.js?pipe=sub&name=A")
|
||||
.then(() => import("./resources/log.js?pipe=sub&name=B"))
|
||||
.then(() => assert_array_equals(log, ["log:B"]))
|
||||
},
|
||||
"Module map's key is the URL after import map resolution");
|
||||
</script>
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
setup({allow_uncaught_exception : true});
|
||||
|
||||
// Hacky glue code to run Jest-based tests as WPT tests.
|
||||
// Only supports resolving.js.
|
||||
function require(name) {
|
||||
return {
|
||||
'URL': URL,
|
||||
'parseFromString': parseFromString,
|
||||
'resolve': resolve
|
||||
};
|
||||
}
|
||||
|
||||
function expect(v) {
|
||||
return {
|
||||
toMatchURL: expected => assert_equals(v, expected),
|
||||
toThrow: expected => assert_throws(expected(), v)
|
||||
};
|
||||
}
|
||||
|
||||
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(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) {
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.contentDocument.write(`
|
||||
<base href="${mapBaseURL}">
|
||||
<script>
|
||||
let isError = false;
|
||||
function onError() {
|
||||
isError = true;
|
||||
}
|
||||
</sc` + `ript>
|
||||
<script type="importmap" onerror="onError()">
|
||||
${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);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!--
|
||||
resolving.js is
|
||||
https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js
|
||||
-->
|
||||
<script type="module" src="resources/resolving.js"></script>
|
|
@ -0,0 +1 @@
|
|||
log.push("log:{{GET[name]}}");
|
|
@ -0,0 +1 @@
|
|||
Access-Control-Allow-Origin: *
|
206
tests/wpt/web-platform-tests/import-maps/resources/resolving.js
Normal file
206
tests/wpt/web-platform-tests/import-maps/resources/resolving.js
Normal file
|
@ -0,0 +1,206 @@
|
|||
'use strict';
|
||||
const { URL } = require('url');
|
||||
const { parseFromString } = require('../lib/parser.js');
|
||||
const { resolve } = require('../lib/resolver.js');
|
||||
|
||||
const mapBaseURL = new URL('https://example.com/app/index.html');
|
||||
const scriptURL = new URL('https://example.com/js/app.mjs');
|
||||
|
||||
function makeResolveUnderTest(mapString) {
|
||||
const map = parseFromString(mapString, mapBaseURL);
|
||||
return specifier => resolve(specifier, map, scriptURL);
|
||||
}
|
||||
|
||||
describe('Unmapped', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{}`);
|
||||
|
||||
it('should resolve ./ specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('./foo')).toMatchURL('https://example.com/js/foo');
|
||||
expect(resolveUnderTest('./foo/bar')).toMatchURL('https://example.com/js/foo/bar');
|
||||
expect(resolveUnderTest('./foo/../bar')).toMatchURL('https://example.com/js/bar');
|
||||
expect(resolveUnderTest('./foo/../../bar')).toMatchURL('https://example.com/bar');
|
||||
});
|
||||
|
||||
it('should resolve ../ specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('../foo')).toMatchURL('https://example.com/foo');
|
||||
expect(resolveUnderTest('../foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
expect(resolveUnderTest('../../../foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
});
|
||||
|
||||
it('should resolve / specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('/foo')).toMatchURL('https://example.com/foo');
|
||||
expect(resolveUnderTest('/foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
expect(resolveUnderTest('/../../foo/bar')).toMatchURL('https://example.com/foo/bar');
|
||||
expect(resolveUnderTest('/../foo/../bar')).toMatchURL('https://example.com/bar');
|
||||
});
|
||||
|
||||
it('should parse absolute fetch-scheme URLs', () => {
|
||||
expect(resolveUnderTest('about:good')).toMatchURL('about:good');
|
||||
expect(resolveUnderTest('https://example.net')).toMatchURL('https://example.net/');
|
||||
expect(resolveUnderTest('https://ex%41mple.com/')).toMatchURL('https://example.com/');
|
||||
expect(resolveUnderTest('https:example.org')).toMatchURL('https://example.org/');
|
||||
expect(resolveUnderTest('https://///example.com///')).toMatchURL('https://example.com///');
|
||||
});
|
||||
|
||||
it('should fail for absolute non-fetch-scheme URLs', () => {
|
||||
expect(() => resolveUnderTest('mailto:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('import:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('javascript:bad')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('wss:bad')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should fail for strings not parseable as absolute URLs and not starting with ./ ../ or /', () => {
|
||||
expect(() => resolveUnderTest('foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('\\foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest(':foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('@foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('%2E/foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('%2E%2E/foo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('.%2Ffoo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('https://ex ample.org/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('https://example.com:demo')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('http://[www.example.com]/')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mapped using the "imports" key only (no scopes)', () => {
|
||||
it('should fail when the mapping is to an empty array', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"moment": null,
|
||||
"lodash": []
|
||||
}
|
||||
}`);
|
||||
|
||||
expect(() => resolveUnderTest('moment')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('lodash')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
describe('Package-like scenarios', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"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/"
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should work for package main modules', () => {
|
||||
expect(resolveUnderTest('moment')).toMatchURL('https://example.com/node_modules/moment/src/moment.js');
|
||||
expect(resolveUnderTest('lodash-dot')).toMatchURL('https://example.com/app/node_modules/lodash-es/lodash.js');
|
||||
expect(resolveUnderTest('lodash-dotdot')).toMatchURL('https://example.com/node_modules/lodash-es/lodash.js');
|
||||
});
|
||||
|
||||
it('should work for package submodules', () => {
|
||||
expect(resolveUnderTest('moment/foo')).toMatchURL('https://example.com/node_modules/moment/src/foo');
|
||||
expect(resolveUnderTest('lodash-dot/foo')).toMatchURL('https://example.com/app/node_modules/lodash-es/foo');
|
||||
expect(resolveUnderTest('lodash-dotdot/foo')).toMatchURL('https://example.com/node_modules/lodash-es/foo');
|
||||
});
|
||||
|
||||
it('should work for package names that end in a slash by just passing through', () => {
|
||||
// TODO: is this the right behavior, or should we throw?
|
||||
expect(resolveUnderTest('moment/')).toMatchURL('https://example.com/node_modules/moment/src/');
|
||||
});
|
||||
|
||||
it('should still fail for package modules that are not declared', () => {
|
||||
expect(() => resolveUnderTest('underscore/')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('underscore/foo')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tricky specifiers', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"package/withslash": "/node_modules/package-with-slash/index.mjs",
|
||||
"not-a-package": "/lib/not-a-package.mjs",
|
||||
".": "/lib/dot.mjs",
|
||||
"..": "/lib/dotdot.mjs",
|
||||
"..\\\\": "/lib/dotdotbackslash.mjs",
|
||||
"%2E": "/lib/percent2e.mjs",
|
||||
"%2F": "/lib/percent2f.mjs"
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should work for explicitly-mapped specifiers that happen to have a slash', () => {
|
||||
expect(resolveUnderTest('package/withslash')).toMatchURL('https://example.com/node_modules/package-with-slash/index.mjs');
|
||||
});
|
||||
|
||||
it('should work when the specifier has punctuation', () => {
|
||||
expect(resolveUnderTest('.')).toMatchURL('https://example.com/lib/dot.mjs');
|
||||
expect(resolveUnderTest('..')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
expect(resolveUnderTest('..\\')).toMatchURL('https://example.com/lib/dotdotbackslash.mjs');
|
||||
expect(resolveUnderTest('%2E')).toMatchURL('https://example.com/lib/percent2e.mjs');
|
||||
expect(resolveUnderTest('%2F')).toMatchURL('https://example.com/lib/percent2f.mjs');
|
||||
});
|
||||
|
||||
it('should fail for attempting to get a submodule of something not declared with a trailing slash', () => {
|
||||
expect(() => resolveUnderTest('not-a-package/foo')).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('URL-like specifiers', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{
|
||||
"imports": {
|
||||
"/node_modules/als-polyfill/index.mjs": "@std/kv-storage",
|
||||
|
||||
"/lib/foo.mjs": "./more/bar.mjs",
|
||||
"./dotrelative/foo.mjs": "/lib/dot.mjs",
|
||||
"../dotdotrelative/foo.mjs": "/lib/dotdot.mjs",
|
||||
|
||||
"/lib/no.mjs": null,
|
||||
"./dotrelative/no.mjs": [],
|
||||
|
||||
"/": "/lib/slash-only.mjs",
|
||||
"./": "/lib/dotslash-only.mjs",
|
||||
|
||||
"/test": "/lib/test1.mjs",
|
||||
"../test": "/lib/test2.mjs"
|
||||
}
|
||||
}`);
|
||||
|
||||
it('should remap to built-in modules', () => {
|
||||
expect(resolveUnderTest('/node_modules/als-polyfill/index.mjs')).toMatchURL('import:@std/kv-storage');
|
||||
expect(resolveUnderTest('https://example.com/node_modules/als-polyfill/index.mjs')).toMatchURL('import:@std/kv-storage');
|
||||
expect(resolveUnderTest('https://///example.com/node_modules/als-polyfill/index.mjs')).toMatchURL('import:@std/kv-storage');
|
||||
});
|
||||
|
||||
it('should remap to other URLs', () => {
|
||||
expect(resolveUnderTest('https://example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs');
|
||||
expect(resolveUnderTest('https://///example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs');
|
||||
expect(resolveUnderTest('/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs');
|
||||
|
||||
expect(resolveUnderTest('https://example.com/app/dotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dot.mjs');
|
||||
expect(resolveUnderTest('../app/dotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dot.mjs');
|
||||
|
||||
expect(resolveUnderTest('https://example.com/dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
expect(resolveUnderTest('../dotdotrelative/foo.mjs')).toMatchURL('https://example.com/lib/dotdot.mjs');
|
||||
});
|
||||
|
||||
it('should fail for URLs that remap to empty arrays', () => {
|
||||
expect(() => resolveUnderTest('https://example.com/lib/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('/lib/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('../lib/no.mjs')).toThrow(TypeError);
|
||||
|
||||
expect(() => resolveUnderTest('https://example.com/app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('/app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
expect(() => resolveUnderTest('../app/dotrelative/no.mjs')).toThrow(TypeError);
|
||||
});
|
||||
|
||||
it('should remap URLs that are just composed from / and .', () => {
|
||||
expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only.mjs');
|
||||
expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only.mjs');
|
||||
expect(resolveUnderTest('../')).toMatchURL('https://example.com/lib/slash-only.mjs');
|
||||
|
||||
expect(resolveUnderTest('https://example.com/app/')).toMatchURL('https://example.com/lib/dotslash-only.mjs');
|
||||
expect(resolveUnderTest('/app/')).toMatchURL('https://example.com/lib/dotslash-only.mjs');
|
||||
expect(resolveUnderTest('../app/')).toMatchURL('https://example.com/lib/dotslash-only.mjs');
|
||||
});
|
||||
|
||||
it('should use the last entry\'s address when URL-like specifiers parse to the same absolute URL', () => {
|
||||
expect(resolveUnderTest('/test')).toMatchURL('https://example.com/lib/test2.mjs');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,205 @@
|
|||
let log = [];
|
||||
|
||||
function expect_log(test, expected_log) {
|
||||
test.step_func_done(() => {
|
||||
const actual_log = log;
|
||||
log = [];
|
||||
assert_array_equals(actual_log, expected_log, 'fallback log');
|
||||
})();
|
||||
}
|
||||
|
||||
// Results of resolving a specifier using import maps.
|
||||
const Result = {
|
||||
// A built-in module (std:blank) is loaded.
|
||||
BUILTIN: "builtin",
|
||||
|
||||
// A failure considered as a fetch error in a module script tree.
|
||||
// <script>'s error event is fired.
|
||||
FETCH_ERROR: "fetch_error",
|
||||
|
||||
// A failure considered as a parse error in a module script tree.
|
||||
// Window's error event is fired.
|
||||
PARSE_ERROR: "parse_error",
|
||||
|
||||
// The specifier is considered as a relative or absolute URL.
|
||||
// Specifier Expected log
|
||||
// ------------------------- ----------------------
|
||||
// ...?name=foo log:foo
|
||||
// data:...log('foo') foo
|
||||
// Others, e.g. @std/blank relative:@std/blank
|
||||
// ------------------------- ----------------------
|
||||
// (The last case assumes a file `@std/blank` that logs `relative:@std/blank`
|
||||
// exists)
|
||||
URL: "URL",
|
||||
};
|
||||
|
||||
const Handler = {
|
||||
// Handlers for <script> element cases.
|
||||
// Note that on a parse error both WindowErrorEvent and ScriptLoadEvent are
|
||||
// called.
|
||||
ScriptLoadEvent: "<script> element's load event handler",
|
||||
ScriptErrorEvent: "<script> element's error event handler",
|
||||
WindowErrorEvent: "window's error event handler",
|
||||
|
||||
// Handlers for dynamic imports.
|
||||
DynamicImportResolve: "dynamic import resolve",
|
||||
DynamicImportReject: "dynamic import reject",
|
||||
};
|
||||
|
||||
// Returns a map with Handler.* as the keys.
|
||||
function getHandlers(t, specifier, expected) {
|
||||
let handlers = {};
|
||||
handlers[Handler.ScriptLoadEvent] = t.unreached_func("Shouldn't load");
|
||||
handlers[Handler.ScriptErrorEvent] =
|
||||
t.unreached_func("script's error event shouldn't be fired");
|
||||
handlers[Handler.WindowErrorEvent] =
|
||||
t.unreached_func("window's error event shouldn't be fired");
|
||||
handlers[Handler.DynamicImportResolve] =
|
||||
t.unreached_func("dynamic import promise shouldn't be resolved");
|
||||
handlers[Handler.DynamicImportReject] =
|
||||
t.unreached_func("dynamic import promise shouldn't be rejected");
|
||||
|
||||
if (expected === Result.FETCH_ERROR) {
|
||||
handlers[Handler.ScriptErrorEvent] = () => expect_log(t, []);
|
||||
handlers[Handler.DynamicImportReject] = () => expect_log(t, []);
|
||||
} else if (expected === Result.PARSE_ERROR) {
|
||||
let error_occurred = false;
|
||||
handlers[Handler.WindowErrorEvent] = () => { error_occurred = true; };
|
||||
handlers[Handler.ScriptLoadEvent] = t.step_func(() => {
|
||||
// Even if a parse error occurs, load event is fired (after
|
||||
// window.onerror is called), so trigger the load handler only if
|
||||
// there was no previous window.onerror call.
|
||||
assert_true(error_occurred, "window.onerror should be fired");
|
||||
expect_log(t, []);
|
||||
});
|
||||
handlers[Handler.DynamicImportReject] = t.step_func(() => {
|
||||
assert_false(error_occurred,
|
||||
"window.onerror shouldn't be fired for dynamic imports");
|
||||
expect_log(t, []);
|
||||
});
|
||||
} else {
|
||||
let expected_log;
|
||||
if (expected === Result.BUILTIN) {
|
||||
expected_log = [];
|
||||
} else if (expected === Result.URL) {
|
||||
const match_data_url = specifier.match(/data:.*log\.push\('(.*)'\)/);
|
||||
const match_log_js = specifier.match(/name=(.*)/);
|
||||
if (match_data_url) {
|
||||
expected_log = [match_data_url[1]];
|
||||
} else if (match_log_js) {
|
||||
expected_log = ["log:" + match_log_js[1]];
|
||||
} else {
|
||||
expected_log = ["relative:" + specifier];
|
||||
}
|
||||
} else {
|
||||
expected_log = [expected];
|
||||
}
|
||||
handlers[Handler.ScriptLoadEvent] = () => expect_log(t, expected_log);
|
||||
handlers[Handler.DynamicImportResolve] = () => expect_log(t, expected_log);
|
||||
}
|
||||
return handlers;
|
||||
}
|
||||
|
||||
// Creates an <iframe> and run a test inside the <iframe>
|
||||
// to separate the module maps and import maps in each test.
|
||||
function testInIframe(importMapString, importMapBaseURL, testScript) {
|
||||
const iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
if (!importMapBaseURL) {
|
||||
importMapBaseURL = document.baseURI;
|
||||
}
|
||||
let content = `
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/import-maps/resources/test-helper.js"></script>
|
||||
<base href="${importMapBaseURL}">
|
||||
`;
|
||||
if (importMapString) {
|
||||
content += `
|
||||
<script type="importmap">
|
||||
${importMapString}
|
||||
</sc` + `ript>
|
||||
`;
|
||||
}
|
||||
content += `
|
||||
<body>
|
||||
<script>
|
||||
setup({ allow_uncaught_exception: true });
|
||||
${testScript}
|
||||
</sc` + `ript>
|
||||
`;
|
||||
iframe.contentDocument.write(content);
|
||||
iframe.contentDocument.close();
|
||||
fetch_tests_from_window(iframe.contentWindow);
|
||||
}
|
||||
|
||||
function testScriptElement(importMapString, importMapBaseURL, specifier, expected, type) {
|
||||
testInIframe(importMapString, importMapBaseURL, `
|
||||
const t = async_test("${specifier}: <script src type=${type}>");
|
||||
const handlers = getHandlers(t, "${specifier}", "${expected}");
|
||||
const script = document.createElement("script");
|
||||
script.setAttribute("type", "${type}");
|
||||
script.setAttribute("src", "${specifier}");
|
||||
script.addEventListener("load", handlers[Handler.ScriptLoadEvent]);
|
||||
script.addEventListener("error", handlers[Handler.ScriptErrorEvent]);
|
||||
window.addEventListener("error", handlers[Handler.WindowErrorEvent]);
|
||||
document.body.appendChild(script);
|
||||
`);
|
||||
}
|
||||
|
||||
function testStaticImport(importMapString, importMapBaseURL, specifier, expected) {
|
||||
testInIframe(importMapString, importMapBaseURL, `
|
||||
const t = async_test("${specifier}: static import");
|
||||
const handlers = getHandlers(t, "${specifier}", "${expected}");
|
||||
const script = document.createElement("script");
|
||||
script.setAttribute("type", "module");
|
||||
script.setAttribute("src",
|
||||
"/import-maps/static-import.js?pipe=sub(none)&url=" +
|
||||
encodeURIComponent("${specifier}"));
|
||||
script.addEventListener("load", handlers[Handler.ScriptLoadEvent]);
|
||||
script.addEventListener("error", handlers[Handler.ScriptErrorEvent]);
|
||||
window.addEventListener("error", handlers[Handler.WindowErrorEvent]);
|
||||
document.body.appendChild(script);
|
||||
`);
|
||||
}
|
||||
|
||||
function testDynamicImport(importMapString, importMapBaseURL, specifier, expected, type) {
|
||||
testInIframe(importMapString, importMapBaseURL, `
|
||||
const t = async_test("${specifier}: dynamic import (from ${type})");
|
||||
const handlers = getHandlers(t, "${specifier}", "${expected}");
|
||||
const script = document.createElement("script");
|
||||
script.setAttribute("type", "${type}");
|
||||
script.innerText =
|
||||
"import(\\"${specifier}\\")" +
|
||||
".then(handlers[Handler.DynamicImportResolve], " +
|
||||
"handlers[Handler.DynamicImportReject]);";
|
||||
script.addEventListener("error",
|
||||
t.unreached_func("top-level inline script shouldn't error"));
|
||||
document.body.appendChild(script);
|
||||
`);
|
||||
}
|
||||
|
||||
function doTests(importMapString, importMapBaseURL, tests) {
|
||||
window.addEventListener("load", () => {
|
||||
for (const specifier in tests) {
|
||||
// <script src> (module scripts)
|
||||
testScriptElement(importMapString, importMapBaseURL, specifier,
|
||||
tests[specifier][0], "module");
|
||||
|
||||
// <script src> (classic scripts)
|
||||
testScriptElement(importMapString, importMapBaseURL, specifier,
|
||||
tests[specifier][1], "text/javascript");
|
||||
|
||||
// static imports.
|
||||
testStaticImport(importMapString, importMapBaseURL, specifier,
|
||||
tests[specifier][2]);
|
||||
|
||||
// dynamic imports from a module script.
|
||||
testDynamicImport(importMapString, importMapBaseURL, specifier,
|
||||
tests[specifier][3], "module");
|
||||
|
||||
// dynamic imports from a classic script.
|
||||
testDynamicImport(importMapString, importMapBaseURL, specifier,
|
||||
tests[specifier][3], "text/javascript");
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
import "{{GET[url]}}";
|
|
@ -78,12 +78,12 @@ callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame)
|
|||
[SecureContext, Exposed=Window] interface XRFrame {
|
||||
readonly attribute XRSession session;
|
||||
|
||||
XRViewerPose? getViewerPose(optional XRReferenceSpace referenceSpace);
|
||||
XRInputPose? getInputPose(XRInputSource inputSource, optional XRReferenceSpace referenceSpace);
|
||||
XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
|
||||
XRPose? getPose(XRSpace space, XRSpace relativeTo);
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window] interface XRSpace : EventTarget {
|
||||
XRRigidTransform? getTransformTo(XRSpace other);
|
||||
|
||||
};
|
||||
|
||||
enum XRReferenceSpaceType {
|
||||
|
@ -159,8 +159,12 @@ interface XRRay {
|
|||
readonly attribute Float32Array matrix;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window] interface XRViewerPose {
|
||||
[SecureContext, Exposed=Window] interface XRPose {
|
||||
readonly attribute XRRigidTransform transform;
|
||||
readonly attribute boolean emulatedPosition;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window] interface XRViewerPose : XRPose {
|
||||
readonly attribute FrozenArray<XRView> views;
|
||||
};
|
||||
|
||||
|
@ -180,13 +184,8 @@ enum XRTargetRayMode {
|
|||
interface XRInputSource {
|
||||
readonly attribute XRHandedness handedness;
|
||||
readonly attribute XRTargetRayMode targetRayMode;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window]
|
||||
interface XRInputPose {
|
||||
readonly attribute boolean emulatedPosition;
|
||||
readonly attribute XRRay targetRay;
|
||||
readonly attribute XRRigidTransform? gripTransform;
|
||||
readonly attribute XRSpace targetRaySpace;
|
||||
readonly attribute XRSpace? gripSpace;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window] interface XRLayer {};
|
||||
|
|
|
@ -72,7 +72,15 @@
|
|||
// notifications.
|
||||
function waitForNotification(t, f) {
|
||||
requestAnimationFrame(function() {
|
||||
requestAnimationFrame(function() { t.step_timeout(f); });
|
||||
requestAnimationFrame(function() { t.step_timeout(f, 0); });
|
||||
});
|
||||
}
|
||||
|
||||
// If you need to wait until the IntersectionObserver algorithm has a chance
|
||||
// to run, but don't need to wait for delivery of the notifications...
|
||||
function waitForFrame(t, f) {
|
||||
requestAnimationFrame(function() {
|
||||
t.step_timeout(f, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -85,9 +93,19 @@ function waitForNotification(t, f) {
|
|||
//
|
||||
// Following these rules will ensure that the test suite will not abort before
|
||||
// all test steps have run.
|
||||
function runTestCycle(f, description) {
|
||||
//
|
||||
// If the 'delay' parameter to the IntersectionObserver constructor is used,
|
||||
// tests will need to add the same delay to their runTestCycle invocations, to
|
||||
// wait for notifications to be generated and delivered.
|
||||
function runTestCycle(f, description, delay) {
|
||||
async_test(function(t) {
|
||||
waitForNotification(t, t.step_func_done(f));
|
||||
if (delay) {
|
||||
step_timeout(() => {
|
||||
waitForNotification(t, t.step_func_done(f));
|
||||
}, delay);
|
||||
} else {
|
||||
waitForNotification(t, t.step_func_done(f));
|
||||
}
|
||||
}, description);
|
||||
}
|
||||
|
||||
|
@ -174,4 +192,4 @@ function checkJsonEntries(actual, expected, description) {
|
|||
function checkIsIntersecting(entries, i, expected) {
|
||||
assert_equals(entries[i].isIntersecting, expected,
|
||||
'entries[' + i + '].target.isIntersecting equals ' + expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<div id="target">target</div>
|
||||
<script>
|
||||
var delay = 100;
|
||||
var results = [];
|
||||
|
||||
function waitForNotification(f) {
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(function () {
|
||||
requestAnimationFrame(function () {
|
||||
setTimeout(f)
|
||||
})
|
||||
})
|
||||
}, delay)
|
||||
}
|
||||
|
||||
window.addEventListener("message", event => {
|
||||
waitForNotification(() => {
|
||||
window.parent.postMessage(results.map(e => e.isVisible), "*");
|
||||
results = [];
|
||||
});
|
||||
});
|
||||
|
||||
onload = () => {
|
||||
var target = document.getElementById("target");
|
||||
var observer = new IntersectionObserver(entries => {
|
||||
results = entries;
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(document.getElementById("target"));
|
||||
window.parent.postMessage("", "*");
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
#occluder {
|
||||
will-change: transform;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="target"></div>
|
||||
<div id="occluder"></div>
|
||||
|
||||
<script>
|
||||
var vw = document.documentElement.clientWidth;
|
||||
var vh = document.documentElement.clientHeight;
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
var occluder;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.getElementById("target");
|
||||
occluder = document.getElementById("occluder");
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!occluder, "occluder exists");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 in a single document using the implicit root, with an animated occluding element.", delay);
|
||||
|
||||
function step0() {
|
||||
occluder.style.animation = "rotate .1s linear";
|
||||
step_timeout(() => {
|
||||
runTestCycle(step1, "occluder.style.animation = 'rotate .1s linear'", delay);
|
||||
}, 50);
|
||||
checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, vw, 0, vh, true, true]);
|
||||
}
|
||||
|
||||
function step1() {
|
||||
checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, vw, 0, vh, true, false]);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
#occluder {
|
||||
margin-top: 10px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: blue;
|
||||
filter: blur(50px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="target"></div>
|
||||
<div id="occluder"></div>
|
||||
|
||||
<script>
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
var occluder;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.getElementById("target");
|
||||
occluder = document.getElementById("occluder");
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!occluder, "occluder exists");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
|
||||
|
||||
function step0() {
|
||||
// Occluding elements with opacity=0 should not affect target visibility.
|
||||
occluder.style.opacity = "0";
|
||||
runTestCycle(step2, "occluder.style.opacity = 0", delay);
|
||||
|
||||
// First notification should report occlusion due to blur filter.
|
||||
checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
|
||||
}
|
||||
|
||||
function step2() {
|
||||
checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
iframe {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 0;
|
||||
}
|
||||
#box-shadow {
|
||||
display: inline-block;
|
||||
box-shadow: -50px -50px 0 50px rgba(255, 0, 0, 0.7);
|
||||
}
|
||||
</style>
|
||||
|
||||
<iframe id=target srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe><div id=box-shadow></div>
|
||||
|
||||
<script>
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
var occluder;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.getElementById("target");
|
||||
occluder = document.getElementById("box-shadow");
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!occluder, "occluder exists");
|
||||
let observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 observing an iframe element.", delay);
|
||||
|
||||
function step0() {
|
||||
occluder.style.boxShadow = "none";
|
||||
runTestCycle(step1, 'occluder.style.boxShadow = "none"', delay);
|
||||
assert_equals(entries.length, 1, "Initial notification.");
|
||||
assert_equals(entries[0].isVisible, false, "Initially occluded.");
|
||||
}
|
||||
|
||||
function step1() {
|
||||
occluder.style.boxShadow = "";
|
||||
runTestCycle(step2, 'occluder.style.boxShadow = ""', delay);
|
||||
assert_equals(entries.length, 2, "Notification after removing box shadow.");
|
||||
assert_equals(entries[1].isVisible, true, "Visible when box shadow removed.");
|
||||
}
|
||||
|
||||
function step2() {
|
||||
assert_equals(entries.length, 3, "Notification after re-adding box shadow.");
|
||||
assert_equals(entries[2].isVisible, false, "Occluded when box shadow re-added.");
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="container">
|
||||
<iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/intersection-observer/resources/v2-subframe.html"></iframe>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async_test(function(t) {
|
||||
let container = document.getElementById("container");
|
||||
let iframe = document.querySelector("iframe");
|
||||
|
||||
function step0(event) {
|
||||
assert_equals(event.data,"");
|
||||
}
|
||||
|
||||
function step1(event) {
|
||||
container.style.opacity = "0.99";
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([true]));
|
||||
}
|
||||
|
||||
function step2(event) {
|
||||
container.style.opacity = "";
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([false]));
|
||||
}
|
||||
|
||||
function step3(event) {
|
||||
container.style.transform = "skew(30deg)";
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([true]));
|
||||
}
|
||||
|
||||
function step4(event) {
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([false]));
|
||||
}
|
||||
|
||||
let steps = [step0, step1, step2, step3, step4];
|
||||
|
||||
window.addEventListener("message", event => {
|
||||
if (steps.length) {
|
||||
t.step_func(steps.shift(), event);
|
||||
waitForFrame(t, () => {
|
||||
iframe.contentWindow.postMessage("", "*")
|
||||
});
|
||||
} else {
|
||||
t.done();
|
||||
}
|
||||
});
|
||||
|
||||
}, "Intersection observer V2 test with visual effects on iframe.");
|
||||
</script>
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
iframe {
|
||||
width: 300px;
|
||||
height: 150px;
|
||||
border: none;
|
||||
}
|
||||
#occluder {
|
||||
will-change: transform;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
|
||||
<iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/intersection-observer/resources/v2-subframe.html"></iframe>
|
||||
<div id="occluder"></div>
|
||||
|
||||
<script>
|
||||
async_test(function(t) {
|
||||
let iframe = document.querySelector("iframe");
|
||||
let occluder = document.getElementById("occluder");
|
||||
|
||||
function step0(event) {
|
||||
assert_equals(event.data,"");
|
||||
}
|
||||
|
||||
function step1(event) {
|
||||
occluder.style.marginTop = "-150px";
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([true]));
|
||||
}
|
||||
|
||||
function step2(event) {
|
||||
occluder.style.marginTop = "";
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([false]));
|
||||
}
|
||||
|
||||
function step3(event) {
|
||||
assert_equals(JSON.stringify(event.data),
|
||||
JSON.stringify([true]));
|
||||
}
|
||||
|
||||
let steps = [step0, step1, step2, step3];
|
||||
|
||||
window.addEventListener("message", event => {
|
||||
if (steps.length) {
|
||||
t.step_func(steps.shift(), event);
|
||||
waitForFrame(t, () => {
|
||||
iframe.contentWindow.postMessage("", "*");
|
||||
});
|
||||
} else {
|
||||
t.done();
|
||||
}
|
||||
});
|
||||
|
||||
}, "Intersection observer V2 test with occlusion of target in iframe.");
|
||||
</script>
|
|
@ -0,0 +1,75 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
#occluder {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="target"></div>
|
||||
<div id="occluder"></div>
|
||||
|
||||
<script>
|
||||
async_test(t => {
|
||||
let entries = [];
|
||||
let delay = 100;
|
||||
let target = document.getElementById("target");
|
||||
let occluder = document.getElementById("occluder");
|
||||
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!occluder, "occluder exists");
|
||||
let observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
// The first notification should be sent without delay.
|
||||
waitForNotification(t, t.step_func(step0));
|
||||
|
||||
function waitForDelay(timerExpiredBeforeLastFrame) {
|
||||
requestAnimationFrame(t.step_func(() => {
|
||||
if (timerExpiredBeforeLastFrame) {
|
||||
// New notifications should have been generated during the previous
|
||||
// frame and delivered by now.
|
||||
assert_equals(entries.length, 2);
|
||||
assert_greater_than(entries[1].time - entries[0].time, delay);
|
||||
assert_false(entries[1].isVisible);
|
||||
t.done();
|
||||
} else {
|
||||
// Observer may not have updated yet. Wait for next frame.
|
||||
let timerExpired = performance.now() - entries[0].time >= delay;
|
||||
waitForDelay(timerExpired);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function step0() {
|
||||
assert_equals(entries.length, 1);
|
||||
assert_true(entries[0].isVisible);
|
||||
// This should trigger a notification on the next run.
|
||||
occluder.style.marginTop = "-10px";
|
||||
// Enter a rAF loop until the delay timer expires.
|
||||
waitForDelay(false);
|
||||
}
|
||||
|
||||
}, "'delay' parameter throttles frequency of notifications.");
|
||||
</script>
|
|
@ -0,0 +1,44 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
iframe {
|
||||
width: 150px;
|
||||
height: 100px;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<iframe srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe>
|
||||
|
||||
<script>
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.querySelector("iframe");
|
||||
assert_true(!!target, "target exists");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 observing an iframe element.", delay);
|
||||
|
||||
function step0() {
|
||||
checkLastEntry(entries, 0, [0, 150, 0, 100, 0, 150, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,71 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
#effects {
|
||||
opacity: 1;
|
||||
filter: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="effects">
|
||||
<div id="target"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
var effects;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.getElementById("target");
|
||||
effects = document.getElementById("effects");
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!effects, "effects exists");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 in a single document using the implicit root, with a non-zero opacity ancestor.", delay);
|
||||
|
||||
function step0() {
|
||||
effects.style.opacity = "0.99";
|
||||
runTestCycle(step1, "effects.style.opacity = 0.99", delay);
|
||||
checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
|
||||
function step1() {
|
||||
effects.style.opacity = "1";
|
||||
runTestCycle(step2, "effects.style.opacity = 1", delay);
|
||||
checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
|
||||
}
|
||||
|
||||
function step2() {
|
||||
effects.style.filter = "grayscale(50%)";
|
||||
runTestCycle(step3, "effects.style.filter = grayscale(50%)", delay);
|
||||
checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
|
||||
function step3() {
|
||||
checkLastEntry(entries, 3, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
#occluder {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="target"></div>
|
||||
<svg id="svg" style="display: block">
|
||||
<foreignObject>
|
||||
<div id="occluder"></div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
var occluder;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.getElementById("target");
|
||||
occluder = document.getElementById("occluder");
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!occluder, "occluder exists");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
|
||||
|
||||
function step0() {
|
||||
svg.style.marginTop = "-10px";
|
||||
runTestCycle(step1, "svg.style.marginTop = '-10px'", delay);
|
||||
checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
|
||||
function step1() {
|
||||
// Occluding elements with opacity=0 should not affect target visibility.
|
||||
svg.style.opacity = "0";
|
||||
runTestCycle(step2, "occluder.style.opacity = 0", delay);
|
||||
checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
|
||||
}
|
||||
|
||||
function step2() {
|
||||
checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../resources/intersection-observer-test-utils.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
}
|
||||
pre, #log {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
#occluder {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="target"></div>
|
||||
<div id="occluder"></div>
|
||||
|
||||
<script>
|
||||
var delay = 100;
|
||||
var entries = [];
|
||||
var target;
|
||||
var occluder;
|
||||
|
||||
runTestCycle(function() {
|
||||
target = document.getElementById("target");
|
||||
occluder = document.getElementById("occluder");
|
||||
assert_true(!!target, "target exists");
|
||||
assert_true(!!occluder, "occluder exists");
|
||||
var observer = new IntersectionObserver(function(changes) {
|
||||
entries = entries.concat(changes)
|
||||
}, {trackVisibility: true, delay: delay});
|
||||
observer.observe(target);
|
||||
entries = entries.concat(observer.takeRecords());
|
||||
assert_equals(entries.length, 0, "No initial notifications.");
|
||||
runTestCycle(step0, "First rAF.", delay);
|
||||
}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
|
||||
|
||||
function step0() {
|
||||
occluder.style.marginTop = "-10px";
|
||||
runTestCycle(step1, "occluder.style.marginTop = '-10px'", delay);
|
||||
checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
|
||||
function step1() {
|
||||
// Occluding elements with opacity=0 should not affect target visibility.
|
||||
occluder.style.opacity = "0";
|
||||
runTestCycle(step2, "occluder.style.opacity = 0", delay);
|
||||
checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
|
||||
}
|
||||
|
||||
function step2() {
|
||||
checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
|
||||
}
|
||||
</script>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue