mirror of
https://github.com/servo/servo.git
synced 2025-07-17 12:23:40 +01:00
Update web-platform-tests to revision 314de955a5102650136404f6439f22f8d838e0f4
This commit is contained in:
parent
521748c01e
commit
6b4094e2a4
133 changed files with 1609 additions and 628 deletions
|
@ -1,11 +1,10 @@
|
||||||
[createImageBitmap-drawImage.html]
|
[createImageBitmap-drawImage.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
|
||||||
[createImageBitmap from a HTMLImageElement, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a HTMLImageElement, and drawImage on the created ImageBitmap]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a Blob, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a Blob, and drawImage on the created ImageBitmap]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a HTMLCanvasElement, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a HTMLCanvasElement, and drawImage on the created ImageBitmap]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -50,7 +49,7 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a Blob with negative sw/sh, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a Blob with negative sw/sh, and drawImage on the created ImageBitmap]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a bitmap HTMLImageElement, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a bitmap HTMLImageElement, and drawImage on the created ImageBitmap]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -173,11 +172,11 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a Blob scaled down, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a Blob scaled down, and drawImage on the created ImageBitmap]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a Blob scaled up, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a Blob scaled up, and drawImage on the created ImageBitmap]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
[createImageBitmap from a Blob resized, and drawImage on the created ImageBitmap]
|
[createImageBitmap from a Blob resized, and drawImage on the created ImageBitmap]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -284,3 +284,45 @@
|
||||||
[Descriptor mathcing priority: Style has higher priority than weight]
|
[Descriptor mathcing priority: Style has higher priority than weight]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '100%' should prefer '110% 120%' over '115% 116%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '110%' should prefer '110% 120%' over '115% 116%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '110%' should prefer '115% 116%' over '105%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '110%' should prefer '105%' over '100%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '110%' should prefer '100%' over '50% 80%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '110%' should prefer '50% 80%' over '60% 70%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '90%' should prefer '90% 100%' over '50% 80%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '90%' should prefer '50% 80%' over '60% 70%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '90%' should prefer '60% 70%' over '110% 140%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-stretch: '90%' should prefer '110% 140%' over '120% 130%']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-style: 'normal' should prefer 'normal' over 'oblique 0deg']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-style: 'normal' should prefer 'oblique 0deg' over 'oblique 10deg 40deg']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-style: 'normal' should prefer 'oblique 10deg 40deg' over 'oblique 20deg 30deg']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Matching font-style: 'normal' should prefer 'oblique 20deg 30deg' over 'oblique -50deg -20deg']
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,12 @@
|
||||||
[Test @font-face matching for weight 1000]
|
[Test @font-face matching for weight 1000]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Test @font-face matching for weight 420]
|
[Test @font-face matching for weight 99]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Test @font-face matching for weight 100]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Test @font-face matching for weight 249]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[vh_not_refreshing_on_chrome.html]
|
|
||||||
expected: FAIL
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
[elementsFromPoint-svg-text.html]
|
||||||
|
[elementsFromPoint for a point inside a <text>]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[elementsFromPoint for a point inside a <tspan> nested in a <text> without content]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[elementsFromPoint for a point inside a <textPath> nested in a <text> without content]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[elementsFromPoint for a point inside an overlapping <tspan> nested in a <text>]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -4,3 +4,6 @@
|
||||||
[iso-2022-jp encoder: basics]
|
[iso-2022-jp encoder: basics]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[iso-2022-jp encoder: U+FFFD]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[fetch.tentative.https.sub.html]
|
||||||
|
[Same-origin fetch]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Same-site fetch]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Cross-site fetch]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
[iframe.tentative.https.sub.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Same-origin iframe]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[Same-site iframe]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[Cross-site iframe]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[img.tentative.https.sub.html]
|
||||||
|
[Same-origin image]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Same-site image]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Cross-site image]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[script.tentative.https.sub.html]
|
||||||
|
[Same-origin script]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Same-site script]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Cross-site script]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[fragment-and-encoding-2.html]
|
||||||
|
[Invalid percent-encoded UTF-8 byte should decode as U+FFFD]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Percent-encoded UTF-8 BOM followed by invalid UTF-8 byte should decode as U+FEFF U+FFFD]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[navigation-within-beforeunload.html]
|
|
||||||
[Triggering navigation from within beforeunload event]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -172,3 +172,63 @@
|
||||||
[XHTML img usemap="http://example.org/#garbage-before-hash-id"]
|
[XHTML img usemap="http://example.org/#garbage-before-hash-id"]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="no-hash-name"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="no-hash-id"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="hash-last#"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap=""]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="#"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="#percent-escape-name-%41"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="#percent-escape-id-%41"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="#no-such-map"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="#different-CASE-name"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[HTML (quirks) IMG usemap="#different-CASE-id"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="no-hash-name"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="no-hash-id"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="hash-last#"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap=""]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="#"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="#percent-escape-name-%41"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="#percent-escape-id-%41"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="#no-such-map"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="#different-CASE-name"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XHTML img usemap="#different-CASE-id"]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[img_find_non_sibling_map.html]
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,4 +1,4 @@
|
||||||
[shader-with-non-reserved-words.html]
|
[context-creation-and-destruction.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Overall test]
|
[Overall test]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
|
@ -1,4 +1,4 @@
|
||||||
[context-release-with-workers.html]
|
[context-creation.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[Overall test]
|
[Overall test]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
|
@ -0,0 +1,2 @@
|
||||||
|
[context-eviction-with-garbage-collection.html]
|
||||||
|
expected: TIMEOUT
|
|
@ -7,71 +7,26 @@
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
<script src="/resources/WebIDLParser.js"></script>
|
<script src="/resources/WebIDLParser.js"></script>
|
||||||
<script src="/resources/idlharness.js"></script>
|
<script src="/resources/idlharness.js"></script>
|
||||||
<script type="text/plain" class="untested">
|
|
||||||
interface Navigator { };
|
|
||||||
|
|
||||||
interface EventTarget {
|
|
||||||
void addEventListener(DOMString type, EventListener? callback, optional boolean capture);
|
|
||||||
void removeEventListener(DOMString type, EventListener? callback, optional boolean capture);
|
|
||||||
boolean dispatchEvent(Event event);
|
|
||||||
};
|
|
||||||
|
|
||||||
[Callback]
|
|
||||||
interface EventListener {
|
|
||||||
void handleEvent(Event event);
|
|
||||||
};
|
|
||||||
[TreatNonObjectAsNull]
|
|
||||||
callback EventHandlerNonNull = any (Event event);
|
|
||||||
typedef EventHandlerNonNull? EventHandler;
|
|
||||||
</script>
|
|
||||||
<script type="text/plain">
|
|
||||||
partial interface Navigator {
|
|
||||||
Promise<BatteryManager> getBattery ();
|
|
||||||
};
|
|
||||||
|
|
||||||
[Exposed=Window]
|
|
||||||
interface BatteryManager : EventTarget {
|
|
||||||
readonly attribute boolean charging;
|
|
||||||
readonly attribute unrestricted double chargingTime;
|
|
||||||
readonly attribute unrestricted double dischargingTime;
|
|
||||||
readonly attribute double level;
|
|
||||||
attribute EventHandler onchargingchange;
|
|
||||||
attribute EventHandler onchargingtimechange;
|
|
||||||
attribute EventHandler ondischargingtimechange;
|
|
||||||
attribute EventHandler onlevelchange;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<script>
|
<script>
|
||||||
"use strict";
|
"use strict";
|
||||||
var t = async_test();
|
|
||||||
var idl_array = new IdlArray();
|
promise_test(async () => {
|
||||||
var idls;
|
const idl_array = new IdlArray();
|
||||||
var manager;
|
const dom_idl = await fetch("/interfaces/dom.idl").then(r => r.text());
|
||||||
[].forEach.call(document.querySelectorAll('script[type=text\\/plain]'), function(node) {
|
const battery_idl = await fetch("/interfaces/battery.idl").then(r => r.text());
|
||||||
idls = node.textContent;
|
const manager = await navigator.getBattery();
|
||||||
idl_array[(node.className === 'untested') ? 'add_untested_idls' : 'add_idls'](idls);
|
|
||||||
|
idl_array.add_untested_idls(dom_idl, {only: ['EventTarget']});
|
||||||
|
idl_array.add_untested_idls('interface EventHandler {};');
|
||||||
|
idl_array.add_untested_idls('interface Navigator {};');
|
||||||
|
idl_array.add_idls(battery_idl);
|
||||||
|
|
||||||
|
window.manager = manager;
|
||||||
|
|
||||||
|
idl_array.add_objects({
|
||||||
|
Navigator: ['navigator'],
|
||||||
|
BatteryManager: ['manager'],
|
||||||
});
|
});
|
||||||
t.step(function() {
|
|
||||||
assert_idl_attribute(navigator, 'getBattery', 'navigator must have getBattery attribute');
|
|
||||||
navigator.getBattery().then(function(bm) {
|
|
||||||
manager = bm;
|
|
||||||
idl_array.add_objects({Navigator: ['navigator'], BatteryManager: ['manager']});
|
|
||||||
idl_array.test();
|
idl_array.test();
|
||||||
t.done();
|
}, "Test IDL implementation of Battery Status API");
|
||||||
}).catch(function(err) {
|
|
||||||
t.assert_unreached("navigator.getBattery failed");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
<p>
|
|
||||||
This test validates the BatteryManager interface IDL.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
This test uses <a href="/resources/idlharness.js">idlharness.js</a>, and
|
|
||||||
is complementary to the <a href="battery-interface.html">battery-interface.html</a>
|
|
||||||
test.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div id="log"></div>
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ def main(request, response):
|
||||||
body = request.cookies[ident].value
|
body = request.cookies[ident].value
|
||||||
response.delete_cookie(ident)
|
response.delete_cookie(ident)
|
||||||
else:
|
else:
|
||||||
response.set_cookie(ident, "COOKIE");
|
response.set_cookie(ident, "COOKIE")
|
||||||
body = "NO_COOKIE"
|
body = "NO_COOKIE"
|
||||||
|
|
||||||
return headers, body
|
return headers, body
|
||||||
|
|
|
@ -10,7 +10,7 @@ def main(request, response):
|
||||||
|
|
||||||
response.headers.set("X-Request-Method", request.method)
|
response.headers.set("X-Request-Method", request.method)
|
||||||
|
|
||||||
response.headers.set("X-A-C-Request-Method", request.headers.get("Access-Control-Request-Method", ""));
|
response.headers.set("X-A-C-Request-Method", request.headers.get("Access-Control-Request-Method", ""))
|
||||||
|
|
||||||
|
|
||||||
#This should reasonably work for most response codes.
|
#This should reasonably work for most response codes.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>CSS Grid Layout Test: Support for percentage values for gap with no defined height for the grid</title>
|
<title>CSS Grid Layout Test: Support for percentage values for gap with indefinite percentage basis</title>
|
||||||
<link rel="help" href="https://www.w3.org/TR/css-grid-1/#gutters">
|
<link rel="help" href="https://www.w3.org/TR/css-grid-1/#gutters">
|
||||||
<link rel="help" href="https://www.w3.org/TR/css-align-3/#gap-shorthand">
|
<link rel="help" href="https://www.w3.org/TR/css-align-3/#gap-shorthand">
|
||||||
<link rel="match" href="../reference/grid-collapsed-row-gutters-ref.html">
|
<link rel="match" href="../reference/grid-percentage-gap-ref.html">
|
||||||
<link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk">
|
<link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk">
|
||||||
<style>
|
<style>
|
||||||
#grid {
|
#grid {
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
grid-template-columns: 90px 90px;
|
grid-template-columns: 90px 90px;
|
||||||
grid-template-rows: 90px 90px;
|
grid-template-rows: 90px 90px;
|
||||||
background-color: green;
|
background-color: green;
|
||||||
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#grid > div {
|
#grid > div {
|
||||||
|
@ -20,10 +21,16 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.</p>
|
<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should be percentage of height.</p>
|
||||||
<div id="grid">
|
<div id="grid">
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="grid" style="display:inline-grid; width:auto; gap:calc(20px + 5%)">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>CSS Grid Layout Test: Support for percentage values for grid-gap with no defined height for the grid as alias for gap</title>
|
<title>CSS Grid Layout Test: Support for percentage values for grid-gap with indefinite percentage basis</title>
|
||||||
<link rel="help" href="https://www.w3.org/TR/css-grid-1/#gutters">
|
<link rel="help" href="https://www.w3.org/TR/css-grid-1/#gutters">
|
||||||
<link rel="help" href="https://www.w3.org/TR/css-align-3/#gap-shorthand">
|
<link rel="help" href="https://www.w3.org/TR/css-align-3/#gap-shorthand">
|
||||||
<link rel="match" href="../reference/grid-collapsed-row-gutters-ref.html">
|
<link rel="match" href="../reference/grid-percentage-gap-ref.html">
|
||||||
<link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk">
|
<link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk">
|
||||||
<style>
|
<style>
|
||||||
#grid {
|
#grid {
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
grid-template-columns: 90px 90px;
|
grid-template-columns: 90px 90px;
|
||||||
grid-template-rows: 90px 90px;
|
grid-template-rows: 90px 90px;
|
||||||
background-color: green;
|
background-color: green;
|
||||||
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#grid > div {
|
#grid > div {
|
||||||
|
@ -20,10 +21,16 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.</p>
|
<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should be percentage of height.</p>
|
||||||
<div id="grid">
|
<div id="grid">
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="grid" style="display:inline-grid; width:auto; grid-gap:calc(20px + 5%)">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>CSS Grid Layout Reference: a square with a green bar</title>
|
|
||||||
<link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk" />
|
|
||||||
<style>
|
|
||||||
#grid {
|
|
||||||
width:200px;
|
|
||||||
height: 180px;
|
|
||||||
background-color: green;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
#grid > div {
|
|
||||||
background-color: silver;
|
|
||||||
width: 90px;
|
|
||||||
height: 90px;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
#grid :nth-child(1) {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#grid :nth-child(2) {
|
|
||||||
top: 0;
|
|
||||||
left: 110px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#grid :nth-child(3) {
|
|
||||||
top: 90px;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#grid :nth-child(4) {
|
|
||||||
top: 90px;
|
|
||||||
left: 110px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should resolve to auto, and therefore collapse to 0 height.</p>
|
|
||||||
<div id="grid">
|
|
||||||
<div></div>
|
|
||||||
<div></div>
|
|
||||||
<div></div>
|
|
||||||
<div></div>
|
|
||||||
</div>
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Grid Layout Reference: percentage grid gaps</title>
|
||||||
|
<link rel="author" title="Rachel Andrew" href="mailto:me@rachelandrew.co.uk" />
|
||||||
|
<style>
|
||||||
|
.grid {
|
||||||
|
width:200px;
|
||||||
|
height: 180px;
|
||||||
|
background-color: green;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid > div {
|
||||||
|
background-color: silver;
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>The test passes if it has the same visual effect as reference. Column gap should be percentage of width. Row gap should be percentage of height.</p>
|
||||||
|
<div class="grid">
|
||||||
|
<div style="top:0; left:0"></div>
|
||||||
|
<div style="top:0; left:110px"></div>
|
||||||
|
<div style="top:108px; left:0"></div>
|
||||||
|
<div style="top:108px; left:110px"></div>
|
||||||
|
</div>
|
||||||
|
<div class="grid" style="height:200px">
|
||||||
|
<div style="top:0; left:0"></div>
|
||||||
|
<div style="top:0; left:120px"></div>
|
||||||
|
<div style="top:120px; left:0"></div>
|
||||||
|
<div style="top:120px; left:120px"></div>
|
||||||
|
</div>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<title>Document.prototype.elementsFromPoint on SVG text content elements</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="resources/elementsFromPoint.js"></script>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#svg {
|
||||||
|
margin: 100px;
|
||||||
|
background-color: rgba(0,180,0,0.2);
|
||||||
|
}
|
||||||
|
text {
|
||||||
|
font-size: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id='sandbox'>
|
||||||
|
<svg id='svg' width='300' height='300'>
|
||||||
|
<defs>
|
||||||
|
<path id="path" d="M10,170h1000"/>
|
||||||
|
</defs>
|
||||||
|
<text id="text1" x="10" y="50">Some text</text>
|
||||||
|
<text id="text2" x="10" y="110"><tspan id="tspan1">Some text</tspan></text>
|
||||||
|
<text id="text3"><textPath id="textpath1" xlink:href="#path">Some text</textPath></text>
|
||||||
|
<text id="text4" x="10" y="230">Text under<tspan id="tspan2" x="10">Text over</tspan></text>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assertElementsFromPoint('document', 125, 125,
|
||||||
|
[text1, svg, sandbox, document.body, document.documentElement]);
|
||||||
|
}, 'elementsFromPoint for a point inside a <text>');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assertElementsFromPoint('document', 125, 185,
|
||||||
|
[tspan1, svg, sandbox, document.body, document.documentElement]);
|
||||||
|
}, 'elementsFromPoint for a point inside a <tspan> nested in a <text> without content');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assertElementsFromPoint('document', 125, 245,
|
||||||
|
[textpath1, svg, sandbox, document.body, document.documentElement]);
|
||||||
|
}, 'elementsFromPoint for a point inside a <textPath> nested in a <text> without content');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assertElementsFromPoint('document', 125, 305,
|
||||||
|
[tspan2, text4, svg, sandbox, document.body, document.documentElement]);
|
||||||
|
}, 'elementsFromPoint for a point inside an overlapping <tspan> nested in a <text>');
|
||||||
|
</script>
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
encode("ab", "ab", "very basic")
|
encode("ab", "ab", "very basic")
|
||||||
// edge cases
|
// edge cases
|
||||||
encode("\u9EA6", "&%2340614;", "Highest-pointer BMP character excluded from encoder");
|
encode("\u9EA6", "%26%2340614%3B", "Highest-pointer BMP character excluded from encoder");
|
||||||
encode("\uD858\uDE6B", "&%23156267;", "Highest-pointer character excluded from encoder");
|
encode("\uD858\uDE6B", "%26%23156267%3B", "Highest-pointer character excluded from encoder");
|
||||||
encode("\u3000", "%A1@", "Lowest-pointer character included in encoder");
|
encode("\u3000", "%A1@", "Lowest-pointer character included in encoder");
|
||||||
encode("\u20AC", "%A3%E1", "Euro; the highest-pointer character before a range of 30 unmapped pointers");
|
encode("\u20AC", "%A3%E1", "Euro; the highest-pointer character before a range of 30 unmapped pointers");
|
||||||
encode("\u4E00", "%A4@", "The lowest-pointer character after the range of 30 unmapped pointers");
|
encode("\u4E00", "%A4@", "The lowest-pointer character after the range of 30 unmapped pointers");
|
||||||
|
@ -24,8 +24,8 @@
|
||||||
encode("\uFFE2", "%C8%CD", "The lowest-pointer character after the range of 41 unmapped pointers");
|
encode("\uFFE2", "%C8%CD", "The lowest-pointer character after the range of 41 unmapped pointers");
|
||||||
encode("\u79D4", "%FE%FE", "The last character in the index");
|
encode("\u79D4", "%FE%FE", "The last character in the index");
|
||||||
// not in index
|
// not in index
|
||||||
encode("\u2603", "&%239731;", "The canonical BMP test character that is not in the index");
|
encode("\u2603", "%26%239731%3B", "The canonical BMP test character that is not in the index");
|
||||||
encode("\uD83D\uDCA9", "&%23128169;", "The canonical astral test character that is not in the index");
|
encode("\uD83D\uDCA9", "%26%23128169%3B", "The canonical astral test character that is not in the index");
|
||||||
// duplicate low bits
|
// duplicate low bits
|
||||||
encode("\uD840\uDFB5", "%FDj", "A Plane 2 character whose low 16 bits match a BMP character that has a lower pointer");
|
encode("\uD840\uDFB5", "%FDj", "A Plane 2 character whose low 16 bits match a BMP character that has a lower pointer");
|
||||||
// prefer last
|
// prefer last
|
||||||
|
|
|
@ -17,5 +17,5 @@
|
||||||
encode("\u4E02", "%81@", "character")
|
encode("\u4E02", "%81@", "character")
|
||||||
encode("\uE4C6", "%A1@", "PUA")
|
encode("\uE4C6", "%A1@", "PUA")
|
||||||
encode("\uE4C5", "%FE%FE", "PUA #2")
|
encode("\uE4C5", "%FE%FE", "PUA #2")
|
||||||
encode("\ud83d\udca9", "&%23128169;", "poo")
|
encode("\ud83d\udca9", "%26%23128169%3B", "poo")
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -15,4 +15,5 @@
|
||||||
encode("s", "s", "very basic")
|
encode("s", "s", "very basic")
|
||||||
encode("\u00A5\u203Es\\\uFF90\u4F69", "%1B(J\\~s%1B(B\\%1B$B%_PP%1B(B", "basics")
|
encode("\u00A5\u203Es\\\uFF90\u4F69", "%1B(J\\~s%1B(B\\%1B$B%_PP%1B(B", "basics")
|
||||||
encode("\x0E\x0F\x1Bx", "%0E%0F%1Bx", "SO/SI ESC")
|
encode("\x0E\x0F\x1Bx", "%0E%0F%1Bx", "SO/SI ESC")
|
||||||
|
encode("\uFFFD", "%26%2365533%3B", "U+FFFD");
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -170,10 +170,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,10 +135,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,10 +179,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,10 +170,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,10 +135,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,10 +179,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,10 +165,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,10 +135,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,10 +175,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,10 +166,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,10 +175,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,10 +136,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,10 +136,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,10 +178,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,10 +135,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,10 +175,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,10 +135,7 @@ function runNext(id) {
|
||||||
for (var j = 0; j < cplist[i].length; j++) {
|
for (var j = 0; j < cplist[i].length; j++) {
|
||||||
var t = tests[i][j];
|
var t = tests[i][j];
|
||||||
t.step(function() {
|
t.step(function() {
|
||||||
assert_equals(
|
assert_equals(results[j], cplist[i][j].expected);
|
||||||
normalizeStr(results[j]),
|
|
||||||
normalizeStr(cplist[i][j].expected)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
t.done();
|
t.done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ function encode(input, expected, desc) {
|
||||||
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
var a = document.createElement("a"); // <a> uses document encoding for URL's query
|
||||||
a.href = "https://example.com/?" + input;
|
a.href = "https://example.com/?" + input;
|
||||||
result = a.search.substr(1); // remove leading "?"
|
result = a.search.substr(1); // remove leading "?"
|
||||||
assert_equals(normalizeStr(result), normalizeStr(expected));
|
assert_equals(result, expected);
|
||||||
}, desc);
|
}, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>'document-stream-insertion' tests</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/feature-policy/experimental-features/resources/common.js"></script>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<iframe></iframe>
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let iframeElement = document.querySelector("iframe");
|
||||||
|
let url = url_base + "document-stream-insertion.html";
|
||||||
|
|
||||||
|
let text_to_write = "<div>FOO<\/div>";
|
||||||
|
let test_cases = [{
|
||||||
|
api: "open",
|
||||||
|
query: "body",
|
||||||
|
expected_value_enabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: "close"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: "write",
|
||||||
|
args: text_to_write,
|
||||||
|
query: "div",
|
||||||
|
expected_value_enabled: "FOO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: "writeln",
|
||||||
|
args: text_to_write,
|
||||||
|
query: "div",
|
||||||
|
expected_value_enabled: "FOO"
|
||||||
|
}];
|
||||||
|
|
||||||
|
// The feature 'document-stream-insertion' is enabled by default and when it
|
||||||
|
// is enabled, all dynamic markup insertion API work as intended.
|
||||||
|
test_cases.forEach((tc) => {
|
||||||
|
promise_test(async() => {
|
||||||
|
await loadUrlInIframe(iframeElement, url);
|
||||||
|
await sendMessageAndGetResponse(iframeElement.contentWindow, tc).then((response) => {
|
||||||
|
assert_false(
|
||||||
|
response.did_throw_exception,
|
||||||
|
`When feature is disabled, invoking 'document.${tc.api}' should not` +
|
||||||
|
" throw an exception.");
|
||||||
|
if (tc.query) {
|
||||||
|
assert_equals(
|
||||||
|
response.value,
|
||||||
|
tc.expected_value_enabled,
|
||||||
|
`The added script tag by 'document.${tc.api}' must have run.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, `Verify 'document.${tc.api}' is not normally blocked.` );
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Disabling 'document-stream-insertion' throws exception on the included API.
|
||||||
|
test_cases.forEach((tc) => {
|
||||||
|
promise_test(async() => {
|
||||||
|
setFeatureState(iframeElement, "document-stream-insertion", "'none'");
|
||||||
|
await loadUrlInIframe(iframeElement, url);
|
||||||
|
await sendMessageAndGetResponse(iframeElement.contentWindow, tc).then((response) => {
|
||||||
|
assert_true(
|
||||||
|
response.did_throw_exception,
|
||||||
|
`When feature is enabled, invoking 'document.${tc.api}' should ` +
|
||||||
|
" throw an exception.");
|
||||||
|
if (tc.query) {
|
||||||
|
assert_not_equals(
|
||||||
|
response.value,
|
||||||
|
tc.expected_value_enabled,
|
||||||
|
`The added script tag by 'document.${tc.api}' must not have run.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, `Verify 'document.${tc.api}' is blocked when the feature is disabled.` );
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,34 @@
|
||||||
|
const url_base = "/feature-policy/experimental-features/resources/";
|
||||||
|
window.messageResponseCallback = null;
|
||||||
|
|
||||||
|
function setFeatureState(iframe, feature, origins) {
|
||||||
|
iframe.setAttribute("allow", `${feature} ${origins};`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise which is resolved when the <iframe> is navigated to |url|
|
||||||
|
// and "load" handler has been called.
|
||||||
|
function loadUrlInIframe(iframe, url) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
iframe.addEventListener("load", resolve);
|
||||||
|
iframe.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Posts |message| to |target| and resolves the promise with the response coming
|
||||||
|
// back from |target|.
|
||||||
|
function sendMessageAndGetResponse(target, message) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
window.messageResponseCallback = resolve;
|
||||||
|
target.postMessage(message, "*");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onMessage(e) {
|
||||||
|
if (window.messageResponseCallback) {
|
||||||
|
window.messageResponseCallback(e.data);
|
||||||
|
window.messageResponseCallback = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("message", onMessage);
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
#spacer {
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.addEventListener("message", onMessageReceived);
|
||||||
|
|
||||||
|
function test(api, args) {
|
||||||
|
let did_throw = false;
|
||||||
|
try {
|
||||||
|
document[api](args);
|
||||||
|
} catch(e) {
|
||||||
|
did_throw = true;
|
||||||
|
}
|
||||||
|
return did_throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMessageReceived(e) {
|
||||||
|
let msg = e.data;
|
||||||
|
|
||||||
|
msg.did_throw_exception = test(msg.api, msg.args);
|
||||||
|
if (msg.query) {
|
||||||
|
let el = document.querySelector(msg.query);
|
||||||
|
msg.value = el ? el.innerHTML : false;
|
||||||
|
}
|
||||||
|
ackMessage(msg, e.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ackMessage(msg, source) {
|
||||||
|
source.postMessage(msg, "*");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
|
@ -1,6 +1,3 @@
|
||||||
const url_base = "/feature-policy/experimental-features/resources/";
|
|
||||||
window.messageResponseCallback = null;
|
|
||||||
|
|
||||||
function rectMaxY(rect) {
|
function rectMaxY(rect) {
|
||||||
return rect.height + rect.y;
|
return rect.height + rect.y;
|
||||||
}
|
}
|
||||||
|
@ -23,33 +20,6 @@ function rects_intersect(rect1, rect2) {
|
||||||
rect2.y < rectMaxY(rect1);
|
rect2.y < rectMaxY(rect1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise which is resolved when the <iframe> is navigated to |url|
|
|
||||||
// and "load" handler has been called.
|
|
||||||
function loadUrlInIframe(iframe, url) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
iframe.addEventListener("load", resolve);
|
|
||||||
iframe.src = url;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Posts |message| to |target| and resolves the promise with the response coming
|
|
||||||
// back from |target|.
|
|
||||||
function sendMessageAndGetResponse(target, message) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
window.messageResponseCallback = resolve;
|
|
||||||
target.postMessage(message, "*");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function rectToString(rect) {
|
function rectToString(rect) {
|
||||||
return `Location: (${rect.x}, ${rect.y}) Size: (${rect.width}, ${rect.height})`;
|
return `Location: (${rect.x}, ${rect.y}) Size: (${rect.width}, ${rect.height})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMessage(e) {
|
|
||||||
if (window.messageResponseCallback) {
|
|
||||||
window.messageResponseCallback(e.data);
|
|
||||||
window.messageResponseCallback = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("message", onMessage);
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/feature-policy/experimental-features/resources/common.js"></script>
|
||||||
<script src="/feature-policy/experimental-features/resources/vertical-scroll.js"></script>
|
<script src="/feature-policy/experimental-features/resources/vertical-scroll.js"></script>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
|
@ -73,7 +74,7 @@ iframe {
|
||||||
// of disabled frames (does not propagate to main frame).
|
// of disabled frames (does not propagate to main frame).
|
||||||
promise_test(async() => {
|
promise_test(async() => {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
iframeElement.allow = "vertical-scroll 'none';";
|
setFeatureState(iframeElement, "vertical-scroll", "'none'");
|
||||||
await loadUrlInIframe(iframeElement, url);
|
await loadUrlInIframe(iframeElement, url);
|
||||||
|
|
||||||
await sendMessageAndGetResponse(
|
await sendMessageAndGetResponse(
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<title>vertical-scroll test for touch-action</title>
|
<title>vertical-scroll test for touch-action</title>
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/feature-policy/experimental-features/resources/common.js"></script>
|
||||||
<script src="/feature-policy/experimental-features/resources/vertical-scroll.js"></script>
|
<script src="/feature-policy/experimental-features/resources/vertical-scroll.js"></script>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
|
@ -81,7 +82,7 @@ iframe {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
|
||||||
// Disallow vertical scroll and reload the <iframe>.
|
// Disallow vertical scroll and reload the <iframe>.
|
||||||
iframeElement.setAttribute("allow", "vertical-scroll 'none';");
|
setFeatureState(iframeElement, "vertical-scroll", "'none'");
|
||||||
await loadUrlInIframe(iframeElement, url);
|
await loadUrlInIframe(iframeElement, url);
|
||||||
|
|
||||||
// Apply the scroll gesture. Main frame should scroll vertically.
|
// Apply the scroll gesture. Main frame should scroll vertically.
|
||||||
|
|
|
@ -49,10 +49,10 @@ def main(request, response):
|
||||||
|
|
||||||
# The only-if-cached redirect tests wants CORS to be okay, the other tests
|
# The only-if-cached redirect tests wants CORS to be okay, the other tests
|
||||||
# are all same-origin anyways and don't care.
|
# are all same-origin anyways and don't care.
|
||||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
response.headers.set("Access-Control-Allow-Origin", "*")
|
||||||
|
|
||||||
if redirect:
|
if redirect:
|
||||||
response.headers.set("Location", redirect);
|
response.headers.set("Location", redirect)
|
||||||
response.status = (302, "Redirect")
|
response.status = (302, "Redirect")
|
||||||
return ""
|
return ""
|
||||||
elif ((inm is not None and inm == tag) or
|
elif ((inm is not None and inm == tag) or
|
||||||
|
|
|
@ -12,4 +12,3 @@ def main(request, response):
|
||||||
return ((401, "Unauthorized"),
|
return ((401, "Unauthorized"),
|
||||||
[("WWW-Authenticate", 'Basic realm="' + realm + '"')],
|
[("WWW-Authenticate", 'Basic realm="' + realm + '"')],
|
||||||
"Please login with credentials 'user' and 'password'")
|
"Please login with credentials 'user' and 'password'")
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ def main(request, response):
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
response.headers.set("Transfer-Encoding", "chunked")
|
response.headers.set("Transfer-Encoding", "chunked")
|
||||||
response.write_status_headers()
|
response.write_status_headers()
|
||||||
time.sleep(delay);
|
time.sleep(delay)
|
||||||
for i in xrange(count):
|
for i in xrange(count):
|
||||||
response.writer.write_content("a\r\nTEST_CHUNK\r\n")
|
response.writer.write_content("a\r\nTEST_CHUNK\r\n")
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
|
|
|
@ -8,7 +8,7 @@ def main(request, response):
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
response.headers.set("Content-type", "text/plain")
|
response.headers.set("Content-type", "text/plain")
|
||||||
response.write_status_headers()
|
response.write_status_headers()
|
||||||
time.sleep(delay);
|
time.sleep(delay)
|
||||||
for i in xrange(count):
|
for i in xrange(count):
|
||||||
response.writer.write_content("TEST_TRICKLE\n")
|
response.writer.write_content("TEST_TRICKLE\n")
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
|
|
|
@ -30,7 +30,7 @@ def main(request, response):
|
||||||
noted_headers[header[0].lower()] = header[1]
|
noted_headers[header[0].lower()] = header[1]
|
||||||
|
|
||||||
if "access-control-allow-origin" not in noted_headers:
|
if "access-control-allow-origin" not in noted_headers:
|
||||||
response.headers.set("Access-Control-Allow-Origin", "*");
|
response.headers.set("Access-Control-Allow-Origin", "*")
|
||||||
if "content-type" not in noted_headers:
|
if "content-type" not in noted_headers:
|
||||||
response.headers.set("Content-Type", "text/plain")
|
response.headers.set("Content-Type", "text/plain")
|
||||||
response.headers.set("Server-Request-Count", len(server_state))
|
response.headers.set("Server-Request-Count", len(server_state))
|
||||||
|
|
11
tests/wpt/web-platform-tests/fetch/sec-metadata/README.md
Normal file
11
tests/wpt/web-platform-tests/fetch/sec-metadata/README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
`Sec-Metadata` Tests
|
||||||
|
====================
|
||||||
|
|
||||||
|
This directory contains tests related to the `Sec-Metadata` proposal:
|
||||||
|
|
||||||
|
: Explainer
|
||||||
|
:: <https://github.com/mikewest/sec-metadata>
|
||||||
|
: "Spec"
|
||||||
|
:: <https://mikewest.github.io/sec-metadata/>
|
||||||
|
|
||||||
|
Note: All of this is tentative, and will change (rapidly).
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/fetch/sec-metadata/resources/helper.js></script>
|
||||||
|
<script>
|
||||||
|
promise_test(t => {
|
||||||
|
return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(j => {
|
||||||
|
assert_header_equals(j.header, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "\"\"",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "same-origin"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "Same-origin fetch");
|
||||||
|
|
||||||
|
promise_test(t => {
|
||||||
|
return fetch("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(j => {
|
||||||
|
assert_header_equals(j.header, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "\"\"",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "same-site"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "Same-site fetch");
|
||||||
|
|
||||||
|
promise_test(t => {
|
||||||
|
return fetch("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py")
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(j => {
|
||||||
|
assert_header_equals(j.header, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "\"\"",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "cross-site"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "Cross-site fetch");
|
||||||
|
</script>
|
|
@ -0,0 +1,63 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/fetch/sec-metadata/resources/helper.js></script>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
async_test(t => {
|
||||||
|
let i = document.createElement('iframe');
|
||||||
|
i.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != i.contentWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "nested",
|
||||||
|
"site": "same-origin"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
document.body.appendChild(i);
|
||||||
|
}, "Same-origin iframe");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let i = document.createElement('iframe');
|
||||||
|
i.src = "https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != i.contentWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "nested",
|
||||||
|
"site": "same-site"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
document.body.appendChild(i);
|
||||||
|
}, "Same-site iframe");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let i = document.createElement('iframe');
|
||||||
|
i.src = "https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py";
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != i.contentWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "nested",
|
||||||
|
"site": "cross-site"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
document.body.appendChild(i);
|
||||||
|
}, "Cross-site iframe");
|
||||||
|
</script>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/referrer-policy/generic/common.js></script>
|
||||||
|
<script src=/fetch/sec-metadata/resources/helper.js></script>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
// These tests reuse the `referrer-policy` infrastructure to load images that
|
||||||
|
// encode their request headers in their pixels. Fun stuff!
|
||||||
|
async_test(t => {
|
||||||
|
loadImageInWindow(
|
||||||
|
"https://{{host}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
|
||||||
|
t.step_func_done(img => {
|
||||||
|
assert_header_equals(decodeImageData(extractImageData(img)).headers["sec-metadata"], {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "image",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "same-origin"
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
window);
|
||||||
|
}, "Same-origin image");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
loadImageInWindow(
|
||||||
|
"https://{{hosts[][www]}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
|
||||||
|
t.step_func_done(img => {
|
||||||
|
assert_header_equals(decodeImageData(extractImageData(img)).headers["sec-metadata"], {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "image",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "same-site"
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
window);
|
||||||
|
}, "Same-site image");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
loadImageInWindow(
|
||||||
|
"https://{{hosts[alt][www]}}:{{ports[https][0]}}/referrer-policy/generic/subresource/image.py",
|
||||||
|
t.step_func_done(img => {
|
||||||
|
assert_header_equals(decodeImageData(extractImageData(img)).headers["sec-metadata"], {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "image",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "cross-site"
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
window);
|
||||||
|
}, "Cross-site image");
|
||||||
|
</script>
|
|
@ -0,0 +1,12 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
def main(request, response):
|
||||||
|
headers = [("Content-Type", "application/json"),
|
||||||
|
("Access-Control-Allow-Credentials", "true")]
|
||||||
|
|
||||||
|
if "origin" in request.headers:
|
||||||
|
headers.append(("Access-Control-Allow-Origin", request.headers["origin"]))
|
||||||
|
|
||||||
|
|
||||||
|
body = json.dumps({ "header": request.headers["sec-metadata"] })
|
||||||
|
return headers, body
|
|
@ -0,0 +1,8 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
def main(request, response):
|
||||||
|
headers = [("Content-Type", "text/javascript")]
|
||||||
|
|
||||||
|
body = "var header = %s;" % json.dumps(request.headers["sec-metadata"]);
|
||||||
|
|
||||||
|
return headers, body
|
|
@ -0,0 +1,16 @@
|
||||||
|
function parse_metadata(value) {
|
||||||
|
let result = {};
|
||||||
|
value.split(',').forEach(item => {
|
||||||
|
let parsed = item.trim().split('=');
|
||||||
|
result[parsed[0]] = parsed[1];
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_header_equals(value, expected) {
|
||||||
|
let result = parse_metadata(value);
|
||||||
|
assert_equals(result.cause, expected.cause, "cause");
|
||||||
|
assert_equals(result.destination, expected.destination, "destination");
|
||||||
|
assert_equals(result.target, expected.target, "target");
|
||||||
|
assert_equals(result.site, expected.site, "site");
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
def main(request, response):
|
||||||
|
headers = [("Content-Type", "text/html")]
|
||||||
|
|
||||||
|
body = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script>
|
||||||
|
var data = %s;
|
||||||
|
if (window.opener)
|
||||||
|
window.opener.postMessage(data, "*");
|
||||||
|
if (window.top != window)
|
||||||
|
window.top.postMessage(data, "*");
|
||||||
|
</script>
|
||||||
|
""" % json.dumps(request.headers["sec-metadata"])
|
||||||
|
return headers, body
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/fetch/sec-metadata/resources/helper.js></script>
|
||||||
|
|
||||||
|
<!-- Same-origin script -->
|
||||||
|
<script src="https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
|
||||||
|
<script>
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(_ => header = null);
|
||||||
|
|
||||||
|
assert_header_equals(header, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "script",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "same-origin"
|
||||||
|
});
|
||||||
|
}, "Same-origin script");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Same-site script -->
|
||||||
|
<script src="https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
|
||||||
|
<script>
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(_ => header = null);
|
||||||
|
|
||||||
|
assert_header_equals(header, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "script",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "same-site"
|
||||||
|
});
|
||||||
|
}, "Same-site script");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Cross-site script -->
|
||||||
|
<script src="https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-script.py"></script>
|
||||||
|
<script>
|
||||||
|
test(t => {
|
||||||
|
t.add_cleanup(_ => header = null);
|
||||||
|
|
||||||
|
assert_header_equals(header, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "script",
|
||||||
|
"target": "subresource",
|
||||||
|
"site": "cross-site"
|
||||||
|
});
|
||||||
|
}, "Cross-site script");
|
||||||
|
</script>
|
|
@ -0,0 +1,127 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<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=/fetch/sec-metadata/resources/helper.js></script>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
// Forced navigations:
|
||||||
|
async_test(t => {
|
||||||
|
let w = window.open("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
|
||||||
|
t.add_cleanup(_ => w.close());
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "top-level",
|
||||||
|
"site": "same-origin"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
}, "Same-origin window, forced");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let w = window.open("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
|
||||||
|
t.add_cleanup(_ => w.close());
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "top-level",
|
||||||
|
"site": "same-site"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
}, "Same-site window, forced");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let w = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
|
||||||
|
t.add_cleanup(_ => w.close());
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "forced",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "top-level",
|
||||||
|
"site": "cross-site"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
}, "Cross-site window, forced");
|
||||||
|
|
||||||
|
// User-activated navigations:
|
||||||
|
async_test(t => {
|
||||||
|
let b = document.createElement('button');
|
||||||
|
b.onclick = t.step_func(_ => {
|
||||||
|
let w = window.open("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
|
||||||
|
t.add_cleanup(_ => w.close());
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "user-activated",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "top-level",
|
||||||
|
"site": "same-origin"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
document.body.appendChild(b);
|
||||||
|
test_driver.click(b);
|
||||||
|
}, "Same-origin window, user-activated");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let b = document.createElement('button');
|
||||||
|
b.onclick = t.step_func(_ => {
|
||||||
|
let w = window.open("https://{{hosts[][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
|
||||||
|
t.add_cleanup(_ => w.close());
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "user-activated",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "top-level",
|
||||||
|
"site": "same-site"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
document.body.appendChild(b);
|
||||||
|
test_driver.click(b);
|
||||||
|
}, "Same-site window, user-activated");
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
let b = document.createElement('button');
|
||||||
|
b.onclick = t.step_func(_ => {
|
||||||
|
let w = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py");
|
||||||
|
t.add_cleanup(_ => w.close());
|
||||||
|
window.addEventListener('message', t.step_func(e => {
|
||||||
|
if (e.source != w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert_header_equals(e.data, {
|
||||||
|
"cause": "user-activated",
|
||||||
|
"destination": "document",
|
||||||
|
"target": "top-level",
|
||||||
|
"site": "cross-site"
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
document.body.appendChild(b);
|
||||||
|
test_driver.click(b);
|
||||||
|
}, "Cross-site window, user-activated");
|
||||||
|
</script>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=windows-1252>
|
||||||
|
<title>Fragment navigation: encoding</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<div style=height:10000px></div>
|
||||||
|
<div id=�></div>
|
||||||
|
<div id=�></div>
|
||||||
|
<script>
|
||||||
|
function goToTop() {
|
||||||
|
location.hash = "top";
|
||||||
|
assert_equals(self.scrollY, 0, "#top");
|
||||||
|
}
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_equals(location.hash, "", "Page must be loaded with no hash");
|
||||||
|
|
||||||
|
location.hash = "%C2";
|
||||||
|
assert_equals(location.hash, "#%C2");
|
||||||
|
assert_greater_than(self.scrollY, 1000, "#%C2");
|
||||||
|
}, "Invalid percent-encoded UTF-8 byte should decode as U+FFFD");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
goToTop();
|
||||||
|
|
||||||
|
location.hash = "%EF%BB%BF%C2";
|
||||||
|
assert_equals(location.hash, "#%EF%BB%BF%C2");
|
||||||
|
assert_greater_than(self.scrollY, 1000, "#%EF%BB%BF%C2");
|
||||||
|
}, "Percent-encoded UTF-8 BOM followed by invalid UTF-8 byte should decode as U+FEFF U+FFFD");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
goToTop();
|
||||||
|
|
||||||
|
location.hash = "%EF%BF%BD";
|
||||||
|
assert_equals(location.hash, "#%EF%BF%BD");
|
||||||
|
assert_greater_than(self.scrollY, 1000, "#%EF%BF%BD");
|
||||||
|
|
||||||
|
goToTop();
|
||||||
|
}, "Percent-encoded UTF-8 byte sequence for U+FFFD should decode as U+FFFD");
|
||||||
|
</script>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=windows-1252>
|
||||||
|
<title>Fragment navigation: encoding</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="log"></div>
|
||||||
|
<div style=height:10000px></div>
|
||||||
|
<div id=ÿ></div>
|
||||||
|
<div id=></div>
|
||||||
|
<script>
|
||||||
|
function goToTop() {
|
||||||
|
location.hash = "top";
|
||||||
|
assert_equals(self.scrollY, 0, "#top");
|
||||||
|
}
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_equals(location.hash, "", "Page must be loaded with no hash");
|
||||||
|
|
||||||
|
location.hash = "\u00FF";
|
||||||
|
assert_equals(location.hash, "#%C3%BF");
|
||||||
|
assert_greater_than(self.scrollY, 1000, "#%C3%BF");
|
||||||
|
}, "U+00FF should find U+00FF");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
goToTop();
|
||||||
|
|
||||||
|
location.hash = "%EF%BB%BF";
|
||||||
|
assert_greater_than(self.scrollY, 1000, "#%EF%BB%BF");
|
||||||
|
}, "Percent-encoded UTF-8 BOM should find U+FEFF as BOM is not stripped when decoding");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
goToTop();
|
||||||
|
|
||||||
|
location.hash = "%FF";
|
||||||
|
assert_equals(self.scrollY, 0, "#%FF");
|
||||||
|
}, "%FF should not find U+00FF as decoding it gives U+FFFD");
|
||||||
|
</script>
|
|
@ -15,7 +15,10 @@ onload = function() {setTimeout(function() {
|
||||||
|
|
||||||
iframe.onload = function() {
|
iframe.onload = function() {
|
||||||
setTimeout(function() {iframe.contentWindow.location="navigation-within-beforeunload-2.html";}, 100);
|
setTimeout(function() {iframe.contentWindow.location="navigation-within-beforeunload-2.html";}, 100);
|
||||||
iframe.onload = t.step_func(function() {assert_equals(counter, 1000); t.done()});
|
// Step 4 of https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigating-across-documents
|
||||||
|
// doesn't seem to allow navigation within a beforeunload handler,
|
||||||
|
// so the counter should not go beyond 1.
|
||||||
|
iframe.onload = t.step_func(function() {assert_equals(counter, 1); t.done()});
|
||||||
};
|
};
|
||||||
|
|
||||||
iframe.src = "navigation-within-beforeunload-1.html?" + Math.random();
|
iframe.src = "navigation-within-beforeunload-1.html?" + Math.random();
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
function expected(encoding) {
|
function expected(encoding) {
|
||||||
return "?" + {
|
return "?" + {
|
||||||
"UTF-8": "%C3%BF",
|
"UTF-8": "%C3%BF",
|
||||||
"windows-1251": "&%23255;",
|
"windows-1251": "%26%23255%3B",
|
||||||
"windows-1252": "%FF"
|
"windows-1252": "%FF"
|
||||||
}[encoding];
|
}[encoding];
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ onload = function() {
|
||||||
'utf-16be':'%C3%A5',
|
'utf-16be':'%C3%A5',
|
||||||
'utf-16le':'%C3%A5',
|
'utf-16le':'%C3%A5',
|
||||||
'windows-1252':'%E5',
|
'windows-1252':'%E5',
|
||||||
'windows-1251':'&%23229;'
|
'windows-1251':'%26%23229%3B'
|
||||||
};
|
};
|
||||||
var expected_current = expected_obj[encoding];
|
var expected_current = expected_obj[encoding];
|
||||||
var expected_utf8 = expected_obj['utf-8'];
|
var expected_utf8 = expected_obj['utf-8'];
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<script src="/common/media.js"></script>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
async_test(function(test)
|
||||||
|
{
|
||||||
|
var video = document.createElement("video");
|
||||||
|
|
||||||
|
// Create an out-of-band text track by adding a track element.
|
||||||
|
var trackElement = document.createElement('track');
|
||||||
|
|
||||||
|
trackElement.addEventListener("error", test.step_func(function()
|
||||||
|
{
|
||||||
|
assert_unreached("'error' event on track element should not fire.")
|
||||||
|
}));
|
||||||
|
|
||||||
|
video.appendChild(trackElement);
|
||||||
|
trackElement.src = 'resources/webvtt-file.vtt';
|
||||||
|
trackElement.track.mode = 'hidden';
|
||||||
|
|
||||||
|
assert_equals(video.textTracks.length, 1);
|
||||||
|
var outOfBandTrack = video.textTracks[0];
|
||||||
|
|
||||||
|
// Load a media file with an inband text track.
|
||||||
|
var inbandTrack = null;
|
||||||
|
var url = "resources/vp8-vorbis-webvtt.webm"
|
||||||
|
|
||||||
|
var firstAddTrackHandler = test.step_func(function()
|
||||||
|
{
|
||||||
|
assert_equals(event.target, video.textTracks);
|
||||||
|
assert_equals(event instanceof window.TrackEvent, true);
|
||||||
|
if (event.track == outOfBandTrack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equals(inbandTrack, null);
|
||||||
|
assert_equals(video.textTracks.length, 2);
|
||||||
|
assert_equals(event.track, video.textTracks[1]);
|
||||||
|
inbandTrack = event.track;
|
||||||
|
|
||||||
|
video.textTracks.removeEventListener("addtrack", firstAddTrackHandler);
|
||||||
|
|
||||||
|
// Clear .src to force the inband track to get destroyed.
|
||||||
|
video.src = "";
|
||||||
|
|
||||||
|
// Verify that the inband track was removed.
|
||||||
|
assert_not_equals(inbandTrack, null);
|
||||||
|
assert_equals(video.textTracks.length, 1);
|
||||||
|
assert_equals(video.textTracks[0], outOfBandTrack);
|
||||||
|
|
||||||
|
// Load the URL again to trigger another 'addtrack' event to make sure
|
||||||
|
// no 'removetrack' event was queued.
|
||||||
|
video.src = url;
|
||||||
|
video.textTracks.addEventListener("addtrack", test.step_func(function()
|
||||||
|
{
|
||||||
|
assert_equals(video.textTracks.length, 2);
|
||||||
|
test.done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
video.textTracks.addEventListener("addtrack", firstAddTrackHandler);
|
||||||
|
|
||||||
|
video.textTracks.addEventListener("removetrack", test.step_func(function()
|
||||||
|
{
|
||||||
|
assert_unreached("'removetrack' event should not fire.")
|
||||||
|
}));
|
||||||
|
|
||||||
|
video.src = url;
|
||||||
|
}, "Tests that the 'removetrack' event is NOT fired for inband TextTrack on a failed load.");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -34,72 +34,6 @@
|
||||||
video.removeChild(trackElement);
|
video.removeChild(trackElement);
|
||||||
video.textTracks.addEventListener("removetrack", test.step_func(trackRemoved));
|
video.textTracks.addEventListener("removetrack", test.step_func(trackRemoved));
|
||||||
}, "Tests that the 'removetrack' event is fired when an out-of-band TextTrack is removed.");
|
}, "Tests that the 'removetrack' event is fired when an out-of-band TextTrack is removed.");
|
||||||
|
|
||||||
async_test(function(test)
|
|
||||||
{
|
|
||||||
var video = document.createElement("video");
|
|
||||||
|
|
||||||
// Create an out-of-band text track by adding a track element.
|
|
||||||
var trackElement = document.createElement('track');
|
|
||||||
|
|
||||||
trackElement.addEventListener("error", test.step_func(function()
|
|
||||||
{
|
|
||||||
assert_unreached("'error' event on track element should not fire.")
|
|
||||||
}));
|
|
||||||
|
|
||||||
video.appendChild(trackElement);
|
|
||||||
trackElement.src = 'resources/webvtt-file.vtt';
|
|
||||||
trackElement.track.mode = 'hidden';
|
|
||||||
|
|
||||||
assert_equals(video.textTracks.length, 1);
|
|
||||||
var outOfBandTrack = video.textTracks[0];
|
|
||||||
|
|
||||||
// Load a media file with an inband text track.
|
|
||||||
var inbandTrack = null;
|
|
||||||
var url = "resources/vp8-vorbis-webvtt.webm"
|
|
||||||
|
|
||||||
var firstAddTrackHandler = test.step_func(function()
|
|
||||||
{
|
|
||||||
assert_equals(event.target, video.textTracks);
|
|
||||||
assert_equals(event instanceof window.TrackEvent, true);
|
|
||||||
if (event.track == outOfBandTrack) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_equals(inbandTrack, null);
|
|
||||||
assert_equals(video.textTracks.length, 2);
|
|
||||||
assert_equals(event.track, video.textTracks[1]);
|
|
||||||
inbandTrack = event.track;
|
|
||||||
|
|
||||||
video.textTracks.removeEventListener("addtrack", firstAddTrackHandler);
|
|
||||||
|
|
||||||
// Clear .src to force the inband track to get destroyed.
|
|
||||||
video.src = "";
|
|
||||||
|
|
||||||
// Verify that the inband track was removed.
|
|
||||||
assert_not_equals(inbandTrack, null);
|
|
||||||
assert_equals(video.textTracks.length, 1);
|
|
||||||
assert_equals(video.textTracks[0], outOfBandTrack);
|
|
||||||
|
|
||||||
// Load the URL again to trigger another 'addtrack' event to make sure
|
|
||||||
// no 'removetrack' event was queued.
|
|
||||||
video.src = url;
|
|
||||||
video.textTracks.addEventListener("addtrack", test.step_func(function()
|
|
||||||
{
|
|
||||||
assert_equals(video.textTracks.length, 2);
|
|
||||||
test.done();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
video.textTracks.addEventListener("addtrack", firstAddTrackHandler);
|
|
||||||
|
|
||||||
video.textTracks.addEventListener("removetrack", test.step_func(function()
|
|
||||||
{
|
|
||||||
assert_unreached("'removetrack' event should not fire.")
|
|
||||||
}));
|
|
||||||
|
|
||||||
video.src = url;
|
|
||||||
}, "Tests that the 'removetrack' event is NOT fired for inband TextTrack on a failed load.");
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
<iframe id="testframe" src="form-data-set-usv-form.html"></iframe>
|
<iframe id="testframe" src="form-data-set-usv-form.html"></iframe>
|
||||||
|
<iframe id="testframe2" src="form-data-set-usv-form.html"></iframe>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
window.onload = t.step_func(() => {
|
window.addEventListener("load", t.step_func(() => {
|
||||||
const iframe = document.querySelector("#testframe");
|
const iframe = document.querySelector("#testframe");
|
||||||
const form = iframe.contentWindow.document.querySelector("form");
|
const form = iframe.contentWindow.document.querySelector("form");
|
||||||
|
|
||||||
|
@ -35,6 +36,17 @@ async_test(t => {
|
||||||
});
|
});
|
||||||
|
|
||||||
form.submit();
|
form.submit();
|
||||||
});
|
}));
|
||||||
});
|
}, 'Strings from form controls should be converted to Unicode scalar values in form submission');
|
||||||
|
|
||||||
|
async_test(t => {
|
||||||
|
window.addEventListener("load", t.step_func_done(() => {
|
||||||
|
const iframe = document.querySelector("#testframe2");
|
||||||
|
const formData = new FormData(iframe.contentWindow.document.querySelector("form"));
|
||||||
|
assert_equals(formData.get("input1\uFFFD"), "input1\uFFFD");
|
||||||
|
assert_equals(formData.get("input2\uFFFD"), "input2\uFFFD");
|
||||||
|
assert_equals(formData.get("input3\uFFFD"), "input3\uFFFD");
|
||||||
|
assert_equals(formData.get("input4\uFFFD"), "input4\uFFFD");
|
||||||
|
}));
|
||||||
|
}, 'Strings from form controls should be converted to Unicode scalar values in FormData');
|
||||||
</script>
|
</script>
|
||||||
|
|
19
tests/wpt/web-platform-tests/interfaces/battery.idl
Normal file
19
tests/wpt/web-platform-tests/interfaces/battery.idl
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// GENERATED CONTENT - DO NOT EDIT
|
||||||
|
// Content of this file was automatically extracted from the Battery Status API spec.
|
||||||
|
// See https://w3c.github.io/battery/
|
||||||
|
|
||||||
|
partial interface Navigator {
|
||||||
|
Promise<BatteryManager> getBattery();
|
||||||
|
};
|
||||||
|
|
||||||
|
[Exposed=Window]
|
||||||
|
interface BatteryManager : EventTarget {
|
||||||
|
readonly attribute boolean charging;
|
||||||
|
readonly attribute unrestricted double chargingTime;
|
||||||
|
readonly attribute unrestricted double dischargingTime;
|
||||||
|
readonly attribute double level;
|
||||||
|
attribute EventHandler onchargingchange;
|
||||||
|
attribute EventHandler onchargingtimechange;
|
||||||
|
attribute EventHandler ondischargingtimechange;
|
||||||
|
attribute EventHandler onlevelchange;
|
||||||
|
};
|
|
@ -1,3 +1,7 @@
|
||||||
|
// GENERATED CONTENT - DO NOT EDIT
|
||||||
|
// Content of this file was automatically extracted from the Gamepad spec.
|
||||||
|
// See https://w3c.github.io/gamepad/
|
||||||
|
|
||||||
interface Gamepad {
|
interface Gamepad {
|
||||||
readonly attribute DOMString id;
|
readonly attribute DOMString id;
|
||||||
readonly attribute long index;
|
readonly attribute long index;
|
||||||
|
|
|
@ -27,8 +27,6 @@ dictionary PaymentMethodData {
|
||||||
dictionary PaymentCurrencyAmount {
|
dictionary PaymentCurrencyAmount {
|
||||||
required DOMString currency;
|
required DOMString currency;
|
||||||
required DOMString value;
|
required DOMString value;
|
||||||
// Note: currencySystem is "at risk" of being removed!
|
|
||||||
DOMString currencySystem = "urn:iso:std:iso:4217";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary PaymentDetailsBase {
|
dictionary PaymentDetailsBase {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
// http://w3c.github.io/selection-api/#selection-interface
|
// GENERATED CONTENT - DO NOT EDIT
|
||||||
|
// Content of this file was automatically extracted from the Selection API spec.
|
||||||
|
// See https://w3c.github.io/selection-api/
|
||||||
|
|
||||||
interface Selection {
|
interface Selection {
|
||||||
readonly attribute Node? anchorNode;
|
readonly attribute Node? anchorNode;
|
||||||
readonly attribute unsigned long anchorOffset;
|
readonly attribute unsigned long anchorOffset;
|
||||||
|
@ -17,15 +20,11 @@ interface Selection {
|
||||||
void collapseToStart();
|
void collapseToStart();
|
||||||
void collapseToEnd();
|
void collapseToEnd();
|
||||||
void extend(Node node, optional unsigned long offset = 0);
|
void extend(Node node, optional unsigned long offset = 0);
|
||||||
void setBaseAndExtent(Node anchorNode,
|
void setBaseAndExtent(Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
|
||||||
unsigned long anchorOffset,
|
|
||||||
Node focusNode,
|
|
||||||
unsigned long focusOffset);
|
|
||||||
void selectAllChildren(Node node);
|
void selectAllChildren(Node node);
|
||||||
[CEReactions]
|
[CEReactions]
|
||||||
void deleteFromDocument();
|
void deleteFromDocument();
|
||||||
boolean containsNode(Node node,
|
boolean containsNode(Node node, optional boolean allowPartialContainment = false);
|
||||||
optional boolean allowPartialContainment = false);
|
|
||||||
stringifier DOMString ();
|
stringifier DOMString ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
9
tests/wpt/web-platform-tests/interfaces/vibration.idl
Normal file
9
tests/wpt/web-platform-tests/interfaces/vibration.idl
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// GENERATED CONTENT - DO NOT EDIT
|
||||||
|
// Content of this file was automatically extracted from the Vibration API spec.
|
||||||
|
// See https://w3c.github.io/vibration/
|
||||||
|
|
||||||
|
typedef (unsigned long or sequence<unsigned long>) VibratePattern;
|
||||||
|
|
||||||
|
partial interface Navigator {
|
||||||
|
boolean vibrate (VibratePattern pattern);
|
||||||
|
};
|
|
@ -13,15 +13,18 @@ function crossOriginUrl(path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function verify(options) {
|
function verify(options) {
|
||||||
var url = options.mode === 'cross-origin' ? crossOriginUrl(options.resource)
|
const url = options.mode === 'cross-origin' ? crossOriginUrl(options.resource)
|
||||||
: resourceUrl(options.resource);
|
: resourceUrl(options.resource);
|
||||||
var entryList = options.performance.getEntriesByName(url);
|
const entryList = options.performance.getEntriesByName(url);
|
||||||
if (entryList.length === 0 && options.allow_no_performance_entry) {
|
if (options.should_no_performance_entry) {
|
||||||
// The performance timeline may not have an entry for a resource
|
// The performance timeline may not have an entry for a resource
|
||||||
// which failed to load.
|
// which failed to load.
|
||||||
|
assert_equals(entryList.length, 0, options.description);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var entry = entryList[0];
|
assert_equals(entryList.length, 1, options.description);
|
||||||
|
const entry = entryList[0];
|
||||||
|
assert_equals(entry.entryType, 'resource', options.description);
|
||||||
assert_greater_than(entry.workerStart, 0, options.description);
|
assert_greater_than(entry.workerStart, 0, options.description);
|
||||||
assert_greater_than_equal(entry.workerStart, entry.startTime, options.description);
|
assert_greater_than_equal(entry.workerStart, entry.startTime, options.description);
|
||||||
assert_less_than_equal(entry.workerStart, entry.fetchStart, options.description);
|
assert_less_than_equal(entry.workerStart, entry.fetchStart, options.description);
|
||||||
|
@ -42,12 +45,12 @@ function verify(options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async_test(function(t) {
|
promise_test(function(t) {
|
||||||
var worker_url = 'resources/resource-timing-worker.js';
|
const worker_url = 'resources/resource-timing-worker.js';
|
||||||
var scope = 'resources/resource-timing-iframe.sub.html';
|
const scope = 'resources/resource-timing-iframe.sub.html';
|
||||||
var registration;
|
let registration;
|
||||||
|
|
||||||
service_worker_unregister_and_register(t, worker_url, scope)
|
return service_worker_unregister_and_register(t, worker_url, scope)
|
||||||
.then(function(r) {
|
.then(function(r) {
|
||||||
registration = r;
|
registration = r;
|
||||||
return wait_for_state(t, r.installing, 'activated');
|
return wait_for_state(t, r.installing, 'activated');
|
||||||
|
@ -56,7 +59,7 @@ async_test(function(t) {
|
||||||
return with_iframe(scope);
|
return with_iframe(scope);
|
||||||
})
|
})
|
||||||
.then(function(frame) {
|
.then(function(frame) {
|
||||||
var performance = frame.contentWindow.performance;
|
const performance = frame.contentWindow.performance;
|
||||||
verify({
|
verify({
|
||||||
performance: performance,
|
performance: performance,
|
||||||
resource: 'resources/dummy.js',
|
resource: 'resources/dummy.js',
|
||||||
|
@ -96,28 +99,45 @@ async_test(function(t) {
|
||||||
resource: 'resources/missing.jpg',
|
resource: 'resources/missing.jpg',
|
||||||
mode: 'same-origin',
|
mode: 'same-origin',
|
||||||
description: 'Network fallback load failure',
|
description: 'Network fallback load failure',
|
||||||
allow_no_performance_entry: true,
|
should_no_performance_entry: true,
|
||||||
});
|
});
|
||||||
verify({
|
verify({
|
||||||
performance: performance,
|
performance: performance,
|
||||||
resource: 'resources/missing.jpg',
|
resource: 'resources/missing.jpg',
|
||||||
mode: 'cross-origin',
|
mode: 'cross-origin',
|
||||||
description: 'Network fallback cross-origin load failure',
|
description: 'Network fallback cross-origin load failure',
|
||||||
allow_no_performance_entry: true,
|
should_no_performance_entry: true,
|
||||||
|
});
|
||||||
|
// Tests for respondWith(fetch()).
|
||||||
|
verify({
|
||||||
|
performance: performance,
|
||||||
|
resource: 'resources/missing.jpg?SWRespondsWithFetch',
|
||||||
|
mode: 'same-origin',
|
||||||
|
description: 'Resource in iframe, nonexistent but responded with fetch to another.',
|
||||||
|
});
|
||||||
|
verify({
|
||||||
|
performance: performance,
|
||||||
|
resource: 'resources/dummy.txt?SWFetched',
|
||||||
|
mode: 'same-origin',
|
||||||
|
description: 'Resource fetched as response from missing.jpg?SWRespondsWithFetch.',
|
||||||
|
should_no_performance_entry: true,
|
||||||
|
});
|
||||||
|
// Test for a normal resource that is unaffected by the Service Worker.
|
||||||
|
verify({
|
||||||
|
performance: performance,
|
||||||
|
resource: 'resources/empty-worker.js',
|
||||||
|
mode: 'same-origin',
|
||||||
|
description: 'Resource untouched by the Service Worker.',
|
||||||
});
|
});
|
||||||
|
|
||||||
frame.remove();
|
frame.remove();
|
||||||
return registration.unregister();
|
return registration.unregister();
|
||||||
})
|
});
|
||||||
.then(function() {
|
|
||||||
t.done();
|
|
||||||
})
|
|
||||||
.catch(unreached_rejection(t));
|
|
||||||
}, 'Controlled resource loads');
|
}, 'Controlled resource loads');
|
||||||
|
|
||||||
test(function() {
|
test(() => {
|
||||||
var url = resourceUrl('resources/test-helpers.sub.js');
|
const url = resourceUrl('resources/test-helpers.sub.js');
|
||||||
var entry = window.performance.getEntriesByName(url)[0];
|
const entry = window.performance.getEntriesByName(url)[0];
|
||||||
assert_equals(entry.workerStart, 0, 'Non-controlled');
|
assert_equals(entry.workerStart, 0, 'Non-controlled');
|
||||||
}, 'Non-controlled resource loads');
|
}, 'Non-controlled resource loads');
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,5 @@
|
||||||
<img src="https://{{domains[www1]}}:{{ports[https][0]}}/service-workers/service-worker/resources/square.png">
|
<img src="https://{{domains[www1]}}:{{ports[https][0]}}/service-workers/service-worker/resources/square.png">
|
||||||
<img src="missing.jpg">
|
<img src="missing.jpg">
|
||||||
<img src="https://{{domains[www1]}}:{{ports[https][0]}}/service-workers/service-worker/resources/missing.jpg">
|
<img src="https://{{domains[www1]}}:{{ports[https][0]}}/service-workers/service-worker/resources/missing.jpg">
|
||||||
|
<img src='missing.jpg?SWRespondsWithFetch'>
|
||||||
|
<script src='empty-worker.js'></script>
|
||||||
|
|
|
@ -6,4 +6,7 @@ self.addEventListener('fetch', function(event) {
|
||||||
setTimeout(_ => resolve(new Response('// Empty javascript')), 50);
|
setTimeout(_ => resolve(new Response('// Empty javascript')), 50);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
else if (event.request.url.indexOf('missing.jpg?SWRespondsWithFetch') != -1) {
|
||||||
|
event.respondWith(fetch('dummy.txt?SWFetched'));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -111,56 +111,54 @@ promise_test(() => {
|
||||||
);
|
);
|
||||||
}, 'closed and ready on a released writer');
|
}, 'closed and ready on a released writer');
|
||||||
|
|
||||||
promise_test(() => {
|
promise_test(t => {
|
||||||
const promises = {};
|
let thisObject = null;
|
||||||
const resolvers = {};
|
|
||||||
for (const methodName of ['start', 'write', 'close', 'abort']) {
|
|
||||||
promises[methodName] = new Promise(resolve => {
|
|
||||||
resolvers[methodName] = resolve;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calls to Sink methods after the first are implicitly ignored. Only the first value that is passed to the resolver
|
// Calls to Sink methods after the first are implicitly ignored. Only the first value that is passed to the resolver
|
||||||
// is used.
|
// is used.
|
||||||
class Sink {
|
class Sink {
|
||||||
start() {
|
start() {
|
||||||
// Called twice
|
// Called twice
|
||||||
resolvers.start(this);
|
t.step(() => {
|
||||||
|
assert_equals(this, thisObject, 'start should be called as a method');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
write() {
|
write() {
|
||||||
resolvers.write(this);
|
t.step(() => {
|
||||||
|
assert_equals(this, thisObject, 'write should be called as a method');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
resolvers.close(this);
|
t.step(() => {
|
||||||
|
assert_equals(this, thisObject, 'close should be called as a method');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abort() {
|
abort() {
|
||||||
resolvers.abort(this);
|
t.step(() => {
|
||||||
|
assert_equals(this, thisObject, 'abort should be called as a method');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const theSink = new Sink();
|
const theSink = new Sink();
|
||||||
|
thisObject = theSink;
|
||||||
const ws = new WritableStream(theSink);
|
const ws = new WritableStream(theSink);
|
||||||
|
|
||||||
const writer = ws.getWriter();
|
const writer = ws.getWriter();
|
||||||
|
|
||||||
writer.write('a');
|
writer.write('a');
|
||||||
writer.close();
|
const closePromise = writer.close();
|
||||||
|
|
||||||
const ws2 = new WritableStream(theSink);
|
const ws2 = new WritableStream(theSink);
|
||||||
const writer2 = ws2.getWriter();
|
const writer2 = ws2.getWriter();
|
||||||
writer2.abort();
|
const abortPromise = writer2.abort();
|
||||||
|
|
||||||
return promises.start
|
return Promise.all([
|
||||||
.then(thisValue => assert_equals(thisValue, theSink, 'start should be called as a method'))
|
closePromise,
|
||||||
.then(() => promises.write)
|
abortPromise
|
||||||
.then(thisValue => assert_equals(thisValue, theSink, 'write should be called as a method'))
|
]);
|
||||||
.then(() => promises.close)
|
|
||||||
.then(thisValue => assert_equals(thisValue, theSink, 'close should be called as a method'))
|
|
||||||
.then(() => promises.abort)
|
|
||||||
.then(thisValue => assert_equals(thisValue, theSink, 'abort should be called as a method'));
|
|
||||||
}, 'WritableStream should call underlying sink methods as methods');
|
}, 'WritableStream should call underlying sink methods as methods');
|
||||||
|
|
||||||
promise_test(t => {
|
promise_test(t => {
|
||||||
|
|
|
@ -154,7 +154,7 @@ promise_test(t => {
|
||||||
start() {
|
start() {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
}, new CountQueuingStrategy({ highWaterMark: 0 }));
|
}, { highWaterMark: 0 });
|
||||||
const writer = ws.getWriter();
|
const writer = ws.getWriter();
|
||||||
catchAndRecord(writer.ready, 'ready');
|
catchAndRecord(writer.ready, 'ready');
|
||||||
catchAndRecord(writer.closed, 'closed');
|
catchAndRecord(writer.closed, 'closed');
|
||||||
|
|
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