mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Update web-platform-tests to revision a184aa4fd5cd8f92eb87ce0035f257f2a4c7c0b2
This commit is contained in:
parent
e1065fa22a
commit
c7e8937c37
84 changed files with 2653 additions and 218 deletions
|
@ -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: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
[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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[hit-test-floats-005.html]
|
|
||||||
[Miss clipped float]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -309,15 +309,6 @@
|
||||||
[Response: combined response Content-Type: text/html;" \\" text/plain ";charset=GBK]
|
[Response: combined response Content-Type: text/html;" \\" text/plain ";charset=GBK]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
||||||
[<iframe>: separate response Content-Type: text/html;" \\" text/plain]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<iframe>: combined response Content-Type: */* text/html]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<iframe>: combined response Content-Type: text/html */*]
|
[<iframe>: combined response Content-Type: text/html */*]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -330,3 +321,9 @@
|
||||||
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[<iframe>: combined response Content-Type: text/html;" text/plain]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[<iframe>: separate response Content-Type: text/plain */*;charset=gbk]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,3 @@
|
||||||
[separate text/javascript x/x]
|
[separate text/javascript x/x]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[separate text/javascript ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
[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
|
||||||
|
|
||||||
[Content-Type-Options%3A%20nosniff]
|
[X-Content-Type-Options%3A%20%22nosniFF%22]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[X-Content-Type-Options%3A%20no%0D%0AX-Content-Type-Options%3A%20nosniff]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_1.html]
|
||||||
|
[Multiple history traversals from the same task]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_4.html]
|
||||||
|
[Multiple history traversals, last would be aborted]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_5.html]
|
||||||
|
[Multiple history traversals, last would be aborted]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[cross-origin-isolated.sub.https.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[self: originAgentCluster must equal true]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[child: originAgentCluster must equal true]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[iframe_sandbox_popups_escaping-1.html]
|
[iframe_sandbox_popups_escaping-1.html]
|
||||||
expected: CRASH
|
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
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[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: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[iframe_sandbox_popups_nonescaping-1.html]
|
[iframe_sandbox_popups_nonescaping-1.html]
|
||||||
expected: TIMEOUT
|
expected: CRASH
|
||||||
[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: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[iframe_sandbox_popups_nonescaping-2.html]
|
[iframe_sandbox_popups_nonescaping-2.html]
|
||||||
expected: TIMEOUT
|
expected: CRASH
|
||||||
[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: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[form-double-submit-2.html]
|
||||||
|
[preventDefault should allow onclick submit() to succeed]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[form-double-submit-3.html]
|
||||||
|
[<button> should have the same double-submit protection as <input type=submit>]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
[input type search: setSelectionRange out of range a second time (must not fire select)]
|
[input type search: setSelectionRange out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type text: selectionStart a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[textarea: selectionDirection a second time (must not fire select)]
|
[textarea: selectionDirection a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -17,30 +14,12 @@
|
||||||
[input type tel: selectionEnd out of range a second time (must not fire select)]
|
[input type tel: selectionEnd out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type password: setSelectionRange() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type search: setRangeText() a second time (must not fire select)]
|
[input type search: setRangeText() a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type url: selectionStart out of range a second time (must not fire select)]
|
[input type url: selectionStart out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type password: selectionStart out of range a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: setSelectionRange out of range a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type password: setSelectionRange out of range a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type tel: setRangeText() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: setSelectionRange() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type text: setSelectionRange out of range a second time (must not fire select)]
|
[input type text: setSelectionRange out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -50,30 +29,51 @@
|
||||||
[input type search: selectionStart out of range a second time (must not fire select)]
|
[input type search: selectionStart out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type tel: selectionDirection a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: select() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: selectionDirection a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type password: selectionEnd a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type search: selectionDirection a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[textarea: setSelectionRange out of range a second time (must not fire select)]
|
[textarea: setSelectionRange out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type tel: select() a second time (must not fire select)]
|
[input type password: select() a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type url: selectionStart a second time (must not fire select)]
|
[input type text: selectionEnd a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type tel: selectionStart a second time (must not fire select)]
|
[input type url: selectionEnd out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type password: selectionEnd out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[textarea: setSelectionRange() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type text: setSelectionRange() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type search: selectionEnd a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type password: setRangeText() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type tel: setSelectionRange out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type text: selectionDirection a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[textarea: selectionStart out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type url: setRangeText() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type password: selectionDirection a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[textarea: selectionEnd out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type search: selectionStart a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[module-delayed.html]
|
|
||||||
[async document.write in a module]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[module-static-import-delayed.html]
|
||||||
|
[document.write in an imported module]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -3,6 +3,3 @@
|
||||||
[The incumbent settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
|
[The incumbent settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[The entry settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[promise-job-entry.html]
|
[promise-job-entry.html]
|
||||||
|
expected: TIMEOUT
|
||||||
[Fulfillment handler on fulfilled promise]
|
[Fulfillment handler on fulfilled promise]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Rejection handler on pending-then-rejected promise]
|
[Rejection handler on pending-then-rejected promise]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Sanity check: this all works as expected with no promises involved]
|
[Sanity check: this all works as expected with no promises involved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -15,5 +16,5 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Fulfillment handler on pending-then-fulfilled promise]
|
[Fulfillment handler on pending-then-fulfilled promise]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -539,3 +539,9 @@
|
||||||
[X SNR (43.824040882292394 dB) is not greater than or equal to 65.737. Got 43.824040882292394.]
|
[X SNR (43.824040882292394 dB) is not greater than or equal to 65.737. Got 43.824040882292394.]
|
||||||
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\]\t4.3013245373868222e+28\t9.3139332532882690e-1\t4.3013245373868222e+28\t4.6181612219179757e+28\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 4.3013245373868222e+28 at index of 28696.\n\tMax RelError of 4.6181612219179757e+28 at index of 28696.\n]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[X SNR (-529.2379582870841 dB) is not greater than or equal to 65.737. Got -529.2379582870841.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[017.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[origin of the script that invoked the method, about:blank]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[017.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[origin of the script that invoked the method, about:blank]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[018.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[origin of the script that invoked the method, javascript:]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[Worker-constructor.html]
|
|
||||||
expected: ERROR
|
|
|
@ -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: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
[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
|
||||||
|
|
|
@ -176521,6 +176521,45 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"css-scroll-snap": {
|
"css-scroll-snap": {
|
||||||
|
"scroll-snap-root-001.html": [
|
||||||
|
"43028cb874d0e2b4899cb3248e20d43dd5930ee3",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/css-scroll-snap/scroll-snap-root-001-ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"scroll-snap-root-002.html": [
|
||||||
|
"302c75634133de666d4262d1a94c9c9ae9bd7b7e",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/css-scroll-snap/scroll-snap-root-002-ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"scroll-snap-root-003.html": [
|
||||||
|
"fc7b28fdf56f360f2ef963d54f4f205426f3ffc9",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/css-scroll-snap/no-red-ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"scroll-target-align-001.html": [
|
"scroll-target-align-001.html": [
|
||||||
"eeda674e07c591cb1d17cce1c8f8bb460c45fbdf",
|
"eeda674e07c591cb1d17cce1c8f8bb460c45fbdf",
|
||||||
[
|
[
|
||||||
|
@ -176717,6 +176756,19 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"scroll-snap-writing-mode-000.html": [
|
||||||
|
"e5d3dd9358bdab8ed06e0d003a13863d2c42aa2d",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/css-scroll-snap/snap-after-initial-layout/scroll-snap-writing-mode-000-ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"writing-mode-horizontal-tb.html": [
|
"writing-mode-horizontal-tb.html": [
|
||||||
"9a680d10d9ff61fc7173118bbfac4fae5b08ff97",
|
"9a680d10d9ff61fc7173118bbfac4fae5b08ff97",
|
||||||
[
|
[
|
||||||
|
@ -259174,7 +259226,7 @@
|
||||||
},
|
},
|
||||||
"support": {
|
"support": {
|
||||||
".azure-pipelines.yml": [
|
".azure-pipelines.yml": [
|
||||||
"155143ef00592c713609a0e7d3e48ddd916b874e",
|
"1c9883ccdec0532499b8df805527ea8e8c37c32f",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
".codecov.yml": [
|
".codecov.yml": [
|
||||||
|
@ -319163,6 +319215,18 @@
|
||||||
"df776353a31f1cef3abe9bc9d195da9be5da2510",
|
"df776353a31f1cef3abe9bc9d195da9be5da2510",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
|
"no-red-ref.html": [
|
||||||
|
"061454fb67a67b9b5b1d62b2603731da3988a3d9",
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
"scroll-snap-root-001-ref.html": [
|
||||||
|
"88f028fb3952b394f6ff4a9548b0b41a26bad131",
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
"scroll-snap-root-002-ref.html": [
|
||||||
|
"663b02b8c420593deda9634d47d44aa45a8596e2",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"scroll-target-001-ref.html": [
|
"scroll-target-001-ref.html": [
|
||||||
"28b00184c2ef5f33f6a2e8927233f6f7f42b1973",
|
"28b00184c2ef5f33f6a2e8927233f6f7f42b1973",
|
||||||
[]
|
[]
|
||||||
|
@ -319172,6 +319236,10 @@
|
||||||
"f3eaa06ac9b7c48479d439041ce51575ad8cc072",
|
"f3eaa06ac9b7c48479d439041ce51575ad8cc072",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
|
"scroll-snap-writing-mode-000-ref.html": [
|
||||||
|
"fe2d4074e26e0bb4417871be39fb37408aa2c498",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"snap-after-initial-layout-ref.html": [
|
"snap-after-initial-layout-ref.html": [
|
||||||
"c8009b626cb63ebcef4a211f8b61249faf36c72f",
|
"c8009b626cb63ebcef4a211f8b61249faf36c72f",
|
||||||
[]
|
[]
|
||||||
|
@ -335323,6 +335391,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"include": {
|
"include": {
|
||||||
|
"editor-test-utils.js": [
|
||||||
|
"3ca014a472fa45991e38d565a10fe9dc9afa6ff8",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"implementation.js": [
|
"implementation.js": [
|
||||||
"44a7afd82d25fdee8b023e3a84a650e4a134de0e",
|
"44a7afd82d25fdee8b023e3a84a650e4a134de0e",
|
||||||
[]
|
[]
|
||||||
|
@ -340152,6 +340224,10 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"getter-special-cases": {
|
"getter-special-cases": {
|
||||||
|
"cross-origin-isolated.sub.https.html.headers": [
|
||||||
|
"5f8621ef83660c66f0d037ea28fafefb558140f1",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"csp-sandbox-no.https.html.headers": [
|
"csp-sandbox-no.https.html.headers": [
|
||||||
"4705ce9dedeeabf8208bf602176511c0cbe2cb76",
|
"4705ce9dedeeabf8208bf602176511c0cbe2cb76",
|
||||||
[]
|
[]
|
||||||
|
@ -340264,6 +340340,14 @@
|
||||||
"9292fe3894e4a82f77a8877b76faa19fe6dfdb47",
|
"9292fe3894e4a82f77a8877b76faa19fe6dfdb47",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
|
"coep-frame.html": [
|
||||||
|
"7cbd89b943ffcae6b6038b1caf905783bbd4aab3",
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
"coep-frame.html.headers": [
|
||||||
|
"4e798cd9f5d3f756df077a43ce9a1a6f9b41fd28",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"crashy-popup.sub.html": [
|
"crashy-popup.sub.html": [
|
||||||
"45c8d5074d22b3233d8bee4c6d1236e8899009e4",
|
"45c8d5074d22b3233d8bee4c6d1236e8899009e4",
|
||||||
[]
|
[]
|
||||||
|
@ -340772,7 +340856,7 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"window-name.sub.html": [
|
"window-name.sub.html": [
|
||||||
"378f588e6b3ba0847a64795d1bca047ba6aa6b8a",
|
"0fa874b2cfc2cfe6d1a0a79348857290215a3ef4",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"window-opener.html": [
|
"window-opener.html": [
|
||||||
|
@ -352321,7 +352405,7 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"input-events-get-target-ranges.js": [
|
"input-events-get-target-ranges.js": [
|
||||||
"f9404e07a5564c64a2863a1329728517fedd5ca7",
|
"004416ec2a02e0abc254f9b2b7d0a0c41b751a7d",
|
||||||
[]
|
[]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -360752,6 +360836,10 @@
|
||||||
"8effa56c98c9f921201553121308591e7431a201",
|
"8effa56c98c9f921201553121308591e7431a201",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
|
"clients-matchall-blob-url-worker.html": [
|
||||||
|
"ee89a0d8b3ee7513ff3817632db32a9f5f2c162a",
|
||||||
|
[]
|
||||||
|
],
|
||||||
"clients-matchall-client-types-dedicated-worker.js": [
|
"clients-matchall-client-types-dedicated-worker.js": [
|
||||||
"5a3f04d33aaae64eb8abed16dc36e8181fed9de6",
|
"5a3f04d33aaae64eb8abed16dc36e8181fed9de6",
|
||||||
[]
|
[]
|
||||||
|
@ -362449,7 +362537,7 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"README.md": [
|
"README.md": [
|
||||||
"fd964cf7e5b75db408e0b5813cb94172186f5c26",
|
"9ab6e1284ad50d2982ea1f6fc78d7a519e796460",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"resources": {
|
"resources": {
|
||||||
|
@ -363625,11 +363713,11 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"update_hosts.yml": [
|
"update_hosts.yml": [
|
||||||
"2036c419380b798eb5f11bfc1508e0ac44cf6249",
|
"64aff7cf46a83e0ad0045065b5ec2e78deb6506d",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"update_manifest.yml": [
|
"update_manifest.yml": [
|
||||||
"b636b23a761ed033c160c8d64589e18506459c19",
|
"e8f28217f1eaa9af3ec67e2b1a64365c8aa87a81",
|
||||||
[]
|
[]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -390553,7 +390641,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"DOMException-constructor-behavior.any.js": [
|
"DOMException-constructor-behavior.any.js": [
|
||||||
"d6e1cdd451ca8de2a6596d0fd31594c15f7318b3",
|
"e9917af2287490c77543146a660d57c822cccf2e",
|
||||||
[
|
[
|
||||||
"WebIDL/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.html",
|
"WebIDL/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.html",
|
||||||
{}
|
{}
|
||||||
|
@ -434735,6 +434823,124 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"typing-around-link-element-at-collapsed-selection.tentative.html": [
|
||||||
|
"92fa2df233f327083f989c7a8abdf855f5005e61",
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&child=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&parent=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=ContentEditable&parent=b&child=i",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=DesignMode",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=DesignMode&child=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=DesignMode&parent=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-collapsed-selection.tentative.html?target=DesignMode&parent=b&child=i",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"typing-around-link-element-at-non-collapsed-selection.tentative.html": [
|
||||||
|
"a9e5790c356c4a910ce7d8565c3fe9a8408e2981",
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&child=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&parent=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=ContentEditable&parent=b&child=i",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=DesignMode",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=DesignMode&child=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=DesignMode&parent=b",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"editing/other/typing-around-link-element-at-non-collapsed-selection.tentative.html?target=DesignMode&parent=b&child=i",
|
||||||
|
{
|
||||||
|
"testdriver": true,
|
||||||
|
"timeout": "long"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
"white-spaces-after-execCommand-delete.tentative.html": [
|
"white-spaces-after-execCommand-delete.tentative.html": [
|
||||||
"1490bf06f55a6c2b1e10afc044b19b108e5dd482",
|
"1490bf06f55a6c2b1e10afc044b19b108e5dd482",
|
||||||
[
|
[
|
||||||
|
@ -461370,6 +461576,13 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"getter-special-cases": {
|
"getter-special-cases": {
|
||||||
|
"cross-origin-isolated.sub.https.html": [
|
||||||
|
"e10d3452b91db3dc6a188bf4113833b699224ff1",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"csp-sandbox-no.https.html": [
|
"csp-sandbox-no.https.html": [
|
||||||
"e0b5f92376287417ab099c49e0b7396dc0d87256",
|
"e0b5f92376287417ab099c49e0b7396dc0d87256",
|
||||||
[
|
[
|
||||||
|
@ -462518,7 +462731,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"clear-window-name.https.html": [
|
"clear-window-name.https.html": [
|
||||||
"39798f1e232f2ba109d64afdcf5031b06620207b",
|
"27601eb7f6db164cde6ac1d0ecda0d69dfab1a75",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
|
@ -530306,6 +530519,13 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"clients-matchall-blob-url-worker.https.html": [
|
||||||
|
"c29bac8b894a2c50828ae3469d3e181d227fe7ac",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"clients-matchall-client-types.https.html": [
|
"clients-matchall-client-types.https.html": [
|
||||||
"54f182b6202cd67cc63e159e7e2d4294fdf975ff",
|
"54f182b6202cd67cc63e159e7e2d4294fdf975ff",
|
||||||
[
|
[
|
||||||
|
@ -549449,7 +549669,7 @@
|
||||||
"web-bundle": {
|
"web-bundle": {
|
||||||
"subresource-loading": {
|
"subresource-loading": {
|
||||||
"link-web-bundle.tentative.html": [
|
"link-web-bundle.tentative.html": [
|
||||||
"7f6de1014cf16be90a2f8ba0551c7c02c92219eb",
|
"2f10cd6b3fdd4dd94dc5767df663583cd8d81071",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
|
@ -549463,7 +549683,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"subresource-loading-from-web-bundle.tentative.html": [
|
"subresource-loading-from-web-bundle.tentative.html": [
|
||||||
"53a9c1b2cc707271c8d7b0e7fb7385fd59839744",
|
"6f38f145bc8795c51961e08fdf09ea4e590d26eb",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
|
@ -552794,7 +553014,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"video-decoder.any.js": [
|
"video-decoder.any.js": [
|
||||||
"33ea2dbe375d5446e68e90405f9867ce8f7fb272",
|
"44e7375a78c013d0a9d0f60a33a04651473c48fb",
|
||||||
[
|
[
|
||||||
"webcodecs/video-decoder.any.html",
|
"webcodecs/video-decoder.any.html",
|
||||||
{
|
{
|
||||||
|
@ -552827,7 +553047,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"video-encoder.any.js": [
|
"video-encoder.any.js": [
|
||||||
"77fe184bafa84786315c3375936dc61927ca304b",
|
"d86e6b61f2039acdf882f7551c7027967eec3ce2",
|
||||||
[
|
[
|
||||||
"webcodecs/video-encoder.any.html",
|
"webcodecs/video-encoder.any.html",
|
||||||
{
|
{
|
||||||
|
@ -552868,7 +553088,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"video-frame-serialization.any.js": [
|
"video-frame-serialization.any.js": [
|
||||||
"524f94374f417ae08798a2d1eeafbc012c028a41",
|
"338f721da8f89e32b63a00dff5d1e62e7b60aa62",
|
||||||
[
|
[
|
||||||
"webcodecs/video-frame-serialization.any.html",
|
"webcodecs/video-frame-serialization.any.html",
|
||||||
{
|
{
|
||||||
|
@ -552909,7 +553129,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"video-frame.any.js": [
|
"video-frame.any.js": [
|
||||||
"9eb6699c06ae541b7e2e3911a913b29a7f5d83cf",
|
"14cce43baf144aedc57eab1a84dd8517dc2804e0",
|
||||||
[
|
[
|
||||||
"webcodecs/video-frame.any.html",
|
"webcodecs/video-frame.any.html",
|
||||||
{
|
{
|
||||||
|
@ -552942,7 +553162,7 @@
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"video-track-reader.html": [
|
"video-track-reader.html": [
|
||||||
"b5d610e9eacf72ee4339f79643e8fe54cb90fd24",
|
"925e8374f58f4e1983d9ed7d05c0324a9028c22a",
|
||||||
[
|
[
|
||||||
null,
|
null,
|
||||||
{}
|
{}
|
||||||
|
@ -555141,6 +555361,13 @@
|
||||||
"timeout": "long"
|
"timeout": "long"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
],
|
||||||
|
"RTCRtpTransceiver-headerExtensionControl.html": [
|
||||||
|
"e823bd830c6e34c159dc511c05721a40b69586b1",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"webrtc-identity": {
|
"webrtc-identity": {
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[hit-test-floats-005.html]
|
|
||||||
[Miss clipped float]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -309,15 +309,6 @@
|
||||||
[fetch(): separate response Content-Type: text/plain ]
|
[fetch(): separate response Content-Type: text/plain ]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
||||||
[<iframe>: separate response Content-Type: text/html;" \\" text/plain]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<iframe>: combined response Content-Type: */* text/html]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[<iframe>: combined response Content-Type: text/html */*]
|
[<iframe>: combined response Content-Type: text/html */*]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -330,3 +321,9 @@
|
||||||
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[<iframe>: combined response Content-Type: text/html;" text/plain]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[<iframe>: separate response Content-Type: text/plain */*;charset=gbk]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,3 @@
|
||||||
[separate text/javascript x/x]
|
[separate text/javascript x/x]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[separate text/javascript ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
[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
|
||||||
|
|
||||||
[Content-Type-Options%3A%20nosniff]
|
[X-Content-Type-Options%3A%20%22nosniFF%22]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[X-Content-Type-Options%3A%20no%0D%0AX-Content-Type-Options%3A%20nosniff]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_1.html]
|
||||||
|
[Multiple history traversals from the same task]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_4.html]
|
||||||
|
[Multiple history traversals, last would be aborted]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[traverse_the_history_5.html]
|
||||||
|
[Multiple history traversals, last would be aborted]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[cross-origin-isolated.sub.https.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[self: originAgentCluster must equal true]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[child: originAgentCluster must equal true]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[iframe_sandbox_popups_escaping-1.html]
|
[iframe_sandbox_popups_escaping-1.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: CRASH
|
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
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[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: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[iframe_sandbox_popups_nonescaping-1.html]
|
[iframe_sandbox_popups_nonescaping-1.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
expected: CRASH
|
||||||
[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: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[iframe_sandbox_popups_nonescaping-2.html]
|
[iframe_sandbox_popups_nonescaping-2.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
expected: CRASH
|
||||||
[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: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[form-double-submit-2.html]
|
||||||
|
[preventDefault should allow onclick submit() to succeed]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[form-double-submit-3.html]
|
||||||
|
[<button> should have the same double-submit protection as <input type=submit>]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
[input type search: setSelectionRange out of range a second time (must not fire select)]
|
[input type search: setSelectionRange out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type text: selectionStart a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[textarea: selectionDirection a second time (must not fire select)]
|
[textarea: selectionDirection a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -17,30 +14,12 @@
|
||||||
[input type tel: selectionEnd out of range a second time (must not fire select)]
|
[input type tel: selectionEnd out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type password: setSelectionRange() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type search: setRangeText() a second time (must not fire select)]
|
[input type search: setRangeText() a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type url: selectionStart out of range a second time (must not fire select)]
|
[input type url: selectionStart out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type password: selectionStart out of range a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: setSelectionRange out of range a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type password: setSelectionRange out of range a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type tel: setRangeText() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: setSelectionRange() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type text: setSelectionRange out of range a second time (must not fire select)]
|
[input type text: setSelectionRange out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -50,30 +29,51 @@
|
||||||
[input type search: selectionStart out of range a second time (must not fire select)]
|
[input type search: selectionStart out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type tel: selectionDirection a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: select() a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type url: selectionDirection a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type password: selectionEnd a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[input type search: selectionDirection a second time (must not fire select)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[textarea: setSelectionRange out of range a second time (must not fire select)]
|
[textarea: setSelectionRange out of range a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type tel: select() a second time (must not fire select)]
|
[input type password: select() a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type url: selectionStart a second time (must not fire select)]
|
[input type text: selectionEnd a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[input type tel: selectionStart a second time (must not fire select)]
|
[input type url: selectionEnd out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type password: selectionEnd out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[textarea: setSelectionRange() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type text: setSelectionRange() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type search: selectionEnd a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type password: setRangeText() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type tel: setSelectionRange out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type text: selectionDirection a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[textarea: selectionStart out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type url: setRangeText() a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type password: selectionDirection a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[textarea: selectionEnd out of range a second time (must not fire select)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[input type search: selectionStart a second time (must not fire select)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[module-delayed.html]
|
|
||||||
[async document.write in a module]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[module-static-import-delayed.html]
|
||||||
|
[document.write in an imported module]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -4,6 +4,3 @@
|
||||||
[The incumbent settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
|
[The incumbent settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[The entry settings object while executing the compiled callback via Web IDL's invoke must be that of the node document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[promise-job-entry.html]
|
[promise-job-entry.html]
|
||||||
|
expected: TIMEOUT
|
||||||
[Fulfillment handler on fulfilled promise]
|
[Fulfillment handler on fulfilled promise]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Rejection handler on pending-then-rejected promise]
|
[Rejection handler on pending-then-rejected promise]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Sanity check: this all works as expected with no promises involved]
|
[Sanity check: this all works as expected with no promises involved]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -15,5 +16,5 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Fulfillment handler on pending-then-fulfilled promise]
|
[Fulfillment handler on pending-then-fulfilled promise]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -767,3 +767,9 @@
|
||||||
[X SNR (43.824040882292394 dB) is not greater than or equal to 65.737. Got 43.824040882292394.]
|
[X SNR (43.824040882292394 dB) is not greater than or equal to 65.737. Got 43.824040882292394.]
|
||||||
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\]\t4.3013245373868222e+28\t9.3139332532882690e-1\t4.3013245373868222e+28\t4.6181612219179757e+28\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 4.3013245373868222e+28 at index of 28696.\n\tMax RelError of 4.6181612219179757e+28 at index of 28696.\n]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[X SNR (-529.2379582870841 dB) is not greater than or equal to 65.737. Got -529.2379582870841.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[017.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[origin of the script that invoked the method, about:blank]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[017.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[origin of the script that invoked the method, about:blank]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[018.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[origin of the script that invoked the method, javascript:]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[Worker-constructor.html]
|
|
||||||
expected: ERROR
|
|
|
@ -233,7 +233,11 @@ jobs:
|
||||||
- template: tools/ci/azure/install_chrome.yml
|
- template: tools/ci/azure/install_chrome.yml
|
||||||
- template: tools/ci/azure/install_firefox.yml
|
- template: tools/ci/azure/install_firefox.yml
|
||||||
- template: tools/ci/azure/update_hosts.yml
|
- template: tools/ci/azure/update_hosts.yml
|
||||||
|
parameters:
|
||||||
|
pyflag: --py2
|
||||||
- template: tools/ci/azure/update_manifest.yml
|
- template: tools/ci/azure/update_manifest.yml
|
||||||
|
parameters:
|
||||||
|
pyflag: --py2
|
||||||
- template: tools/ci/azure/tox_pytest.yml
|
- template: tools/ci/azure/tox_pytest.yml
|
||||||
parameters:
|
parameters:
|
||||||
directory: tools/wpt/
|
directory: tools/wpt/
|
||||||
|
@ -403,7 +407,11 @@ jobs:
|
||||||
# - template: tools/ci/azure/install_chrome.yml
|
# - template: tools/ci/azure/install_chrome.yml
|
||||||
# - template: tools/ci/azure/install_firefox.yml
|
# - template: tools/ci/azure/install_firefox.yml
|
||||||
- template: tools/ci/azure/update_hosts.yml
|
- template: tools/ci/azure/update_hosts.yml
|
||||||
|
parameters:
|
||||||
|
pyflag: --py2
|
||||||
- template: tools/ci/azure/update_manifest.yml
|
- template: tools/ci/azure/update_manifest.yml
|
||||||
|
parameters:
|
||||||
|
pyflag: --py2
|
||||||
- template: tools/ci/azure/tox_pytest.yml
|
- template: tools/ci/azure/tox_pytest.yml
|
||||||
parameters:
|
parameters:
|
||||||
directory: tools/wpt/
|
directory: tools/wpt/
|
||||||
|
|
|
@ -100,6 +100,7 @@ test(function() {
|
||||||
{name: "InvalidModificationError", code: 13},
|
{name: "InvalidModificationError", code: 13},
|
||||||
{name: "NamespaceError", code: 14},
|
{name: "NamespaceError", code: 14},
|
||||||
{name: "InvalidAccessError", code: 15},
|
{name: "InvalidAccessError", code: 15},
|
||||||
|
{name: "TypeMismatchError", code: 17},
|
||||||
{name: "SecurityError", code: 18},
|
{name: "SecurityError", code: 18},
|
||||||
{name: "NetworkError", code: 19},
|
{name: "NetworkError", code: 19},
|
||||||
{name: "AbortError", code: 20},
|
{name: "AbortError", code: 20},
|
||||||
|
@ -107,7 +108,25 @@ test(function() {
|
||||||
{name: "QuotaExceededError", code: 22},
|
{name: "QuotaExceededError", code: 22},
|
||||||
{name: "TimeoutError", code: 23},
|
{name: "TimeoutError", code: 23},
|
||||||
{name: "InvalidNodeTypeError", code: 24},
|
{name: "InvalidNodeTypeError", code: 24},
|
||||||
{name: "DataCloneError", code: 25}
|
{name: "DataCloneError", code: 25},
|
||||||
|
|
||||||
|
// These were removed from the error names table.
|
||||||
|
// See https://github.com/heycam/webidl/pull/946.
|
||||||
|
{name: "DOMStringSizeError", code: 0},
|
||||||
|
{name: "NoDataAllowedError", code: 0},
|
||||||
|
{name: "ValidationError", code: 0},
|
||||||
|
|
||||||
|
// The error names which don't have legacy code values.
|
||||||
|
{name: "EncodingError", code: 0},
|
||||||
|
{name: "NotReadableError", code: 0},
|
||||||
|
{name: "UnknownError", code: 0},
|
||||||
|
{name: "ConstraintError", code: 0},
|
||||||
|
{name: "DataError", code: 0},
|
||||||
|
{name: "TransactionInactiveError", code: 0},
|
||||||
|
{name: "ReadOnlyError", code: 0},
|
||||||
|
{name: "VersionError", code: 0},
|
||||||
|
{name: "OperationError", code: 0},
|
||||||
|
{name: "NotAllowedError", code: 0}
|
||||||
].forEach(function(test_case) {
|
].forEach(function(test_case) {
|
||||||
test(function() {
|
test(function() {
|
||||||
var ex = new DOMException("msg", test_case.name);
|
var ex = new DOMException("msg", test_case.name);
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>CSS Reference: No Red</title>
|
||||||
|
|
||||||
|
<p>Test passes if there is no red.
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>CSS Scroll Snap Reference</title>
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
overflow: hidden; /* hide scrollbars for reftest analysis */
|
||||||
|
}
|
||||||
|
|
||||||
|
#target {
|
||||||
|
position: absolute;
|
||||||
|
top: 25%;
|
||||||
|
width: 100%;
|
||||||
|
margin: 25vh 0;
|
||||||
|
border-top: solid blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="target">
|
||||||
|
<div>Test passes if the blue line above is centered in the viewport.</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>scroll-snap-type + scroll-padding propagates root to viewport</title>
|
||||||
|
<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
|
||||||
|
<link rel='help' href='https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type'>
|
||||||
|
<link rel='help' href='https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding'>
|
||||||
|
<link rel='match' href='scroll-snap-root-001-ref.html'>
|
||||||
|
<meta name='assert'
|
||||||
|
content="Test passes if scroll snap properties on root are applied to viewport.">
|
||||||
|
|
||||||
|
<style type='text/css'>
|
||||||
|
html, body { margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
scroll-snap-type: block mandatory;
|
||||||
|
scroll-padding: 25%;
|
||||||
|
overflow: hidden; /* hide scrollbars for reftest analysis */
|
||||||
|
}
|
||||||
|
|
||||||
|
#fail {
|
||||||
|
font: bold 2em;
|
||||||
|
background: red;
|
||||||
|
height: 120vh;
|
||||||
|
margin-bottom: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#target {
|
||||||
|
margin-bottom: 120vh;
|
||||||
|
scroll-margin: 25vh;
|
||||||
|
scroll-snap-align: start;
|
||||||
|
border-top: solid blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="fail">FAIL</div>
|
||||||
|
|
||||||
|
<div id="target">
|
||||||
|
<div>Test passes if the blue line above is centered in the viewport.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('target').scrollIntoView();
|
||||||
|
</script>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>CSS Scroll Snap Reference</title>
|
||||||
|
|
||||||
|
<style type='text/css'>
|
||||||
|
html, body { margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
#target {
|
||||||
|
border-bottom: solid orange thick;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="target">
|
||||||
|
<div>Test passes if the orange stripe below is exactly at the bottom of the viewport.</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>scroll-padding does not propagate body to viewport</title>
|
||||||
|
<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
|
||||||
|
<link rel='help' href='https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type'>
|
||||||
|
<link rel='help' href='https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding'>
|
||||||
|
<link rel='match' href='scroll-snap-root-002-ref.html'>
|
||||||
|
<meta name='assert'
|
||||||
|
content="Test passes if scroll-snap-padding on body is not applied to viewport.">
|
||||||
|
|
||||||
|
<style type='text/css'>
|
||||||
|
html, body { margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
scroll-snap-type: block mandatory;
|
||||||
|
overflow: hidden; /* hide scrollbars for reftest analysis */
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
scroll-padding: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#fail {
|
||||||
|
height: 120vh;
|
||||||
|
font: bold 2em;
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#target {
|
||||||
|
margin: 120vh 0;
|
||||||
|
scroll-snap-align: end;
|
||||||
|
border-bottom: solid orange thick;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="fail">FAIL</div>
|
||||||
|
|
||||||
|
<div id="target">
|
||||||
|
<div>Test passes if the orange stripe below is exactly at the bottom of the viewport.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('target').scrollIntoView();
|
||||||
|
</script>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>scroll-snap-type does not propagate body to viewport</title>
|
||||||
|
<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
|
||||||
|
<link rel='help' href='https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type'>
|
||||||
|
<link rel='help' href='https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding'>
|
||||||
|
<link rel='match' href='no-red-ref.html'>
|
||||||
|
<meta name='assert'
|
||||||
|
content="Test passes if scroll-snap-type on body is not applied to viewport.">
|
||||||
|
|
||||||
|
<style type='text/css'>
|
||||||
|
:root {
|
||||||
|
overflow: hidden; /* hide scrollbars for reftest analysis */
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
scroll-snap-type: block mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pass {
|
||||||
|
height: 120vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#target {
|
||||||
|
scroll-snap-align: start;
|
||||||
|
height: 100vh;
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p id="pass">Test passes if there is no red.
|
||||||
|
|
||||||
|
<div id="target">
|
||||||
|
<div>FAIL</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,167 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>
|
||||||
|
CSS Scroll Snap Reference
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
/* lay out in a nice grid */
|
||||||
|
display: grid;
|
||||||
|
gap: 0.25em;
|
||||||
|
grid-template-columns: repeat(6, max-content);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroller {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: solid silver;
|
||||||
|
border-block-start-color: blue;
|
||||||
|
border-inline-start-color: blue;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.target {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: orange;
|
||||||
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TB { writing-mode: horizontal-tb; }
|
||||||
|
.LR { writing-mode: vertical-lr; }
|
||||||
|
.RL { writing-mode: vertical-rl; }
|
||||||
|
.ltr { direction: ltr; }
|
||||||
|
.rtl { direction: rtl; }
|
||||||
|
|
||||||
|
.TB.invert .target { top: auto; }
|
||||||
|
.LR.invert .target { left: auto; }
|
||||||
|
.RL.invert .target { right: auto; }
|
||||||
|
|
||||||
|
.TB.ltr.invert .target { left: auto; }
|
||||||
|
.TB.rtl.invert .target { right: auto; }
|
||||||
|
.LR.ltr.invert .target { top: auto; }
|
||||||
|
.LR.rtl.invert .target { bottom: auto; }
|
||||||
|
.RL.ltr.invert .target { top: auto; }
|
||||||
|
.RL.rtl.invert .target { bottom: auto; }
|
||||||
|
|
||||||
|
/* not absolutizing the border colors, so that the test passes even if css-logical is not supported; */
|
||||||
|
.large.invert {
|
||||||
|
border: solid silver;
|
||||||
|
border-block-end-color: blue;
|
||||||
|
border-inline-end-color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>Test passes if there is an orange square tucked into each blue corner without gaps,
|
||||||
|
and there is no red.
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<!-- Simple Small Cases -->
|
||||||
|
|
||||||
|
<div class="scroller TB ltr small">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr small">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr small">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl small">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl small">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl small">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Target-inverted Small Cases
|
||||||
|
This row should be identical to the previous. -->
|
||||||
|
<div class="scroller TB ltr small invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr small invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr small invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl small invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl small invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl small invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Simple Large Cases -->
|
||||||
|
|
||||||
|
<div class="scroller TB ltr large">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr large">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr large">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl large">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl large">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl large">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Target-inverted Large Cases
|
||||||
|
This is the fun one. -->
|
||||||
|
|
||||||
|
<div class="scroller TB ltr large invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr large invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr large invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl large invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl large invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl large invert">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div> <!-- wrapper -->
|
|
@ -0,0 +1,237 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>
|
||||||
|
scroll-snap-align vs writing-mode
|
||||||
|
</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap/#re-snap">
|
||||||
|
<link rel="match" href="scroll-snap-writing-mode-000-ref.html">
|
||||||
|
<link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
/* lay out in a nice grid */
|
||||||
|
display: grid;
|
||||||
|
gap: 0.25em;
|
||||||
|
grid-template-columns: repeat(6, max-content);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroller {
|
||||||
|
scroll-snap-type: both mandatory;
|
||||||
|
overflow: hidden;
|
||||||
|
scroll-padding: 0;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: solid silver;
|
||||||
|
border-block-start-color: blue;
|
||||||
|
border-inline-start-color: blue;
|
||||||
|
}
|
||||||
|
.area {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.target {
|
||||||
|
margin: 5px;
|
||||||
|
scroll-snap-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .target {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large .target {
|
||||||
|
width: 51px;
|
||||||
|
height: 51px;
|
||||||
|
border-block-end: 20px solid red;
|
||||||
|
border-inline-end: 20px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large .target::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TB { writing-mode: horizontal-tb; }
|
||||||
|
.LR { writing-mode: vertical-lr; }
|
||||||
|
.RL { writing-mode: vertical-rl; }
|
||||||
|
.ltr { direction: ltr; }
|
||||||
|
.rtl { direction: rtl; }
|
||||||
|
|
||||||
|
.TB.ltr.invert .target { writing-mode: vertical-rl; direction: rtl; }
|
||||||
|
.TB.rtl.invert .target { writing-mode: vertical-lr; direction: rtl; }
|
||||||
|
.LR.ltr.invert .target { writing-mode: vertical-rl; direction: rtl; }
|
||||||
|
.LR.rtl.invert .target { writing-mode: vertical-rl; direction: ltr; }
|
||||||
|
.RL.ltr.invert .target { writing-mode: vertical-lr; direction: rtl; }
|
||||||
|
.RL.rtl.invert .target { writing-mode: horizontal-tb; direction: ltr; }
|
||||||
|
|
||||||
|
.large.invert {
|
||||||
|
/* key off target‘s writing mode, which we just inverted */
|
||||||
|
border: solid silver;
|
||||||
|
border-block-end-color: blue;
|
||||||
|
border-inline-end-color: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>Test passes if there is an orange square tucked into each blue corner without gaps,
|
||||||
|
and there is no red.
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<!-- Simple Small Cases -->
|
||||||
|
|
||||||
|
<div class="scroller TB ltr small">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr small">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr small">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl small">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl small">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl small">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Target-inverted Small Cases
|
||||||
|
This row should be identical to the previous. -->
|
||||||
|
<div class="scroller TB ltr small invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr small invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr small invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl small invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl small invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl small invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Simple Large Cases -->
|
||||||
|
|
||||||
|
<div class="scroller TB ltr large">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr large">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr large">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl large">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl large">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl large">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Target-inverted Large Cases
|
||||||
|
This is the fun one. -->
|
||||||
|
|
||||||
|
<div class="scroller TB ltr large invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR ltr large invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL ltr large invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller TB rtl large invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller LR rtl large invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scroller RL rtl large invert">
|
||||||
|
<div class="area">
|
||||||
|
<div class="target"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div> <!-- wrapper -->
|
|
@ -0,0 +1,344 @@
|
||||||
|
/**
|
||||||
|
* EditorTestUtils is a helper utilities to test HTML editor. This can be
|
||||||
|
* instantiated per an editing host. If you test `designMode`, the editing
|
||||||
|
* host should be the <body> element.
|
||||||
|
*/
|
||||||
|
class EditorTestUtils {
|
||||||
|
kShift = "\uE008";
|
||||||
|
kMeta = "\uE03d";
|
||||||
|
kControl = "\uE009";
|
||||||
|
kAlt = "\uE00A";
|
||||||
|
|
||||||
|
editingHost;
|
||||||
|
|
||||||
|
constructor(aEditingHost, aHarnessWindow = window) {
|
||||||
|
this.editingHost = aEditingHost;
|
||||||
|
if (aHarnessWindow != this.window) {
|
||||||
|
this.window.test_driver.set_test_context(aHarnessWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get document() {
|
||||||
|
return this.editingHost.ownerDocument;
|
||||||
|
}
|
||||||
|
get window() {
|
||||||
|
return this.document.defaultView;
|
||||||
|
}
|
||||||
|
get selection() {
|
||||||
|
return this.window.getSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendKey(key, modifier) {
|
||||||
|
if (!modifier) {
|
||||||
|
return new this.window.test_driver.Actions()
|
||||||
|
.keyDown(key)
|
||||||
|
.keyUp(key)
|
||||||
|
.send();
|
||||||
|
}
|
||||||
|
return new this.window.test_driver.Actions()
|
||||||
|
.keyDown(modifier)
|
||||||
|
.keyDown(key)
|
||||||
|
.keyUp(key)
|
||||||
|
.keyUp(modifier)
|
||||||
|
.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendDeleteKey(modifier) {
|
||||||
|
const kDeleteKey = "\uE017";
|
||||||
|
return this.sendKey(kDeleteKey, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendBackspaceKey(modifier) {
|
||||||
|
const kBackspaceKey = "\uE003";
|
||||||
|
return this.sendKey(kBackspaceKey, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendArrowLeftKey(modifier) {
|
||||||
|
const kArrowLeft = "\uE012";
|
||||||
|
return this.sendKey(kArrowLeft, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendArrowRightKey(modifier) {
|
||||||
|
const kArrowRight = "\uE014";
|
||||||
|
return this.sendKey(kArrowRight, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendHomeKey(modifier) {
|
||||||
|
const kHome = "\uE011";
|
||||||
|
return this.sendKey(kHome, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendEndKey(modifier) {
|
||||||
|
const kEnd = "\uE010";
|
||||||
|
return this.sendKey(kEnd, modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to `setupDiv` in editing/include/tests.js, this method sets
|
||||||
|
// innerHTML value of this.editingHost, and sets multiple selection ranges
|
||||||
|
// specified with the markers.
|
||||||
|
// - `[` specifies start boundary in a text node
|
||||||
|
// - `{` specifies start boundary before a node
|
||||||
|
// - `]` specifies end boundary in a text node
|
||||||
|
// - `}` specifies end boundary after a node
|
||||||
|
setupEditingHost(innerHTMLWithRangeMarkers) {
|
||||||
|
const startBoundaries = innerHTMLWithRangeMarkers.match(/\{|\[/g) || [];
|
||||||
|
const endBoundaries = innerHTMLWithRangeMarkers.match(/\}|\]/g) || [];
|
||||||
|
if (startBoundaries.length !== endBoundaries.length) {
|
||||||
|
throw "Should match number of open/close markers";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editingHost.innerHTML = innerHTMLWithRangeMarkers;
|
||||||
|
this.editingHost.focus();
|
||||||
|
|
||||||
|
if (startBoundaries.length === 0) {
|
||||||
|
// Don't remove the range for now since some tests may assume that
|
||||||
|
// setting innerHTML does not remove all selection ranges.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let getNextRangeAndDeleteMarker = startNode => {
|
||||||
|
let getNextLeafNode = node => {
|
||||||
|
let inclusiveDeepestFirstChildNode = container => {
|
||||||
|
while (container.firstChild) {
|
||||||
|
container = container.firstChild;
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
};
|
||||||
|
if (node.hasChildNodes()) {
|
||||||
|
return inclusiveDeepestFirstChildNode(node);
|
||||||
|
}
|
||||||
|
if (node.nextSibling) {
|
||||||
|
return inclusiveDeepestFirstChildNode(node.nextSibling);
|
||||||
|
}
|
||||||
|
let nextSibling = (child => {
|
||||||
|
for (
|
||||||
|
let parent = child.parentElement;
|
||||||
|
parent && parent != this.editingHost;
|
||||||
|
parent = parent.parentElement
|
||||||
|
) {
|
||||||
|
if (parent.nextSibling) {
|
||||||
|
return parent.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})(node);
|
||||||
|
if (!nextSibling) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return inclusiveDeepestFirstChildNode(nextSibling);
|
||||||
|
};
|
||||||
|
let scanMarkerInTextNode = (textNode, offset) => {
|
||||||
|
return /[\{\[\]\}]/.exec(textNode.data.substr(offset));
|
||||||
|
};
|
||||||
|
let startMarker = ((startContainer, startOffset) => {
|
||||||
|
let scanStartMakerInTextNode = (textNode, offset) => {
|
||||||
|
let scanResult = scanMarkerInTextNode(textNode, offset);
|
||||||
|
if (scanResult === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (scanResult[0] === "}" || scanResult[0] === "]") {
|
||||||
|
throw "An end marker is found before a start marker";
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
marker: scanResult[0],
|
||||||
|
container: textNode,
|
||||||
|
offset: scanResult.index + offset
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (startContainer.nodeType === Node.TEXT_NODE) {
|
||||||
|
let scanResult = scanStartMakerInTextNode(
|
||||||
|
startContainer,
|
||||||
|
startOffset
|
||||||
|
);
|
||||||
|
if (scanResult !== null) {
|
||||||
|
return scanResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let nextNode = startContainer;
|
||||||
|
while ((nextNode = getNextLeafNode(nextNode))) {
|
||||||
|
if (nextNode.nodeType === Node.TEXT_NODE) {
|
||||||
|
let scanResult = scanStartMakerInTextNode(nextNode, 0);
|
||||||
|
if (scanResult !== null) {
|
||||||
|
return scanResult;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})(startNode, 0);
|
||||||
|
if (startMarker === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let endMarker = ((startContainer, startOffset) => {
|
||||||
|
let scanEndMarkerInTextNode = (textNode, offset) => {
|
||||||
|
let scanResult = scanMarkerInTextNode(textNode, offset);
|
||||||
|
if (scanResult === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (scanResult[0] === "{" || scanResult[0] === "[") {
|
||||||
|
throw "A start marker is found before an end marker";
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
marker: scanResult[0],
|
||||||
|
container: textNode,
|
||||||
|
offset: scanResult.index + offset
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (startContainer.nodeType === Node.TEXT_NODE) {
|
||||||
|
let scanResult = scanEndMarkerInTextNode(startContainer, startOffset);
|
||||||
|
if (scanResult !== null) {
|
||||||
|
return scanResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let nextNode = startContainer;
|
||||||
|
while ((nextNode = getNextLeafNode(nextNode))) {
|
||||||
|
if (nextNode.nodeType === Node.TEXT_NODE) {
|
||||||
|
let scanResult = scanEndMarkerInTextNode(nextNode, 0);
|
||||||
|
if (scanResult !== null) {
|
||||||
|
return scanResult;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})(startMarker.container, startMarker.offset + 1);
|
||||||
|
if (endMarker === null) {
|
||||||
|
throw "Found an open marker, but not found corresponding close marker";
|
||||||
|
}
|
||||||
|
let indexOfContainer = (container, child) => {
|
||||||
|
let offset = 0;
|
||||||
|
for (let node = container.firstChild; node; node = node.nextSibling) {
|
||||||
|
if (node == child) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
throw "child must be a child node of container";
|
||||||
|
};
|
||||||
|
let deleteFoundMarkers = () => {
|
||||||
|
let removeNode = node => {
|
||||||
|
let container = node.parentElement;
|
||||||
|
let offset = indexOfContainer(container, node);
|
||||||
|
node.remove();
|
||||||
|
return { container, offset };
|
||||||
|
};
|
||||||
|
if (startMarker.container == endMarker.container) {
|
||||||
|
// If the text node becomes empty, remove it and set collapsed range
|
||||||
|
// to the position where there is the text node.
|
||||||
|
if (startMarker.container.length === 2) {
|
||||||
|
if (!/[\[\{][\]\}]/.test(startMarker.container.data)) {
|
||||||
|
throw `Unexpected text node (data: "${startMarker.container.data}")`;
|
||||||
|
}
|
||||||
|
let { container, offset } = removeNode(startMarker.container);
|
||||||
|
startMarker.container = endMarker.container = container;
|
||||||
|
startMarker.offset = endMarker.offset = offset;
|
||||||
|
startMarker.marker = endMarker.marker = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startMarker.container.data = `${startMarker.container.data.substring(
|
||||||
|
0,
|
||||||
|
startMarker.offset
|
||||||
|
)}${startMarker.container.data.substring(
|
||||||
|
startMarker.offset + 1,
|
||||||
|
endMarker.offset
|
||||||
|
)}${startMarker.container.data.substring(endMarker.offset + 1)}`;
|
||||||
|
if (startMarker.offset >= startMarker.container.length) {
|
||||||
|
startMarker.offset = endMarker.offset =
|
||||||
|
startMarker.container.length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
endMarker.offset--; // remove the start marker's length
|
||||||
|
if (endMarker.offset > endMarker.container.length) {
|
||||||
|
endMarker.offset = endMarker.container.length;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (startMarker.container.length === 1) {
|
||||||
|
let { container, offset } = removeNode(startMarker.container);
|
||||||
|
startMarker.container = container;
|
||||||
|
startMarker.offset = offset;
|
||||||
|
startMarker.marker = "";
|
||||||
|
} else {
|
||||||
|
startMarker.container.data = `${startMarker.container.data.substring(
|
||||||
|
0,
|
||||||
|
startMarker.offset
|
||||||
|
)}${startMarker.container.data.substring(startMarker.offset + 1)}`;
|
||||||
|
}
|
||||||
|
if (endMarker.container.length === 1) {
|
||||||
|
let { container, offset } = removeNode(endMarker.container);
|
||||||
|
endMarker.container = container;
|
||||||
|
endMarker.offset = offset;
|
||||||
|
endMarker.marker = "";
|
||||||
|
} else {
|
||||||
|
endMarker.container.data = `${endMarker.container.data.substring(
|
||||||
|
0,
|
||||||
|
endMarker.offset
|
||||||
|
)}${endMarker.container.data.substring(endMarker.offset + 1)}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deleteFoundMarkers();
|
||||||
|
|
||||||
|
let handleNodeSelectMarker = () => {
|
||||||
|
if (startMarker.marker === "{") {
|
||||||
|
if (startMarker.offset === 0) {
|
||||||
|
// The range start with the text node.
|
||||||
|
let container = startMarker.container.parentElement;
|
||||||
|
startMarker.offset = indexOfContainer(
|
||||||
|
container,
|
||||||
|
startMarker.container
|
||||||
|
);
|
||||||
|
startMarker.container = container;
|
||||||
|
} else if (startMarker.offset === startMarker.container.data.length) {
|
||||||
|
// The range start after the text node.
|
||||||
|
let container = startMarker.container.parentElement;
|
||||||
|
startMarker.offset =
|
||||||
|
indexOfContainer(container, startMarker.container) + 1;
|
||||||
|
startMarker.container = container;
|
||||||
|
} else {
|
||||||
|
throw 'Start marker "{" is allowed start or end of a text node';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (endMarker.marker === "}") {
|
||||||
|
if (endMarker.offset === 0) {
|
||||||
|
// The range ends before the text node.
|
||||||
|
let container = endMarker.container.parentElement;
|
||||||
|
endMarker.offset = indexOfContainer(container, endMarker.container);
|
||||||
|
endMarker.container = container;
|
||||||
|
} else if (endMarker.offset === endMarker.container.data.length) {
|
||||||
|
// The range ends with the text node.
|
||||||
|
let container = endMarker.container.parentElement;
|
||||||
|
endMarker.offset =
|
||||||
|
indexOfContainer(container, endMarker.container) + 1;
|
||||||
|
endMarker.container = container;
|
||||||
|
} else {
|
||||||
|
throw 'End marker "}" is allowed start or end of a text node';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handleNodeSelectMarker();
|
||||||
|
|
||||||
|
let range = document.createRange();
|
||||||
|
range.setStart(startMarker.container, startMarker.offset);
|
||||||
|
range.setEnd(endMarker.container, endMarker.offset);
|
||||||
|
return range;
|
||||||
|
};
|
||||||
|
|
||||||
|
let ranges = [];
|
||||||
|
for (
|
||||||
|
let range = getNextRangeAndDeleteMarker(this.editingHost.firstChild);
|
||||||
|
range;
|
||||||
|
range = getNextRangeAndDeleteMarker(range.endContainer)
|
||||||
|
) {
|
||||||
|
ranges.push(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selection.removeAllRanges();
|
||||||
|
for (let range of ranges) {
|
||||||
|
this.selection.addRange(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selection.rangeCount != ranges.length) {
|
||||||
|
throw `Failed to set selection to the given ranges whose length is ${ranges.length}, but only ${this.selection.rangeCount} ranges are added`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,520 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
|
<meta name="variant" content="?target=ContentEditable">
|
||||||
|
<meta name="variant" content="?target=ContentEditable&parent=b">
|
||||||
|
<meta name="variant" content="?target=ContentEditable&child=b">
|
||||||
|
<meta name="variant" content="?target=ContentEditable&parent=b&child=i">
|
||||||
|
<meta name="variant" content="?target=DesignMode">
|
||||||
|
<meta name="variant" content="?target=DesignMode&parent=b">
|
||||||
|
<meta name="variant" content="?target=DesignMode&child=b">
|
||||||
|
<meta name="variant" content="?target=DesignMode&parent=b&child=i">
|
||||||
|
<title>Testing inserting content around link element</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 src="/resources/testdriver-actions.js"></script>
|
||||||
|
<script src="../include/editor-test-utils.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div contenteditable></div>
|
||||||
|
<iframe srcdoc="
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<script>document.designMode='on';</script>
|
||||||
|
<script src='/resources/testdriver.js'></script>
|
||||||
|
<script src='/resources/testdriver-vendor.js'></script>
|
||||||
|
<script src='/resources/testdriver-actions.js'></script>
|
||||||
|
<body></body>
|
||||||
|
</html>"></iframe>
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const params = new URLSearchParams(location.search.substring(1));
|
||||||
|
const kTarget = params.get("target");
|
||||||
|
const kParentTag = params.get("parent") === null
|
||||||
|
? ["", ""]
|
||||||
|
: [`<${params.get("parent")}>`, `</${params.get("parent")}>`];
|
||||||
|
const kChildTag = params.get("child") === null
|
||||||
|
? ["", ""]
|
||||||
|
: [`<${params.get("child")}>`, `</${params.get("child")}>`];
|
||||||
|
const kLinkDesc = (() => {
|
||||||
|
let result = ""
|
||||||
|
if (kParentTag[0] !== "") {
|
||||||
|
result += `in ${kParentTag[0]} `;
|
||||||
|
if (kChildTag[0] !== "") {
|
||||||
|
result += "and ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kChildTag[0] !== "") {
|
||||||
|
result += `containing ${kChildTag[0]} `;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})();
|
||||||
|
const kNewContainerOfLink = (() => {
|
||||||
|
if (kParentTag !== "" && kChildTag !== "") {
|
||||||
|
return [`${kParentTag[0]}${kChildTag[0]}`, `${kChildTag[1]}${kParentTag[1]}`];
|
||||||
|
}
|
||||||
|
if (kParentTag !== "") {
|
||||||
|
return kParentTag;
|
||||||
|
}
|
||||||
|
if (kChildTag !== "") {
|
||||||
|
return kChildTag;
|
||||||
|
}
|
||||||
|
return ["", ""];
|
||||||
|
})();
|
||||||
|
const kSelectorForTextNodeContainer = kChildTag[0] === ""
|
||||||
|
? "a"
|
||||||
|
: `a > ${kChildTag[0].substr(1, kChildTag[0].length - 2)}`;
|
||||||
|
|
||||||
|
function getEditingHost() {
|
||||||
|
return kTarget === "ContentEditable"
|
||||||
|
? document.querySelector("div[contenteditable]")
|
||||||
|
: document.querySelector("iframe").contentDocument.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPromiseTest(test) {
|
||||||
|
promise_test(async () => {
|
||||||
|
let editingHost = getEditingHost();
|
||||||
|
let utils = new EditorTestUtils(editingHost);
|
||||||
|
utils.setupEditingHost(test.innerHTML);
|
||||||
|
utils.window.focus();
|
||||||
|
utils.document.body.focus();
|
||||||
|
editingHost.focus();
|
||||||
|
await test.run(utils);
|
||||||
|
if (Array.isArray(test.expectedResult)) {
|
||||||
|
assert_in_array(editingHost.innerHTML, test.expectedResult);
|
||||||
|
} else {
|
||||||
|
assert_equals(editingHost.innerHTML, test.expectedResult);
|
||||||
|
}
|
||||||
|
}, `${test.description.trim()} in ${test.innerHTML}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
addEventListener("load", resolve, { once: true });
|
||||||
|
});
|
||||||
|
}, "");
|
||||||
|
|
||||||
|
if (kChildTag[0] === "") {
|
||||||
|
// Immediately after creating a link with Document.execCommand.
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Replacing text in a link ${kLinkDesc}with "XY"`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">XY${kParentTag[1]}</a></p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">XY${kParentTag[1]}</a><br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after making a link ${kLinkDesc}(following Selection.collapseToEnd)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
utils.selection.collapseToEnd();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">abc</a>XY${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">abc</a>XY${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after making a link ${kLinkDesc}(following ArrowRight key press)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
await utils.sendArrowRightKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">abc</a>XY${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">abc</a>XY${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after making a link ${kLinkDesc}(following End key press)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
await utils.sendEndKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">abc</a>XY${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">abc</a>XY${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after making a link ${kLinkDesc}(following Selection.collapseToStart)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
utils.selection.collapseToStart();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}XY<a href="about:blank">abc</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}XY<a href="about:blank">abc</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after making a link ${kLinkDesc}(following ArrowLeft key press)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
await utils.sendArrowLeftKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}XY<a href="about:blank">abc</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}XY<a href="about:blank">abc</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after making a link ${kLinkDesc}(following Home key press)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[abc]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.document.execCommand("createLink", false, "about:blank");
|
||||||
|
await utils.sendHomeKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}XY<a href="about:blank">abc</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}XY<a href="about:blank">abc</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after setting caret position to middle of a link ${kLinkDesc}(Selection.collapse)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}[]abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.selection.collapse(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 2);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abXYc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abXYc${kChildTag[1]}</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after setting caret position to middle of a link ${kLinkDesc}(Selection.addRange)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}[]abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.selection.removeAllRanges();
|
||||||
|
let range = utils.document.createRange();
|
||||||
|
range.setStart(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 2);
|
||||||
|
utils.selection.addRange(range);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abXYc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abXYc${kChildTag[1]}</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after setting caret position to start of a link ${kLinkDesc}(Selection.collapse)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[]c${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.selection.collapse(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 0);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[2]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after setting caret position to start of a link ${kLinkDesc}(Selection.addRange)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[]c${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.selection.removeAllRanges();
|
||||||
|
let range = utils.document.createRange();
|
||||||
|
range.setStart(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 0);
|
||||||
|
utils.selection.addRange(range);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[2]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after setting caret position to end of a link ${kLinkDesc}(Selection.collapse)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[]c${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.selection.collapse(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, "abc".length);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[2]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after setting caret position to end of a link ${kLinkDesc}(Selection.addRange)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[]c${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
utils.selection.collapse(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, "abc".length);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[2]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Type text after moving caret with Range API.
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after modifying caret position to middle of a link ${kLinkDesc}`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}[]abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
let range = utils.selection.getRangeAt(0);
|
||||||
|
range.setStart(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 2);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abXYc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abXYc${kChildTag[1]}</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after modifying caret position to start of a link ${kLinkDesc}`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[]c${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
let range = utils.selection.getRangeAt(0);
|
||||||
|
range.setStart(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 0);
|
||||||
|
range.setEnd(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, 0);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after modifying caret position to end of a link ${kLinkDesc}`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[]c${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
let range = utils.selection.getRangeAt(0);
|
||||||
|
range.setStart(utils.editingHost.querySelector(kSelectorForTextNodeContainer).firstChild, "abc".length);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Type text after deleting character immediately before/after a link.
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting following character of a link ${kLinkDesc}(Backspace)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abc${kChildTag[1]}</a>d[]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.sendBackspaceKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting following character of a link ${kLinkDesc}(execCommand("delete"))`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abc${kChildTag[1]}</a>d[]${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.document.execCommand("delete", false);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting a previous character of a link ${kLinkDesc}(Delete)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[]z<a href="about:blank">${kChildTag[0]}abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.sendDeleteKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting a previous character of a link ${kLinkDesc}(execCommand("forwarddelete"))`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}[]z<a href="about:blank">${kChildTag[0]}abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.document.execCommand("forwarddelete", false);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Type text after deleting the last character in a link.
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting last character of a link ${kLinkDesc}(Backspace)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abcd[]${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.sendBackspaceKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[1]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting last character of a link ${kLinkDesc}(execCommand("delete"))`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abcd[]${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.document.execCommand("delete", false);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[1]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting last character of a link ${kLinkDesc}(Delete)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abc[]d${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.sendDeleteKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting last character of a link ${kLinkDesc}(execCommand("forwarddelete"))`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abc[]d${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.document.execCommand("forwarddelete", false);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Type text after deleting the first character in a link.
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting first character of a link ${kLinkDesc}(Backspace)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}z[]abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.sendBackspaceKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting first character of a link ${kLinkDesc}(execCommand("delete"))`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}z[]abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.document.execCommand("delete", false);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting first character of a link ${kLinkDesc}(Delete)`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}[]zabc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.sendDeleteKey();
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting first character of a link ${kLinkDesc}(execCommand("forwarddelete"))`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}[]zabc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await utils.document.execCommand("forwarddelete", false);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,214 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="timeout" content="long">
|
||||||
|
<meta name="variant" content="?target=ContentEditable">
|
||||||
|
<meta name="variant" content="?target=ContentEditable&parent=b">
|
||||||
|
<meta name="variant" content="?target=ContentEditable&child=b">
|
||||||
|
<meta name="variant" content="?target=ContentEditable&parent=b&child=i">
|
||||||
|
<meta name="variant" content="?target=DesignMode">
|
||||||
|
<meta name="variant" content="?target=DesignMode&parent=b">
|
||||||
|
<meta name="variant" content="?target=DesignMode&child=b">
|
||||||
|
<meta name="variant" content="?target=DesignMode&parent=b&child=i">
|
||||||
|
<title>Testing inserting content at non-collapsed selection around link element</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 src="/resources/testdriver-actions.js"></script>
|
||||||
|
<script src="../include/editor-test-utils.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div contenteditable></div>
|
||||||
|
<iframe srcdoc="
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<script>document.designMode='on';</script>
|
||||||
|
<script src='/resources/testdriver.js'></script>
|
||||||
|
<script src='/resources/testdriver-vendor.js'></script>
|
||||||
|
<script src='/resources/testdriver-actions.js'></script>
|
||||||
|
<body></body>
|
||||||
|
</html>"></iframe>
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const params = new URLSearchParams(location.search.substring(1));
|
||||||
|
const kTarget = params.get("target");
|
||||||
|
const kParentTag = params.get("parent") === null
|
||||||
|
? ["", ""]
|
||||||
|
: [`<${params.get("parent")}>`, `</${params.get("parent")}>`];
|
||||||
|
const kChildTag = params.get("child") === null
|
||||||
|
? ["", ""]
|
||||||
|
: [`<${params.get("child")}>`, `</${params.get("child")}>`];
|
||||||
|
const kLinkDesc = (() => {
|
||||||
|
let result = ""
|
||||||
|
if (kParentTag[0] !== "") {
|
||||||
|
result += `in ${kParentTag[0]} `;
|
||||||
|
if (kChildTag[0] !== "") {
|
||||||
|
result += "and ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kChildTag[0] !== "") {
|
||||||
|
result += `containing ${kChildTag[0]} `;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})();
|
||||||
|
const kNewContainerOfLink = (() => {
|
||||||
|
if (kParentTag !== "" && kChildTag !== "") {
|
||||||
|
return [`${kParentTag[0]}${kChildTag[0]}`, `${kChildTag[1]}${kParentTag[1]}`];
|
||||||
|
}
|
||||||
|
if (kParentTag !== "") {
|
||||||
|
return kParentTag;
|
||||||
|
}
|
||||||
|
if (kChildTag !== "") {
|
||||||
|
return kChildTag;
|
||||||
|
}
|
||||||
|
return ["", ""];
|
||||||
|
})();
|
||||||
|
|
||||||
|
function getEditingHost() {
|
||||||
|
return kTarget === "ContentEditable"
|
||||||
|
? document.querySelector("div[contenteditable]")
|
||||||
|
: document.querySelector("iframe").contentDocument.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPromiseTest(test) {
|
||||||
|
promise_test(async () => {
|
||||||
|
let editingHost = getEditingHost();
|
||||||
|
let utils = new EditorTestUtils(editingHost);
|
||||||
|
utils.setupEditingHost(test.innerHTML);
|
||||||
|
utils.window.focus();
|
||||||
|
utils.document.body.focus();
|
||||||
|
editingHost.focus();
|
||||||
|
await test.run(utils);
|
||||||
|
if (Array.isArray(test.expectedResult)) {
|
||||||
|
assert_in_array(editingHost.innerHTML, test.expectedResult);
|
||||||
|
} else {
|
||||||
|
assert_equals(editingHost.innerHTML, test.expectedResult);
|
||||||
|
}
|
||||||
|
}, `${test.description} in ${test.innerHTML}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
addEventListener("load", resolve, { once: true });
|
||||||
|
});
|
||||||
|
}, "");
|
||||||
|
|
||||||
|
for (const test of [
|
||||||
|
["Direct typing", utils => {}],
|
||||||
|
["Backspace", utils => { return utils.sendBackspaceKey(); }],
|
||||||
|
["Delete", utils => { return utils.sendDeleteKey(); }],
|
||||||
|
["execCommand(\"delete\")", utils => { utils.document.execCommand("delete", false); }],
|
||||||
|
["execCommand(\"forwarddelete\")", utils => { utils.document.execCommand("forwarddelete", false); }],
|
||||||
|
]) {
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting first character of a link ${kLinkDesc}(${test[0]})`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}[z]abc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await test[1](utils);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: (() => {
|
||||||
|
if (test[0] === "Direct typing") {
|
||||||
|
return [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}XYabc${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}XYabc${kChildTag[1]}</a>${kParentTag[1]}<br></p>`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}XY<a href="about:blank">abc</a>${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
];
|
||||||
|
})(),
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting last character in a non-collapsed range of a link ${kLinkDesc}(${test[0]})`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abc[d]${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await test[1](utils);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: (() => {
|
||||||
|
if (test[0] === "Direct typing") {
|
||||||
|
return [
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abcXY${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}abcXY${kChildTag[1]}</a>${kParentTag[1]}<br></p>`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">abc</a>XY${kNewContainerOfLink[1]}<br></p>`,
|
||||||
|
];
|
||||||
|
})(),
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting text after middle of a link ${kLinkDesc}(${test[0]})`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}<a href="about:blank">${kChildTag[0]}ab[cd${kChildTag[1]}</a>de]f${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await test[1](utils);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">ab</a>XY${kChildTag[1]}f${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kNewContainerOfLink[0]}<a href="about:blank">ab</a>XY${kChildTag[1]}f${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting text before middle of a link ${kLinkDesc}(${test[0]})`,
|
||||||
|
innerHTML: `<p>${kParentTag[0]}a[bc<a href="about:blank">${kChildTag[0]}de]f${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
run: async (utils) => {
|
||||||
|
await test[1](utils);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
`<p>${kParentTag[0]}aXY<a href="about:blank">${kChildTag[0]}f${kChildTag[1]}</a>${kParentTag[1]}</p>`,
|
||||||
|
`<p>${kParentTag[0]}aXY<a href="about:blank">${kChildTag[0]}f${kChildTag[1]}</a>${kParentTag[1]}<br></p>`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (kParentTag[0] !== "" || kChildTag[0] !== "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting text between 2 same links (${test[0]})`,
|
||||||
|
innerHTML: '<p><a href="about:blank">a[bc</a><a href="about:blank">de]f</a></p>',
|
||||||
|
run: async (utils) => {
|
||||||
|
await test[1](utils);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
'<p><a href="about:blank">a</a>XY<a href="about:blank">f</a></p>',
|
||||||
|
'<p><a href="about:blank">a</a>XY<a href="about:blank">f</a><br></p>',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
addPromiseTest({
|
||||||
|
description: `Inserting "XY" after deleting text between 2 different links (${test[0]})`,
|
||||||
|
innerHTML: '<p><a href="about:blank">a[bc</a><a href="http://example.com/">de]f</a></p>',
|
||||||
|
run: async (utils) => {
|
||||||
|
await test[1](utils);
|
||||||
|
await utils.sendKey("X", utils.kShiftKey);
|
||||||
|
await utils.sendKey("Y", utils.kShiftKey);
|
||||||
|
},
|
||||||
|
expectedResult: [
|
||||||
|
'<p><a href="about:blank">a</a>XY<a href="http://example.com/">f</a></p>',
|
||||||
|
'<p><a href="about:blank">a</a>XY<a href="http://example.com/">f</a><br></p>',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>window.originAgentCluster must be implied by cross-origin isolation</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<iframe src="//{{domains[www1]}}:{{location[port]}}/html/browsers/origin/origin-keyed-agent-clusters/resources/coep-frame.html"></iframe>
|
||||||
|
|
||||||
|
<div id="log"></div>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import { testGetter } from "../resources/helpers.mjs";
|
||||||
|
|
||||||
|
setup({ explicit_done: true });
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
// Cross-origin isolated pages are always origin-keyed.
|
||||||
|
testGetter(self, true, "self");
|
||||||
|
|
||||||
|
// Child frames of cross-origin isolated pages must also be cross-origin
|
||||||
|
// isolated, and thus also origin-keyed. Make sure the implementation doesn't
|
||||||
|
// treat them specially in some wierd way, for the purposes of this
|
||||||
|
// implication.
|
||||||
|
testGetter(0, true, "child");
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,2 @@
|
||||||
|
Cross-Origin-Embedder-Policy: require-corp
|
||||||
|
Cross-Origin-Opener-Policy: same-origin
|
|
@ -0,0 +1,5 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>A page with COEP set that will respond when asked</title>
|
||||||
|
|
||||||
|
<script type="module" src="send-header-page-script.mjs"></script>
|
|
@ -0,0 +1,2 @@
|
||||||
|
Cross-Origin-Embedder-Policy: require-corp
|
||||||
|
Cross-Origin-Resource-Policy: cross-origin
|
|
@ -100,6 +100,13 @@ promise_test(async t => {
|
||||||
await pollResultAndCheck(t, id, "");
|
await pollResultAndCheck(t, id, "");
|
||||||
}, "Window.name is reset at the first cross-origin navigation");
|
}, "Window.name is reset at the first cross-origin navigation");
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const id = token();
|
||||||
|
|
||||||
|
window.open(`resources/window-name.sub.html?open|navOpener=about:blank|reportOpener=${id}|closeOpener|close`, id, "noopener");
|
||||||
|
await pollResultAndCheck(t, id, id);
|
||||||
|
}, "window.name is not reset after navigating to an about:blank page from a non-about:blank page");
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -40,6 +40,42 @@ async function proceedTest() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (step === "closeOpener") {
|
||||||
|
if (window.opener) {
|
||||||
|
window.opener.close();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.startsWith("navOpener=")) {
|
||||||
|
if (!window.opener) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = step.split("=")[1];
|
||||||
|
window.opener.location.href = url;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step === "open") {
|
||||||
|
const url = new URL(window.location);
|
||||||
|
url.host = "{{host}}:{{ports[https][0]}}";
|
||||||
|
url.search = "?" + steps.join("|");
|
||||||
|
window.open(url);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.startsWith("reportOpener=")) {
|
||||||
|
const id = step.split("=")[1];
|
||||||
|
const stashURL = new URL("window-name-stash.py", location);
|
||||||
|
stashURL.searchParams.set('id', id);
|
||||||
|
stashURL.searchParams.set('value', window.opener.name);
|
||||||
|
|
||||||
|
await fetch(stashURL, { method: "POST" });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (step.startsWith("set=")) {
|
if (step.startsWith("set=")) {
|
||||||
window.name = step.split("=")[1];
|
window.name = step.split("=")[1];
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// TODO: extend `EditorTestUtils` in editing/include/edit-test-utils.mjs
|
||||||
|
|
||||||
const kBackspaceKey = "\uE003";
|
const kBackspaceKey = "\uE003";
|
||||||
const kDeleteKey = "\uE017";
|
const kDeleteKey = "\uE017";
|
||||||
const kArrowRight = "\uE014";
|
const kArrowRight = "\uE014";
|
||||||
|
@ -323,7 +325,7 @@ function setupEditor(innerHTMLWithRangeMarkers) {
|
||||||
return {
|
return {
|
||||||
marker: scanResult[0],
|
marker: scanResult[0],
|
||||||
container: textNode,
|
container: textNode,
|
||||||
offset: scanResult.index + offset,
|
offset: scanResult.index + offset
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (startContainer.nodeType === Node.TEXT_NODE) {
|
if (startContainer.nodeType === Node.TEXT_NODE) {
|
||||||
|
@ -359,7 +361,7 @@ function setupEditor(innerHTMLWithRangeMarkers) {
|
||||||
return {
|
return {
|
||||||
marker: scanResult[0],
|
marker: scanResult[0],
|
||||||
container: textNode,
|
container: textNode,
|
||||||
offset: scanResult.index + offset,
|
offset: scanResult.index + offset
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (startContainer.nodeType === Node.TEXT_NODE) {
|
if (startContainer.nodeType === Node.TEXT_NODE) {
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>Service Worker: Clients.matchAll with a blob URL worker client</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="resources/test-helpers.sub.js"></script>
|
||||||
|
<script>
|
||||||
|
const SCRIPT = 'resources/clients-matchall-worker.js';
|
||||||
|
|
||||||
|
promise_test(async (t) => {
|
||||||
|
const scope = 'resources/clients-matchall-blob-url-worker.html';
|
||||||
|
|
||||||
|
const reg = await service_worker_unregister_and_register(t, SCRIPT, scope);
|
||||||
|
t.add_cleanup(_ => reg.unregister());
|
||||||
|
await wait_for_state(t, reg.installing, 'activated');
|
||||||
|
|
||||||
|
const frame = await with_iframe(scope);
|
||||||
|
t.add_cleanup(_ => frame.remove());
|
||||||
|
|
||||||
|
{
|
||||||
|
const message = await frame.contentWindow.waitForWorker();
|
||||||
|
assert_equals(message.data, 'Worker is ready.',
|
||||||
|
'Worker should reply to the message.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
const message = await new Promise(resolve => {
|
||||||
|
channel.port1.onmessage = resolve;
|
||||||
|
frame.contentWindow.navigator.serviceWorker.controller.postMessage(
|
||||||
|
{port: channel.port2, options: {type: 'worker'}}, [channel.port2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
checkMessageEvent(message);
|
||||||
|
|
||||||
|
}, 'Test Clients.matchAll() with a blob URL worker client.');
|
||||||
|
|
||||||
|
promise_test(async (t) => {
|
||||||
|
const scope = 'resources/blank.html';
|
||||||
|
|
||||||
|
const reg = await service_worker_unregister_and_register(t, SCRIPT, scope);
|
||||||
|
t.add_cleanup(_ => reg.unregister());
|
||||||
|
await wait_for_state(t, reg.installing, 'activated');
|
||||||
|
|
||||||
|
const workerScript = `
|
||||||
|
self.onmessage = (e) => {
|
||||||
|
self.postMessage("Worker is ready.");
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
const blob = new Blob([workerScript], { type: 'text/javascript' });
|
||||||
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
|
const worker = new Worker(blobUrl);
|
||||||
|
|
||||||
|
{
|
||||||
|
const message = await new Promise(resolve => {
|
||||||
|
worker.onmessage = resolve;
|
||||||
|
worker.postMessage("Ping to worker.");
|
||||||
|
});
|
||||||
|
assert_equals(message.data, 'Worker is ready.',
|
||||||
|
'Worker should reply to the message.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = new MessageChannel();
|
||||||
|
const message = await new Promise(resolve => {
|
||||||
|
channel.port1.onmessage = resolve;
|
||||||
|
reg.active.postMessage(
|
||||||
|
{port: channel.port2,
|
||||||
|
options: {includeUncontrolled: true, type: 'worker'}},
|
||||||
|
[channel.port2]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
checkMessageEvent(message);
|
||||||
|
|
||||||
|
}, 'Test Clients.matchAll() with an uncontrolled blob URL worker client.');
|
||||||
|
|
||||||
|
function checkMessageEvent(e) {
|
||||||
|
assert_equals(e.data.length, 1);
|
||||||
|
|
||||||
|
const workerClient = e.data[0];
|
||||||
|
assert_equals(workerClient[0], undefined); // visibilityState
|
||||||
|
assert_equals(workerClient[1], undefined); // focused
|
||||||
|
assert_true(workerClient[2].includes('blob:')); // url
|
||||||
|
assert_equals(workerClient[3], 'worker'); // type
|
||||||
|
assert_equals(workerClient[4], 'none'); // frameType
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script>
|
||||||
|
const workerScript = `
|
||||||
|
self.onmessage = (e) => {
|
||||||
|
self.postMessage("Worker is ready.");
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
const blob = new Blob([workerScript], { type: 'text/javascript' });
|
||||||
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
|
const worker = new Worker(blobUrl);
|
||||||
|
|
||||||
|
function waitForWorker() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
worker.onmessage = resolve;
|
||||||
|
worker.postMessage("Ping to worker.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -1,3 +1,3 @@
|
||||||
# Streams Tests
|
# Streams Tests
|
||||||
|
|
||||||
The work on the streams tests is closely tracked by the specification authors, who maintain a reference implementation intended to match the spec line-by-line while passing all of these tests. See [the whatwg/streams repository for details](https://github.com/whatwg/streams/tree/master/reference-implementation). Some tests may be in that repository while the spec sections they test are still undergoing heavy churn.
|
The work on the streams tests is closely tracked by the specification authors, who maintain a reference implementation intended to match the spec line-by-line while passing all of these tests. See [the whatwg/streams repository for details](https://github.com/whatwg/streams/tree/main/reference-implementation). Some tests may be in that repository while the spec sections they test are still undergoing heavy churn.
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
parameters:
|
||||||
|
pyflag: --py3
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- script: ./wpt make-hosts-file | sudo tee -a /etc/hosts
|
- script: ./wpt make-hosts-file | sudo tee -a /etc/hosts
|
||||||
displayName: 'Update hosts (macOS)'
|
displayName: 'Update hosts (macOS)'
|
||||||
|
@ -5,6 +8,6 @@ steps:
|
||||||
- powershell: |
|
- powershell: |
|
||||||
$hostFile = "$env:systemroot\System32\drivers\etc\hosts"
|
$hostFile = "$env:systemroot\System32\drivers\etc\hosts"
|
||||||
Copy-Item -Path $hostFile -Destination "$hostFile.back" -Force
|
Copy-Item -Path $hostFile -Destination "$hostFile.back" -Force
|
||||||
python wpt --py2 make-hosts-file | Out-File $env:systemroot\System32\drivers\etc\hosts -Encoding ascii -Append
|
python wpt ${{ parameters.pyflag }} make-hosts-file | Out-File $env:systemroot\System32\drivers\etc\hosts -Encoding ascii -Append
|
||||||
displayName: 'Update hosts (Windows)'
|
displayName: 'Update hosts (Windows)'
|
||||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
|
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
parameters:
|
||||||
|
pyflag: --py3
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# `python wpt` instead of `./wpt` is to make this work on Windows:
|
# `python wpt` instead of `./wpt` is to make this work on Windows:
|
||||||
- script: python wpt --py2 manifest
|
- script: python wpt ${{ parameters.pyflag }} manifest
|
||||||
displayName: 'Update manifest'
|
displayName: 'Update manifest'
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<link id="link_empty" />
|
<link id="link_empty" />
|
||||||
<link id="link_web_bundle_1" rel="webbundle" />
|
<link id="link_web_bundle_1" rel="webbundle" />
|
||||||
<link id="link_web_bundle_2" rel="webbundle" resources="foo" />
|
<link id="link_web_bundle_2" rel="webbundle" resources="foo" />
|
||||||
|
<link id="link_web_bundle_3" rel="webbundle" scopes="bar" />
|
||||||
<script>
|
<script>
|
||||||
test(() => {
|
test(() => {
|
||||||
assert_false(
|
assert_false(
|
||||||
|
@ -22,6 +23,17 @@
|
||||||
);
|
);
|
||||||
}, "resources must be defined on HTMLLinkElement prototype");
|
}, "resources must be defined on HTMLLinkElement prototype");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_false(
|
||||||
|
"scopes" in Element.prototype,
|
||||||
|
"scopes must not be defined on Element prototype"
|
||||||
|
);
|
||||||
|
assert_true(
|
||||||
|
"scopes" in HTMLLinkElement.prototype,
|
||||||
|
"scopes must be defined on HTMLLinkElement prototype"
|
||||||
|
);
|
||||||
|
}, "scopes must be defined on HTMLLinkElement prototype");
|
||||||
|
|
||||||
test(() => {
|
test(() => {
|
||||||
const link = document.createElement("link");
|
const link = document.createElement("link");
|
||||||
assert_true(link.relList.supports("webbundle"));
|
assert_true(link.relList.supports("webbundle"));
|
||||||
|
@ -55,6 +67,16 @@
|
||||||
"foo",
|
"foo",
|
||||||
"resources attribute must return the specified value"
|
"resources attribute must return the specified value"
|
||||||
);
|
);
|
||||||
|
assert_equals(
|
||||||
|
document.querySelector("#link_web_bundle_2").getAttribute("scopes"),
|
||||||
|
null,
|
||||||
|
"scopes attribute must return null when the attribute is not given"
|
||||||
|
);
|
||||||
|
assert_equals(
|
||||||
|
document.querySelector("#link_web_bundle_3").getAttribute("scopes"),
|
||||||
|
"bar",
|
||||||
|
"scopes attribute must return the specified value"
|
||||||
|
);
|
||||||
// TODO: Test more variant of resoruces attribute values.
|
// TODO: Test more variant of resoruces attribute values.
|
||||||
}, "resoruces attribute must return null or specified value");
|
}, "resoruces attribute must return null or specified value");
|
||||||
|
|
||||||
|
@ -75,5 +97,23 @@
|
||||||
"https://test2.example.com"
|
"https://test2.example.com"
|
||||||
]);
|
]);
|
||||||
}, "resources must be DOMTokenList");
|
}, "resources must be DOMTokenList");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const link = document.createElement("link");
|
||||||
|
assert_class_string(link.scopes, "DOMTokenList");
|
||||||
|
assert_equals(
|
||||||
|
String(link.scopes.value),
|
||||||
|
"",
|
||||||
|
"scopes.value should return the empty list for an undefined scopes attribute"
|
||||||
|
);
|
||||||
|
link.setAttribute(
|
||||||
|
"scopes",
|
||||||
|
"https://test1.example.com https://test2.example.com "
|
||||||
|
);
|
||||||
|
assert_array_equals(link.scopes, [
|
||||||
|
"https://test1.example.com",
|
||||||
|
"https://test2.example.com"
|
||||||
|
]);
|
||||||
|
}, "scopes must be DOMTokenList");
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -80,7 +80,42 @@
|
||||||
assert_equals(
|
assert_equals(
|
||||||
await loadScriptAndWaitReport(classic_script_url),
|
await loadScriptAndWaitReport(classic_script_url),
|
||||||
'classic script from network');
|
'classic script from network');
|
||||||
}, 'Dynamically loading classic script from web bundle');
|
}, 'Dynamically loading classic script from web bundle with link.resources');
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
const classic_script_url = 'http://web-platform.test:8001/web-bundle/resources/wbn/dynamic/classic_script.js';
|
||||||
|
const scope = 'http://web-platform.test:8001/web-bundle/resources/wbn/dynamic/';
|
||||||
|
const link = document.createElement("link");
|
||||||
|
link.rel = "webbundle";
|
||||||
|
link.href = "../resources/wbn/dynamic1.wbn";
|
||||||
|
link.scopes.add(scope);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
assert_equals(
|
||||||
|
await loadScriptAndWaitReport(classic_script_url),
|
||||||
|
'classic script from dynamic1.wbn');
|
||||||
|
link.href = "../resources/wbn/dynamic2.wbn";
|
||||||
|
// Loading the classic script should not reuse the previously loaded
|
||||||
|
// script. So in this case, the script must be loaded from dynamic2.wbn.
|
||||||
|
assert_equals(
|
||||||
|
await loadScriptAndWaitReport(classic_script_url),
|
||||||
|
'classic script from dynamic2.wbn');
|
||||||
|
// Changes the scope not to hit the classic_script.js.
|
||||||
|
link.scopes = scope + 'dummy';
|
||||||
|
// And in this case, the script must be loaded from network.
|
||||||
|
assert_equals(
|
||||||
|
await loadScriptAndWaitReport(classic_script_url),
|
||||||
|
'classic script from network');
|
||||||
|
// Adds the scope to hit the classic_script.js.
|
||||||
|
link.scopes.add(scope + 'classic_');
|
||||||
|
assert_equals(
|
||||||
|
await loadScriptAndWaitReport(classic_script_url),
|
||||||
|
'classic script from dynamic2.wbn');
|
||||||
|
document.body.removeChild(link);
|
||||||
|
// And in this case, the script must be loaded from network.
|
||||||
|
assert_equals(
|
||||||
|
await loadScriptAndWaitReport(classic_script_url),
|
||||||
|
'classic script from network');
|
||||||
|
}, 'Dynamically loading classic script from web bundle with link.scopes');
|
||||||
|
|
||||||
promise_test(() => {
|
promise_test(() => {
|
||||||
return addLinkAndWaitForLoad("../resources/wbn/dynamic1.wbn?test-event");
|
return addLinkAndWaitForLoad("../resources/wbn/dynamic1.wbn?test-event");
|
||||||
|
@ -108,7 +143,19 @@
|
||||||
link.resources = url;
|
link.resources = url;
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
assert_equals(await loadScriptAndWaitReport(url), 'OK');
|
assert_equals(await loadScriptAndWaitReport(url), 'OK');
|
||||||
}, 'Subresource loading with urn:uuid: URL');
|
document.body.removeChild(link);
|
||||||
|
}, 'Subresource loading with urn:uuid: URL with link.resources');
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
const url = 'urn:uuid:020111b3-437a-4c5c-ae07-adb6bbffb720';
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.rel = 'webbundle';
|
||||||
|
link.href = '../resources/wbn/urn-uuid.wbn';
|
||||||
|
link.scopes = 'urn:uuid:';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
assert_equals(await loadScriptAndWaitReport(url), 'OK');
|
||||||
|
document.body.removeChild(link);
|
||||||
|
}, 'Subresource loading with urn:uuid: URL with link.scopes');
|
||||||
|
|
||||||
promise_test(async () => {
|
promise_test(async () => {
|
||||||
const wbn_url = 'http://web-platform.test:8001/web-bundle/resources/wbn/subresource.wbn?test-resources-update';
|
const wbn_url = 'http://web-platform.test:8001/web-bundle/resources/wbn/subresource.wbn?test-resources-update';
|
||||||
|
|
|
@ -199,7 +199,7 @@ promise_test(async t => {
|
||||||
assert_equals(frame.cropWidth, 320, "cropWidth");
|
assert_equals(frame.cropWidth, 320, "cropWidth");
|
||||||
assert_equals(frame.cropHeight, 240, "cropHeight");
|
assert_equals(frame.cropHeight, 240, "cropHeight");
|
||||||
assert_equals(frame.timestamp, 0, "timestamp");
|
assert_equals(frame.timestamp, 0, "timestamp");
|
||||||
frame.destroy();
|
frame.close();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error(e) {
|
error(e) {
|
||||||
|
|
|
@ -222,14 +222,14 @@ promise_test(async t => {
|
||||||
|
|
||||||
encoder.encode(frame);
|
encoder.encode(frame);
|
||||||
|
|
||||||
// |frame| is not longer valid since it has been destroyed.
|
// |frame| is not longer valid since it has been closed.
|
||||||
assert_not_equals(frame.timestamp, timestamp);
|
assert_not_equals(frame.timestamp, timestamp);
|
||||||
assert_throws_dom("InvalidStateError", () => frame.clone());
|
assert_throws_dom("InvalidStateError", () => frame.clone());
|
||||||
|
|
||||||
encoder.close();
|
encoder.close();
|
||||||
|
|
||||||
return endAfterEventLoopTurn();
|
return endAfterEventLoopTurn();
|
||||||
}, 'Test encoder consumes (destroys) frames.');
|
}, 'Test encoder consumes (closes) frames.');
|
||||||
|
|
||||||
promise_test(async t => {
|
promise_test(async t => {
|
||||||
let encoder = new VideoEncoder(getDefaultCodecInit(t));
|
let encoder = new VideoEncoder(getDefaultCodecInit(t));
|
||||||
|
@ -251,12 +251,11 @@ promise_test(async t => {
|
||||||
let encoder = new VideoEncoder(getDefaultCodecInit(t));
|
let encoder = new VideoEncoder(getDefaultCodecInit(t));
|
||||||
|
|
||||||
let frame = await createVideoFrame(640, 480, 0);
|
let frame = await createVideoFrame(640, 480, 0);
|
||||||
frame.destroy();
|
frame.close();
|
||||||
|
|
||||||
encoder.configure(defaultConfig);
|
encoder.configure(defaultConfig);
|
||||||
|
|
||||||
frame.destroy();
|
|
||||||
assert_throws_dom("OperationError", () => {
|
assert_throws_dom("OperationError", () => {
|
||||||
encoder.encode(frame)
|
encoder.encode(frame)
|
||||||
});
|
});
|
||||||
}, 'Verify encoding destroyed frames throws.');
|
}, 'Verify encoding closed frames throws.');
|
||||||
|
|
|
@ -25,8 +25,8 @@ test(t => {
|
||||||
assert_equals(frame.cropWidth, clone.cropWidth);
|
assert_equals(frame.cropWidth, clone.cropWidth);
|
||||||
assert_equals(frame.cropHeight, clone.cropHeight);
|
assert_equals(frame.cropHeight, clone.cropHeight);
|
||||||
|
|
||||||
frame.destroy();
|
frame.close();
|
||||||
clone.destroy();
|
clone.close();
|
||||||
}, 'Test we can clone a VideoFrame.');
|
}, 'Test we can clone a VideoFrame.');
|
||||||
|
|
||||||
test(t => {
|
test(t => {
|
||||||
|
@ -35,23 +35,23 @@ test(t => {
|
||||||
let copy = frame;
|
let copy = frame;
|
||||||
let clone = frame.clone();
|
let clone = frame.clone();
|
||||||
|
|
||||||
frame.destroy();
|
frame.close();
|
||||||
|
|
||||||
assert_not_equals(copy.timestamp, defaultInit.timestamp);
|
assert_not_equals(copy.timestamp, defaultInit.timestamp);
|
||||||
assert_equals(clone.timestamp, defaultInit.timestamp);
|
assert_equals(clone.timestamp, defaultInit.timestamp);
|
||||||
|
|
||||||
clone.destroy();
|
clone.close();
|
||||||
}, 'Verify destroying a frame doesn\'t affect its clones.');
|
}, 'Verify closing a frame doesn\'t affect its clones.');
|
||||||
|
|
||||||
test(t => {
|
test(t => {
|
||||||
let frame = createDefaultVideoFrame();
|
let frame = createDefaultVideoFrame();
|
||||||
|
|
||||||
frame.destroy();
|
frame.close();
|
||||||
|
|
||||||
assert_throws_dom("InvalidStateError", () => {
|
assert_throws_dom("InvalidStateError", () => {
|
||||||
let clone = frame.clone();
|
let clone = frame.clone();
|
||||||
});
|
});
|
||||||
}, 'Verify cloning a destroyed frame throws.');
|
}, 'Verify cloning a closed frame throws.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
let localFrame = createDefaultVideoFrame();
|
let localFrame = createDefaultVideoFrame();
|
||||||
|
@ -62,7 +62,7 @@ async_test(t => {
|
||||||
|
|
||||||
externalPort.onmessage = t.step_func((e) => {
|
externalPort.onmessage = t.step_func((e) => {
|
||||||
let externalFrame = e.data;
|
let externalFrame = e.data;
|
||||||
externalFrame.destroy();
|
externalFrame.close();
|
||||||
externalPort.postMessage("Done");
|
externalPort.postMessage("Done");
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ async_test(t => {
|
||||||
|
|
||||||
localPort.postMessage(localFrame);
|
localPort.postMessage(localFrame);
|
||||||
|
|
||||||
}, 'Verify destroying frames propagates accross contexts.');
|
}, 'Verify closing frames propagates accross contexts.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
let localFrame = createDefaultVideoFrame();
|
let localFrame = createDefaultVideoFrame();
|
||||||
|
@ -83,18 +83,18 @@ async_test(t => {
|
||||||
|
|
||||||
externalPort.onmessage = t.step_func((e) => {
|
externalPort.onmessage = t.step_func((e) => {
|
||||||
let externalFrame = e.data;
|
let externalFrame = e.data;
|
||||||
externalFrame.destroy();
|
externalFrame.close();
|
||||||
externalPort.postMessage("Done");
|
externalPort.postMessage("Done");
|
||||||
})
|
})
|
||||||
|
|
||||||
localPort.onmessage = t.step_func_done((e) => {
|
localPort.onmessage = t.step_func_done((e) => {
|
||||||
assert_equals(localFrame.timestamp, defaultInit.timestamp);
|
assert_equals(localFrame.timestamp, defaultInit.timestamp);
|
||||||
localFrame.destroy();
|
localFrame.close();
|
||||||
})
|
})
|
||||||
|
|
||||||
localPort.postMessage(localFrame.clone());
|
localPort.postMessage(localFrame.clone());
|
||||||
|
|
||||||
}, 'Verify destroying cloned frames doesn\'t propagate accross contexts.');
|
}, 'Verify closing cloned frames doesn\'t propagate accross contexts.');
|
||||||
|
|
||||||
async_test(t => {
|
async_test(t => {
|
||||||
let localFrame = createDefaultVideoFrame();
|
let localFrame = createDefaultVideoFrame();
|
||||||
|
@ -104,11 +104,11 @@ async_test(t => {
|
||||||
|
|
||||||
localPort.onmessage = t.unreached_func();
|
localPort.onmessage = t.unreached_func();
|
||||||
|
|
||||||
localFrame.destroy();
|
localFrame.close();
|
||||||
|
|
||||||
assert_throws_dom("DataCloneError", () => {
|
assert_throws_dom("DataCloneError", () => {
|
||||||
localPort.postMessage(localFrame);
|
localPort.postMessage(localFrame);
|
||||||
});
|
});
|
||||||
|
|
||||||
t.done();
|
t.done();
|
||||||
}, 'Verify posting destroyed frames throws.');
|
}, 'Verify posting closed frames throws.');
|
||||||
|
|
|
@ -12,7 +12,7 @@ test(t => {
|
||||||
assert_equals(frame.cropWidth, 32, "displayWidth");
|
assert_equals(frame.cropWidth, 32, "displayWidth");
|
||||||
assert_equals(frame.cropHeight, 16, "displayHeight");
|
assert_equals(frame.cropHeight, 16, "displayHeight");
|
||||||
|
|
||||||
frame.destroy();
|
frame.close();
|
||||||
}, 'Test we can construct a VideoFrame.');
|
}, 'Test we can construct a VideoFrame.');
|
||||||
|
|
||||||
test(t => {
|
test(t => {
|
||||||
|
@ -24,7 +24,7 @@ test(t => {
|
||||||
assert_equals(frame.cropWidth, 1, "displayWidth");
|
assert_equals(frame.cropWidth, 1, "displayWidth");
|
||||||
assert_equals(frame.cropHeight, 1, "displayHeight");
|
assert_equals(frame.cropHeight, 1, "displayHeight");
|
||||||
|
|
||||||
frame.destroy();
|
frame.close();
|
||||||
}, 'Test we can construct an odd-sized VideoFrame.');
|
}, 'Test we can construct an odd-sized VideoFrame.');
|
||||||
|
|
||||||
test(t => {
|
test(t => {
|
||||||
|
@ -63,7 +63,7 @@ test(t => {
|
||||||
// guarantees about the color space.
|
// guarantees about the color space.
|
||||||
assert_equals(view[0], 94, "Y value at (0, 0)");
|
assert_equals(view[0], 94, "Y value at (0, 0)");
|
||||||
|
|
||||||
frame.destroy();
|
frame.close();
|
||||||
}, 'Test we can read planar data from a VideoFrame.');
|
}, 'Test we can read planar data from a VideoFrame.');
|
||||||
|
|
||||||
test(t => {
|
test(t => {
|
||||||
|
@ -78,15 +78,15 @@ test(t => {
|
||||||
|
|
||||||
assert_equals(frame.planes.length, 3, "number of planes");
|
assert_equals(frame.planes.length, 3, "number of planes");
|
||||||
|
|
||||||
// Attempt to read Y plane data, but destroy the frame first.
|
// Attempt to read Y plane data, but close the frame first.
|
||||||
let yPlane = frame.planes[0];
|
let yPlane = frame.planes[0];
|
||||||
let yLength = yPlane.length;
|
let yLength = yPlane.length;
|
||||||
frame.destroy();
|
frame.close();
|
||||||
|
|
||||||
let buffer = new ArrayBuffer(yLength);
|
let buffer = new ArrayBuffer(yLength);
|
||||||
let view = new Uint8Array(buffer);
|
let view = new Uint8Array(buffer);
|
||||||
assert_throws_dom("InvalidStateError", () => yPlane.readInto(view));
|
assert_throws_dom("InvalidStateError", () => yPlane.readInto(view));
|
||||||
}, 'Test we cannot read planar data from a destroyed VideoFrame.');
|
}, 'Test we cannot read planar data from a closed VideoFrame.');
|
||||||
|
|
||||||
test(t => {
|
test(t => {
|
||||||
let image = makeImageBitmap(32, 16);
|
let image = makeImageBitmap(32, 16);
|
||||||
|
|
|
@ -38,7 +38,7 @@ promise_test(async function(t) {
|
||||||
assert_equals(frame.codedWidth, testVideo.width);
|
assert_equals(frame.codedWidth, testVideo.width);
|
||||||
assert_equals(frame.codedHeight, testVideo.height);
|
assert_equals(frame.codedHeight, testVideo.height);
|
||||||
assert_not_equals(frame.timestamp, null);
|
assert_not_equals(frame.timestamp, null);
|
||||||
frame.destroy();
|
frame.close();
|
||||||
|
|
||||||
if (++numberFrames == 5) {
|
if (++numberFrames == 5) {
|
||||||
vtr.stop();
|
vtr.stop();
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>RTCRtpParameters encodings</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/webrtc/dictionary-helper.js"></script>
|
||||||
|
<script src="/webrtc/RTCRtpParameters-helper.js"></script>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
async function negotiate(pc1, pc2) {
|
||||||
|
const offer = await pc1.createOffer();
|
||||||
|
await pc1.setLocalDescription(offer);
|
||||||
|
await pc2.setRemoteDescription(offer);
|
||||||
|
const answer = await pc2.createAnswer();
|
||||||
|
await pc2.setLocalDescription(answer);
|
||||||
|
await pc1.setRemoteDescription(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('video');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
let capability = capabilities.find((capability) => {
|
||||||
|
return capability.uri == "urn:ietf:params:rtp-hdrext:sdes:mid" &&
|
||||||
|
capability.direction != "stopped";
|
||||||
|
});
|
||||||
|
assert_not_equals(capability, undefined);
|
||||||
|
capability = capabilities.find((capability) => {
|
||||||
|
return capability.uri == "urn:3gpp:video-orientation" &&
|
||||||
|
capability.direction != "stopped";
|
||||||
|
});
|
||||||
|
assert_not_equals(capability, undefined);
|
||||||
|
}, `the video transceiver.headerExtensionsToOffer() includes mandatory extensions`);
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('audio');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
let capability = capabilities.find((capability) => {
|
||||||
|
return capability.uri == "urn:ietf:params:rtp-hdrext:sdes:mid" &&
|
||||||
|
capability.direction != "stopped";
|
||||||
|
});
|
||||||
|
assert_not_equals(capability, undefined);
|
||||||
|
}, `the audio transceiver.headerExtensionsToOffer() includes mandatory extensions`);
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('audio');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
capabilities[0].uri = "";
|
||||||
|
assert_throws_js(TypeError, () => {
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
}, 'transceiver should throw TypeError when setting an empty URI');
|
||||||
|
}, `setOfferedRtpHeaderExtensions throws TypeError on encountering missing URI`);
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('audio');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
capabilities[0].uri = "4711";
|
||||||
|
assert_throws_dom("NotSupportedError", () => {
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
}, 'transceiver should throw NotSupported when setting an unknown URI');
|
||||||
|
}, `setOfferedRtpHeaderExtensions throws NotSupported on encountering unknown URI`);
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('audio');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
let capability = capabilities.find((capability) => {
|
||||||
|
return capability.uri == "urn:ietf:params:rtp-hdrext:sdes:mid";
|
||||||
|
});
|
||||||
|
["sendonly", "recvonly", "inactive", "stopped"].map(direction => {
|
||||||
|
capability.direction = direction;
|
||||||
|
assert_throws_dom("InvalidModificationError", () => {
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
}, `transceiver should throw InvalidModificationError when setting a mandatory header extension\'s direction to ${direction}`);
|
||||||
|
});
|
||||||
|
}, `setOfferedRtpHeaderExtensions throws InvalidModificationError when setting a mandatory header extension\'s direction to something else than "sendrecv"`);
|
||||||
|
|
||||||
|
test(function(t) {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('audio');
|
||||||
|
let capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
let selected_capability = capabilities.find((capability) => {
|
||||||
|
return capability.direction == "sendrecv" &&
|
||||||
|
capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid";
|
||||||
|
});
|
||||||
|
selected_capability.direction = "stopped";
|
||||||
|
const offered_capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
let altered_capability = capabilities.find((capability) => {
|
||||||
|
return capability.uri == selected_capability.uri &&
|
||||||
|
capability.direction == "stopped";
|
||||||
|
});
|
||||||
|
assert_not_equals(altered_capability, undefined);
|
||||||
|
}, `modified direction set by setOfferedRtpHeaderExtensions is visible in headerExtensionsOffered`);
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('video');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
const offer = await pc.createOffer();
|
||||||
|
const extmaps = offer
|
||||||
|
.sdp
|
||||||
|
.split("\n")
|
||||||
|
.filter(line => { return line.includes("a=extmap"); })
|
||||||
|
.join("\n");
|
||||||
|
for (const capability of capabilities) {
|
||||||
|
if (capability.direction == "stopped") {
|
||||||
|
assert_false(extmaps.includes(capability.uri));
|
||||||
|
} else {
|
||||||
|
assert_true(extmaps.includes(capability.uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, `unstopped extensions turn up in offer`);
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const pc = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc.close());
|
||||||
|
const transceiver = pc.addTransceiver('video');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
const selected_capability = capabilities.find((capability) => {
|
||||||
|
return capability.direction == "sendrecv" &&
|
||||||
|
capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid" &&
|
||||||
|
capability.uri != "urn:3gpp:video-orientation";
|
||||||
|
});
|
||||||
|
selected_capability.direction = "stopped";
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
const offer = await pc.createOffer();
|
||||||
|
const extmaps = offer
|
||||||
|
.sdp
|
||||||
|
.split("\n")
|
||||||
|
.filter(line => { return line.includes("a=extmap"); })
|
||||||
|
.join("\n");
|
||||||
|
for (const capability of capabilities) {
|
||||||
|
if (capability.direction == "stopped") {
|
||||||
|
assert_false(extmaps.includes(capability.uri));
|
||||||
|
} else {
|
||||||
|
assert_true(extmaps.includes(capability.uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, `stopped extensions do not turn up in offers`);
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const pc1 = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc1.close());
|
||||||
|
const pc2 = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc2.close());
|
||||||
|
|
||||||
|
// Disable a non-mandatory extension before first negotiation.
|
||||||
|
const transceiver = pc1.addTransceiver('video');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
const selected_capability = capabilities.find((capability) => {
|
||||||
|
return capability.direction == "sendrecv" &&
|
||||||
|
capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid" &&
|
||||||
|
capability.uri != "urn:3gpp:video-orientation";
|
||||||
|
});
|
||||||
|
selected_capability.direction = "stopped";
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
|
||||||
|
await negotiate(pc1, pc2);
|
||||||
|
const negotiated_capabilites = transceiver.headerExtensionsNegotiated;
|
||||||
|
|
||||||
|
// Attempt enabling the extension.
|
||||||
|
selected_capability.direction = "sendrecv";
|
||||||
|
|
||||||
|
// The enabled extension should not be part of the negotiated set.
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
await negotiate(pc1, pc2);
|
||||||
|
assert_not_equals(
|
||||||
|
transceiver.headerExtensionsNegotiated.find(capability => {
|
||||||
|
return capability.uri == selected_capability.uri &&
|
||||||
|
capability.direction == "sendrecv";
|
||||||
|
}), undefined);
|
||||||
|
}, `the set of negotiated extensions grows with subsequent offers`);
|
||||||
|
|
||||||
|
promise_test(async t => {
|
||||||
|
const pc1 = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc1.close());
|
||||||
|
const pc2 = new RTCPeerConnection();
|
||||||
|
t.add_cleanup(() => pc2.close());
|
||||||
|
|
||||||
|
// Disable a non-mandatory extension before first negotiation.
|
||||||
|
const transceiver = pc1.addTransceiver('video');
|
||||||
|
const capabilities = transceiver.headerExtensionsToOffer;
|
||||||
|
const selected_capability = capabilities.find((capability) => {
|
||||||
|
return capability.direction == "sendrecv" &&
|
||||||
|
capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid" &&
|
||||||
|
capability.uri != "urn:3gpp:video-orientation";
|
||||||
|
});
|
||||||
|
selected_capability.direction = "stopped";
|
||||||
|
transceiver.setOfferedRtpHeaderExtensions(capabilities);
|
||||||
|
|
||||||
|
await negotiate(pc1, pc2);
|
||||||
|
const negotiated_capabilites = transceiver.headerExtensionsNegotiated;
|
||||||
|
|
||||||
|
for (const capability of negotiated_capabilites) {
|
||||||
|
assert_not_equals(capabilities.find((cap) => {
|
||||||
|
return cap.uri == capability.uri && cap.direction != "stopped";
|
||||||
|
}), undefined);
|
||||||
|
}
|
||||||
|
for (const capability of capabilities) {
|
||||||
|
if (capability.direction != "stopped") {
|
||||||
|
assert_not_equals(negotiated_capabilites.find((cap) => {
|
||||||
|
return cap.uri == capability.uri;
|
||||||
|
}), undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, `the set of negotiated extensions is the set of unstopped extensions`);
|
||||||
|
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue