Update web-platform-tests to revision 548818eee08f7a6e31b9706b352b5d44b2f6d024

This commit is contained in:
WPT Sync Bot 2019-12-12 08:22:50 +00:00
parent 82fd8d1daf
commit 5e74467d68
112 changed files with 1704 additions and 536 deletions

View file

@ -7,7 +7,7 @@
expected: FAIL
[Opening a blob URL in a new window immediately before revoking it works.]
expected: FAIL
expected: TIMEOUT
[Opening a blob URL in a noopener about:blank window immediately before revoking it works.]
expected: FAIL

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,2 @@
[no-transition-from-ua-to-blocking-stylesheet.html]
expected: TIMEOUT
expected: FAIL

View file

@ -0,0 +1,8 @@
[MediaQueryList-extends-EventTarget.html]
expected: TIMEOUT
[removeEventListener removes listener]
expected: NOTRUN
[addEventListener "once" option is respected]
expected: TIMEOUT

View file

@ -84,3 +84,45 @@
[Inserting a custom element into a detached shadow tree that belongs to an HTML document fetched by XHR must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into the document of the template elements must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into an HTML document fetched by XHR must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into the document of an iframe must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into a cloned document must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into an HTML document fetched by XHR must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into a document created by createHTMLDocument must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into a new document must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into an HTML document created by createDocument must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into a cloned document must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into a document created by createHTMLDocument must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into the document of the template elements must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into the document of an iframe must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the shadow host's shadow of a custom element from the owner document into a new document must enqueue and invoke adoptedCallback]
expected: FAIL
[Moving the <template>'s content of a custom element from the owner document into an HTML document created by createDocument must enqueue and invoke adoptedCallback]
expected: FAIL

View file

@ -0,0 +1,16 @@
[adoption.window.html]
[appendChild() and DocumentFragment]
expected: FAIL
[appendChild() and ShadowRoot]
expected: FAIL
[adoptNode() and ShadowRoot]
expected: FAIL
[adoptNode() and DocumentFragment with host]
expected: FAIL
[appendChild() and DocumentFragment with host]
expected: FAIL

View file

@ -38,6 +38,9 @@
[Redirect 307 with HEAD]
expected: FAIL
[Redirect 303 with TESTING]
expected: FAIL
[redirect-method.any.html]
[Redirect 301 with GET]
@ -79,3 +82,6 @@
[Redirect 307 with HEAD]
expected: FAIL
[Redirect 303 with TESTING]
expected: FAIL

View file

@ -309,3 +309,24 @@
[<iframe>: separate response Content-Type: */* text/html]
expected: FAIL
[<iframe>: combined response Content-Type: */* text/html]
expected: FAIL
[<iframe>: separate response Content-Type: text/html;" text/plain]
expected: FAIL
[<iframe>: separate response Content-Type: text/html */*;charset=gbk]
expected: FAIL
[<iframe>: separate response Content-Type: text/html */*]
expected: FAIL
[<iframe>: separate response Content-Type: text/html;" \\" text/plain]
expected: FAIL
[<iframe>: combined response Content-Type: text/html;x=" text/plain]
expected: FAIL
[<iframe>: separate response Content-Type: text/plain */*;charset=gbk]
expected: FAIL

View file

@ -11,3 +11,6 @@
[X-Content-Type-Options%3A%20nosniff%0C]
expected: FAIL
[X-Content-Type-Options%3A%20'NosniFF']
expected: FAIL

View file

@ -11,7 +11,7 @@
expected: TIMEOUT
[Embedded credentials matching the top-level are treated as network errors for cross-origin URLs.]
expected: TIMEOUT
expected: FAIL
[Embedded credentials matching the top-level are not treated as network errors for same-origin URLs.]
expected: TIMEOUT

View file

@ -1,4 +0,0 @@
[traverse_the_history_1.html]
[Multiple history traversals from the same task]
expected: FAIL

View file

@ -0,0 +1,4 @@
[traverse_the_history_5.html]
[Multiple history traversals, last would be aborted]
expected: FAIL

View file

@ -0,0 +1,4 @@
[document-domain-nested-navigate.window.html]
[Navigated frame to about:blank and document.domain]
expected: FAIL

View file

@ -1,4 +1,5 @@
[supported-elements.html]
expected: TIMEOUT
[Contenteditable element should support autofocus]
expected: FAIL
@ -9,7 +10,7 @@
expected: FAIL
[Area element should support autofocus]
expected: FAIL
expected: TIMEOUT
[Host element with delegatesFocus should support autofocus]
expected: FAIL

View file

@ -2,3 +2,6 @@
[Mutating the style element: mutating a Comment node]
expected: FAIL
[Mutating the style element: inserting an empty DocumentFragment node]
expected: FAIL

View file

@ -1,6 +1,5 @@
[iframe_sandbox_popups_escaping-3.html]
type: testharness
expected: TIMEOUT
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: TIMEOUT
expected: FAIL

View file

@ -90,3 +90,12 @@
[[INPUT in NUMBER status\] The value attribute is empty string]
expected: FAIL
[[INPUT in NUMBER status\] Step mismatch when step is a very small floating number and value is not its integral multiple]
expected: FAIL
[[INPUT in NUMBER status\] No step mismatch when step is a floating number in exponent format and value is its integral multiple]
expected: FAIL
[[INPUT in NUMBER status\] No step mismatch when step is a floating number and value is its integral multiple]
expected: FAIL

View file

@ -8,7 +8,7 @@
expected: FAIL
[Check that rel=noopener with target=_top does a normal load]
expected: TIMEOUT
expected: FAIL
[Check that targeting of rel=noopener with a given name reuses an existing window with that name]
expected: NOTRUN

View file

@ -1,4 +1,5 @@
[crossorigin-sandwich-TAO.sub.html]
expected: ERROR
[There should be one entry.]
expected: FAIL

View file

@ -1,5 +0,0 @@
[018.html]
expected: TIMEOUT
[origin of the script that invoked the method, javascript:]
expected: TIMEOUT

View file

@ -0,0 +1,5 @@
[017.html]
expected: TIMEOUT
[origin of the script that invoked the method, about:blank]
expected: TIMEOUT

View file

@ -1,5 +0,0 @@
[018.html]
expected: TIMEOUT
[origin of the script that invoked the method, javascript:]
expected: TIMEOUT

View file

@ -362,7 +362,6 @@ jobs:
- template: tools/ci/azure/pip_install.yml
parameters:
packages: virtualenv
- template: tools/ci/azure/install_fonts.yml
- template: tools/ci/azure/install_certs.yml
- template: tools/ci/azure/install_safari.yml
- template: tools/ci/azure/update_hosts.yml

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<title>setTransform with DOMMatrix behaves correctly</title>
<html class="reftest-wait">
<link rel="help" href="https://drafts.css-houdini.org/css-paint-api/">
<link rel="match" href="setTransform-ref.html">
<style>
.container {
width: 200px;
height: 200px;
}
#foo {
background: paint(foo);
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="foo" class="container"></div>
<script id="code" type="text/worklet">
registerPaint('foo', class {
paint(ctx, geom) {
ctx.fillStyle = 'green';
let m = ctx.getTransform();
m.a = 2;
m.d = 2;
ctx.setTransform(m);
ctx.fillRect(0, 0, 50, 50);
}
});
</script>
<script>
importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<title>setTransform with DOMMatrix behaves correctly</title>
<html class="reftest-wait">
<link rel="help" href="https://drafts.css-houdini.org/css-paint-api/">
<link rel="match" href="setTransform-ref.html">
<style>
.container {
width: 200px;
height: 200px;
}
#foo {
background: paint(foo);
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="foo" class="container"></div>
<script id="code" type="text/worklet">
registerPaint('foo', class {
paint(ctx, geom) {
ctx.fillStyle = 'green';
ctx.setTransform({a: 2, d: 2});
ctx.fillRect(0, 0, 50, 50);
}
});
</script>
<script>
importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<title>setTransform with NaN should be ignored</title>
<html class="reftest-wait">
<link rel="help" href="https://drafts.css-houdini.org/css-paint-api/">
<link rel="match" href="setTransform-ref.html">
<style>
.container {
width: 200px;
height: 200px;
}
#foo {
background: paint(foo);
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="foo" class="container"></div>
<script id="code" type="text/worklet">
registerPaint('foo', class {
paint(ctx, geom) {
ctx.fillStyle = 'green';
// Set to a NaN should be ignored.
ctx.setTransform({a: NaN, d:2});
ctx.fillRect(0, 0, 100, 100);
}
});
</script>
<script>
importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<title>setTransform with Infinity should be ignored</title>
<html class="reftest-wait">
<link rel="help" href="https://drafts.css-houdini.org/css-paint-api/">
<link rel="match" href="setTransform-ref.html">
<style>
.container {
width: 200px;
height: 200px;
}
#foo {
background: paint(foo);
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="foo" class="container"></div>
<script id="code" type="text/worklet">
registerPaint('foo', class {
paint(ctx, geom) {
ctx.fillStyle = 'green';
// Set to Infinity should be ignored.
ctx.setTransform({a: Infinity, d:2});
ctx.fillRect(0, 0, 100, 100);
}
});
</script>
<script>
importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<canvas id ="canvas" width="200" height="200"></canvas>
<script>
var ctx = document.getElementById('canvas').getContext('2d');
ctx.fillStyle = 'green';
let m = ctx.getTransform();
m.a = 2;
m.d = 2;
ctx.setTransform(m);
ctx.fillRect(0, 0, 50, 50);
</script>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1432">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<style>
#containing-block {
position: relative;
width: 100px;
height: 100px;
background: red;
display: flex;
}
#containing-block > div {
flex-grow: 1;
}
#inner-flex {
display: flex;
justify-content: center;
}
span {
display: inline-block;
inline-size: 50px;
block-size: 10px;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div id="containing-block" style="flex-direction: row;">
<div id="inner-flex" style="margin: 10px; height: 100px;">
<div style="position: absolute; top: 0; height: 100px; background: green;">
<span></span>
<span></span>
</div>
</div>
<div style="height: 100px; background: green;"></div>
</div>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1432">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<style>
#containing-block {
position: relative;
width: 100px;
height: 100px;
background: red;
display: flex;
}
#containing-block > div {
flex-grow: 1;
}
#inner-flex {
display: flex;
align-items: center;
}
span {
display: inline-block;
inline-size: 50px;
block-size: 10px;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div id="containing-block" style="flex-direction: column;">
<div id="inner-flex" style="margin: 10px; width: 100px;">
<div style="position: absolute; left: 0; width: 100px; background: green; writing-mode: vertical-rl;">
<span></span>
<span></span>
</div>
</div>
<div style="width: 100px; background: green;"></div>
</div>

View file

@ -2,6 +2,7 @@
<meta charset="utf-8" />
<title>CSS Reftest Reference</title>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="mismatch" href="marker-font-variant-numeric-normal-ref.html">
<style>
@font-face {
/* This font looks different with 'font-variant-numeric: tabular-nums' */

View file

@ -4,7 +4,6 @@
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<link rel="match" href="marker-font-variant-numeric-default-ref.html">
<link rel="mismatch" href="marker-font-variant-numeric-normal-ref.html">
<meta name="assert" content="Checks that the markers have the same width thanks to 'font-variant-numeric: tabular-nums', and thus the black boxes are perfectly aligned">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>

View file

@ -2,6 +2,7 @@
<meta charset="utf-8" />
<title>CSS Reftest Reference</title>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="mismatch" href="marker-font-variant-numeric-default-ref.html">
<style>
@font-face {
/* This font looks different with 'font-variant-numeric: tabular-nums' */

View file

@ -4,7 +4,6 @@
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<link rel="match" href="marker-font-variant-numeric-normal-ref.html">
<link rel="mismatch" href="marker-font-variant-numeric-default-ref.html">
<meta name="assert" content="Checks that the marker default 'font-variant-numeric: tabular-nums' can be overridden with 'font-variant-numeric: normal'">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>

View file

@ -2,6 +2,7 @@
<meta charset="utf-8" />
<title>CSS Reftest Reference</title>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="mismatch" href="marker-unicode-bidi-normal-ref.html">
<style>
ol {
float: left;

View file

@ -4,7 +4,6 @@
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<link rel="match" href="marker-unicode-bidi-default-ref.html">
<link rel="mismatch" href="marker-unicode-bidi-normal-ref.html">
<meta name="assert" content="Checks that the markers are isolated from the list items by the bidi algorithm">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>

View file

@ -2,6 +2,7 @@
<meta charset="utf-8" />
<title>CSS Reftest Reference</title>
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="mismatch" href="marker-unicode-bidi-default-ref.html">
<style>
ol {
float: left;

View file

@ -4,7 +4,6 @@
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
<link rel="match" href="marker-unicode-bidi-normal-ref.html">
<link rel="mismatch" href="marker-unicode-bidi-default-ref.html">
<meta name="assert" content="Checks that the marker default 'unicode-bidi: isolate' can be overridden with 'unicode-bidi: normal'">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>

View file

@ -9,6 +9,7 @@ div {
font-size: 10px;
font-family: Ahem;
width: 5.1ch;
border: 1px solid blue;
}
</style>
<body>
@ -18,4 +19,7 @@ div {
<div>1234&shy;xx</div>
<div>12345&shy;xx</div>
<div>123456&shy;xx</div>
<div style="width: 10ch"><span>ren&shy;for&shy;cer</span>99999</div>
<div><span>00&shy;1</span>222</div>
</body>

View file

@ -4,6 +4,8 @@
div {
font-size: 10px;
font-family: Ahem;
width: 5.1ch;
border: 1px solid blue;
}
</style>
<body>
@ -13,4 +15,7 @@ div {
<div>1234-<br>xx</div>
<div>12345-<br>xx</div>
<div>123456-<br>xx</div>
<div style="width: 10ch">renfor-<br>cer99999</div>
<div>00-<br>1222</div>
</body>

View file

@ -2,6 +2,7 @@
<meta charset=utf-8>
<title>CSS Typed OM IDL</title>
<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#idl-index">
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/WebIDLParser.js"></script>

View file

@ -51,7 +51,9 @@ var getWindow = mql => {
var waitForChangesReported = () => {
return new Promise(resolve => {
step_timeout(resolve, 75);
requestAnimationFrame(() => {
requestAnimationFrame(resolve);
});
});
};

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<title>CSS Motion Path: offset-anchor with transform-box: fill-box on the svg g element</title>
<link rel="help" href="https://drafts.fxtf.org/motion-1/#offset-anchor-property">
<link rel="match" href="offset-anchor-transform-box-fill-box-ref.html">
<meta name="assert" content="Tests offset-anchor together with a fill-box transform-box on the <g> element">
<style>
#target {
transform-box: fill-box;
offset-anchor: 25% 25%;
offset-path: path("M75,-25v100");
offset-distance: 50%;
}
</style>
<svg width="400" height="400">
<rect width="100" height="100" fill="red"/>
<g id='target'>
<rect x="150" y="100" width="100" height="100" fill="green"/>
</g>
</svg>

View file

@ -117,6 +117,38 @@ document_types().forEach(function (entry) {
});
}, 'Moving the shadow host of a custom element from the owner document into ' + documentName + ' must enqueue and invoke adoptedCallback');
promise_test(function () {
return getDocument().then(function (doc) {
const instance = document.createElement('my-custom-element');
const host = document.createElement('div');
const shadowRoot = host.attachShadow({mode: 'closed'});
shadowRoot.appendChild(instance);
document.body.appendChild(host);
calls = [];
doc.documentElement.appendChild(shadowRoot);
assert_array_equals(calls, ['disconnected', 'adopted', document, doc, 'connected']);
});
}, 'Moving the shadow host\'s shadow of a custom element from the owner document into ' + documentName + ' must enqueue and invoke adoptedCallback');
promise_test(function () {
return getDocument().then(function (doc) {
const instance = document.createElement('my-custom-element');
const template = document.createElement('template');
const templateContent = template.content;
templateContent.appendChild(instance);
document.body.appendChild(template);
calls = [];
doc.documentElement.appendChild(templateContent);
if (doc === templateContent.ownerDocument) {
assert_array_equals(calls, ['connected']);
} else {
assert_array_equals(calls, ['adopted', templateContent.ownerDocument, doc, 'connected']);
}
});
}, 'Moving the <template>\'s content of a custom element from the owner document into ' + documentName + ' must enqueue and invoke adoptedCallback');
promise_test(function () {
return getDocument().then(function (doc) {
var instance = document.createElement('my-custom-element');

View file

@ -29,8 +29,8 @@ Test authors are encouraged to use the builder API to generate the sequence of a
API can be accessed via the `new test_driver.Actions()` object, and actions are defined in [testdriver-actions.js](https://github.com/web-platform-tests/wpt/blob/master/resources/testdriver-actions.js)
The `actions.send()` function causes the sequence of actions to be sent to the browser. It is based on the [WebDriver API](https://w3c.github.io/webdriver/#actions).
The action can be a keyboard action, a pointer action or a pause. It returns a `Promise` that
resolves after the actions have been sent or rejects if an error was thrown.
The action can be a keyboard action, a pointer action or a pause. It returns a promise that
resolves after the actions have been sent, or rejects if an error was thrown.
Example:
@ -49,7 +49,7 @@ let actions = new test_driver.Actions()
actions.send();
```
Calling into `send()` is going to dispatch the action sequence (via `test_driver.action_sequence`) and also returns a `Promise` which should be handled however is appropriate in the test. The other functions in the `Actions()` object are going to modify the state of the object by adding a new action in the sequence and return the same object. So the functions can be easily chained as shown in the example above. Here is a list of helper functions in the `Actions` class:
Calling into `send()` is going to dispatch the action sequence (via `test_driver.action_sequence`) and also returns a promise which should be handled however is appropriate in the test. The other functions in the `Actions()` object are going to modify the state of the object by adding a new action in the sequence and returning the same object. So the functions can be easily chained, as shown in the example above. Here is a list of helper functions in the `Actions` class:
```
pointerDown: Create a pointerDown event for the current default pointer source
@ -68,19 +68,19 @@ addKeyboard: Add a new key input source with the given name
### bless
Usage: `test_driver.bless(intent, action)`
* `intent`: a string describing the motivation for this invocation
* `action`: an optional function
* _intent_: a string describing the motivation for this invocation
* _action_: an optional function
This function simulates [activation][activation], allowing tests to
perform privileged operations that require user interaction. For
example, sandboxed iframes with the
example, sandboxed iframes with
`allow-top-navigation-by-user-activation` may only navigate their
parent's browsing context under these circumstances. The `intent`
parent's browsing context under these circumstances. The _intent_
string is presented to human operators when the test is not run in
automation.
This method returns a promise which is resolved with the result of
invoking the `action` function. If no such function is provided, the
invoking the _action_ function. If no such function is provided, the
promise is resolved with the value `undefined`.
Example:
@ -96,11 +96,11 @@ test_driver.bless('initiate media playback', function () {
### click
Usage: `test_driver.click(element)`
* `element`: a DOM Element object
* _element_: a DOM Element object
This function causes a click to occur on the target element (an
`Element` object), potentially scrolling the document to make it
possible to click it. It returns a `Promise` that resolves after the
possible to click it. It returns a promise that resolves after the
click has occurred or rejects if the element cannot be clicked (for
example, it is obscured by an element on top of it).
@ -111,16 +111,16 @@ being called and the promise settling.
### send_keys
Usage: `test_driver.send_keys(element, keys)`
* `element`: a DOM Element object
* `keys`: string to send to the element
* _element_: a DOM Element object
* _keys_: string to send to the element
This function causes the string `keys` to be send to the target
This function causes the string _keys_ to be sent to the target
element (an `Element` object), potentially scrolling the document to
make it possible to send keys. It returns a `Promise` that resolves
after the keys have been send or rejects if the keys cannot be sent
make it possible to send keys. It returns a promise that resolves
after the keys have been sent, or rejects if the keys cannot be sent
to the element.
Note that if the element that's keys need to be send to does not have
Note that if the element that the keys need to be sent to does not have
a unique ID, the document must not have any DOM mutations made
between the function being called and the promise settling.
@ -128,3 +128,27 @@ To send special keys, one must send the respective key's codepoint. Since this u
For example, to send the tab key you would send "\uE004".
[activation]: https://html.spec.whatwg.org/multipage/interaction.html#activation
### set_permission
Usage: `test_driver.set_permission(descriptor, state, one_realm)`
* _descriptor_: a
[PermissionDescriptor](https://w3c.github.io/permissions/#dictdef-permissiondescriptor)
or derived object
* _state_: a
[PermissionState](https://w3c.github.io/permissions/#enumdef-permissionstate)
value
* _one_realm_: a boolean that indicates whether the permission settings
apply to only one realm
This function causes permission requests and queries for the status of a
certain permission type (e.g. "push", or "background-fetch") to always
return _state_. It returns a promise that resolves after the permission has
been set to be overridden with _state_.
Example:
``` js
await test_driver.set_permission({ name: "background-fetch" }, "denied");
await test_driver.set_permission({ name: "push", userVisibleOnly: true }, "granted", true);
```

View file

@ -0,0 +1,58 @@
// Testing DocumentFragment with host separately as it has a different node document by design
test(() => {
const df = document.createElement("template").content;
const child = df.appendChild(new Text('hi'));
assert_not_equals(df.ownerDocument, document);
const nodeDocument = df.ownerDocument;
document.body.appendChild(df);
assert_equals(df.childNodes.length, 0);
assert_equals(child.ownerDocument, document);
assert_equals(df.ownerDocument, nodeDocument);
}, `appendChild() and DocumentFragment with host`);
test(() => {
const df = document.createElement("template").content;
const child = df.appendChild(new Text('hi'));
const nodeDocument = df.ownerDocument;
document.adoptNode(df);
assert_equals(df.childNodes.length, 1);
assert_equals(child.ownerDocument, nodeDocument);
assert_equals(df.ownerDocument, nodeDocument);
}, `adoptNode() and DocumentFragment with host`);
[
{
"name": "DocumentFragment",
"creator": doc => doc.createDocumentFragment()
},
{
"name": "ShadowRoot",
"creator": doc => doc.createElementNS("http://www.w3.org/1999/xhtml", "div").attachShadow({mode: "closed"})
}
].forEach(dfTest => {
test(() => {
const doc = new Document();
const df = dfTest.creator(doc);
const child = df.appendChild(new Text('hi'));
assert_equals(df.ownerDocument, doc);
document.body.appendChild(df);
assert_equals(df.childNodes.length, 0);
assert_equals(child.ownerDocument, document);
assert_equals(df.ownerDocument, doc);
}, `appendChild() and ${dfTest.name}`);
test(() => {
const doc = new Document();
const df = dfTest.creator(doc);
const child = df.appendChild(new Text('hi'));
if (dfTest.name === "ShadowRoot") {
assert_throws("HierarchyRequestError", () => document.adoptNode(df));
} else {
document.adoptNode(df);
assert_equals(df.childNodes.length, 1);
assert_equals(child.ownerDocument, document);
assert_equals(df.ownerDocument, document);
}
}, `adoptNode() and ${dfTest.name}`);
});

View file

@ -7,28 +7,70 @@
// |opts.expectedBodyAsString|: the expected response body as a string. The
// server is expected to echo the request body. The default is the empty string
// if the request after redirection isn't POST; otherwise it's |opts.body|.
// |opts.expectedRequestContentType|: the expected Content-Type of redirected
// request.
function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, method, expectedMethod, opts) {
var url = redirectUrl;
var urlParameters = "?redirect_status=" + redirectStatus;
let url = redirectUrl;
let urlParameters = "?redirect_status=" + redirectStatus;
urlParameters += "&location=" + encodeURIComponent(redirectLocation);
var requestInit = {"method": method, "redirect": "follow"};
let requestHeaders = {
"Content-Encoding": "Identity",
"Content-Language": "en-US",
"Content-Location": "foo",
};
let requestInit = {"method": method, "redirect": "follow", "headers" : requestHeaders};
opts = opts || {};
if (opts.body)
if (opts.body) {
requestInit.body = opts.body;
}
promise_test(function(test) {
return fetch(url + urlParameters, requestInit).then(function(resp) {
let expectedRequestContentType = "NO";
if (opts.expectedRequestContentType) {
expectedRequestContentType = opts.expectedRequestContentType;
}
assert_equals(resp.status, 200, "Response's status is 200");
assert_equals(resp.type, "basic", "Response's type basic");
assert_equals(resp.headers.get("x-request-method"), expectedMethod, "Request method after redirection is " + expectedMethod);
assert_equals(
resp.headers.get("x-request-method"),
expectedMethod,
"Request method after redirection is " + expectedMethod);
let hasRequestBodyHeader = true;
if (opts.expectedStripRequestBodyHeader) {
hasRequestBodyHeader = !opts.expectedStripRequestBodyHeader;
}
assert_equals(
resp.headers.get("x-request-content-type"),
expectedRequestContentType,
"Request Content-Type after redirection is " + expectedRequestContentType);
[
"Content-Encoding",
"Content-Language",
"Content-Location"
].forEach(header => {
let xHeader = "x-request-" + header.toLowerCase();
let expectedValue = hasRequestBodyHeader ? requestHeaders[header] : "NO";
assert_equals(
resp.headers.get(xHeader),
expectedValue,
"Request " + header + " after redirection is " + expectedValue);
});
assert_true(resp.redirected);
return resp.text().then(function(text) {
let expectedBody = "";
if (expectedMethod == "POST")
if (expectedMethod == "POST") {
expectedBody = opts.expectedBodyAsString || requestInit.body;
}
let expectedContentLength = expectedBody ? expectedBody.length.toString() : "NO";
assert_equals(text, expectedBody, "request body");
});
assert_equals(
resp.headers.get("x-request-content-length"),
expectedContentLength,
"Request Content-Length after redirection is " + expectedContentLength);
});
});
}, desc);
}
@ -49,19 +91,20 @@ const blobBody = new Blob(["it's me the blob!", " ", "and more blob!"]);
const blobBodyAsString = "it's me the blob! and more blob!";
redirectMethod("Redirect 301 with GET", redirUrl, locationUrl, 301, "GET", "GET");
redirectMethod("Redirect 301 with POST", redirUrl, locationUrl, 301, "POST", "GET", { body: stringBody });
redirectMethod("Redirect 301 with POST", redirUrl, locationUrl, 301, "POST", "GET", { body: stringBody, expectedStripRequestBodyHeader: true });
redirectMethod("Redirect 301 with HEAD", redirUrl, locationUrl, 301, "HEAD", "HEAD");
redirectMethod("Redirect 302 with GET", redirUrl, locationUrl, 302, "GET", "GET");
redirectMethod("Redirect 302 with POST", redirUrl, locationUrl, 302, "POST", "GET", { body: stringBody });
redirectMethod("Redirect 302 with POST", redirUrl, locationUrl, 302, "POST", "GET", { body: stringBody, expectedStripRequestBodyHeader: true });
redirectMethod("Redirect 302 with HEAD", redirUrl, locationUrl, 302, "HEAD", "HEAD");
redirectMethod("Redirect 303 with GET", redirUrl, locationUrl, 303, "GET", "GET");
redirectMethod("Redirect 303 with POST", redirUrl, locationUrl, 303, "POST", "GET", { body: stringBody });
redirectMethod("Redirect 303 with POST", redirUrl, locationUrl, 303, "POST", "GET", { body: stringBody, expectedStripRequestBodyHeader: true });
redirectMethod("Redirect 303 with HEAD", redirUrl, locationUrl, 303, "HEAD", "HEAD");
redirectMethod("Redirect 303 with TESTING", redirUrl, locationUrl, 303, "TESTING", "GET", { expectedStripRequestBodyHeader: true });
redirectMethod("Redirect 307 with GET", redirUrl, locationUrl, 307, "GET", "GET");
redirectMethod("Redirect 307 with POST (string body)", redirUrl, locationUrl, 307, "POST", "POST", { body: stringBody });
redirectMethod("Redirect 307 with POST (string body)", redirUrl, locationUrl, 307, "POST", "POST", { body: stringBody , expectedRequestContentType: "text/plain;charset=UTF-8"});
redirectMethod("Redirect 307 with POST (blob body)", redirUrl, locationUrl, 307, "POST", "POST", { body: blobBody, expectedBodyAsString: blobBodyAsString });
redirectMethod("Redirect 307 with HEAD", redirUrl, locationUrl, 307, "HEAD", "HEAD");

View file

@ -8,4 +8,9 @@ def main(request, response):
headers.append(("Access-Control-Expose-Headers", "x-request-method"))
headers.append(("x-request-method", request.method))
headers.append(("x-request-content-type", request.headers.get("Content-Type", "NO")))
headers.append(("x-request-content-length", request.headers.get("Content-Length", "NO")))
headers.append(("x-request-content-encoding", request.headers.get("Content-Encoding", "NO")))
headers.append(("x-request-content-language", request.headers.get("Content-Language", "NO")))
headers.append(("x-request-content-location", request.headers.get("Content-Location", "NO")))
return headers, request.body

View file

@ -0,0 +1,16 @@
async_test(t => {
// Setting document.domain makes this document cross-origin with that of the frame. However,
// about:blank will end up reusing the origin of this document, at which point the frame's
// document is no longer cross-origin.
const frame = document.body.appendChild(document.createElement('iframe'));
document.domain = document.domain;
frame.src = "/common/blank.html";
frame.onload = t.step_func(() => {
assert_throws("SecurityError", () => window[0].document);
frame.src = "about:blank";
frame.onload = t.step_func_done(() => {
// Ensure we can access the child browsing context after navigation to non-initial about:blank
assert_equals(window[0].document, frame.contentDocument);
});
});
}, "Navigated frame to about:blank and document.domain");

View file

@ -0,0 +1,10 @@
test(() => {
// As the initial:about frame document reuses the origin of this document, setting document.domain
// from the frame, resulting in a origin mutation, has no effect on these documents being able to
// reach each other, as they share the same "physical" origin.
document.body.appendChild(document.createElement('iframe'));
const script = document.createElement("script");
script.text = "document.domain = document.domain";
window[0].document.body.appendChild(script);
assert_equals(window[0].document.body.localName, "body");
}, "Initial about:blank frame and document.domain in the frame");

View file

@ -0,0 +1,9 @@
test(() => {
// As the initial:about frame document reuses the origin of this document, setting document.domain
// from this document, resulting in a origin mutation, has no effect on these documents being able
// to reach each other, as they share the same "physical" origin.
document.body.appendChild(document.createElement('iframe'));
document.domain = document.domain;
// Ensure we can still access the child browsing context
assert_equals(window[0].document.body.localName, "body");
}, "Initial about:blank frame and document.domain");

View file

@ -11,6 +11,7 @@
</style>
<img src="/images/green.png">
<img src="/images/green.png" width=100 height=125>
<img src="" width=100 height=125>
<script>
let t = async_test("Image width and height attributes are used to infer aspect-ratio");
function assert_ratio(img, expected) {
@ -46,7 +47,8 @@ t.step(function() {
onload = t.step_func_done(function() {
let images = document.querySelectorAll("img");
assert_ratio(images[2], 1.266); // 1.266 is the original aspect ratio of blue.png
assert_ratio(images[3], 1.266); // 1.266 is the original aspect ratio of blue.png
assert_equals(getComputedStyle(images[2]).height, "0px"); // aspect-ratio doesn't override intrinsic size of images that don't have any src.
assert_ratio(images[1], 2.0); // 2.0 is the original aspect ratio of green.png
assert_ratio(images[0], 2.0); // Loaded image's aspect ratio, at least by default, overrides width / height ratio.
});

View file

@ -37,3 +37,12 @@ test(t => {
comment.remove();
assert_not_equals(sheet, style.sheet);
}, "Mutating the style element: removing a Comment node");
test(t => {
const style = document.body.appendChild(document.createElement("style"));
const sheet = style.sheet;
t.add_cleanup(() => style.remove());
assert_not_equals(sheet, null);
style.appendChild(new DocumentFragment());
assert_equals(sheet, style.sheet);
}, "Mutating the style element: inserting an empty DocumentFragment node");

View file

@ -69,7 +69,10 @@
{conditions: {step: "", value: "-.8"}, expected: true, name: "[target] The step attribute is not set and the value attribute is a floating number"},
{conditions: {step: 2 * 1 * 1, value: ""}, expected: false, name: "[target] The value attribute is empty string"},
{conditions: {step: 2 * 1 * 1, value: "2"}, expected: false, name: "[target] The value must match the step"},
{conditions: {step: 2 * 1 * 1, value: "3"}, expected: true, name: "[target] The value must mismatch the step"}
{conditions: {step: 2 * 1 * 1, value: "3"}, expected: true, name: "[target] The value must mismatch the step"},
{conditions: {step: 0.003, value: "3.6"}, expected: false, name: "[target] No step mismatch when step is a floating number and value is its integral multiple"},
{conditions: {step: 1e-12, value: "-12345678.9"}, expected: false, name: "[target] No step mismatch when step is a floating number in exponent format and value is its integral multiple"},
{conditions: {step: 3e-15, value: "17"}, expected: true, name: "[target] Step mismatch when step is a very small floating number and value is not its integral multiple"},
]
}
];

View file

@ -1,16 +1,23 @@
var validator = {
test_tooLong: function(ctl, data) {
var self = this;
test(function () {
self.pre_check(ctl, "tooLong");
test(function() {
self.pre_check(ctl, 'tooLong');
self.set_conditions(ctl, data.conditions);
if (data.dirty)
self.set_dirty(ctl);
if (data.expected)
assert_true(ctl.validity.tooLong, "The validity.tooLong should be true.");
else
assert_false(ctl.validity.tooLong, "The validity.tooLong should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.dirty)
self.set_dirty(ctl);
if (data.expected)
assert_true(
ctl.validity.tooLong,
'The validity.tooLong should be true' + condStr);
else
assert_false(
ctl.validity.tooLong,
'The validity.tooLong should be false' + condStr);
});
}, data.name);
},
@ -19,13 +26,19 @@ var validator = {
test(function () {
self.pre_check(ctl, "tooShort");
self.set_conditions(ctl, data.conditions);
if (data.dirty)
self.set_dirty(ctl);
if (data.expected)
assert_true(ctl.validity.tooShort, "The validity.tooShort should be true.");
else
assert_false(ctl.validity.tooShort, "The validity.tooShort should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.dirty)
self.set_dirty(ctl);
if (data.expected)
assert_true(
ctl.validity.tooShort,
'The validity.tooShort should be true' + condStr);
else
assert_false(
ctl.validity.tooShort,
'The validity.tooShort should be false' + condStr);
});
}, data.name);
},
@ -34,11 +47,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "patternMismatch");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.patternMismatch, "The validity.patternMismatch should be true.");
else
assert_false(ctl.validity.patternMismatch, "The validity.patternMismatch should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.patternMismatch,
'The validity.patternMismatch should be true' + condStr);
else
assert_false(
ctl.validity.patternMismatch,
'The validity.patternMismatch should be false' + condStr);
});
}, data.name);
},
@ -47,10 +66,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "valueMissing");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.valueMissing, "The validity.valueMissing should be true.");
else
assert_false(ctl.validity.valueMissing, "The validity.valueMissing should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.valueMissing,
'The validity.valueMissing should be true' + condStr);
else
assert_false(
ctl.validity.valueMissing,
'The validity.valueMissing should be false' + condStr);
});
}, data.name);
},
@ -59,11 +85,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "typeMismatch");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.typeMismatch, "The validity.typeMismatch should be true.");
else
assert_false(ctl.validity.typeMismatch, "The validity.typeMismatch should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.typeMismatch,
'The validity.typeMismatch should be true' + condStr);
else
assert_false(
ctl.validity.typeMismatch,
'The validity.typeMismatch should be false' + condStr);
});
}, data.name);
},
@ -72,11 +104,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "rangeOverflow");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.rangeOverflow, "The validity.rangeOverflow should be true.");
else
assert_false(ctl.validity.rangeOverflow, "The validity.rangeOverflow should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.rangeOverflow,
'The validity.rangeOverflow should be true' + condStr);
else
assert_false(
ctl.validity.rangeOverflow,
'The validity.rangeOverflow should be false' + condStr);
});
}, data.name);
},
@ -85,10 +123,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "rangeUnderflow");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.rangeUnderflow, "The validity.rangeUnderflow should be true.");
else
assert_false(ctl.validity.rangeUnderflow, "The validity.rangeUnderflow should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.rangeUnderflow,
'The validity.rangeUnderflow should be true' + condStr);
else
assert_false(
ctl.validity.rangeUnderflow,
'The validity.rangeUnderflow should be false' + condStr);
});
}, data.name);
},
@ -97,11 +142,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "stepMismatch");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.stepMismatch, "The validity.stepMismatch should be true.");
else
assert_false(ctl.validity.stepMismatch, "The validity.stepMismatch should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.stepMismatch,
'The validity.stepMismatch should be true' + condStr);
else
assert_false(
ctl.validity.stepMismatch,
'The validity.stepMismatch should be false' + condStr);
});
}, data.name);
},
@ -110,11 +161,17 @@ var validator = {
test(function () {
self.pre_check(ctl, "badInput");
self.set_conditions(ctl, data.conditions);
if (data.expected)
assert_true(ctl.validity.badInput, "The validity.badInput should be true.");
else
assert_false(ctl.validity.badInput, "The validity.badInput should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected)
assert_true(
ctl.validity.badInput,
'The validity.badInput should be true' + condStr);
else
assert_false(
ctl.validity.badInput,
'The validity.badInput should be false' + condStr);
});
}, data.name);
},
@ -123,29 +180,45 @@ var validator = {
test(function () {
self.pre_check(ctl, "customError");
ctl.setCustomValidity(data.conditions.message);
if (data.expected) {
assert_true(ctl.validity.customError, "The validity.customError attribute should be true.");
assert_equals(ctl.validationMessage, data.conditions.message,
"The validationMessage attribute should be '" + data.conditions.message + "'.");
} else {
assert_false(ctl.validity.customError, "The validity.customError attribute should be false.");
assert_equals(ctl.validationMessage, "", "The validationMessage attribute must be empty.");
}
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.expected) {
assert_true(
ctl.validity.customError,
'The validity.customError attribute should be true' + condStr);
assert_equals(
ctl.validationMessage, data.conditions.message,
'The validationMessage attribute should be \'' +
data.conditions.message + '\'' + condStr);
} else {
assert_false(
ctl.validity.customError,
'The validity.customError attribute should be false' + condStr);
assert_equals(
ctl.validationMessage, '',
'The validationMessage attribute must be empty' + condStr);
}
});
}, data.name);
},
test_isValid: function (ctl, data) {
test_isValid: function(ctl, data) {
var self = this;
test(function () {
self.set_conditions(ctl, data.conditions);
if (data.dirty)
self.set_dirty(ctl);
if (data.expected)
assert_true(ctl.validity.valid, "The validity.valid should be true.");
else
assert_false(ctl.validity.valid, "The validity.valid should be false.");
self.iterate_over(ctl, data).forEach(function(val) {
const {ctl, data, condStr} = val;
if (data.dirty)
self.set_dirty(ctl);
if (data.expected)
assert_true(
ctl.validity.valid,
'The validity.valid should be true' + condStr);
else
assert_false(
ctl.validity.valid,
'The validity.valid should be false' + condStr);
});
}, data.name);
},
@ -166,7 +239,7 @@ var validator = {
}, data.name);
},
test_checkValidity: function (ctl, data) {
test_checkValidity: function(ctl, data) {
var self = this;
test(function () {
var eventFired = false;
@ -210,7 +283,7 @@ var validator = {
}, data.name + " (in a form)");
},
test_reportValidity: function (ctl, data) {
test_reportValidity: function(ctl, data) {
var self = this;
test(function () {
var eventFired = false;
@ -255,13 +328,13 @@ var validator = {
}, data.name + " (in a form)");
},
test_support_type: function (ctl, typ, testName) {
test_support_type: function(ctl, typ, testName) {
test(function () {
assert_equals(ctl.type, typ, "The " + typ + " type should be supported.");
}, testName);
},
set_conditions: function (ctl, obj) {
set_conditions: function(ctl, obj) {
[
"checked",
"disabled",
@ -322,7 +395,28 @@ var validator = {
}
},
run_test: function (testee, method) {
iterate_over: function(ctl, data) {
// Iterate over normal, disabled, readonly, and both.
var ctlDisabled = ctl.cloneNode(true);
ctlDisabled.disabled = true;
var ctlReadonly = ctl.cloneNode(true);
ctlReadonly.readonly = true;
var ctlBoth = ctl.cloneNode(true);
ctlBoth.disabled = true;
ctlBoth.readonly = true;
return [
{ctl: ctl, data: data, condStr: '.'},
{ctl: ctlDisabled, data: data, condStr: ', when control is disabled.'},
{ctl: ctlReadonly, data: data, condStr: ', when control is readonly.'},
{
ctl: ctlBoth,
data: data,
condStr: ', when control is disabled & readonly.'
},
]
},
run_test: function(testee, method) {
var testMethod = "test_" + method;
if (typeof this[testMethod] !== "function") {
return false;
@ -363,7 +457,7 @@ var validator = {
prefix = "[" + testee[i].tag + "] ";
if (testElements[i].tag === "select") {
ele.add(new Option("test1", ""));
ele.add(new Option('test1', '')); // Placeholder
ele.add(new Option("test2", 1));
}

View file

@ -1,19 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<meta name="author" title="Takayoshi Kochi" href="mailto:kochi@chromium.org">
<meta name="assert" title="host-including inclusive ancestor should be checked for template content">
<link rel="help" href="https://dom.spec.whatwg.org/#concept-tree-host-including-inclusive-ancestor">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>
<div id="parent">
<template id="tmpl"><span>Happy Templating!</span></template>
</div>
</body>
<script>
test(() => {
var parent = document.getElementById('parent');
@ -53,12 +45,11 @@ test(() => {
assert_not_equals(new_doc, tmpl_doc);
// Try moving tmpl.content to new_doc and check the results.
var new_node = new_doc.adoptNode(tmpl.content);
assert_equals(new_node.ownerDocument, new_doc);
const tmplContentNodeDocument = tmpl.content.ownerDocument;
const tmplContentAdoptResult = new_doc.adoptNode(tmpl.content);
assert_equals(tmpl.content, tmplContentAdoptResult);
assert_equals(tmpl.ownerDocument, document);
assert_equals(tmpl.content.ownerDocument, new_doc);
assert_not_equals(tmpl.content.ownerDocument, tmpl_doc);
assert_not_equals(tmpl.content.ownerDocument, document);
assert_equals(tmpl.content.ownerDocument, tmplContentNodeDocument);
// Hierarchy checks at various combinations.
assert_throws('HierarchyRequestError', () => {
@ -79,7 +70,7 @@ test(() => {
assert_equals(tmpl.content.firstChild, span,
'<span> should be kept until it is removed, even after ' +
'adopted to another document.');
new_doc.body.appendChild(new_node);
new_doc.body.appendChild(tmpl.content);
assert_equals(tmpl.content.firstChild, null,
'<span> should be removed from template content.');
assert_equals(tmpl_content_reference, tmpl.content,
@ -88,4 +79,3 @@ test(() => {
}, 'Template content should throw exception when its ancestor in ' +
'a different document but connected via host is being append.');
</script>
</html>

View file

@ -0,0 +1,6 @@
[multiTouchPointsReleaseFirstPoint.html]
expected:
if product == "firefox" or product == "safari": ERROR
[TestDriver actions: two touch points with one moving one pause]
expected:
if product == "chrome": FAIL

View file

@ -0,0 +1,6 @@
[multiTouchPointsReleaseSecondPoint.html]
expected:
if product == "firefox" or product == "safari": ERROR
[TestDriver actions: two touch points with one moving one pause]
expected:
if product == "chrome": FAIL

View file

@ -1,4 +1,4 @@
[generate_test_report.html]
expected:
if product == "firefox": ERROR
if product == "safari" or product == "epiphany" or product == "webkit": ERROR
[TestDriver generate_test_report method]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL

View file

@ -1,3 +1,8 @@
[set_permission.https.html]
expected:
if product != "chrome": ERROR
[Grant Permission for one realm]
expected:
if product != "chrome": FAIL
[Deny Permission, omit one realm]
expected:
if product != "chrome": FAIL

View file

@ -1,3 +1,28 @@
[virtual_authenticator.html]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": ERROR
[Can create an authenticator]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL
[Can add a credential]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL
[Can get the credentials]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL
[Can remove a credential]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL
[Can remove all credentials]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL
[Can set user verified]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL
[Can remove a virtual authenticator]
expected:
if product == "firefox" or product == "safari" or product == "epiphany" or product == "webkit": FAIL

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>TestDriver actions: two touch points with one moving one pause</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<style>
div#test1{
position: fixed;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: blue;
}
</style>
<div id="test1">
</div>
<script>
let event_type = [];
let event_id = [];
async_test(t => {
let test1 = document.getElementById("test1");
document.getElementById("test1").addEventListener("pointerdown",
e => {event_type.push(e.type); event_id.push(e.pointerId);});
document.getElementById("test1").addEventListener("pointerup",
e => {event_type.push(e.type); event_id.push(e.pointerId);});
document.getElementById("test1").addEventListener("pointermove",
e => {event_type.push(e.type); event_id.push(e.pointerId);});
let actions = new test_driver.Actions()
.addPointer("touchPointer1", "touch")
.addPointer("touchPointer2", "touch")
.pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
.pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
.pointerDown({sourceName: "touchPointer1"})
.pointerDown({sourceName: "touchPointer2"})
.pointerUp({sourceName: "touchPointer1"})
.pointerMove(10, 10, {origin: test1, sourceName: "touchPointer2"})
.pointerUp({sourceName: "touchPointer2"});
actions.send()
.then(t.step_func_done(() => {
assert_array_equals(event_type, ["pointerdown", "pointerdown", "pointerup", "pointermove", "pointerup"]);
assert_array_equals(event_id, [2, 3, 2, 3, 3]);
}))
.catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
});
</script>

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>TestDriver actions: two touch points with one moving one pause</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<style>
div#test1{
position: fixed;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: blue;
}
</style>
<div id="test1">
</div>
<script>
let event_type = [];
let event_id = [];
async_test(t => {
let test1 = document.getElementById("test1");
document.getElementById("test1").addEventListener("pointerdown",
e => {event_type.push(e.type); event_id.push(e.pointerId);});
document.getElementById("test1").addEventListener("pointerup",
e => {event_type.push(e.type); event_id.push(e.pointerId);});
document.getElementById("test1").addEventListener("pointermove",
e => {event_type.push(e.type); event_id.push(e.pointerId);});
let actions = new test_driver.Actions()
.addPointer("touchPointer1", "touch")
.addPointer("touchPointer2", "touch")
.pointerMove(0, 0, {origin: test1, sourceName: "touchPointer1"})
.pointerMove(10, 0, {origin: test1, sourceName: "touchPointer2"})
.pointerDown({sourceName: "touchPointer1"})
.pointerDown({sourceName: "touchPointer2"})
.pointerMove(10, 10, {origin: test1, sourceName: "touchPointer1"})
.pointerUp({sourceName: "touchPointer2"})
.pointerUp({sourceName: "touchPointer1"});
actions.send()
.then(t.step_func_done(() => {
assert_array_equals(event_type, ["pointerdown", "pointerdown", "pointermove", "pointerup", "pointerup"]);
assert_array_equals(event_id, [2, 3, 2, 3, 2]);
}))
.catch(e => t.step_func(() => assert_unreached("Actions sequence failed " + e)));
});
</script>

View file

@ -24,7 +24,7 @@ let credential = {
isResidentCredential: false,
};
let authenticator_id;
let authenticator_id = null;
promise_test(async t => {
authenticator_id = await test_driver.add_virtual_authenticator({

View file

@ -19,6 +19,12 @@ interface CookieStore : EventTarget {
Promise<void> delete(USVString name);
Promise<void> delete(CookieStoreDeleteOptions options);
[Exposed=ServiceWorker]
Promise<void> subscribeToChanges(sequence<CookieStoreGetOptions> subscriptions);
[Exposed=ServiceWorker]
Promise<sequence<CookieStoreGetOptions>> getChangeSubscriptions();
[Exposed=Window]
attribute EventHandler onchange;
};
@ -71,7 +77,8 @@ dictionary CookieListItem {
typedef sequence<CookieListItem> CookieList;
[Exposed=Window, SecureContext]
[Exposed=Window,
SecureContext]
interface CookieChangeEvent : Event {
constructor(DOMString type, optional CookieChangeEventInit eventInitDict = {});
readonly attribute CookieList changed;
@ -83,8 +90,8 @@ dictionary CookieChangeEventInit : EventInit {
CookieList deleted;
};
[Exposed=ServiceWorker]
interface ExtendableCookieChangeEvent : ExtendableEvent {
[Exposed=ServiceWorker
] interface ExtendableCookieChangeEvent : ExtendableEvent {
constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict = {});
readonly attribute CookieList changed;
readonly attribute CookieList deleted;
@ -95,13 +102,6 @@ dictionary ExtendableCookieChangeEventInit : ExtendableEventInit {
CookieList deleted;
};
[Exposed=(ServiceWorker,Window), SecureContext]
interface CookieStoreManager {
Promise<void> subscribe(sequence<CookieStoreGetOptions> subscriptions);
Promise<sequence<CookieStoreGetOptions>> getSubscriptions();
Promise<void> unsubscribe(sequence<CookieStoreGetOptions> subscriptions);
};
[SecureContext]
partial interface Window {
[Replaceable, SameObject] readonly attribute CookieStore cookieStore;
@ -109,10 +109,6 @@ partial interface Window {
partial interface ServiceWorkerGlobalScope {
[Replaceable, SameObject] readonly attribute CookieStore cookieStore;
attribute EventHandler oncookiechange;
};
[Exposed=(ServiceWorker,Window), SecureContext]
partial interface ServiceWorkerRegistration {
readonly attribute CookieStoreManager cookies;
};

View file

@ -3,6 +3,7 @@
// (https://github.com/tidoust/reffy-reports)
// Source: Feature Policy (https://w3c.github.io/webappsec-feature-policy/)
[Exposed=Window]
interface FeaturePolicy {
boolean allowsFeature(DOMString feature, optional DOMString origin);
sequence<DOMString> features();
@ -17,6 +18,7 @@ partial interface Document {
partial interface HTMLIFrameElement {
[SameObject] readonly attribute FeaturePolicy featurePolicy;
};
[Exposed=Window]
interface FeaturePolicyViolationReportBody : ReportBody {
readonly attribute DOMString featureId;

View file

@ -8,7 +8,6 @@ dictionary RTCConfiguration {
RTCIceTransportPolicy iceTransportPolicy;
RTCBundlePolicy bundlePolicy;
RTCRtcpMuxPolicy rtcpMuxPolicy;
DOMString peerIdentity;
sequence<RTCCertificate> certificates;
[EnforceRange] octet iceCandidatePoolSize = 0;
};
@ -296,11 +295,9 @@ dictionary RTCRtpParameters {
dictionary RTCRtpSendParameters : RTCRtpParameters {
required DOMString transactionId;
required sequence<RTCRtpEncodingParameters> encodings;
RTCDegradationPreference degradationPreference = "balanced";
};
dictionary RTCRtpReceiveParameters : RTCRtpParameters {
required sequence<RTCRtpDecodingParameters> encodings;
};
dictionary RTCRtpCodingParameters {
@ -315,12 +312,6 @@ dictionary RTCRtpEncodingParameters : RTCRtpCodingParameters {
double scaleResolutionDownBy;
};
enum RTCDegradationPreference {
"maintain-framerate",
"maintain-resolution",
"balanced"
};
dictionary RTCRtcpParameters {
DOMString cname;
boolean reducedSize;
@ -615,14 +606,6 @@ enum RTCErrorDetailType {
"data-channel-failure",
"dtls-failure",
"fingerprint-failure",
"idp-bad-script-failure",
"idp-execution-failure",
"idp-load-failure",
"idp-need-login",
"idp-timeout",
"idp-tls-failure",
"idp-token-expired",
"idp-token-invalid",
"sctp-failure",
"sdp-syntax-error",
"hardware-encoder-not-available",

View file

@ -193,7 +193,7 @@ interface XRWebGLLayer {
readonly attribute boolean antialias;
readonly attribute boolean ignoreDepthValues;
[SameObject] readonly attribute WebGLFramebuffer framebuffer;
[SameObject] readonly attribute WebGLFramebuffer? framebuffer;
readonly attribute unsigned long framebufferWidth;
readonly attribute unsigned long framebufferHeight;

View file

@ -5,6 +5,7 @@
<link rel="help" href="https://github.com/scott-little/lazyload">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="common.js"></script>
</head>
<!--
@ -24,12 +25,16 @@ Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
window.addEventListener("load", t.step_func(function() {
assert_true(has_in_viewport_loaded, "The in_viewport element should have loaded before window.load().");
assert_true(document.getElementById("in_viewport").complete);
assert_false(has_window_loaded, "The window.load() event should only fire once.");
has_window_loaded = true;
document.getElementById("below_viewport").scrollIntoView();
}));
const below_viewport_img_onload = t.step_func_done(function() {
assert_true(is_image_fully_loaded(
document.getElementById("below_viewport"),
document.getElementById("in_viewport")));
assert_true(has_window_loaded, "The window.load() event should have fired before below_viewport loaded.");
});
</script>

View file

@ -8,7 +8,7 @@ async_test(t => {
return;
assert_equals(entry.entryType, 'longtask');
assert_equals(entry.name, 'self');
assert_greater_than(longtask.duration, 50);
assert_greater_than(entry.duration, 50);
longtaskObserved = true;
});
assert_true(longtaskObserved, 'Did not observe buffered longtask.');

View file

@ -70,49 +70,6 @@
test.done();
});
}, "Test HTMLVideoElement.getVideoPlaybackQuality() with MediaSource API");
mediasource_testafterdataloaded(function(test, mediaElement, mediaSource, segmentInfo, sourceBuffer, mediaData)
{
var previousQuality = mediaElement.getVideoPlaybackQuality();
var timeUpdateCount = 0;
var startTime = 0;
mediaElement.addEventListener("timeupdate", test.step_func(function (e)
{
var videoElement = e.target;
var newQuality = videoElement.getVideoPlaybackQuality();
var now = window.performance.now();
assert_greater_than_equal(newQuality.totalFrameDelay, 0, "totalFrameDelay >= 0");
assert_greater_than_equal(newQuality.totalFrameDelay, previousQuality.totalFrameDelay,
"totalFrameDelay increases monotonically");
assert_less_than(newQuality.totalFrameDelay, (now - startTime) / 1000,
"totalFrameDelay does not exceed the time elapsed since playback started");
previousQuality = newQuality;
timeUpdateCount++;
}));
mediaElement.addEventListener('error', test.unreached_func("Unexpected event 'error'"));
sourceBuffer.appendBuffer(mediaData);
test.expectEvent(sourceBuffer, 'updateend', 'sourceBuffer');
test.waitForExpectedEvents(function()
{
assert_false(sourceBuffer.updating, "updating");
mediaSource.endOfStream();
assert_less_than(mediaSource.duration, 10, "duration");
startTime = window.performance.now();
mediaElement.play().catch(test.unreached_func("Unexpected promise rejection"));
test.expectEvent(mediaElement, 'ended', 'mediaElement');
});
test.waitForExpectedEvents(function()
{
assert_greater_than(timeUpdateCount, 2, "timeUpdateCount");
test.done();
});
}, "Test the totalFrameDelay attribute of HTMLVideoElement.getVideoPlaybackQuality() with MediaSource API");
</script>
</body>
</html>

View file

@ -19,24 +19,24 @@
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testIFrameSrcInPortal');
assertInitialHistoryState();
}, 'Setting iframe src navigates independently in a portal');
}, 'Setting iframe src navigates independently with replacement in a portal');
promise_test(async () => {
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testCrossSiteIFrameSrcInPortal');
assertInitialHistoryState();
}, 'Setting cross site iframe src navigates independently in a portal');
}, 'Setting cross site iframe src navigates independently with replacement in a portal');
promise_test(async () => {
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testIFrameNavInPortal');
assertInitialHistoryState();
}, 'iframe navigates itself independently in a portal');
}, 'iframe navigates itself independently with replacement in a portal');
promise_test(async () => {
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testCrossSiteIFrameNavInPortal');
assertInitialHistoryState();
}, 'Cross site iframe navigates itself independently in a portal');
}, 'Cross site iframe navigates itself independently with replacement in a portal');
</script>
</body>

View file

@ -19,7 +19,7 @@
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testHistoryPushStateInPortal');
assertInitialHistoryState();
}, 'history.pushState navigates independently in a portal');
}, 'history.pushState navigates independently with replacement in a portal');
promise_test(async () => {
assertInitialHistoryState();
@ -31,7 +31,7 @@
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testLocationAssignInPortal');
assertInitialHistoryState();
}, 'location.assign navigates independently in a portal');
}, 'location.assign navigates independently with replacement in a portal');
promise_test(async () => {
assertInitialHistoryState();
@ -43,12 +43,12 @@
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testSetLocationHrefInPortal');
assertInitialHistoryState();
}, 'Setting location.href navigates independently in a portal');
}, 'Setting location.href navigates independently with replacement in a portal');
promise_test(async () => {
assertInitialHistoryState();
await runTestInPortal(portalSrc, 'testSyntheticAnchorClickInPortal');
assertInitialHistoryState();
}, 'Synthetic anchor click navigates independently in a portal');
}, 'Synthetic anchor click navigates independently with replacement in a portal');
</script>
</body>

View file

@ -37,10 +37,10 @@
frameHistoryLength =
await messageFrameAndAwaitResponse(iframe, 'reportHistoryLength');
assert(
history.length == 2, 'History length changed when iframe src set');
history.length == 1, 'History length unchanged when iframe src set');
assert(
frameHistoryLength == 2,
'History length in iframe changed when iframe src set');
frameHistoryLength == 1,
'History length in iframe unchanged when iframe src set');
}
function testIFrameSrcInPortal() {
@ -66,10 +66,10 @@
let frameHistoryLength =
await messageFrameAndAwaitResponse(iframe, 'reportHistoryLength');
assert(
history.length == 2, 'History length changed when iframe navigates');
history.length == 1, 'History length unchanged when iframe navigates');
assert(
frameHistoryLength == 2,
'History length in iframe changed when iframe navigates');
frameHistoryLength == 1,
'History length in iframe unchanged when iframe navigates');
}
function testIFrameNavInPortal() {

View file

@ -8,7 +8,7 @@
history.pushState('teststate', null, null);
assert(history.length == 2, 'History length changed');
assert(history.length == 1, 'History length unchanged');
assert(history.state == 'teststate', 'Update state');
}
@ -27,7 +27,7 @@
let initialLocation = location.href;
location.assign('#test');
assert(history.length == 2, 'History length changed');
assert(history.length == 1, 'History length unchanged');
assert(location.href != initialLocation, 'Update location');
}
@ -45,7 +45,7 @@
let initialLocation = location.href;
location.href = '#test';
assert(history.length == 2, 'History length changed');
assert(history.length == 1, 'History length unchanged');
assert(location.href != initialLocation, 'Update location');
}
@ -59,7 +59,7 @@
anchor.click();
assert(history.length == 2, 'History length changed');
assert(history.length == 1, 'History length unchanged');
assert(location.href != initialLocation, 'Update location');
}
</script>

View file

@ -1,2 +0,0 @@
Content-Type: text/css;charset=utf-8
Cache-Control: max-age=3600

View file

@ -0,0 +1,4 @@
spec: https://wicg.github.io/ScrollToTextFragment/
suggested_reviewers:
- nburris
- bokan

View file

@ -0,0 +1,78 @@
<!doctype html>
<title>Navigating to a text fragment directive</title>
<meta charset=utf-8>
<link rel="help" href="https://wicg.github.io/ScrollToTextFragment/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/common/utils.js"></script>
<script src="stash.js"></script>
<script>
// Test security restriction for user activation
for (let user_activation of [true, false]) {
promise_test(t => new Promise((resolve, reject) => {
let key = token();
if (user_activation) {
test_driver.bless('Open a URL with a text fragment directive', () => {
window.open(`scroll-to-text-fragment-target.html?key=${key}#:~:text=test`, '_blank', 'noopener');
});
} else {
window.open(`scroll-to-text-fragment-target.html?key=${key}#:~:text=test`, '_blank', 'noopener');
}
fetchResults(key, resolve, reject);
}).then(data => {
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
if (user_activation) {
assert_equals(data.scrollPosition, 'text', 'Expected window.open() with a user activation to scroll to text.');
} else {
assert_equals(data.scrollPosition, 'top', 'Expected window.open() with no user activation to not activate text fragment directive.');
}
}), `Test that a text fragment directive requires a user activation (user_activation=${user_activation}).`);
}
// Test security restriction for no window opener
for (let noopener of [true, false]) {
promise_test(t => new Promise((resolve, reject) => {
let key = token();
test_driver.bless('Open a URL with a text fragment directive', () => {
if (noopener) {
window.open(`scroll-to-text-fragment-target.html?key=${key}#:~:text=test`, '_blank', 'noopener');
} else {
window.open(`scroll-to-text-fragment-target.html?key=${key}#:~:text=test`, '_blank');
}
});
fetchResults(key, resolve, reject);
}).then(data => {
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
if (noopener) {
assert_equals(data.scrollPosition, 'text', 'Expected window.open() with noopener to scroll to text.');
} else {
assert_equals(data.scrollPosition, 'top', 'Expected window.open() with opener to not activate text fragment directive.');
}
}), `Test that a text fragment directive is not activated when there is a window opener (noopener=${noopener}).`);
}
// Test security restriction for no activation in an iframe
promise_test(t => new Promise((resolve, reject) => {
let key = token();
let frame = document.createElement('iframe');
document.body.appendChild(frame);
test_driver.bless('Navigate the iframe with a text fragment directive', () => {
frame.src = `scroll-to-text-fragment-target.html?key=${key}#:~:text=test`;
});
fetchResults(key, resolve, reject);
}).then(data => {
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
assert_equals(data.scrollPosition, 'top', 'Expected iframe navigation to not activate text fragment directive.');
}), 'Test that a text fragment directive is not activated within an iframe.');
</script>

View file

@ -1,5 +1,6 @@
<!doctype html>
<title>Navigating to a text fragment anchor</title>
<script src="stash.js"></script>
<script>
function isInView(element) {
let rect = element.getBoundingClientRect();
@ -8,8 +9,6 @@ function isInView(element) {
}
function checkScroll() {
let bc = new BroadcastChannel('scroll-to-text-fragment');
let position = 'unknown';
if (window.scrollY == 0)
position = 'top';
@ -30,9 +29,10 @@ function checkScroll() {
else if (isInView(document.getElementById('horizontal-scroll')) && window.scrollX > 0)
position = 'horizontal-scroll';
bc.postMessage({ scrollPosition: position, href: window.location.href });
bc.close();
window.close();
let results = { scrollPosition: position, href: window.location.href };
let key = (new URL(document.location)).searchParams.get("key");
stashResults(key, results);
}
</script>
<style>

View file

@ -7,6 +7,16 @@
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/common/utils.js"></script>
<script src="stash.js"></script>
<!--
This test suite performs scroll to text navigations to
scroll-to-text-fragment-target.html and then checks the results, which are
communicated back from the target page via the WPT Stash server (see stash.py).
This structure is necessary because scroll to text security restrictions
specifically restrict the navigator from being able to observe the result of
the navigation, e.g. the target page cannot have a window opener.
-->
<script>
let test_cases = [
// Test non-text fragment directives
@ -217,82 +227,18 @@ let test_cases = [
];
for (const test_case of test_cases) {
promise_test(t => new Promise(resolve => {
let channel = new BroadcastChannel('scroll-to-text-fragment');
channel.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
promise_test(t => new Promise((resolve, reject) => {
let key = token();
test_driver.bless('Open a URL with a text fragment directive', () => {
window.open('scroll-to-text-fragment-target.html' + test_case.fragment, '_blank', 'noopener');
window.open(`scroll-to-text-fragment-target.html?key=${key}${test_case.fragment}`, '_blank', 'noopener');
});
fetchResults(key, resolve, reject);
}).then(data => {
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
assert_equals(data.scrollPosition, test_case.expect_position,
`Expected ${test_case.fragment} (${test_case.description}) to scroll to ${test_case.expect_position}.`);
}), `Test navigation with fragment: ${test_case.description}.`);
}
promise_test(t => new Promise(resolve => {
let channel = new BroadcastChannel('scroll-to-text-fragment');
channel.addEventListener("message", e => {
assert_equals(e.data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
// The first navigation has no user activation.
assert_equals(e.data.scrollPosition, 'top', 'Expected window.open() with no user activation to not activate text fragment directive.');
// Now ensure that a navigation with a user activation does activate the text fragment directive.
test_driver.bless('Open a URL with a text fragment directive', () => {
window.open('scroll-to-text-fragment-target.html#:~:text=test', '_blank', 'noopener');
});
channel.addEventListener("message", e => {
resolve(e.data.scrollPosition);
}, {once: true});
}, {once: true});
window.open('scroll-to-text-fragment-target.html#:~:text=test', '_blank', 'noopener');
}).then(scrollPosition => {
assert_equals(scrollPosition, 'text', 'Expected window.open() with a user activation to scroll to text.');
}), 'Test that a text fragment directive is not activated without a user activation');
promise_test(t => new Promise(resolve => {
let channel = new BroadcastChannel('scroll-to-text-fragment');
channel.addEventListener("message", e => {
assert_equals(e.data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
// The first navigation has an opener.
assert_equals(e.data.scrollPosition, 'top', 'Expected window.open() with opener to not activate text fragment directive.');
// Now ensure that a navigation with noopener does activate the text fragment directive.
test_driver.bless('Open a URL with a text fragment directive', () => {
window.open('scroll-to-text-fragment-target.html#:~:text=test', '_blank', 'noopener');
});
channel.addEventListener("message", e => {
resolve(e.data.scrollPosition);
}, {once: true});
}, {once: true});
test_driver.bless('Open a URL with a text fragment directive', () => {
window.open('scroll-to-text-fragment-target.html#:~:text=test', '_blank');
});
}).then(scrollPosition => {
assert_equals(scrollPosition, 'text', 'Expected window.open() with noopener to scroll to text.');
}), 'Test that a text fragment directive is not activated when there is a window opener.');
promise_test(t => new Promise(resolve => {
let channel = new BroadcastChannel('scroll-to-text-fragment');
channel.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
let frame = document.createElement('iframe');
document.body.appendChild(frame);
test_driver.bless('Navigate the iframe with a text fragment directive', () => {
frame.src = 'scroll-to-text-fragment-target.html#:~:text=test';
});
}).then(data => {
assert_equals(data.href.indexOf(':~:'), -1, 'Expected fragment directive to be stripped from the URL.');
assert_equals(data.scrollPosition, 'top', 'Expected iframe navigation to not activate text fragment directive.');
}), 'Test that a text fragment directive is not activated within an iframe.');
</script>

View file

@ -0,0 +1,23 @@
// Put test results into Stash
function stashResults(key, results) {
fetch(`/scroll-to-text-fragment/stash.py?key=${key}`, {
method: 'POST',
body: JSON.stringify(results)
});
}
// Fetch test results from the Stash
function fetchResults(key, resolve, reject) {
fetch(`/scroll-to-text-fragment/stash.py?key=${key}`).then(response => {
return response.text();
}).then(text => {
if (text) {
try {
const results = JSON.parse(text);
resolve(results);
} catch(e) {
reject();
}
}
});
}

View file

@ -0,0 +1,17 @@
import time
def main(request, response):
key = request.GET.first("key")
if request.method == "POST":
# Received result data from target page
request.server.stash.put(key, request.body, '/scroll-to-text-fragment/')
return "ok"
else:
# Request for result data from test page
value = request.server.stash.take(key, '/scroll-to-text-fragment/')
# Poll until data is stashed
while value is None:
time.sleep(.1)
value = request.server.stash.take(key, '/scroll-to-text-fragment/')
return value

View file

@ -188,3 +188,13 @@ for (const preventCancel of [true, false]) {
}, `an undefined rejection from write should cause pipeTo() to reject when preventCancel is ${preventCancel}`);
}
promise_test(t => {
const rs = new ReadableStream();
const ws = new WritableStream();
return promise_rejects(t, new TypeError(), rs.pipeTo(ws, {
get preventAbort() {
ws.getWriter();
}
}), 'pipeTo should reject');
}, 'pipeTo() should reject if an option getter grabs a writer');

View file

@ -253,3 +253,14 @@ promise_test(() => {
assert_array_equals(writable.events, [], 'writable should not be aborted');
});
}, 'preventAbort should work');
test(() => {
const rs = new ReadableStream();
const readable = new ReadableStream();
const writable = new WritableStream();
assert_throws(new TypeError(), () => rs.pipeThrough({readable, writable}, {
get preventAbort() {
writable.getWriter();
}
}), 'pipeThrough should throw');
}, 'pipeThrough() should throw if an option getter grabs a writer');

View file

@ -11,7 +11,6 @@ steps:
- template: pip_install.yml
parameters:
packages: virtualenv
- template: install_fonts.yml
- template: install_certs.yml
- template: install_safari.yml
- template: update_hosts.yml

View file

@ -9,7 +9,8 @@ import subprocess
import sys
browser_specific_args = {
"firefox": ["--install-browser"]
"firefox": ["--install-browser"],
"servo": ["--install-browser", "--processes=12"]
}
@ -67,6 +68,10 @@ def main(product, commit_range, wpt_args):
]
wpt_args += browser_specific_args.get(product, [])
# Hack to run servo with one process only for wdspec
if product == "servo" and "--test-type=wdspec" in wpt_args:
wpt_args = [item for item in wpt_args if not item.startswith("--processes")]
command = ["python", "./wpt", "run"] + wpt_args + [product]
logger.info("Executing command: %s" % " ".join(command))

View file

@ -4,7 +4,7 @@ components:
workerType: ci
schedulerId: taskcluster-github
deadline: "24 hours"
image: harjgam/web-platform-tests:0.33
image: harjgam/web-platform-tests:0.34
maxRunTime: 7200
artifacts:
public/results:

View file

@ -15,8 +15,11 @@ RUN apt-get -qqy update \
fluxbox \
gdebi \
git \
gstreamer1.0-plugins-bad \
libosmesa6-dev \
libvirt-daemon-system \
libvirt-clients \
libunwind8 \
locales \
openjdk-8-jre-headless \
pulseaudio \

View file

@ -484,10 +484,6 @@ def check_parsed(repo_root, path, f):
if len(testharnessreport_nodes) > 1:
errors.append(rules.MultipleTestharnessReport.error(path))
testharnesscss_nodes = source_file.root.findall(".//{http://www.w3.org/1999/xhtml}link[@href='/resources/testharness.css']")
if testharnesscss_nodes:
errors.append(rules.PresentTestharnessCSS.error(path))
for element in source_file.variant_nodes:
if "content" not in element.attrib:
errors.append(rules.VariantMissing.error(path))

View file

@ -199,11 +199,6 @@ class MultipleTestharnessReport(Rule):
description = "More than one `<script src='/resources/testharnessreport.js'>`"
class PresentTestharnessCSS(Rule):
name = "PRESENT-TESTHARNESSCSS"
description = "Explicit link to testharness.css present"
class VariantMissing(Rule):
name = "VARIANT-MISSING"
description = collapse("""

View file

@ -410,29 +410,6 @@ def test_missing_testdriver_vendor():
]
def test_present_testharnesscss():
code = b"""
<html xmlns="http://www.w3.org/1999/xhtml">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="stylesheet" href="/resources/testharness.css"/>
</html>
"""
error_map = check_with_files(code)
for (filename, (errors, kind)) in error_map.items():
check_errors(errors)
if kind in ["web-lax", "web-strict"]:
assert errors == [
("PRESENT-TESTHARNESSCSS", "Explicit link to testharness.css present", filename, None),
]
elif kind == "python":
assert errors == [
("PARSE-FAILED", "Unable to parse file", filename, 2),
]
def test_testharness_path():
code = b"""\
<html xmlns="http://www.w3.org/1999/xhtml">

View file

@ -46,6 +46,7 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
rv["pause_after_test"] = kwargs["pause_after_test"]
if test_type == "wdspec":
rv["capabilities"] = {}
rv["webdriver_binary"] = kwargs["binary"]
return rv

View file

@ -148,7 +148,7 @@ class TimedRunner(object):
executor = threading.Thread(target=self.run_func)
executor.start()
# Add twice the timeout multiplier since the called function is expected to
# Add twice the extra timeout since the called function is expected to
# wait at least self.timeout + self.extra_timeout and this gives some leeway
timeout = self.timeout + 2 * self.extra_timeout if self.timeout else None
finished = self.result_flag.wait(timeout)
@ -654,6 +654,8 @@ class CallbackHandler(object):
WebDriver. Things that are more different to WebDriver may need to create a
fully custom implementation."""
unimplemented_exc = (NotImplementedError,)
def __init__(self, logger, protocol, test_window):
self.protocol = protocol
self.test_window = test_window
@ -700,6 +702,9 @@ class CallbackHandler(object):
raise ValueError("Unknown action %s" % action)
try:
result = action_handler(payload)
except self.unimplemented_exc:
self.logger.warning("Action %s not implemented" % action)
self._send_message("complete", "error", "Action %s not implemented" % action)
except Exception:
self.logger.warning("Action %s failed" % action)
self.logger.warning(traceback.format_exc())

View file

@ -31,7 +31,10 @@ from .protocol import (ActionSequenceProtocolPart,
ClickProtocolPart,
SendKeysProtocolPart,
TestDriverProtocolPart,
CoverageProtocolPart)
CoverageProtocolPart,
GenerateTestReportProtocolPart,
VirtualAuthenticatorProtocolPart,
SetPermissionProtocolPart)
from ..testrunner import Stop
from ..webdriver_server import GeckoDriverServer
@ -481,6 +484,44 @@ class MarionetteCoverageProtocolPart(CoverageProtocolPart):
# This usually happens if the process crashed
pass
class MarionetteGenerateTestReportProtocolPart(GenerateTestReportProtocolPart):
def setup(self):
self.marionette = self.parent.marionette
def generate_test_report(self, config):
raise NotImplementedError("generate_test_report not yet implemented")
class MarionetteVirtualAuthenticatorProtocolPart(VirtualAuthenticatorProtocolPart):
def setup(self):
self.marionette = self.parent.marionette
def add_virtual_authenticator(self, config):
raise NotImplementedError("add_virtual_authenticator not yet implemented")
def remove_virtual_authenticator(self, authenticator_id):
raise NotImplementedError("remove_virtual_authenticator not yet implemented")
def add_credential(self, authenticator_id, credential):
raise NotImplementedError("add_credential not yet implemented")
def get_credentials(self, authenticator_id):
raise NotImplementedError("get_credentials not yet implemented")
def remove_credential(self, authenticator_id, credential_id):
raise NotImplementedError("remove_credential not yet implemented")
def remove_all_credentials(self, authenticator_id):
raise NotImplementedError("remove_all_credentials not yet implemented")
def set_user_verified(self, authenticator_id, uv):
raise NotImplementedError("set_user_verified not yet implemented")
class MarionetteSetPermissionProtocolPart(SetPermissionProtocolPart):
def setup(self):
self.marionette = self.parent.marionette
def set_permission(self, name, state, one_realm):
raise NotImplementedError("set_permission not yet implemented")
class MarionetteProtocol(Protocol):
implements = [MarionetteBaseProtocolPart,
@ -493,7 +534,10 @@ class MarionetteProtocol(Protocol):
MarionetteActionSequenceProtocolPart,
MarionetteTestDriverProtocolPart,
MarionetteAssertsProtocolPart,
MarionetteCoverageProtocolPart]
MarionetteCoverageProtocolPart,
MarionetteGenerateTestReportProtocolPart,
MarionetteVirtualAuthenticatorProtocolPart,
MarionetteSetPermissionProtocolPart]
def __init__(self, executor, browser, capabilities=None, timeout_multiplier=1, e10s=True, ccov=False):
do_delayed_imports()

View file

@ -31,6 +31,10 @@ import webdriver as client
here = os.path.join(os.path.split(__file__)[0])
class WebDriverCallbackHandler(CallbackHandler):
unimplemented_exc = (NotImplementedError, client.UnknownCommandException)
class WebDriverBaseProtocolPart(BaseProtocolPart):
def setup(self):
self.webdriver = self.parent.webdriver
@ -376,7 +380,7 @@ class WebDriverTestharnessExecutor(TestharnessExecutor):
parent_window,
timeout=5*self.timeout_multiplier)
self.protocol.base.set_window(test_window)
handler = CallbackHandler(self.logger, protocol, test_window)
handler = WebDriverCallbackHandler(self.logger, protocol, test_window)
protocol.webdriver.url = url
if not self.supports_eager_pageload:

View file

@ -19,7 +19,7 @@
result = JSON.parse(data.message).result
pending_resolve(result);
} else {
pending_reject();
pending_reject(`${data.status}: ${data.message}`);
}
});

Some files were not shown because too many files have changed in this diff Show more