Update web-platform-tests to revision 2b4f117a8fc636fc316b3864763db6b28e8a42bc

This commit is contained in:
WPT Sync Bot 2020-12-10 08:21:05 +00:00
parent d7e7e43a80
commit 7ae94b8030
116 changed files with 3431 additions and 487 deletions

View file

@ -4,7 +4,7 @@
expected: TIMEOUT expected: TIMEOUT
[Opening a blob URL in a new window immediately before revoking it works.] [Opening a blob URL in a new window immediately before revoking it works.]
expected: FAIL expected: TIMEOUT
[Fetching a blob URL immediately before revoking it works in an iframe.] [Fetching a blob URL immediately before revoking it works in an iframe.]
expected: FAIL expected: FAIL

View file

@ -0,0 +1,4 @@
[hit-test-floats-003.html]
[Miss float below something else]
expected: FAIL

View file

@ -0,0 +1,4 @@
[hit-test-floats-004.html]
[Miss float below something else]
expected: FAIL

View file

@ -0,0 +1,4 @@
[hit-test-floats-005.html]
[Miss clipped float]
expected: FAIL

View file

@ -0,0 +1,2 @@
[one-element-animation.html]
expected: TIMEOUT

View file

@ -0,0 +1,4 @@
[elementFromPoint-001.html]
[CSSOM View - 5 - extensions to the Document interface]
expected: FAIL

View file

@ -1,4 +0,0 @@
[elementsFromPoint-invalid-cases.html]
[The root element is the last element returned for otherwise empty queries within the viewport]
expected: FAIL

View file

@ -0,0 +1,7 @@
[offsetTopLeft-border-box.html]
[container: 1]
expected: FAIL
[container: 0]
expected: FAIL

View file

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

View file

@ -53,3 +53,6 @@
[combined text/javascript ] [combined text/javascript ]
expected: FAIL expected: FAIL
[separate text/javascript x/x]
expected: FAIL

View file

@ -11,6 +11,6 @@
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!] [X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
expected: FAIL expected: FAIL
[X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff] [X-Content-Type-Options%3A%20'NosniFF']
expected: FAIL expected: FAIL

View file

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

View file

@ -0,0 +1,5 @@
[sandbox-javascript-window-open.html]
expected: TIMEOUT
[window.open in sandbox iframe]
expected: TIMEOUT

View file

@ -1,8 +1,7 @@
[embedded-opener-remove-frame.html] [embedded-opener-remove-frame.html]
expected: TIMEOUT
[opener of discarded nested browsing context] [opener of discarded nested browsing context]
expected: FAIL expected: FAIL
[opener of discarded auxiliary browsing context] [opener of discarded auxiliary browsing context]
expected: TIMEOUT expected: FAIL

View file

@ -171,3 +171,6 @@
[XHTML img usemap="#hash-id"] [XHTML img usemap="#hash-id"]
expected: FAIL expected: FAIL
[HTML (standards) IMG usemap="no-hash-name"]
expected: FAIL

View file

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

View file

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

View file

@ -1,5 +1,4 @@
[iframe_sandbox_popups_nonescaping-3.html] [iframe_sandbox_popups_nonescaping-3.html]
expected: TIMEOUT
[Check that popups from a sandboxed iframe do not escape the sandbox] [Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN expected: FAIL

View file

@ -1,4 +0,0 @@
[form-double-submit-3.html]
[<button> should have the same double-submit protection as <input type=submit>]
expected: FAIL

View file

@ -1,4 +0,0 @@
[activation-behavior.window.html]
[<a> that is not connected should be followed]
expected: FAIL

View file

@ -20,3 +20,9 @@
[Test iframe from non-existent host] [Test iframe from non-existent host]
expected: FAIL expected: FAIL
[Same-origin empty iframe with a 200 status gets reported]
expected: FAIL
[Cross-origin empty iframe with a 200 status gets reported]
expected: FAIL

View file

@ -1,5 +1,4 @@
[realtimeanalyser-fft-scaling.html] [realtimeanalyser-fft-scaling.html]
expected: TIMEOUT
[X 2048-point FFT peak position is not equal to 64. Got 0.] [X 2048-point FFT peak position is not equal to 64. Got 0.]
expected: FAIL expected: FAIL

View file

@ -380,3 +380,9 @@
[X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[28696\]\t9.9558435935349637e+18\t9.3139332532882690e-1\t9.9558435935349637e+18\t1.0689193622919801e+19\t3.8985999999999999e-3\n\t[28697\]\t7.0477002859115601e-1\t9.0675884485244751e-1\t2.0198881626129150e-1\t2.2275913536212616e-1\t3.8985999999999999e-3\n\tMax AbsError of 9.9558435935349637e+18 at index of 28696.\n\tMax RelError of 1.0689193622919801e+19 at index of 28696.\n] [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[28696\]\t9.9558435935349637e+18\t9.3139332532882690e-1\t9.9558435935349637e+18\t1.0689193622919801e+19\t3.8985999999999999e-3\n\t[28697\]\t7.0477002859115601e-1\t9.0675884485244751e-1\t2.0198881626129150e-1\t2.2275913536212616e-1\t3.8985999999999999e-3\n\tMax AbsError of 9.9558435935349637e+18 at index of 28696.\n\tMax RelError of 1.0689193622919801e+19 at index of 28696.\n]
expected: FAIL expected: FAIL
[X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[28696\]\t-1.6657697667767275e+26\t9.3139332532882690e-1\t1.6657697667767275e+26\t1.7884708011930731e+26\t3.8985999999999999e-3\n\t[28697\]\t7.0477002859115601e-1\t9.0675884485244751e-1\t2.0198881626129150e-1\t2.2275913536212616e-1\t3.8985999999999999e-3\n\tMax AbsError of 1.6657697667767275e+26 at index of 28696.\n\tMax RelError of 1.7884708011930731e+26 at index of 28696.\n]
expected: FAIL
[X SNR (-480.9982135660622 dB) is not greater than or equal to 65.737. Got -480.9982135660622.]
expected: FAIL

View file

@ -1,4 +1,5 @@
[audiocontext-not-fully-active.html] [audiocontext-not-fully-active.html]
expected: TIMEOUT
[frame in navigated remote-site frame] [frame in navigated remote-site frame]
expected: FAIL expected: FAIL

View file

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

View file

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

View file

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

View file

@ -1,5 +1,4 @@
[sharedworker-in-worker.html] [sharedworker-in-worker.html]
expected: ERROR
[Base URL in workers: new SharedWorker()] [Base URL in workers: new SharedWorker()]
expected: FAIL expected: FAIL

View file

@ -0,0 +1,2 @@
[Worker-constructor.html]
expected: ERROR

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
[hit-test-floats-003.html]
[Miss float below something else]
expected: FAIL

View file

@ -0,0 +1,4 @@
[hit-test-floats-004.html]
[Miss float below something else]
expected: FAIL

View file

@ -0,0 +1,4 @@
[hit-test-floats-005.html]
[Miss clipped float]
expected: FAIL

View file

@ -0,0 +1,2 @@
[one-element-animation.html]
expected: TIMEOUT

View file

@ -0,0 +1,2 @@
[image-orientation-iframe.html]
expected: TIMEOUT

View file

@ -0,0 +1,4 @@
[elementFromPoint-001.html]
[CSSOM View - 5 - extensions to the Document interface]
expected: FAIL

View file

@ -1,4 +0,0 @@
[elementsFromPoint-invalid-cases.html]
[The root element is the last element returned for otherwise empty queries within the viewport]
expected: FAIL

View file

@ -0,0 +1,7 @@
[offsetTopLeft-border-box.html]
[container: 1]
expected: FAIL
[container: 0]
expected: FAIL

View file

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

View file

@ -53,3 +53,6 @@
[combined text/javascript ] [combined text/javascript ]
expected: FAIL expected: FAIL
[separate text/javascript x/x]
expected: FAIL

View file

@ -11,6 +11,6 @@
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!] [X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
expected: FAIL expected: FAIL
[X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff] [X-Content-Type-Options%3A%20'NosniFF']
expected: FAIL expected: FAIL

View file

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

View file

@ -0,0 +1,5 @@
[sandbox-javascript-window-open.html]
expected: TIMEOUT
[window.open in sandbox iframe]
expected: TIMEOUT

View file

@ -1,5 +1,4 @@
[embedded-opener-remove-frame.html] [embedded-opener-remove-frame.html]
expected: TIMEOUT
[opener and "removed" embedded documents] [opener and "removed" embedded documents]
expected: FAIL expected: FAIL
@ -7,5 +6,5 @@
expected: FAIL expected: FAIL
[opener of discarded auxiliary browsing context] [opener of discarded auxiliary browsing context]
expected: TIMEOUT expected: FAIL

View file

@ -172,3 +172,6 @@
[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 (standards) IMG usemap="no-hash-name"]
expected: FAIL

View file

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

View file

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

View file

@ -1,5 +1,4 @@
[iframe_sandbox_popups_nonescaping-3.html] [iframe_sandbox_popups_nonescaping-3.html]
expected: TIMEOUT
[Check that popups from a sandboxed iframe do not escape the sandbox] [Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN expected: FAIL

View file

@ -1,4 +0,0 @@
[form-double-submit-3.html]
[<button> should have the same double-submit protection as <input type=submit>]
expected: FAIL

View file

@ -1,4 +0,0 @@
[activation-behavior.window.html]
[<a> that is not connected should be followed]
expected: FAIL

View file

@ -20,3 +20,9 @@
[Test iframe from non-existent host] [Test iframe from non-existent host]
expected: FAIL expected: FAIL
[Same-origin empty iframe with a 200 status gets reported]
expected: FAIL
[Cross-origin empty iframe with a 200 status gets reported]
expected: FAIL

View file

@ -1,5 +1,4 @@
[realtimeanalyser-fft-scaling.html] [realtimeanalyser-fft-scaling.html]
expected: TIMEOUT
[X 2048-point FFT peak position is not equal to 64. Got 0.] [X 2048-point FFT peak position is not equal to 64. Got 0.]
expected: FAIL expected: FAIL

View file

@ -608,3 +608,9 @@
[X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[28696\]\t9.9558435935349637e+18\t9.3139332532882690e-1\t9.9558435935349637e+18\t1.0689193622919801e+19\t3.8985999999999999e-3\n\t[28697\]\t7.0477002859115601e-1\t9.0675884485244751e-1\t2.0198881626129150e-1\t2.2275913536212616e-1\t3.8985999999999999e-3\n\tMax AbsError of 9.9558435935349637e+18 at index of 28696.\n\tMax RelError of 1.0689193622919801e+19 at index of 28696.\n] [X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[28696\]\t9.9558435935349637e+18\t9.3139332532882690e-1\t9.9558435935349637e+18\t1.0689193622919801e+19\t3.8985999999999999e-3\n\t[28697\]\t7.0477002859115601e-1\t9.0675884485244751e-1\t2.0198881626129150e-1\t2.2275913536212616e-1\t3.8985999999999999e-3\n\tMax AbsError of 9.9558435935349637e+18 at index of 28696.\n\tMax RelError of 1.0689193622919801e+19 at index of 28696.\n]
expected: FAIL expected: FAIL
[X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...\] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[28696\]\t-1.6657697667767275e+26\t9.3139332532882690e-1\t1.6657697667767275e+26\t1.7884708011930731e+26\t3.8985999999999999e-3\n\t[28697\]\t7.0477002859115601e-1\t9.0675884485244751e-1\t2.0198881626129150e-1\t2.2275913536212616e-1\t3.8985999999999999e-3\n\tMax AbsError of 1.6657697667767275e+26 at index of 28696.\n\tMax RelError of 1.7884708011930731e+26 at index of 28696.\n]
expected: FAIL
[X SNR (-480.9982135660622 dB) is not greater than or equal to 65.737. Got -480.9982135660622.]
expected: FAIL

View file

@ -1,4 +1,5 @@
[audiocontext-not-fully-active.html] [audiocontext-not-fully-active.html]
expected: TIMEOUT
[frame in navigated remote-site frame] [frame in navigated remote-site frame]
expected: FAIL expected: FAIL

View file

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

View file

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

View file

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

View file

@ -1,5 +1,4 @@
[sharedworker-in-worker.html] [sharedworker-in-worker.html]
expected: ERROR
[Base URL in workers: new SharedWorker()] [Base URL in workers: new SharedWorker()]
expected: FAIL expected: FAIL

View file

@ -0,0 +1,2 @@
[Worker-constructor.html]
expected: ERROR

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<body>
<canvas id="canvas" width="100" height="100"></canvas>
</body>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(100, 100, 0)';
ctx.fillRect(0, 0, 100, 100);
</script>

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-color">
<link rel="match" href="one-element-animation-ref.html">
<style>
.container {
width: 100px;
height: 100px;
background-color: green;
/* Use a long animation that start at 50% progress where the slope of the
selected timing function is zero. By setting up the animation in this way,
we accommodate lengthy delays in running the test without a potential drift
in the animated property value. This is important for avoiding flakes,
especially on debug builds. The screenshots are taken as soon as the
animation is ready, thus the long animation duration has no bearing on
the actual duration of the test. */
animation: bgcolor 1000000s cubic-bezier(0,1,1,0) -500000s;
}
@keyframes bgcolor {
0% { background-color: rgb(0, 200, 0); }
100% { background-color: rgb(200, 0, 0); }
}
</style>
<script src="/common/reftest-wait.js"></script>
<body>
<div class="container"></div>
<script>
document.getAnimations()[0].ready.then(() => {
takeScreenshot();
});
</script>
</body>
</html>

View file

@ -1,8 +0,0 @@
<!doctype HTML>
<html>
<meta charset="utf8">
<title>CSS Content Visibility: auto in overflow hidden paints (reference)</title>
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
<div>content</div>

View file

@ -1,16 +0,0 @@
<!doctype HTML>
<meta charset="utf8">
<title>CSS Content Visibility: auto in overflow hidden paints</title>
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
<link rel="match" href="content-visibility-079-ref.html">
<meta name="assert" content="content-visibility auto element paints in an overflow hidden element that is not sized">
<style>
.auto { content-visibility: auto; }
.overflow { overflow: hidden; }
</style>
<div class=overflow>
<div class=auto>content</div>
</div>

View file

@ -124,6 +124,14 @@ Note that if the element to be clicked does not have a unique ID, the
document must not have any DOM mutations made between the function document must not have any DOM mutations made between the function
being called and the promise settling. being called and the promise settling.
## delete_all_cookies
Usage: `test_driver.delete_all_cookies(context=null)`
* _context_: an optional WindowProxy for the browsing context in which to
perform the call.
This function deletes all cookies for the current browsing context.
### send_keys ### send_keys
Usage: `test_driver.send_keys(element, keys)` Usage: `test_driver.send_keys(element, keys)`

View file

@ -0,0 +1,18 @@
<script>
// Forward message from the openee toward the parent.
window.addEventListener("message", event => top.postMessage(event.data, "*"));
let check_sandboxed = `"
<script>
try {
document.domain = document.domain;
opener.postMessage('allow-document-domain', '*');
} catch (error) {
opener.postMessage('disallow-document-domain', '*');
}
</scr`+`ipt>
"`;
window.open('about:blank', "window_name");
window.open("javascript:" + check_sandboxed, "window_name");
</script>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>window.open in sandbox iframe</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<body>
<script>
promise_test(async test => {
let message = new Promise(resolve => {
window.addEventListener("message", event => resolve(event.data));
});
let iframe = document.createElement("iframe");
iframe.sandbox = "allow-scripts allow-popups allow-same-origin";
iframe.src = "./resources/sandbox-javascript-window-open.html";
document.body.appendChild(iframe);
assert_equals(await message, "disallow-document-domain");
});
</script>

View file

@ -1,4 +1,4 @@
importScripts("/resources/testharness.js"); importScripts("/resources/testharness.js");
importScripts("module/evaluation-order-setup.mjs"); importScripts("module/evaluation-order-setup.mjs");
importScripts("module/evaluation-order-1-worker.mjs"); importScripts("evaluation-order-1-worker.js");
importScripts("module/evaluation-order-1.mjs"); importScripts("module/evaluation-order-1.mjs");

View file

@ -0,0 +1,9 @@
globalThis.expectedLog = [
"step-1-1", "step-1-2",
"global-error", "error",
"microtask",
];
globalThis.test_load.step_timeout(() => globalThis.testDone(), 0);
done();

View file

@ -1,7 +1,7 @@
globalThis.expectedLog = [ globalThis.expectedLog = [
"step-1-1", "step-1-2", "step-1-1", "step-1-2",
"global-error", "error",
"microtask", "microtask",
"global-error", "error",
]; ];
globalThis.test_load.step_timeout(() => globalThis.testDone(), 0); globalThis.test_load.step_timeout(() => globalThis.testDone(), 0);

View file

@ -9,8 +9,8 @@
window.addEventListener("load", event => globalThis.testDone()); window.addEventListener("load", event => globalThis.testDone());
globalThis.expectedLog = [ globalThis.expectedLog = [
"step-1-1", "step-1-2", "step-1-1", "step-1-2",
"global-error", "error",
"microtask", "microtask",
"global-error", "error",
"script-load", "script-load",
"global-load" "global-load"
]; ];

View file

@ -1,7 +1,7 @@
globalThis.expectedLog = [ globalThis.expectedLog = [
"step-2.2-1", "step-2.2-2", "step-2.2-1", "step-2.2-2",
"global-error", "error",
"microtask-2.2", "microtask-2.2",
"global-error", "error",
]; ];
done(); done();

View file

@ -7,8 +7,8 @@
import "./evaluation-order-setup.mjs"; import "./evaluation-order-setup.mjs";
globalThis.expectedLog = [ globalThis.expectedLog = [
"step-2.2-1", "step-2.2-2", "step-2.2-1", "step-2.2-2",
"global-error", "error",
"microtask-2.2", "microtask-2.2",
"global-error", "error",
"script-load", "script-load",
"global-load", "global-load",
]; ];

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>TestDriver delete_all_cookies method</title>
<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>
promise_test(async t => {
document.cookie = "test1=1";
document.cookie = "test2=2; path=/";
document.cookie = "test3=3; path=/cookies/resources";
return test_driver.delete_all_cookies().then(() => {
assert_true(document.cookie === "");
});
}, "DOM-set cookies get deleted");
promise_test(async t => {
const cookie = "test1=1";
const encoded = encodeURIComponent(cookie);
await fetch(`/cookies/resources/cookie.py?set=${encoded}`)
const cookie2 = "test2=2; path=/";
const encoded2 = encodeURIComponent(cookie2);
await fetch(`/cookies/resources/cookie.py?set=${encoded2}`)
const cookie3 = "test3=3; path=/cookies/resources";
const encoded3 = encodeURIComponent(cookie3);
await fetch(`/cookies/resources/cookie.py?set=${encoded3}`)
const cookie4 = "test4=4; HttpOnly";
const encoded4 = encodeURIComponent(cookie4);
await fetch(`/cookies/resources/cookie.py?set=${encoded4}`)
return test_driver.delete_all_cookies().then(() => {
assert_true(document.cookie === "");
});
}, "HTTP-set cookies get deleted");
</script>

View file

@ -724,6 +724,7 @@ MISSING DEPENDENCY: mediacapture-image/resources/imagecapture-helpers.js
MISSING DEPENDENCY: orientation-event/resources/orientation-event-helpers.js MISSING DEPENDENCY: orientation-event/resources/orientation-event-helpers.js
MISSING DEPENDENCY: resources/test-only-api.js MISSING DEPENDENCY: resources/test-only-api.js
MISSING DEPENDENCY: screen_enumeration/resources/screenenumeration-helpers.js MISSING DEPENDENCY: screen_enumeration/resources/screenenumeration-helpers.js
MISSING DEPENDENCY: serial/resources/automation.js
MISSING DEPENDENCY: shape-detection/resources/shapedetection-helpers.js MISSING DEPENDENCY: shape-detection/resources/shapedetection-helpers.js
MISSING DEPENDENCY: web-nfc/resources/nfc-helpers.js MISSING DEPENDENCY: web-nfc/resources/nfc-helpers.js
MISSING DEPENDENCY: webusb/resources/usb-helpers.js MISSING DEPENDENCY: webusb/resources/usb-helpers.js

View file

@ -18,3 +18,8 @@ promise_test(async testCase => {
assert_equals(fileNames.indexOf('test_file'), -1); assert_equals(fileNames.indexOf('test_file'), -1);
}, 'nativeIO.getAll does not return file deleted by nativeIO.delete'); }, 'nativeIO.getAll does not return file deleted by nativeIO.delete');
promise_test(async testCase => {
await nativeIO.delete('test_file');
// Delete a second time if the file existed before the first delete.
await nativeIO.delete('test_file');
}, 'nativeIO.delete does not fail when deleting a non-existing file');

View file

@ -17,3 +17,9 @@ test(testCase => {
const fileNames = nativeIO.getAllSync(); const fileNames = nativeIO.getAllSync();
assert_equals(fileNames.indexOf('test_file'), -1); assert_equals(fileNames.indexOf('test_file'), -1);
}, 'nativeIO.getAllSync does not return file deleted by nativeIO.deleteSync'); }, 'nativeIO.getAllSync does not return file deleted by nativeIO.deleteSync');
test(testCase => {
nativeIO.deleteSync('test_file');
// Delete a second time if the file existed before the first delete.
nativeIO.deleteSync('test_file');
}, 'nativeIO.deleteSync does not fail when deleting a non-existing file');

View file

@ -5,8 +5,7 @@
'use strict'; 'use strict';
setup(async () => { setup(async () => {
assert_implements(nativeIO.rename, assert_implements(nativeIO.rename, 'nativeIO.rename is not implemented.');
"nativeIO.rename is not implemented.");
}); });
promise_test(async testCase => { promise_test(async testCase => {
@ -29,8 +28,9 @@ promise_test(async testCase => {
await file1.close(); await file1.close();
await file2.close(); await file2.close();
await promise_rejects_dom(testCase, "UnknownError", await promise_rejects_dom(
nativeIO.rename('test_file_1', 'test_file_2')); testCase, 'NoModificationAllowedError',
nativeIO.rename('test_file_1', 'test_file_2'));
const fileNamesAfterRename = await nativeIO.getAll(); const fileNamesAfterRename = await nativeIO.getAll();
assert_in_array('test_file_1', fileNamesAfterRename); assert_in_array('test_file_1', fileNamesAfterRename);
@ -53,10 +53,12 @@ promise_test(async testCase => {
const readSharedArrayBuffer2 = new SharedArrayBuffer(writtenBytes2.length); const readSharedArrayBuffer2 = new SharedArrayBuffer(writtenBytes2.length);
const readBytes2 = new Uint8Array(readSharedArrayBuffer2); const readBytes2 = new Uint8Array(readSharedArrayBuffer2);
await file2_after.read(readBytes2, 0); await file2_after.read(readBytes2, 0);
assert_array_equals(readBytes1, writtenBytes1, assert_array_equals(
'the bytes read should match the bytes written'); readBytes1, writtenBytes1,
assert_array_equals(readBytes2, writtenBytes2, 'the bytes read should match the bytes written');
'the bytes read should match the bytes written'); assert_array_equals(
readBytes2, writtenBytes2,
'the bytes read should match the bytes written');
}, 'nativeIO.rename does not overwrite an existing file.'); }, 'nativeIO.rename does not overwrite an existing file.');
promise_test(async testCase => { promise_test(async testCase => {
@ -65,8 +67,9 @@ promise_test(async testCase => {
await file.close(); await file.close();
await nativeIO.delete('test_file'); await nativeIO.delete('test_file');
}); });
await promise_rejects_dom(testCase, "UnknownError", await promise_rejects_dom(
nativeIO.rename('test_file', 'renamed_test_file')); testCase, 'NoModificationAllowedError',
nativeIO.rename('test_file', 'renamed_test_file'));
await file.close(); await file.close();
const fileNamesAfterRename = await nativeIO.getAll(); const fileNamesAfterRename = await nativeIO.getAll();
@ -86,10 +89,10 @@ promise_test(async testCase => {
const file = await nativeIO.open('test_file'); const file = await nativeIO.open('test_file');
await file.close(); await file.close();
for (let name of kBadNativeIoNames) { for (let name of kBadNativeIoNames) {
await promise_rejects_js(testCase, TypeError, await promise_rejects_js(
nativeIO.rename('test_file', name)); testCase, TypeError, nativeIO.rename('test_file', name));
await promise_rejects_js(testCase, TypeError, await promise_rejects_js(
nativeIO.rename(name, 'test_file_2')); testCase, TypeError, nativeIO.rename(name, 'test_file_2'));
} }
}, 'nativeIO.rename does not allow renaming from or to invalid names.'); }, 'nativeIO.rename does not allow renaming from or to invalid names.');
@ -105,11 +108,13 @@ promise_test(async testCase => {
}); });
// First rename fails, as source is still open. // First rename fails, as source is still open.
await promise_rejects_dom(testCase, "UnknownError", await promise_rejects_dom(
nativeIO.rename('opened_file', 'closed_file')); testCase, 'NoModificationAllowedError',
nativeIO.rename('opened_file', 'closed_file'));
// First rename fails again, as source has not been unlocked. // First rename fails again, as source has not been unlocked.
await promise_rejects_dom(testCase, "UnknownError", await promise_rejects_dom(
nativeIO.rename('opened_file', 'closed_file')); testCase, 'NoModificationAllowedError',
nativeIO.rename('opened_file', 'closed_file'));
}, 'Failed nativeIO.rename does not unlock the source.'); }, 'Failed nativeIO.rename does not unlock the source.');
promise_test(async testCase => { promise_test(async testCase => {
@ -124,9 +129,22 @@ promise_test(async testCase => {
}); });
// First rename fails, as destination is still open. // First rename fails, as destination is still open.
await promise_rejects_dom(testCase, "UnknownError", await promise_rejects_dom(
nativeIO.rename('closed_file', 'opened_file')); testCase, 'NoModificationAllowedError',
nativeIO.rename('closed_file', 'opened_file'));
// First rename fails again, as destination has not been unlocked. // First rename fails again, as destination has not been unlocked.
await promise_rejects_dom(testCase, "UnknownError", await promise_rejects_dom(
nativeIO.rename('closed_file', 'opened_file')); testCase, 'NoModificationAllowedError',
nativeIO.rename('closed_file', 'opened_file'));
}, 'Failed nativeIO.rename does not unlock the destination.'); }, 'Failed nativeIO.rename does not unlock the destination.');
promise_test(async testCase => {
// Make sure that the file does not exist.
await nativeIO.delete('does_not_exist');
testCase.add_cleanup(async () => {
await nativeIO.delete('new_does_not_exist');
});
await promise_rejects_dom(
testCase, 'NotFoundError',
nativeIO.rename('does_not_exist', 'new_does_not_exist'));
}, 'Renaming a non-existing file fails with a NotFoundError.');

View file

@ -6,8 +6,8 @@
setup(() => { setup(() => {
// Without this assertion, one test passes even if renameSync is not defined // Without this assertion, one test passes even if renameSync is not defined
assert_implements(nativeIO.renameSync, assert_implements(
"nativeIO.renameSync is not implemented."); nativeIO.renameSync, 'nativeIO.renameSync is not implemented.');
}); });
test(testCase => { test(testCase => {
@ -26,8 +26,9 @@ test(testCase => {
file1.close(); file1.close();
file2.close(); file2.close();
assert_throws_dom("UnknownError", assert_throws_dom(
() => nativeIO.renameSync('test_file_1', 'test_file_2')); 'NoModificationAllowedError',
() => nativeIO.renameSync('test_file_1', 'test_file_2'));
const fileNamesAfterRename = nativeIO.getAllSync(); const fileNamesAfterRename = nativeIO.getAllSync();
assert_in_array('test_file_1', fileNamesAfterRename); assert_in_array('test_file_1', fileNamesAfterRename);
@ -45,12 +46,14 @@ test(testCase => {
}); });
const readBytes1 = new Uint8Array(writtenBytes1.length); const readBytes1 = new Uint8Array(writtenBytes1.length);
file1_after.read(readBytes1, 0); file1_after.read(readBytes1, 0);
assert_array_equals(readBytes1, writtenBytes1, assert_array_equals(
'the bytes read should match the bytes written'); readBytes1, writtenBytes1,
'the bytes read should match the bytes written');
const readBytes2 = new Uint8Array(writtenBytes2.length); const readBytes2 = new Uint8Array(writtenBytes2.length);
file2_after.read(readBytes2, 0); file2_after.read(readBytes2, 0);
assert_array_equals(readBytes2, writtenBytes2, assert_array_equals(
'the bytes read should match the bytes written'); readBytes2, writtenBytes2,
'the bytes read should match the bytes written');
}, 'nativeIO.renameSync does not overwrite an existing file.'); }, 'nativeIO.renameSync does not overwrite an existing file.');
test(testCase => { test(testCase => {
@ -59,8 +62,9 @@ test(testCase => {
file.close(); file.close();
nativeIO.deleteSync('test_file'); nativeIO.deleteSync('test_file');
}); });
assert_throws_dom("UnknownError", () => assert_throws_dom(
nativeIO.renameSync('test_file', 'renamed_test_file')); 'NoModificationAllowedError',
() => nativeIO.renameSync('test_file', 'renamed_test_file'));
file.close(); file.close();
const fileNamesAfterRename = nativeIO.getAllSync(); const fileNamesAfterRename = nativeIO.getAllSync();
@ -97,11 +101,13 @@ test(testCase => {
}); });
// First rename fails, as source is still open. // First rename fails, as source is still open.
assert_throws_dom("UnknownError", assert_throws_dom(
() => nativeIO.renameSync('opened_file', 'closed_file')); 'NoModificationAllowedError',
() => nativeIO.renameSync('opened_file', 'closed_file'));
// First rename fails again, as source has not been unlocked. // First rename fails again, as source has not been unlocked.
assert_throws_dom("UnknownError", assert_throws_dom(
() => nativeIO.renameSync('opened_file', 'closed_file')); 'NoModificationAllowedError',
() => nativeIO.renameSync('opened_file', 'closed_file'));
}, 'Failed nativeIO.renameSync does not unlock the source.'); }, 'Failed nativeIO.renameSync does not unlock the source.');
test(testCase => { test(testCase => {
@ -116,9 +122,22 @@ test(testCase => {
}); });
// First rename fails, as destination is still open. // First rename fails, as destination is still open.
assert_throws_dom("UnknownError", assert_throws_dom(
() => nativeIO.renameSync('closed_file', 'opened_file')); 'NoModificationAllowedError',
() => nativeIO.renameSync('closed_file', 'opened_file'));
// First rename fails again, as destination has not been unlocked. // First rename fails again, as destination has not been unlocked.
assert_throws_dom("UnknownError", assert_throws_dom(
() => nativeIO.renameSync('closed_file', 'opened_file')); 'NoModificationAllowedError',
() => nativeIO.renameSync('closed_file', 'opened_file'));
}, 'Failed nativeIO.renameSync does not unlock the destination.'); }, 'Failed nativeIO.renameSync does not unlock the destination.');
test(testCase => {
// Make sure that the file does not exist.
nativeIO.deleteSync('does_not_exist');
testCase.add_cleanup(() => {
nativeIO.deleteSync('new_name');
});
assert_throws_dom(
'NotFoundError',
() => nativeIO.renameSync('does_not_exist', 'new_name'));
}, 'Renaming a non-existing file fails with a NotFoundError.');

View file

@ -9,7 +9,10 @@
<script> <script>
let reportedReferrer = () => { let reportedReferrer = () => {
return new Promise(resolve => { return new Promise(resolve => {
window.addEventListener("message", msg => resolve(msg.data.referrer)); window.addEventListener("message", function listener(msg) {
window.removeEventListener("message", listener, false);
resolve(msg.data.referrer);
});
}); });
}; };
@ -29,6 +32,7 @@
location.origin + "/custom"); location.origin + "/custom");
document.body.appendChild(iframe); document.body.appendChild(iframe);
await iframe_load_1; await iframe_load_1;
let referrer_1_result = await referrer_1;
// 2. Change the referrer policy of the main document. // 2. Change the referrer policy of the main document.
document.getElementsByTagName('meta')[0].content = "unsafe-url"; document.getElementsByTagName('meta')[0].content = "unsafe-url";
@ -47,7 +51,7 @@
// Despite the main document has changed its referrer policy in (2), the // Despite the main document has changed its referrer policy in (2), the
// reported referrer for the history navigation to about:srcdoc in (4) must // reported referrer for the history navigation to about:srcdoc in (4) must
// match with the one originally reported in (1). // match with the one originally reported in (1).
assert_equals(await referrer_1, undefined, assert_equals(referrer_1_result, undefined,
"First navigation uses correct policy."); "First navigation uses correct policy.");
assert_equals(await referrer_2, undefined, assert_equals(await referrer_2, undefined,
"History navigation reuses original policy."); "History navigation reuses original policy.");
@ -57,10 +61,13 @@
// If we initiate a new about:srcdoc navigation, the new referrer policy // If we initiate a new about:srcdoc navigation, the new referrer policy
// should apply. // should apply.
const new_iframe = document.createElement("iframe"); const new_iframe = document.createElement("iframe");
let new_iframe_load = iframeLoaded(new_iframe);
let new_iframe_referrer = reportedReferrer(); let new_iframe_referrer = reportedReferrer();
new_iframe.srcdoc = createScriptString(get_host_info().REMOTE_ORIGIN, new_iframe.srcdoc = createScriptString(get_host_info().REMOTE_ORIGIN,
location.origin + "/custom"); location.origin + "/custom");
document.body.appendChild(new_iframe); document.body.appendChild(new_iframe);
await new_iframe_load;
assert_equals(await new_iframe_referrer, self.origin + '/custom'); assert_equals(await new_iframe_referrer, self.origin + '/custom');
}, "New srcdoc iframe uses new policy."); }, "New srcdoc iframe uses new policy.");
</script> </script>

View file

@ -64,6 +64,16 @@ promise_test(t => {
return run_test(t, url.toString(), csp_directive); return run_test(t, url.toString(), csp_directive);
}, "Cross-origin iframe that doesn't comply with CSP attribute gets reported"); }, "Cross-origin iframe that doesn't comply with CSP attribute gets reported");
promise_test(t => {
const url = new URL("/resource-timing/resources/200_empty.asis", location.href);
return run_test(t, url.toString(), csp_directive);
}, "Same-origin empty iframe with a 200 status gets reported");
promise_test(t => {
const url = new URL("/resource-timing/resources/200_empty.asis", REMOTE_ORIGIN);
return run_test(t, url.toString(), csp_directive);
}, "Cross-origin empty iframe with a 200 status gets reported");
</script> </script>
</body> </body>
</html> </html>

View file

@ -0,0 +1,3 @@
HTTP/1.0 200 OK
Content-Length: 0

View file

@ -0,0 +1,427 @@
// Implementation of an UnderlyingSource to create a ReadableStream from a Mojo
// data pipe consumer handle.
class DataPipeSource {
constructor(consumer) {
this.consumer_ = consumer;
}
async pull(controller) {
let chunk = new ArrayBuffer(64);
let {result, numBytes} = this.consumer_.readData(chunk);
if (result == Mojo.RESULT_OK) {
controller.enqueue(new Uint8Array(chunk, 0, numBytes));
return;
} else if (result == Mojo.RESULT_FAILED_PRECONDITION) {
controller.close();
return;
} else if (result == Mojo.RESULT_SHOULD_WAIT) {
await this.readable();
return this.pull(controller);
}
}
cancel() {
if (this.watcher_)
this.watcher_.cancel();
this.consumer_.close();
}
readable() {
return new Promise((resolve) => {
this.watcher_ =
this.consumer_.watch({ readable: true, peerClosed: true }, () => {
this.watcher_.cancel();
this.watcher_ = undefined;
resolve();
});
});
}
}
// Implementation of an UnderlyingSink to create a WritableStream from a Mojo
// data pipe producer handle.
class DataPipeSink {
constructor(producer) {
this._producer = producer;
}
async write(chunk, controller) {
while (true) {
let {result, numBytes} = this._producer.writeData(chunk);
if (result == Mojo.RESULT_OK) {
if (numBytes == chunk.byteLength) {
return;
}
chunk = chunk.slice(numBytes);
} else if (result == Mojo.RESULT_FAILED_PRECONDITION) {
throw new DOMException('The pipe is closed.', 'InvalidStateError');
} else if (result == Mojo.RESULT_SHOULD_WAIT) {
await this.writable();
}
}
}
close() {
assert_equals(undefined, this._watcher);
this._producer.close();
}
abort(reason) {
if (this._watcher)
this._watcher.cancel();
this._producer.close();
}
writable() {
return new Promise((resolve) => {
this._watcher =
this._producer.watch({ writable: true, peerClosed: true }, () => {
this._watcher.cancel();
this._watcher = undefined;
resolve();
});
});
}
}
// Implementation of blink.mojom.SerialPort.
class FakeSerialPort {
constructor() {
this.inputSignals_ = {
dataCarrierDetect: false,
clearToSend: false,
ringIndicator: false,
dataSetReady: false
};
this.inputSignalFailure_ = false;
this.outputSignals_ = {
dataTerminalReady: false,
requestToSend: false,
break: false
};
this.outputSignalFailure_ = false;
}
open(options, client) {
if (this.binding_ !== undefined) {
// Port already open.
return null;
}
let portPtr = new device.mojom.SerialPortPtr();
this.binding_ = new mojo.Binding(
device.mojom.SerialPort, this, mojo.makeRequest(portPtr));
this.binding_.setConnectionErrorHandler(() => {
this.close();
});
this.options_ = options;
this.client_ = client;
// OS typically sets DTR on open.
this.outputSignals_.dataTerminalReady = true;
return portPtr;
}
write(data) {
return this.writer_.write(data);
}
read() {
return this.reader_.read();
}
// Reads from the port until at least |targetLength| is read or the stream is
// closed. The data is returned as a combined Uint8Array.
readWithLength(targetLength) {
return readWithLength(this.reader_, targetLength);
}
simulateReadError(error) {
this.writer_.close();
this.writer_.releaseLock();
this.writer_ = undefined;
this.writable_ = undefined;
this.client_.onReadError(error);
}
simulateParityError() {
this.simulateReadError(device.mojom.SerialReceiveError.PARITY_ERROR);
}
simulateDisconnectOnRead() {
this.simulateReadError(device.mojom.SerialReceiveError.DISCONNECTED);
}
simulateWriteError(error) {
this.reader_.cancel();
this.reader_ = undefined;
this.readable_ = undefined;
this.client_.onSendError(error);
}
simulateSystemErrorOnWrite() {
this.simulateWriteError(device.mojom.SerialSendError.SYSTEM_ERROR);
}
simulateDisconnectOnWrite() {
this.simulateWriteError(device.mojom.SerialSendError.DISCONNECTED);
}
simulateInputSignals(signals) {
this.inputSignals_ = signals;
}
simulateInputSignalFailure(fail) {
this.inputSignalFailure_ = fail;
}
get outputSignals() {
return this.outputSignals_;
}
simulateOutputSignalFailure(fail) {
this.outputSignalFailure_ = fail;
}
writable() {
if (this.writable_)
return Promise.resolve();
if (!this.writablePromise_) {
this.writablePromise_ = new Promise((resolve) => {
this.writableResolver_ = resolve;
});
}
return this.writablePromise_;
}
readable() {
if (this.readable_)
return Promise.resolve();
if (!this.readablePromise_) {
this.readablePromise_ = new Promise((resolve) => {
this.readableResolver_ = resolve;
});
}
return this.readablePromise_;
}
async startWriting(in_stream) {
this.readable_ = new ReadableStream(new DataPipeSource(in_stream));
this.reader_ = this.readable_.getReader();
if (this.readableResolver_) {
this.readableResolver_();
this.readableResolver_ = undefined;
this.readablePromise_ = undefined;
}
}
async startReading(out_stream) {
this.writable_ = new WritableStream(new DataPipeSink(out_stream));
this.writer_ = this.writable_.getWriter();
if (this.writableResolver_) {
this.writableResolver_();
this.writableResolver_ = undefined;
this.writablePromise_ = undefined;
}
}
async flush(mode) {
switch (mode) {
case device.mojom.SerialPortFlushMode.kReceive:
this.writer_.abort();
this.writer_.releaseLock();
this.writer_ = undefined;
this.writable_ = undefined;
break;
case device.mojom.SerialPortFlushMode.kTransmit:
this.reader_.cancel();
this.reader_ = undefined;
this.readable_ = undefined;
break;
}
}
async drain() {
await this.reader_.closed;
}
async getControlSignals() {
if (this.inputSignalFailure_) {
return {signals: null};
}
const signals = {
dcd: this.inputSignals_.dataCarrierDetect,
cts: this.inputSignals_.clearToSend,
ri: this.inputSignals_.ringIndicator,
dsr: this.inputSignals_.dataSetReady
};
return {signals};
}
async setControlSignals(signals) {
if (this.outputSignalFailure_) {
return {success: false};
}
if (signals.hasDtr) {
this.outputSignals_.dataTerminalReady = signals.dtr;
}
if (signals.hasRts) {
this.outputSignals_.requestToSend = signals.rts;
}
if (signals.hasBrk) {
this.outputSignals_.break = signals.brk;
}
return { success: true };
}
async configurePort(options) {
this.options_ = options;
return { success: true };
}
async getPortInfo() {
return {
bitrate: this.options_.bitrate,
data_bits: this.options_.data_bits,
parity_bit: this.options_.parity_bit,
stop_bits: this.options_.stop_bits,
cts_flow_control: this.options_.has_cts_flow_control ?
this.options_.cts_flow_control : false
};
}
async close() {
// OS typically clears DTR on close.
this.outputSignals_.dataTerminalReady = false;
if (this.writer_) {
this.writer_.close();
this.writer_.releaseLock();
this.writer_ = undefined;
}
this.writable_ = undefined;
if (this.binding_) {
this.binding_.close();
this.binding_ = undefined;
}
return {};
}
}
// Implementation of blink.mojom.SerialService.
class FakeSerialService {
constructor() {
this.interceptor_ =
new MojoInterfaceInterceptor(blink.mojom.SerialService.name);
this.interceptor_.oninterfacerequest = e => this.bind(e.handle);
this.bindingSet_ = new mojo.BindingSet(blink.mojom.SerialService);
this.clients_ = [];
this.nextToken_ = 0;
this.reset();
}
start() {
this.interceptor_.start();
}
stop() {
this.interceptor_.stop();
}
reset() {
this.ports_ = new Map();
this.selectedPort_ = null;
}
addPort(info) {
let portInfo = new blink.mojom.SerialPortInfo();
if (info?.usbVendorId !== undefined) {
portInfo.hasUsbVendorId = true;
portInfo.usbVendorId = info.usbVendorId;
}
if (info?.usbProductId !== undefined) {
portInfo.hasUsbProductId = true;
portInfo.usbProductId = info.usbProductId;
}
let token = ++this.nextToken_;
portInfo.token = new mojoBase.mojom.UnguessableToken();
portInfo.token.high = 0;
portInfo.token.low = token;
let record = {
portInfo: portInfo,
fakePort: new FakeSerialPort(),
};
this.ports_.set(token, record);
for (let client of this.clients_) {
client.onPortAdded(portInfo);
}
return token;
}
removePort(token) {
let record = this.ports_.get(token);
if (record === undefined) {
return;
}
this.ports_.delete(token);
for (let client of this.clients_) {
client.onPortRemoved(record.portInfo);
}
}
setSelectedPort(token) {
this.selectedPort_ = this.ports_.get(token);
}
getFakePort(token) {
let record = this.ports_.get(token);
if (record === undefined)
return undefined;
return record.fakePort;
}
bind(handle) {
this.bindingSet_.addBinding(this, handle);
}
async setClient(client_remote) {
this.clients_.push(client_remote);
}
async getPorts() {
return {
ports: Array.from(this.ports_, ([token, record]) => record.portInfo)
};
}
async requestPort(filters) {
if (this.selectedPort_)
return { port: this.selectedPort_.portInfo };
else
return { port: null };
}
async openPort(token, options, client) {
let record = this.ports_.get(token.low);
if (record !== undefined) {
return {port: record.fakePort.open(options, client)};
} else {
return {port: null};
}
}
}
fakeSerialService = new FakeSerialService();

View file

@ -146,6 +146,24 @@
y: centerPoint[1]}); y: centerPoint[1]});
}, },
/**
* Deletes all cookies.
*
* This matches the behaviour of the {@link
* https://w3c.github.io/webdriver/#delete-all-cookies|WebDriver
* Delete All Cookies command}.
*
* @param {WindowProxy} context - Browsing context in which
* to run the call, or null for the current
* browsing context.
*
* @returns {Promise} fulfilled after cookies are deleted, or rejected in
* the cases the WebDriver command errors
*/
delete_all_cookies: function(context=null) {
return window.test_driver_internal.delete_all_cookies(context);
},
/** /**
* Send keys to an element * Send keys to an element
* *
@ -458,6 +476,10 @@
}); });
}, },
delete_all_cookies: function(context=null) {
return Promise.reject(new Error("unimplemented"));
},
send_keys: function(element, keys) { send_keys: function(element, keys) {
if (this.in_automation) { if (this.in_automation) {
return Promise.reject(new Error('Not implemented')); return Promise.reject(new Error('Not implemented'));

View file

@ -0,0 +1,75 @@
'use strict';
// These tests rely on the User Agent providing an implementation of the
// FakeSerialService interface which replaces the platform-specific
// implementation of the Web Serial API with one that can be automated from
// Javascript for testing purposes.
//
// In Chromium-based browsers this implementation is provided by a polyfill
// in order to reduce the amount of test-only code shipped to users. To enable
// these tests the browser must be run with these options:
//
// --enable-blink-features=MojoJS,MojoJSTest
async function loadChromiumResources() {
const chromiumResources = [
'/gen/mojo/public/mojom/base/unguessable_token.mojom.js',
'/gen/services/device/public/mojom/serial.mojom.js',
'/gen/third_party/blink/public/mojom/serial/serial.mojom.js',
];
await loadMojoResources(chromiumResources);
}
// Returns a SerialPort instance and associated FakeSerialPort instance.
async function getFakeSerialPort(fake) {
let token = fake.addPort();
let fakePort = fake.getFakePort(token);
let ports = await navigator.serial.getPorts();
assert_equals(ports.length, 1);
let port = ports[0];
assert_true(port instanceof SerialPort);
return { port, fakePort };
}
let fakeSerialService = undefined;
function serial_test(func, name, properties) {
promise_test(async (test) => {
assert_implements(navigator.serial, 'missing navigator.serial');
if (fakeSerialService === undefined) {
// Try loading a polyfill for the fake serial service.
if (isChromiumBased) {
await loadChromiumResources();
await loadScript('/resources/chromium/fake-serial.js');
}
}
assert_implements(fakeSerialService, 'missing fakeSerialService after initialization');
fakeSerialService.start();
try {
await func(test, fakeSerialService);
} finally {
fakeSerialService.stop();
fakeSerialService.reset();
}
}, name, properties);
}
function trustedClick() {
return new Promise(resolve => {
let button = document.createElement('button');
button.textContent = 'click to continue test';
button.style.display = 'block';
button.style.fontSize = '20px';
button.style.padding = '10px';
button.onclick = () => {
document.body.removeChild(button);
resolve();
};
document.body.appendChild(button);
test_driver.click(button);
});
}

View file

@ -0,0 +1,26 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await promise_rejects_dom(t, 'InvalidStateError', port.close());
}, 'A SerialPort cannot be closed if it was never opened.');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600});
await port.close();
await promise_rejects_dom(t, 'InvalidStateError', port.close());
}, 'A SerialPort cannot be closed if it is already closed.');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600});
const closePromise = port.close();
await promise_rejects_dom(t, 'InvalidStateError', port.close());
await closePromise;
}, 'A SerialPort cannot be closed if it is being closed.');

View file

@ -0,0 +1,197 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const targets = [navigator.serial, port];
const expectedTargets = [navigator.serial];
const actualTargets = [];
function eventHandler(evt) {
actualTargets.push(evt.currentTarget);
if (evt.currentTarget == navigator.serial) {
evt.stopPropagation();
}
}
targets.forEach((target) => {
target.addEventListener('foo', eventHandler, {capture: true});
// stopPropagation() during capturing prevents bubbling.
target.addEventListener('foo', eventHandler);
t.add_cleanup(() => {
target.removeEventListener('foo', eventHandler, {capture: true});
target.removeEventListener('foo', eventHandler);
});
});
port.dispatchEvent(new CustomEvent('foo', {bubbles: true}));
assert_array_equals(actualTargets, expectedTargets, 'actualTargets');
}, 'stopPropagation() during capturing');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const targets = [navigator.serial, port];
const expectedTargets = [navigator.serial];
const actualTargets = [];
function eventHandler(evt) {
actualTargets.push(evt.currentTarget);
if (evt.currentTarget == navigator.serial) {
evt.cancelBubble = true;
}
}
targets.forEach((target) => {
target.addEventListener('foo', eventHandler, {capture: true});
// Setting cancelBubble during capturing prevents bubbling.
target.addEventListener('foo', eventHandler);
t.add_cleanup(() => {
target.removeEventListener('foo', eventHandler, {capture: true});
target.removeEventListener('foo', eventHandler);
});
});
port.dispatchEvent(new CustomEvent('foo', {bubbles: true}));
assert_array_equals(actualTargets, expectedTargets, 'actualTargets');
}, 'Set cancelBubble during capturing');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const targets = [navigator.serial, port];
const expectedTargets = [port];
const actualTargets = [];
function eventHandler(evt) {
actualTargets.push(evt.currentTarget);
if (evt.currentTarget == port) {
evt.stopPropagation();
}
}
targets.forEach((target) => {
target.addEventListener('foo', eventHandler);
t.add_cleanup(() => {
target.removeEventListener('foo', eventHandler);
});
});
port.dispatchEvent(new CustomEvent('foo', {bubbles: true}));
assert_array_equals(actualTargets, expectedTargets, 'actualTargets');
}, 'stopPropagation() during bubbling');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const targets = [navigator.serial, port];
const expectedTargets = [port];
const actualTargets = [];
function eventHandler(evt) {
actualTargets.push(evt.currentTarget);
if (evt.currentTarget == port) {
evt.cancelBubble = true;
}
}
targets.forEach((target) => {
target.addEventListener('foo', eventHandler);
t.add_cleanup(() => {
target.removeEventListener('foo', eventHandler);
});
});
port.dispatchEvent(new CustomEvent('foo', {bubbles: true}));
assert_array_equals(actualTargets, expectedTargets, 'actualTargets');
}, 'Set cancelBubble during bubbling');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const targets = [navigator.serial, port];
const expectedTargets = [
navigator.serial,
port,
navigator.serial,
port,
];
const expectedTypes = [
'foo',
'bar',
'bar',
'foo',
];
const actualTargets = [];
const actualTypes = [];
function eventHandler(evt) {
actualTargets.push(evt.currentTarget);
actualTypes.push(evt.type);
if (evt.currentTarget == navigator.serial && evt.type == 'foo') {
port.dispatchEvent(new CustomEvent('bar', {bubbles: true}));
}
}
targets.forEach((target) => {
target.addEventListener('foo', eventHandler, {capture: true});
target.addEventListener('bar', eventHandler);
t.add_cleanup(() => {
target.removeEventListener('foo', eventHandler, {capture: true});
target.removeEventListener('bar', eventHandler);
});
});
port.dispatchEvent(new CustomEvent('foo', {bubbles: true}));
assert_array_equals(actualTargets, expectedTargets, 'actualTargets');
assert_array_equals(actualTypes, expectedTypes, 'actualTypes');
}, 'An event dispatched in an event handler is propagated before continuing');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const targets = [navigator.serial, port];
const expected = [
'capturing Serial',
'capturing SerialPort',
'bubbling SerialPort',
'bubbling Serial',
];
const actual = [];
targets.forEach((target) => {
const bubblingEventHandler = () => {
actual.push(`bubbling ${target.constructor.name}`);
};
target.addEventListener('foo', bubblingEventHandler);
const capturingEventHandler = () => {
actual.push(`capturing ${target.constructor.name}`);
};
target.addEventListener('foo', capturingEventHandler, {capture: true});
t.add_cleanup(() => {
target.removeEventListener('foo', bubblingEventHandler, {capture: true});
target.removeEventListener('foo', capturingEventHandler);
});
});
port.dispatchEvent(new CustomEvent('foo', {bubbles: true}));
assert_array_equals(actual, expected);
}, 'Capturing and bubbling events delivered to listeners in the expected order');

View file

@ -0,0 +1,24 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
// Wait for getPorts() to resolve in order to ensure that the Mojo client
// interface has been configured.
let ports = await navigator.serial.getPorts();
assert_equals(ports.length, 0);
[{},
{usbVendorId: 1},
{usbProductId: 2},
{usbVendorId: 1, usbProductId: 2},
].forEach((expectedInfo) => {
serial_test(async (t, fake) => {
let watcher = new EventWatcher(t, navigator.serial, ['connect']);
fake.addPort(expectedInfo);
let evt = await watcher.wait_for(['connect']);
let info = evt.target.getInfo();
assert_object_equals(expectedInfo, info);
}, `getInfo() returns ${JSON.stringify(expectedInfo)}`);
});
}, 'getInfo() meta test');

View file

@ -0,0 +1,63 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await promise_rejects_dom(t, 'InvalidStateError', port.getSignals());
}, 'getSignals() rejects if the port is not open');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600});
let expectedSignals = {
dataCarrierDetect: false,
clearToSend: false,
ringIndicator: false,
dataSetReady: false
};
fakePort.simulateInputSignals(expectedSignals);
let signals = await port.getSignals();
assert_object_equals(signals, expectedSignals);
expectedSignals.dataCarrierDetect = true;
fakePort.simulateInputSignals(expectedSignals);
signals = await port.getSignals();
assert_object_equals(signals, expectedSignals, 'DCD set');
expectedSignals.clearToSend = true;
fakePort.simulateInputSignals(expectedSignals);
signals = await port.getSignals();
assert_object_equals(signals, expectedSignals, 'CTS set');
expectedSignals.ringIndicator = true;
fakePort.simulateInputSignals(expectedSignals);
signals = await port.getSignals();
assert_object_equals(signals, expectedSignals, 'RI set');
expectedSignals.dataSetReady = true;
fakePort.simulateInputSignals(expectedSignals);
signals = await port.getSignals();
assert_object_equals(signals, expectedSignals, 'DSR set');
}, 'getSignals() returns the current state of input control signals');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600});
fakePort.simulateInputSignalFailure(true);
await promise_rejects_dom(t, 'NetworkError', port.getSignals());
fakePort.simulateInputSignalFailure(false);
const expectedSignals = {
dataCarrierDetect: false,
clearToSend: false,
ringIndicator: false,
dataSetReady: false
};
const signals = await port.getSignals();
assert_object_equals(signals, expectedSignals);
await port.close();
}, 'getSignals() rejects on failure');

View file

@ -0,0 +1,40 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
// Don't listen for 'disconnect' events on navigator.serial so we can listen
// for them on each SerialPort instance instead.
const eventWatcher = new EventWatcher(t, navigator.serial, ['connect']);
// Wait for getPorts() to resolve in order to ensure that the Mojo client
// interface has been configured.
let ports = await navigator.serial.getPorts();
assert_equals(ports.length, 0);
// Add ports one at a time so that we can map tokens to ports.
const token1 = fake.addPort();
const port1 = (await eventWatcher.wait_for(['connect'])).target;
const port1Watcher = new EventWatcher(t, port1, ['disconnect']);
const token2 = fake.addPort();
const port2 = (await eventWatcher.wait_for(['connect'])).target;
const port2Watcher = new EventWatcher(t, port2, ['disconnect']);
fake.removePort(token2);
const event1 = await port2Watcher.wait_for(['disconnect']);
assert_true(event1 instanceof Event);
assert_equals(event1.target, port2);
ports = await navigator.serial.getPorts();
assert_equals(ports.length, 1);
assert_equals(ports[0], port1);
fake.removePort(token1);
const event2 = await port1Watcher.wait_for(['disconnect']);
assert_true(event2 instanceof Event);
assert_equals(event2.target, port1);
ports = await navigator.serial.getPorts();
assert_equals(ports.length, 0);
}, 'A "disconnect" event is fired on ports when they are removed.');

View file

@ -0,0 +1,95 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600});
return promise_rejects_dom(
t, 'InvalidStateError', port.open({baudRate: 9600}));
}, 'A SerialPort cannot be opened if it is already open.');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const firstRequest = port.open({baudRate: 9600});
await promise_rejects_dom(
t, 'InvalidStateError', port.open({baudRate: 9600}));
await firstRequest;
}, 'Simultaneous calls to open() are disallowed.');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await promise_rejects_js(t, TypeError, port.open({}));
await Promise.all([-1, 0].map(
baudRate => {
return promise_rejects_js(t, TypeError, port.open({baudRate}))}));
}, 'Baud rate is required and must be greater than zero.');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await Promise.all([-1, 0, 6, 9].map(dataBits => {
return promise_rejects_js(
t, TypeError, port.open({baudRate: 9600, dataBits}));
}));
await[undefined, 7, 8].reduce(async (previousTest, dataBits) => {
await previousTest;
await port.open({baudRate: 9600, dataBits});
await port.close();
}, Promise.resolve());
}, 'Data bits must be 7 or 8');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await Promise.all([0, null, 'cats'].map(parity => {
return promise_rejects_js(
t, TypeError, port.open({baudRate: 9600, parity}),
`Should reject parity option "${parity}"`);
}));
await[undefined, 'none', 'even', 'odd'].reduce(
async (previousTest, parity) => {
await previousTest;
await port.open({baudRate: 9600, parity});
await port.close();
},
Promise.resolve());
}, 'Parity must be "none", "even" or "odd"');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await Promise.all([-1, 0, 3, 4].map(stopBits => {
return promise_rejects_js(
t, TypeError, port.open({baudRate: 9600, stopBits}));
}));
await[undefined, 1, 2].reduce(async (previousTest, stopBits) => {
await previousTest;
await port.open({baudRate: 9600, stopBits});
await port.close();
}, Promise.resolve());
}, 'Stop bits must be 1 or 2');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await promise_rejects_js(
t, TypeError, port.open({baudRate: 9600, bufferSize: -1}));
await promise_rejects_js(
t, TypeError, port.open({baudRate: 9600, bufferSize: 0}));
}, 'Buffer size must be greater than zero.');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
const bufferSize = 1 * 1024 * 1024 * 1024 /* 1 GiB */;
return promise_rejects_js(
t, TypeError, port.open({baudRate: 9600, bufferSize}));
}, 'Unreasonably large buffer sizes are rejected.');

View file

@ -0,0 +1,69 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600, bufferSize: 64});
const reader = port.readable.getReader();
const readPromise = reader.read();
await reader.cancel();
const {value, done} = await readPromise;
assert_true(done);
assert_equals(undefined, value);
await port.close();
}, 'Can cancel while reading');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600, bufferSize: 64});
const reader = port.readable.getReader();
const closed = (async () => {
const {value, done} = await reader.read();
assert_true(done);
assert_equals(undefined, value);
reader.releaseLock();
await port.close();
assert_equals(port.readable, null);
})();
await reader.cancel();
await closed;
}, 'Can close while canceling');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600, bufferSize: 64});
const reader = port.readable.getReader();
await fakePort.writable();
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
await fakePort.write(data);
await reader.cancel();
await port.close();
}, 'Cancel discards a small amount of data waiting to be read');
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
// Select a buffer size smaller than the amount of data transferred.
await port.open({baudRate: 9600, bufferSize: 64});
const reader = port.readable.getReader();
await fakePort.writable();
const data = new Uint8Array(1024);
// Writing will fail because there was more data to send than could fit in the
// buffer and none of it was read.
const writePromise =
promise_rejects_dom(t, 'InvalidStateError', fakePort.write(data));
await reader.cancel();
await writePromise;
await port.close();
}, 'Cancel discards a large amount of data waiting to be read');

View file

@ -0,0 +1,30 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
// Select a buffer size larger than the amount of data transferred.
await port.open({baudRate: 9600, bufferSize: 64});
const decoder = new TextDecoderStream();
const streamClosed = port.readable.pipeTo(decoder.writable);
const readable = decoder.readable.pipeThrough(new TransformStream())
.pipeThrough(new TransformStream())
.pipeThrough(new TransformStream())
.pipeThrough(new TransformStream());
const reader = readable.getReader();
await fakePort.writable();
fakePort.write(new TextEncoder().encode('Hello world!'));
const {value, done} = await reader.read();
assert_false(done);
assert_equals('Hello world!', value);
await reader.cancel('arbitrary reason');
await streamClosed.catch(reason => {
assert_equals('arbitrary reason', reason);
});
await port.close();
}, 'Stream closure is observable through a long chain of transforms');

View file

@ -0,0 +1,17 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
await port.open({baudRate: 9600});
assert_true(port.readable instanceof ReadableStream);
const reader = port.readable.getReader();
await promise_rejects_js(t, TypeError, port.close());
reader.releaseLock();
await port.close();
assert_equals(port.readable, null);
}, 'Port cannot be closed while readable is locked');

View file

@ -0,0 +1,25 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
// Select a buffer size smaller than the amount of data transferred.
await port.open({baudRate: 9600, bufferSize: 64});
const reader = port.readable.getReader();
await fakePort.writable();
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
fakePort.write(data);
fakePort.simulateDisconnectOnRead();
const {value, done} = await reader.read();
assert_false(done);
compareArrays(data, value);
await promise_rejects_dom(t, 'NetworkError', reader.read());
assert_equals(port.readable, null);
await port.close();
}, 'Disconnect error closes readable and sets it to null');

View file

@ -0,0 +1,23 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
// Select a buffer size smaller than the amount of data transferred.
await port.open({baudRate: 9600, bufferSize: 64});
const reader = port.readable.getReader();
await fakePort.writable();
const data = new Uint8Array(1024); // Much larger than bufferSize above.
for (let i = 0; i < data.byteLength; ++i)
data[i] = i & 0xff;
fakePort.write(data);
const value = await readWithLength(reader, data.byteLength);
compareArrays(data, value);
reader.releaseLock();
await port.close();
}, 'Can read a large amount of data');

View file

@ -0,0 +1,21 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
assert_equals(port.readable, null);
await port.open({baudRate: 9600});
const readable = port.readable;
assert_true(readable instanceof ReadableStream);
await port.close();
assert_equals(port.readable, null);
const reader = readable.getReader();
const {value, done} = await reader.read();
assert_true(done);
assert_equals(value, undefined);
}, 'SerialPort.readable is set by open() and closes on port close');

View file

@ -0,0 +1,52 @@
// META: script=/resources/test-only-api.js
// META: script=/serial/resources/common.js
// META: script=resources/automation.js
// ParityError is not (as of 2020/03/23) a valid DOMException, so cannot use
// promise_rejects_dom for it.
async function promise_rejects_with_parity_error(t, promise) {
return promise
.then(() => {
assert_false('Should have rejected');
})
.catch(e => {
assert_equals(e.constructor, DOMException);
assert_equals(e.name, 'ParityError');
});
}
serial_test(async (t, fake) => {
const {port, fakePort} = await getFakeSerialPort(fake);
// Select a buffer size smaller than the amount of data transferred.
await port.open({baudRate: 9600, bufferSize: 64});
let readable = port.readable;
let reader = readable.getReader();
await fakePort.writable();
const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
fakePort.write(data);
fakePort.simulateParityError();
let {value, done} = await reader.read();
assert_false(done);
compareArrays(data, value);
await promise_rejects_with_parity_error(t, reader.read());
assert_not_equals(port.readable, readable);
readable = port.readable;
assert_true(readable instanceof ReadableStream);
reader = port.readable.getReader();
await fakePort.writable();
fakePort.write(data);
({value, done} = await reader.read());
assert_false(done);
compareArrays(data, value);
reader.releaseLock();
await port.close();
assert_equals(port.readable, null);
}, 'Parity error closes readable and replaces it with a new stream');

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