mirror of
https://github.com/servo/servo.git
synced 2025-07-03 13:33:39 +01:00
Update web-platform-tests to revision ad99a9e949c6006cc0f609501de77a0edb1e593a
This commit is contained in:
parent
6e28d7b3ec
commit
f1ca6b4be4
89 changed files with 2406 additions and 267 deletions
|
@ -1,4 +0,0 @@
|
|||
[hit-test-floats-002.html]
|
||||
[Hit test float]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[hit-test-floats-004.html]
|
||||
[Miss float below something else]
|
||||
expected: FAIL
|
||||
|
|
@ -324,15 +324,9 @@
|
|||
[<iframe>: separate response Content-Type: text/html */*;charset=gbk]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html */*]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/plain */*]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html;" \\" text/plain]
|
||||
[<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -53,6 +53,6 @@
|
|||
[combined text/javascript ]
|
||||
expected: FAIL
|
||||
|
||||
[separate text/javascript x/x]
|
||||
[separate text/javascript; charset=windows-1252 text/javascript]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -11,9 +11,3 @@
|
|||
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
|
||||
expected: FAIL
|
||||
|
||||
[Content-Type-Options%3A%20nosniff]
|
||||
expected: FAIL
|
||||
|
||||
[X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[traverse_the_history_5.html]
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[creating_browsing_context_test_01.html]
|
||||
[first argument: absolute url]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[skip-another-top-level-browsing-context.html]
|
||||
expected: TIMEOUT
|
||||
[Autofocus elements queued in another top-level browsing context's documents should be skipped.]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,16 +1,20 @@
|
|||
[supported-elements.html]
|
||||
expected: TIMEOUT
|
||||
[Contenteditable element should support autofocus]
|
||||
expected: FAIL
|
||||
|
||||
[Host element with delegatesFocus including no focusable descendants should be skipped]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Element with tabindex should support autofocus]
|
||||
expected: FAIL
|
||||
|
||||
[Area element should support autofocus]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Host element with delegatesFocus should support autofocus]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Non-HTMLElement should not support autofocus]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[iframe_sandbox_popups_escaping-1.html]
|
||||
expected: TIMEOUT
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[iframe_sandbox_popups_escaping-2.html]
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[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]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[iframe_sandbox_popups_nonescaping-1.html]
|
||||
expected: TIMEOUT
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe do not escape the sandbox]
|
||||
expected: NOTRUN
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[iframe_sandbox_popups_nonescaping-2.html]
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe do not escape the sandbox]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[iframe_sandbox_popups_nonescaping-3.html]
|
||||
expected: TIMEOUT
|
||||
[Check that popups from a sandboxed iframe do not escape the sandbox]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[form-double-submit-3.html]
|
||||
[<button> should have the same double-submit protection as <input type=submit>]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[base-url-worker-importScripts.html]
|
||||
[Relative URL-like from same-origin importScripts()]
|
||||
expected: FAIL
|
||||
|
||||
[Relative URL-like from cross-origin importScripts()]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[base-url.sub.html]
|
||||
[Relative URL-like from cross origin classic <script> without crossorigin attribute]
|
||||
expected: FAIL
|
||||
|
||||
[Relative URL-like from cross origin module <script>]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[iframe_005.html]
|
||||
[document.write external script into iframe write back into parent]
|
||||
expected: FAIL
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
[promise-job-entry.html]
|
||||
expected: TIMEOUT
|
||||
[Fulfillment handler on fulfilled promise]
|
||||
expected: FAIL
|
||||
|
||||
[Rejection handler on pending-then-rejected promise]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
[Sanity check: this all works as expected with no promises involved]
|
||||
expected: FAIL
|
||||
|
@ -15,5 +16,5 @@
|
|||
expected: FAIL
|
||||
|
||||
[Fulfillment handler on pending-then-fulfilled promise]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[017.html]
|
||||
expected: TIMEOUT
|
||||
[origin of the script that invoked the method, about:blank]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
[shared-worker-in-data-url-context.window.html]
|
||||
expected: TIMEOUT
|
||||
[Create a shared worker in a data url frame]
|
||||
expected: FAIL
|
||||
|
||||
[Create a data url shared worker in a data url frame]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -17086,6 +17086,41 @@
|
|||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"protocol-handler-fragment-manual.https.html": [
|
||||
"15617865691878af2069dfbbf4d397bf3a442600",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"protocol-handler-fragment-nosw-manual.https.html": [
|
||||
"be3a6be6665246ccffa1d60f0e11f376b3280cb5",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"protocol-handler-path-manual.https.html": [
|
||||
"085c5723ec412d027ef0ccca13855839477ffe70",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"protocol-handler-query-manual.https.html": [
|
||||
"8ce65a5bad8826326dc4b5c85c6476174bbd5954",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"protocol-handler-query-nosw-manual.https.html": [
|
||||
"9b4473fb8952ba93c79d17b71725b97c6bf2b208",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -270664,6 +270699,14 @@
|
|||
"6d1eedb1fcbfda2bf27f74af1b34763adc62d599",
|
||||
[]
|
||||
],
|
||||
"not-embeddable-frame.html": [
|
||||
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
|
||||
[]
|
||||
],
|
||||
"not-embeddable-frame.html.sub.headers": [
|
||||
"beecdb765cd02cc6f15700d773e66e8844b941da",
|
||||
[]
|
||||
],
|
||||
"redirect-throw-function.sub.py": [
|
||||
"1bc89abf7176bbada8f0c8c35fd699f52bb0e8a9",
|
||||
[]
|
||||
|
@ -270710,6 +270753,10 @@
|
|||
},
|
||||
"sandbox": {
|
||||
"support": {
|
||||
"post-origin-on-load-worker.js": [
|
||||
"21ce5748ab8b1edbfd04c8f77a3fba54739a73d5",
|
||||
[]
|
||||
],
|
||||
"sandboxed-data-iframe.sub.html": [
|
||||
"fafd4dc7707ab0d26ed2c67f34c26920649795f8",
|
||||
[]
|
||||
|
@ -322644,7 +322691,7 @@
|
|||
[]
|
||||
],
|
||||
"from-local-system.md": [
|
||||
"8c71e535baa907f1ef86641ee6211adb7d0c2423",
|
||||
"91823444d5d4813afb020d00b2fca188f4a22f21",
|
||||
[]
|
||||
],
|
||||
"from-web.md": [
|
||||
|
@ -337409,6 +337456,36 @@
|
|||
[]
|
||||
],
|
||||
"dynamic-import": {
|
||||
"alpha": {
|
||||
"import.js": [
|
||||
"b2ac52df2a18d4bdcf49310352c2bafbeb0269c4",
|
||||
[]
|
||||
],
|
||||
"worker-importScripts.sub.js": [
|
||||
"904d32f9bfd7110c1cb1c7104f54118c86aba30e",
|
||||
[]
|
||||
]
|
||||
},
|
||||
"beta": {
|
||||
"import.js": [
|
||||
"7de1c68182571b80afabd79661f3fed025a2a34f",
|
||||
[]
|
||||
],
|
||||
"redirect.py": [
|
||||
"f2fd1ebd51d4ad5f4ef0582510600eb3731fd2c7",
|
||||
[]
|
||||
]
|
||||
},
|
||||
"gamma": {
|
||||
"base-url.sub.js": [
|
||||
"ec7784983d1182831d3ab910bca7eb54322eec62",
|
||||
[]
|
||||
],
|
||||
"import.js": [
|
||||
"435c1369be2f7a214b003ee8efa734ba8478cc7b",
|
||||
[]
|
||||
]
|
||||
},
|
||||
"propagate-nonce-external.js": [
|
||||
"3b97d2f40e914af5d22ecc338913dcb0591927ba",
|
||||
[]
|
||||
|
@ -338885,6 +338962,24 @@
|
|||
[]
|
||||
]
|
||||
},
|
||||
"system-state-and-capabilities": {
|
||||
"the-navigator-object": {
|
||||
"resources": {
|
||||
"handler-sw.js": [
|
||||
"5fd915d17f98d8fa9c3c81451f46d71bc6cd024e",
|
||||
[]
|
||||
],
|
||||
"handler-tools.js": [
|
||||
"073287265cfe5f5b219ad6f61ffed89556a1e5cb",
|
||||
[]
|
||||
],
|
||||
"handler.html": [
|
||||
"552e5417842e67bb5b917268e0250a951614267c",
|
||||
[]
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"the-windoworworkerglobalscope-mixin": {
|
||||
"README.md": [
|
||||
"10ae3e5f03601a67e247f771cf73fdfddfdda12f",
|
||||
|
@ -340437,7 +340532,7 @@
|
|||
[]
|
||||
],
|
||||
"web-share.idl": [
|
||||
"c29a29d0b4ede94153a75860344ab4824e91b6d5",
|
||||
"b66bcd81fe9c951c2e70a58596380353b7046d97",
|
||||
[]
|
||||
],
|
||||
"webaudio.idl": [
|
||||
|
@ -350532,7 +350627,7 @@
|
|||
[]
|
||||
],
|
||||
"taskcluster-run.py": [
|
||||
"61d05689287a33c3470089e929d0c8871b6a46ef",
|
||||
"d228e21990a1960bd19b3a1ea16207cc3fcfad55",
|
||||
[]
|
||||
],
|
||||
"tc": {
|
||||
|
@ -350545,13 +350640,17 @@
|
|||
[]
|
||||
],
|
||||
"decision.py": [
|
||||
"0820a6798b5b233581eb561a973cb97ff2af44e1",
|
||||
"f52f5b093f0f41632613578f449188f82bc03ab9",
|
||||
[]
|
||||
],
|
||||
"download.py": [
|
||||
"359ec33405048c134ddcfac7a564ea9a17ac1b14",
|
||||
[]
|
||||
],
|
||||
"github_checks_output.py": [
|
||||
"d799be911660f566701be5ebc3b90caf117075e2",
|
||||
[]
|
||||
],
|
||||
"sink_task.py": [
|
||||
"ba76d27640c86197736d7edc9e8ed86fe8ec4bd0",
|
||||
[]
|
||||
|
@ -350562,7 +350661,7 @@
|
|||
],
|
||||
"tasks": {
|
||||
"test.yml": [
|
||||
"dd14fc71b915e90f0625dc1120aed3c86a787e53",
|
||||
"2fc11e0b27b853c5af507581ebd44772741d20d0",
|
||||
[]
|
||||
]
|
||||
},
|
||||
|
@ -357563,7 +357662,7 @@
|
|||
[]
|
||||
],
|
||||
"stability.py": [
|
||||
"3f8989729fde0ee45cf783bc698307e38c844d90",
|
||||
"605b40281a1b559e47d6aa795bb5cbd4b8715177",
|
||||
[]
|
||||
],
|
||||
"testdriver-extra.js": [
|
||||
|
@ -357697,7 +357796,7 @@
|
|||
[]
|
||||
],
|
||||
"wptcommandline.py": [
|
||||
"f322d77fbddefabc8fd187ebbc8cadaea8ea1086",
|
||||
"ea586825616132b410127124ad2152ae88554cde",
|
||||
[]
|
||||
],
|
||||
"wptlogging.py": [
|
||||
|
@ -384835,6 +384934,13 @@
|
|||
}
|
||||
]
|
||||
],
|
||||
"report-frame-ancestors.sub.html": [
|
||||
"a5aa1661c1085a61bedfe88b41ee389f62f577d2",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"report-multiple-violations-01.html": [
|
||||
"7a92f1b955639eb26bfd4a737ee1a930fdec6592",
|
||||
[
|
||||
|
@ -385004,6 +385110,13 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"meta-element.sub.html": [
|
||||
"cd8da8f14c4ad775b9034131315867dec08cd2e8",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"sandbox-allow-scripts-subframe.sub.html": [
|
||||
"1d6db3cde71cddb66f5536720a632b537465cbff",
|
||||
[
|
||||
|
@ -457945,7 +458058,7 @@
|
|||
]
|
||||
],
|
||||
"reporting-redirect-with-same-origin-allow-popups.https.html": [
|
||||
"7dba76c4ef5434d49d7800da14eb980f79728f44",
|
||||
"bb76df811da5949c2d6f5196428a4a09d8bd9a56",
|
||||
[
|
||||
null,
|
||||
{
|
||||
|
@ -469554,6 +469667,29 @@
|
|||
]
|
||||
],
|
||||
"dynamic-import": {
|
||||
"alpha": {
|
||||
"base-url-worker-importScripts.html": [
|
||||
"817cf6d5ddfdc186454de0e3a672a865e2ced416",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"base-url-worker.sub.html": [
|
||||
"a12204281cc43e64c7f1f4f7cdaf37958567b516",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"base-url.sub.html": [
|
||||
"f7d4927a104c78e2f3d41e0899c7deadb5ca3d1c",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
]
|
||||
},
|
||||
"dynamic-imports-credentials.sub.html": [
|
||||
"b939a3ef1639db8027519ac004cd3197e254c0b9",
|
||||
[
|
||||
|
@ -476172,6 +476308,24 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"input-events-get-target-ranges-backspace.tentative.html": [
|
||||
"cf512269b07e0177214f7d9059150a77b85eb225",
|
||||
[
|
||||
null,
|
||||
{
|
||||
"testdriver": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"input-events-get-target-ranges-forwarddelete.tentative.html": [
|
||||
"3780324cf92bfa0c712045d89e43e903e3a1c9c6",
|
||||
[
|
||||
null,
|
||||
{
|
||||
"testdriver": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"input-events-typing.html": [
|
||||
"a894beea9bd381313b999e45abe0b4b8f61c804b",
|
||||
[
|
||||
|
@ -477048,7 +477202,7 @@
|
|||
]
|
||||
],
|
||||
"invisible-images-composited-1.html": [
|
||||
"495645ab41eccb80464a2ceb7de83a2136ecfbf7",
|
||||
"7723d2f2bea5b622395e09ae1bd7fd4bb6cf87bc",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
|
@ -477226,20 +477380,6 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"inline-flow-shift-vertical-rl.html": [
|
||||
"06bc34c37dd0559bfe6bedcc956ec2e2734c14b3",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"inline-flow-shift.html": [
|
||||
"39550da6588eeb7aca7001ab592ee0177d26ca56",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"local-shift-without-viewport-shift.html": [
|
||||
"37729f1c13c298b5a2d95c46b7a4f199d8943022",
|
||||
[
|
||||
|
@ -477261,13 +477401,6 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"outline.html": [
|
||||
"1fed8e92f5e4b60cd83646405b6bd77e673c076f",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"partially-clipped-visual-rect.html": [
|
||||
"3b18b98dd93312c37b9e2f25918df50266a09243",
|
||||
[
|
||||
|
@ -516250,6 +516383,17 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"case-sensitivity.any.js": [
|
||||
"1c0b0dcac361fe02eefc1dd5035955d10dc37151",
|
||||
[
|
||||
"user-timing/case-sensitivity.any.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"user-timing/case-sensitivity.any.worker.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"clearMarks.html": [
|
||||
"92c60a3bbb856bd05bf13f12bde09dac7eefb6e6",
|
||||
[
|
||||
|
@ -561705,7 +561849,7 @@
|
|||
]
|
||||
],
|
||||
"response.py": [
|
||||
"dc1328998810faacf74f1b94b54ed59f48e84e4d",
|
||||
"cbe9e7d7fb14680f027d6fdc15d409ac19a7320c",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[hit-test-floats-002.html]
|
||||
[Hit test float]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[hit-test-floats-004.html]
|
||||
[Miss float below something else]
|
||||
expected: FAIL
|
||||
|
|
@ -324,15 +324,9 @@
|
|||
[<iframe>: separate response Content-Type: text/html */*;charset=gbk]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html */*]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/plain */*]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html;" \\" text/plain]
|
||||
[<iframe>: combined response Content-Type: text/html;charset=gbk text/plain text/html]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -53,6 +53,6 @@
|
|||
[combined text/javascript ]
|
||||
expected: FAIL
|
||||
|
||||
[separate text/javascript x/x]
|
||||
[separate text/javascript; charset=windows-1252 text/javascript]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -11,9 +11,3 @@
|
|||
[X-Content-Type-Options%3A%20nosniff%2C%2C%40%23%24%23%25%25%26%5E%26%5E*()()11!]
|
||||
expected: FAIL
|
||||
|
||||
[Content-Type-Options%3A%20nosniff]
|
||||
expected: FAIL
|
||||
|
||||
[X-Content-Type-Options%3A%0D%0AX-Content-Type-Options%3A%20nosniff]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[traverse_the_history_5.html]
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[creating_browsing_context_test_01.html]
|
||||
[first argument: absolute url]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[skip-another-top-level-browsing-context.html]
|
||||
expected: TIMEOUT
|
||||
[Autofocus elements queued in another top-level browsing context's documents should be skipped.]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
[supported-elements.html]
|
||||
expected: TIMEOUT
|
||||
[Contenteditable element should support autofocus]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -6,11 +7,14 @@
|
|||
expected: FAIL
|
||||
|
||||
[Host element with delegatesFocus including no focusable descendants should be skipped]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Area element should support autofocus]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Host element with delegatesFocus should support autofocus]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Non-HTMLElement should not support autofocus]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[iframe_sandbox_popups_escaping-1.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[iframe_sandbox_popups_escaping-2.html]
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[iframe_sandbox_popups_escaping-3.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[iframe_sandbox_popups_nonescaping-1.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe do not escape the sandbox]
|
||||
expected: NOTRUN
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[iframe_sandbox_popups_nonescaping-2.html]
|
||||
type: testharness
|
||||
expected: CRASH
|
||||
[Check that popups from a sandboxed iframe do not escape the sandbox]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[iframe_sandbox_popups_nonescaping-3.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Check that popups from a sandboxed iframe do not escape the sandbox]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[form-double-submit-3.html]
|
||||
[<button> should have the same double-submit protection as <input type=submit>]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[base-url-worker-importScripts.html]
|
||||
[Relative URL-like from same-origin importScripts()]
|
||||
expected: FAIL
|
||||
|
||||
[Relative URL-like from cross-origin importScripts()]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[base-url.sub.html]
|
||||
[Relative URL-like from cross origin classic <script> without crossorigin attribute]
|
||||
expected: FAIL
|
||||
|
||||
[Relative URL-like from cross origin module <script>]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[iframe_005.html]
|
||||
[document.write external script into iframe write back into parent]
|
||||
expected: FAIL
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
[promise-job-entry.html]
|
||||
expected: TIMEOUT
|
||||
[Fulfillment handler on fulfilled promise]
|
||||
expected: FAIL
|
||||
|
||||
[Rejection handler on pending-then-rejected promise]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
[Sanity check: this all works as expected with no promises involved]
|
||||
expected: FAIL
|
||||
|
@ -15,5 +16,5 @@
|
|||
expected: FAIL
|
||||
|
||||
[Fulfillment handler on pending-then-fulfilled promise]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[017.html]
|
||||
expected: TIMEOUT
|
||||
[origin of the script that invoked the method, about:blank]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
[shared-worker-in-data-url-context.window.html]
|
||||
expected: TIMEOUT
|
||||
[Create a shared worker in a data url frame]
|
||||
expected: FAIL
|
||||
|
||||
[Create a data url shared worker in a data url frame]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[hit_test_multiple_sc.html]
|
||||
[Hit testing works for following stacking contexts]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[hit-test-background.html]
|
||||
[Hit testing backgrounds of content should report the same element as the content]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[hit_test_multiple_sc.html]
|
||||
[Hit testing works for following stacking contexts]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[hit_test_pos_fixed.html]
|
||||
[Hit-test of an element with position: fixed should discard scroll offset]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<title>Reporting works with frame-ancestors</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="./support/not-embeddable-frame.html?reportID={{$id:uuid()}}"></iframe>
|
||||
<script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-ancestors&reportID={{$id}}'></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,5 @@
|
|||
Expires: Mon, 26 Jul 1997 05:00:00 GMT
|
||||
Cache-Control: no-store, no-cache, must-revalidate
|
||||
Cache-Control: post-check=0, pre-check=0, false
|
||||
Pragma: no-cache
|
||||
Content-Security-Policy: frame-ancestors 'none'; report-uri ../../support/report.py?op=put&reportID={{GET[reportID]}}
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<meta content="sandbox allow-scripts" http-equiv="Content-Security-Policy">
|
||||
<body>
|
||||
<iframe id="iframe"></iframe>
|
||||
<script>
|
||||
// According to
|
||||
// https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-content-security-policy
|
||||
// `sandbox` directives must be ignored when delivered via `<meta>`.
|
||||
test(() => {
|
||||
assert_equals(location.origin, "{{location[scheme]}}://{{location[host]}}");
|
||||
}, "Document shouldn't be sandboxed by <meta>");
|
||||
|
||||
// Note: sandbox directive for workers are not yet specified.
|
||||
// https://github.com/w3c/webappsec-csp/issues/279
|
||||
// Anyway workers shouldn't be affected by sandbox directives in `<meta>`.
|
||||
async_test(t => {
|
||||
const worker = new Worker("support/post-origin-on-load-worker.js");
|
||||
worker.onerror = t.unreached_func("Worker construction failed");
|
||||
worker.onmessage = t.step_func_done(e => {
|
||||
assert_equals(e.data, "{{location[scheme]}}://{{location[host]}}");
|
||||
});
|
||||
}, "Worker shouldn't be sandboxed by inheriting <meta>");
|
||||
|
||||
parent.async_test(t => {
|
||||
// Although <iframe about:blank> should inherit parent's CSP,
|
||||
// sandbox directives in <meta> should be ignored in the first place,
|
||||
// so workers created from such <iframe>s shouldn't also be sandboxed.
|
||||
const iframeDocument = document.querySelector("#iframe").contentDocument;
|
||||
const script = iframeDocument.createElement("script");
|
||||
script.innerText = `
|
||||
const worker = new Worker("support/post-origin-on-load-worker.js");
|
||||
worker.onerror = () => parent.postMessage("onerror", "*");
|
||||
worker.onmessage = (e) => parent.postMessage(e.data, "*");
|
||||
`;
|
||||
iframeDocument.body.appendChild(script);
|
||||
|
||||
// Receive message from <iframe>.
|
||||
onmessage = t.step_func_done(e => {
|
||||
assert_equals(e.data, "{{location[scheme]}}://{{location[host]}}");
|
||||
});
|
||||
}, "Worker shouldn't be sandboxed when created <iframe> inheriting parent's CSP with sandbox <meta>");
|
||||
</script>
|
||||
</body>
|
|
@ -0,0 +1 @@
|
|||
postMessage(self.origin);
|
|
@ -39,9 +39,6 @@ wherever you currently set your PATH.
|
|||
See also [additional setup required to run Safari](safari.md).
|
||||
|
||||
### Windows Setup
|
||||
**Note:** In general, Windows Subsystem for Linux will provide the smoothest
|
||||
user experience for running web-platform-tests on Windows, where installation
|
||||
and usage are similar to Linux.
|
||||
|
||||
Download and install [Python 2.7](https://www.python.org/downloads). The
|
||||
installer includes `pip` by default.
|
||||
|
@ -63,6 +60,15 @@ started using:
|
|||
python wpt serve
|
||||
```
|
||||
|
||||
#### Windows Subsystem for Linux
|
||||
|
||||
Optionally on Windows you can use the [Windows Subsystem for
|
||||
Linux](https://docs.microsoft.com/en-us/windows/wsl/about) (WSL). If doing so,
|
||||
installation and usage are similar to the Linux instructions. Be aware that WSL
|
||||
may attempt to override `/etc/hosts` each time it is launched, which would then
|
||||
require you to re-run [`hosts` File Setup](#hosts-file-setup). This behavior
|
||||
[can be configured](https://docs.microsoft.com/en-us/windows/wsl/wsl-config#network).
|
||||
|
||||
### `hosts` File Setup
|
||||
|
||||
To get the tests running, you need to set up the test domains in your
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<script src=/common/get-host-info.sub.js></script>
|
||||
<script src="/common/utils.js"></script>
|
||||
<script src="../resources/dispatcher.js"></script>
|
||||
<script src="../resources/try-access.js"></script>
|
||||
<script>
|
||||
|
||||
const directory = "/html/cross-origin-opener-policy/reporting";
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Base URLs used in resolving specifiers in dynamic imports from importScripts()</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
fetch_tests_from_worker(new Worker("./worker-importScripts.sub.js"));
|
||||
</script>
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Base URLs used in resolving specifiers in dynamic imports from workers</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
fetch_tests_from_worker(new Worker(
|
||||
"../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"));
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Base URLs used in resolving specifiers in dynamic imports</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<script>
|
||||
self.testName = "same origin classic <script>";
|
||||
self.baseUrlSanitized = false;
|
||||
</script>
|
||||
<script src="../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script>
|
||||
|
||||
<script>
|
||||
self.testName = "cross origin classic <script> without crossorigin attribute";
|
||||
self.baseUrlSanitized = true;
|
||||
</script>
|
||||
<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script>
|
||||
|
||||
<script>
|
||||
self.testName = "cross origin classic <script> with crossorigin attribute";
|
||||
self.baseUrlSanitized = false;
|
||||
</script>
|
||||
<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" crossorigin></script>
|
||||
|
||||
<script>
|
||||
self.testName = "cross origin module <script>";
|
||||
self.baseUrlSanitized = false;
|
||||
</script>
|
||||
<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" type="module"></script>
|
|
@ -0,0 +1 @@
|
|||
export const A = { "from": "alpha/import.js" };
|
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
|
||||
importScripts("/resources/testharness.js");
|
||||
|
||||
// CORS-same-origin
|
||||
self.testName = "same-origin importScripts()";
|
||||
self.baseUrlSanitized = false;
|
||||
importScripts("../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js");
|
||||
|
||||
// CORS-cross-origin
|
||||
self.testName = "cross-origin importScripts()";
|
||||
self.baseUrlSanitized = true;
|
||||
importScripts("../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js");
|
||||
|
||||
done();
|
|
@ -0,0 +1 @@
|
|||
export const A = { "from": "beta/import.js" };
|
|
@ -0,0 +1,19 @@
|
|||
def main(request, response):
|
||||
"""Simple handler that causes redirection.
|
||||
|
||||
The request should typically have two query parameters:
|
||||
status - The status to use for the redirection. Defaults to 302.
|
||||
location - The resource to redirect to.
|
||||
"""
|
||||
status = 302
|
||||
if b"status" in request.GET:
|
||||
try:
|
||||
status = int(request.GET.first(b"status"))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
response.status = status
|
||||
|
||||
location = request.GET.first(b"location")
|
||||
|
||||
response.headers.set(b"Location", location)
|
|
@ -0,0 +1,58 @@
|
|||
"use strict";
|
||||
|
||||
// This script triggers import(), and thus the base URL of this script
|
||||
// (either loaded by `<script>` or `importScripts()`) is used as the base URL
|
||||
// of resolving relative URL-like specifiers in `import()`.
|
||||
|
||||
// The following fields should be set by the callers of this script
|
||||
// (unless loaded as the worker top-level script):
|
||||
// - self.testName (string)
|
||||
// - self.baseUrlSanitized (boolean)
|
||||
|
||||
// When this script is loaded as the worker top-level script:
|
||||
if ('DedicatedWorkerGlobalScope' in self &&
|
||||
self instanceof DedicatedWorkerGlobalScope &&
|
||||
!self.testName) {
|
||||
importScripts("/resources/testharness.js");
|
||||
self.testName = 'worker top-level script';
|
||||
// Worker top-level scripts are always same-origin.
|
||||
self.baseUrlSanitized = false;
|
||||
}
|
||||
|
||||
{
|
||||
// This could change by the time the test is executed, so we save it now.
|
||||
// As this script is loaded multiple times, savedBaseUrlSanitized is scoped.
|
||||
const savedBaseUrlSanitized = self.baseUrlSanitized;
|
||||
|
||||
promise_test(() => {
|
||||
const promise = import("./import.js?pipe=header(Access-Control-Allow-Origin,*)&label=relative-" + self.testName);
|
||||
if (savedBaseUrlSanitized) {
|
||||
// The base URL is "about:blank" and thus import() here should fail.
|
||||
return promise.then(module => {
|
||||
// This code should be unreached, but assert_equals() is used here
|
||||
// to log `module.A["from"]` in case of unexpected resolution.
|
||||
assert_equals(module.A["from"], "(unreached)",
|
||||
"Relative URL-like specifier resolution should fail");
|
||||
assert_unreached();
|
||||
},
|
||||
() => {});
|
||||
} else {
|
||||
// The base URL is the response URL of this script, i.e.
|
||||
// `.../gamma/base-url.sub.js`.
|
||||
return promise.then(module => {
|
||||
assert_equals(module.A["from"], "gamma/import.js");
|
||||
});
|
||||
}
|
||||
},
|
||||
"Relative URL-like from " + self.testName);
|
||||
}
|
||||
|
||||
promise_test(() => {
|
||||
return import("http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js?pipe=header(Access-Control-Allow-Origin,*)&label=absolute-" + self.testName)
|
||||
.then(module => {
|
||||
assert_equals(module.A["from"], "gamma/import.js");
|
||||
})
|
||||
},
|
||||
"Absolute URL-like from " + self.testName);
|
||||
|
||||
done();
|
|
@ -0,0 +1 @@
|
|||
export const A = { "from": "gamma/import.js" };
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
|
||||
<meta charset=windows-1254>
|
||||
<meta name=timeout content=long>
|
||||
<title>registerProtocolHandler() and a handler with %s in the fragment</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
|
||||
<script>
|
||||
// Configure expectations for individual test
|
||||
window.type = "fragment";
|
||||
window.noSW = false;
|
||||
</script>
|
||||
<script src=resources/handler-tools.js></script>
|
||||
<ol>
|
||||
<li><p>First, register the handler: <button onclick='register()'>Register</button>.
|
||||
<li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
|
||||
<li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
|
||||
</ol>
|
||||
<div id=log></div>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
|
||||
<meta charset=windows-1254>
|
||||
<meta name=timeout content=long>
|
||||
<title>registerProtocolHandler() and a handler with %s in the fragment (does not use a service worker)</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
|
||||
<script>
|
||||
// Configure expectations for individual test
|
||||
window.type = "fragment";
|
||||
window.noSW = true;
|
||||
</script>
|
||||
<script src=resources/handler-tools.js></script>
|
||||
<ol>
|
||||
<li><p>First, register the handler: <button onclick='register()'>Register</button>.
|
||||
<li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
|
||||
<li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
|
||||
</ol>
|
||||
<div id=log></div>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
|
||||
<meta charset=windows-1254>
|
||||
<meta name=timeout content=long>
|
||||
<title>registerProtocolHandler() and a handler with %s in the path</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
|
||||
<script>
|
||||
// Configure expectations for individual test
|
||||
window.type = "path";
|
||||
window.noSW = false;
|
||||
</script>
|
||||
<script src=resources/handler-tools.js></script>
|
||||
<ol>
|
||||
<li><p>First, register the handler: <button onclick='register()'>Register</button>.
|
||||
<li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
|
||||
<li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
|
||||
</ol>
|
||||
<div id=log></div>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
|
||||
<meta charset=windows-1254>
|
||||
<meta name=timeout content=long>
|
||||
<title>registerProtocolHandler() and a handler with %s in the query</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
|
||||
<script>
|
||||
// Configure expectations for individual test
|
||||
window.type = "query";
|
||||
window.noSW = false;
|
||||
</script>
|
||||
<script src=resources/handler-tools.js></script>
|
||||
<ol>
|
||||
<li><p>First, register the handler: <button onclick='register()'>Register</button>.
|
||||
<li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
|
||||
<li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
|
||||
</ol>
|
||||
<div id=log></div>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<!-- Use a non-UTF-8 encoding to see how the handler URL is parsed -->
|
||||
<meta charset=windows-1254>
|
||||
<meta name=timeout content=long>
|
||||
<title>registerProtocolHandler() and a handler with %s in the query (does not use a service worker)</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
|
||||
<script>
|
||||
// Configure expectations for individual test
|
||||
window.type = "query";
|
||||
window.noSW = true;
|
||||
</script>
|
||||
<script src=resources/handler-tools.js></script>
|
||||
<ol>
|
||||
<li><p>First, register the handler: <button onclick='register()'>Register</button>.
|
||||
<li><p>Then, run the test: <button onclick='runTest()'>Run</button>.
|
||||
<li><p>Or, run the test with U+0000 NULL: <button onclick='runTest({ includeNull: true })'>Run NULL</button>.
|
||||
</ol>
|
||||
<div id=log></div>
|
|
@ -0,0 +1,3 @@
|
|||
onfetch = e => {
|
||||
e.respondWith(fetch("handler.html"));
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// These can be used in an environment that has these global variables defined:
|
||||
// * type (one of "path", "query", or "fragment")
|
||||
// * noSW (a boolean)
|
||||
|
||||
if (type === "path" && noSW) {
|
||||
throw new Error("There is no support for a path handler without a service worker.");
|
||||
}
|
||||
|
||||
const swString = noSW ? "" : "sw";
|
||||
const handler = {
|
||||
"path": "PSS%sPSE/?QES\u2020QEE#FES\u2020FEE",
|
||||
"query": "?QES\u2020QEEPSS%sPSE#FES\u2020FEE",
|
||||
"fragment": "?QES\u2020QEE#FES\u2020FEEPSS%sPSE"
|
||||
}[type];
|
||||
const scheme = `web+wpt${type}${swString}`;
|
||||
|
||||
function register() {
|
||||
const handlerURL = noSW ? `resources/handler.html${handler}${type}` : `resources/handler/${type}/${handler}`;
|
||||
navigator.registerProtocolHandler(scheme, handlerURL, `WPT ${type} handler${noSW ? ", without service worker" : ""}`);
|
||||
}
|
||||
|
||||
function runTest({ includeNull = false } = {}) {
|
||||
promise_test(async t => {
|
||||
const bc = new BroadcastChannel(`protocol-handler-${type}${swString}`);
|
||||
if (!noSW) {
|
||||
const reg = await service_worker_unregister_and_register(t, "resources/handler-sw.js", "resources/handler/");
|
||||
t.add_cleanup(async () => await reg.unregister());
|
||||
await wait_for_state(t, reg.installing, 'activated');
|
||||
}
|
||||
const a = document.body.appendChild(document.createElement("a"));
|
||||
const codePoints = [];
|
||||
let i = includeNull ? 0 : 1;
|
||||
for (; i < 0x82; i++) {
|
||||
codePoints.push(String.fromCharCode(i));
|
||||
}
|
||||
a.href = `${scheme}:${codePoints.join("")}`;
|
||||
a.target = "_blank";
|
||||
a.click();
|
||||
await new Promise(resolve => {
|
||||
bc.onmessage = t.step_func(e => {
|
||||
resultingURL = e.data;
|
||||
assert_equals(stringBetweenMarkers(resultingURL, "QES", "QEE"), "%86", "query baseline");
|
||||
assert_equals(stringBetweenMarkers(resultingURL, "FES", "FEE"), "%E2%80%A0", "fragment baseline");
|
||||
assert_equals(stringBetweenMarkers(resultingURL, "PSS", "PSE"), `${encodeURIComponent(scheme)}%3A${includeNull ? "%2500" : ""}%2501%2502%2503%2504%2505%2506%2507%2508%250B%250C%250E%250F%2510%2511%2512%2513%2514%2515%2516%2517%2518%2519%251A%251B%251C%251D%251E%251F%20!%22%23%24%25%26${type === "query" ? "%27" : "'"}()*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%257F%25C2%2580%25C2%2581`, "actual test");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function stringBetweenMarkers(string, start, end) {
|
||||
return string.substring(string.indexOf(start) + start.length, string.indexOf(end));
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<!doctype html>
|
||||
<p>This popup can be closed if it does not close itself.
|
||||
<p>
|
||||
<script>
|
||||
// This resource either gets navigated to through a service worker as a result of a URL that looks
|
||||
// like:
|
||||
// https://.../html/webappapis/system-state-and-capabilities/the-navigator-object/resources/handler/{type}/...
|
||||
// (the host is excluded to not upset the lint tool)
|
||||
// or it gets navigated to directly with the type appended to the end of the URL. In that case type
|
||||
// can only be fragment or query.
|
||||
|
||||
let type = null;
|
||||
let swString = null;
|
||||
if (new URL(document.URL).pathname.endsWith("handler.html")) {
|
||||
swString = "";
|
||||
type = (document.URL.endsWith("fragment")) ? "fragment" : "query";
|
||||
} else {
|
||||
type = document.URL.split("/")[9];
|
||||
swString = "sw";
|
||||
}
|
||||
new BroadcastChannel(`protocol-handler-${type}${swString}`).postMessage(document.URL);
|
||||
window.close();
|
||||
</script>
|
|
@ -0,0 +1,811 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>InputEvent.getTargetRanges() at Backspace</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>
|
||||
<div contenteditable></div>
|
||||
<script>
|
||||
const kBackspaceKey = "\uE003";
|
||||
const kShift = "\uE008";
|
||||
const kMeta = "\uE03d";
|
||||
const kControl = "\uE009";
|
||||
const kAlt = "\uE00A";
|
||||
|
||||
let selection = getSelection();
|
||||
let editor = document.querySelector("div[contenteditable]");
|
||||
let beforeinput = [];
|
||||
let input = [];
|
||||
editor.addEventListener("beforeinput", (e) => {
|
||||
// NOTE: Blink makes `getTargetRanges()` return empty range after propagaion,
|
||||
// but this test wants to check the result during propagation.
|
||||
// Therefore, we need to cache the result, but will assert if
|
||||
// `getTargetRanges()` returns different ranges after checking the
|
||||
// cached ranges.
|
||||
e.cachedRanges = e.getTargetRanges();
|
||||
beforeinput.push(e);
|
||||
});
|
||||
editor.addEventListener("input", (e) => {
|
||||
e.cachedRanges = e.getTargetRanges();
|
||||
input.push(e);
|
||||
});
|
||||
|
||||
function reset() {
|
||||
editor.focus();
|
||||
beforeinput = [];
|
||||
input = [];
|
||||
}
|
||||
|
||||
function getRangeDescription(range) {
|
||||
function getNodeDescription(node) {
|
||||
if (!node) {
|
||||
return "null";
|
||||
}
|
||||
switch (node.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
case Node.COMMENT_NODE:
|
||||
case Node.CDATA_SECTION_NODE:
|
||||
return `${node.nodeName} "${node.data}"`;
|
||||
case Node.ELEMENT_NODE:
|
||||
return `<${node.nodeName.toLowerCase()}>`;
|
||||
default:
|
||||
return `${node.nodeName}`;
|
||||
}
|
||||
}
|
||||
if (range === null) {
|
||||
return "null";
|
||||
}
|
||||
if (range === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
return range.startContainer == range.endContainer && range.startOffset == range.endOffset
|
||||
? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})`
|
||||
: `(${getNodeDescription(range.startContainer)}, ${range.startOffset}) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`;
|
||||
}
|
||||
|
||||
function getArrayOfRangesDescription(arrayOfRanges) {
|
||||
if (arrayOfRanges === null) {
|
||||
return "null";
|
||||
}
|
||||
if (arrayOfRanges === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
if (!Array.isArray(arrayOfRanges)) {
|
||||
return "Unknown Object";
|
||||
}
|
||||
if (arrayOfRanges.length === 0) {
|
||||
return "[]";
|
||||
}
|
||||
let result = "[";
|
||||
for (let range of arrayOfRanges) {
|
||||
result += `{${getRangeDescription(range)}},`;
|
||||
}
|
||||
result += "]";
|
||||
return result;
|
||||
}
|
||||
|
||||
function sendBackspaceKey(modifier) {
|
||||
if (!modifier) {
|
||||
return new test_driver.Actions()
|
||||
.keyDown(kBackspaceKey)
|
||||
.keyUp(kBackspaceKey)
|
||||
.send();
|
||||
}
|
||||
return new test_driver.Actions()
|
||||
.keyDown(modifier)
|
||||
.keyDown(kBackspaceKey)
|
||||
.keyUp(kBackspaceKey)
|
||||
.keyUp(modifier)
|
||||
.send();
|
||||
}
|
||||
|
||||
function checkGetTargetRangesKeepReturningSameValue(event) {
|
||||
// https://github.com/w3c/input-events/issues/114
|
||||
assert_equals(getArrayOfRangesDescription(event.getTargetRanges()),
|
||||
getArrayOfRangesDescription(event.cachedRanges),
|
||||
`${event.type}.getTargetRanges() should keep returning the same array of ranges even after its propagation finished`);
|
||||
}
|
||||
|
||||
function checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedRange) {
|
||||
assert_equals(beforeinput.length, 1,
|
||||
"One beforeinput event should be fired if the key operation deletes something");
|
||||
assert_true(Array.isArray(beforeinput[0].cachedRanges),
|
||||
"beforeinput[0].getTargetRanges() should return an array of StaticRange instances during propagation");
|
||||
// Before checking the length of array of ranges, we should check first range
|
||||
// first because the first range data is more important than whether there
|
||||
// are additional unexpected ranges.
|
||||
if (beforeinput[0].cachedRanges.length > 0) {
|
||||
assert_equals(
|
||||
getRangeDescription(beforeinput[0].cachedRanges[0]),
|
||||
getRangeDescription(expectedRange),
|
||||
`beforeinput.getTargetRanges() should return expected range (inputType is "${beforeinput[0].inputType}")`);
|
||||
assert_equals(beforeinput[0].cachedRanges.length, 1,
|
||||
"beforeinput.getTargetRanges() should return one range within an array");
|
||||
}
|
||||
assert_equals(beforeinput[0].cachedRanges, 1,
|
||||
"One range should be returned from getTargetRanges() when the key operation deletes something");
|
||||
checkGetTargetRangesKeepReturningSameValue(beforeinput[0]);
|
||||
}
|
||||
|
||||
function checkGetTargetRangesOfInputOnDeleteSomething() {
|
||||
assert_equals(input.length, 1,
|
||||
"One input event should be fired if the key operation deletes something");
|
||||
// https://github.com/w3c/input-events/issues/113
|
||||
assert_true(Array.isArray(input[0].cachedRanges),
|
||||
"input[0].getTargetRanges() should return an array of StaticRange instances during propagation");
|
||||
assert_equals(input[0].cachedRanges.length, 0,
|
||||
"input[0].getTargetRanges() should return empty array during propagation");
|
||||
checkGetTargetRangesKeepReturningSameValue(input[0]);
|
||||
}
|
||||
|
||||
function checkBeforeinputAndInputEventsOnNOOP() {
|
||||
assert_equals(beforeinput.length, 0,
|
||||
"beforeinput event shouldn't be fired when the key operation does not cause modifying the DOM tree");
|
||||
assert_equals(input.length, 0,
|
||||
"input event shouldn't be fired when the key operation does not cause modifying the DOM tree");
|
||||
}
|
||||
|
||||
// Simply deletes the previous ASCII character of caret position.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 1);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>bc</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 0,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 1,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>a[]bc</p>"');
|
||||
|
||||
// Simply deletes the previous ASCII character of caret position.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 2);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>ac</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>ab[]c</p>"');
|
||||
|
||||
// Simply deletes the previous ASCII character of caret position.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 3);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>ab</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 2,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc[]</p>"');
|
||||
|
||||
// Should delete the `<span>` element becase it becomes empty.
|
||||
// However, we need discussion whether the `<span>` element should be
|
||||
// contained by a range of `getTargetRanges()`.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>a<span>b</span>c</p>";
|
||||
let c = editor.querySelector("span").nextSibling;
|
||||
selection.collapse(c, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>ac</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: c,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>a<span>b</span>[]c</p>"');
|
||||
|
||||
// Should delete the `<span>` element becase it becomes empty.
|
||||
// However, we need discussion whether the `<span>` element should be
|
||||
// contained by a range of `getTargetRanges()`.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>a<span>b</span>c</p>";
|
||||
let b = editor.querySelector("span").firstChild;
|
||||
selection.collapse(b, 1);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>ac</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>a<span>b[]</span>c</p>"');
|
||||
|
||||
// Invisible leading white-space may be deleted when the first visible
|
||||
// character is deleted. If it's deleted, it should be contained by
|
||||
// the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p> abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 2);
|
||||
await sendBackspaceKey();
|
||||
assert_in_array(editor.innerHTML, ["<p>bc</p>", "<p> bc</p>"]);
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: editor.firstChild.firstChild.length == 2 ? 0 : 1,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p> a[]bc</p>"');
|
||||
|
||||
// Invisible leading white-spaces in current block and invisible trailing
|
||||
// white-spaces in the previous block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(def, 3);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc </p><p> []def</p>"');
|
||||
|
||||
// Invisible leading white-spaces in current block and invisible trailing
|
||||
// white-spaces in the previous block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(def, 2);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc </p><p> [] def</p>"');
|
||||
|
||||
// Invisible leading white-spaces in current block and invisible trailing
|
||||
// white-spaces in the previous block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(def, 1);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc </p><p> [] def</p>"');
|
||||
|
||||
// Invisible leading white-spaces in current block and invisible trailing
|
||||
// white-spaces in the previous block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(def, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc </p><p>[] def</p>"');
|
||||
|
||||
// Invisible leading white-spaces in current block and invisible trailing
|
||||
// white-spaces in the previous block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.setBaseAndExtent(abc, 6, def, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc [</p><p>] def</p>"');
|
||||
|
||||
// Invisible leading white-spaces in the current block should be deleted
|
||||
// for avoiding they becoming visible when the blocks are joined, but
|
||||
// preformatted trailing white-spaces in the first block shouldn't be
|
||||
// deleted. Perhaps, the invisible white-spaces should be contained by
|
||||
// the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<pre>abc </pre><p> def</p>";
|
||||
let pre = editor.firstChild;
|
||||
let abc = pre.firstChild;
|
||||
let p = pre.nextSibling;
|
||||
let def = p.firstChild;
|
||||
selection.collapse(def, 3);
|
||||
await sendBackspaceKey();
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
// Shouldn't make the invisible white-spaces visible.
|
||||
assert_equals(editor.innerHTML, "<pre>abc def</pre>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 6,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<pre>abc </pre><p> []def</p>"');
|
||||
|
||||
// Invisible leading/trailing white-spaces in the current block should be
|
||||
// deleted for avoiding they becoming visible when the blocks are joined, but
|
||||
// preformatted trailing white-spaces in the first block shouldn't be
|
||||
// deleted. Perhaps, the invisible leading white-spaces should be contained
|
||||
// by the range of `getTargetRanges()`, but needs discussion.
|
||||
// And also not sure whether the trailing white-spaces should be contained
|
||||
// by additional range of `getTargetRanges()` or not because of the
|
||||
// implementation cost and runtime cost. Needs discuss.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<pre>abc </pre><p> def </p>";
|
||||
let pre = editor.firstChild;
|
||||
let abc = pre.firstChild;
|
||||
let p = pre.nextSibling;
|
||||
let def = p.firstChild;
|
||||
selection.collapse(def, 3);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<pre>abc def </pre>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 6,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<pre>abc </pre><p> []def </p>"');
|
||||
|
||||
// Invisible trailing white-spaces in the first block should be deleted
|
||||
// when the block is joined with the preformated following block, but
|
||||
// the leading white-spaces in the preformatted block shouldn't be
|
||||
// removed. So, in this case, the invisible trailing white-spaces should
|
||||
// be in the range of `getTargetRanges()`, but not so for the preformatted
|
||||
// visible leading white-spaces. But needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><pre> def</pre>";
|
||||
let p = editor.firstChild;
|
||||
let abc = p.firstChild;
|
||||
let pre = p.nextSibling;
|
||||
let def = pre.firstChild;
|
||||
selection.collapse(def, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_in_array(editor.innerHTML, ["<p>abc def</p>",
|
||||
"<p>abc def</p>",
|
||||
"<p>abc def</p>",
|
||||
"<p>abc def</p>"]);
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 6,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc </p><pre>[] def</pre>"');
|
||||
|
||||
// If the first block has invisible `<br>` element and joining it with
|
||||
// the following block, the invisible trailing `<br>` element should be
|
||||
// deleted and join the blocks. Therefore, the target range should contain
|
||||
// the `<br>` element and block boundaries. But maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br></p><p>def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(def, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p1,
|
||||
startOffset: 1,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc<br></p><p>[]def</p>"');
|
||||
|
||||
// If the first block has invisible `<br>` element for empty last line and
|
||||
// joining it with the following block, the invisible trailing `<br>` element
|
||||
// should be deleted and join the blocks. Therefore, the target range should
|
||||
// contain the `<br>` element and block boundaries. But maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br><br></p><p>def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(def, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abc<br>def</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p1,
|
||||
startOffset: 2,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc<br><br></p><p>[]def</p>"');
|
||||
|
||||
// Deleting visible `<br>` element should be contained by a range of
|
||||
// `getTargetRanges()`.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br>def</p>";
|
||||
let def = editor.querySelector("br").nextSibling;
|
||||
selection.collapse(def, 0);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc<br>[]def</p>"');
|
||||
|
||||
// Deleting visible `<br>` element should be contained by a range of
|
||||
// `getTargetRanges()`. However, when only the `<br>` element is selected,
|
||||
// the range shouldn't start from nor end by surrounding text nodes?
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br>def</p>";
|
||||
selection.setBaseAndExtent(editor.firstChild, 1, editor.firstChild, 2);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<p>abc{<br>}def</p>"');
|
||||
|
||||
// Joining parent block and child block should remove invisible preceding
|
||||
// white-spaces of the child block and invisible leading white-spaces in
|
||||
// the child block, and they should be contained in a range of
|
||||
// `getTargetRanges()`, but maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<div>abc <p> def<br>ghi</p></div>";
|
||||
let p = editor.querySelector("p");
|
||||
let def = p.firstChild;
|
||||
let abc = editor.firstChild.firstChild;
|
||||
selection.collapse(def, 3);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<div>abcdef<p>ghi</p></div>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<div>abc <p> []def<br>ghi</p></div>"');
|
||||
|
||||
// Joining child block and parent block should remove invisible trailing
|
||||
// white-spaces of the child block and invisible following white-spaces
|
||||
// in the parent block, and they should be contained by a range of
|
||||
// `getTaregetRanges()`, but maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<div><p>abc </p> def</div>";
|
||||
let abc = editor.querySelector("p").firstChild;
|
||||
let def = editor.querySelector("p").nextSibling;
|
||||
selection.collapse(def, 3);
|
||||
await sendBackspaceKey();
|
||||
assert_equals(editor.innerHTML, "<div><p>abcdef</p></div>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Backspace at "<div><p>abc </p> []def</div>"');
|
||||
|
||||
// The following tests check whether the range returned from
|
||||
// `beforeinput[0].getTargetRanges()` is modified or different range is
|
||||
// modified instead. I.e., they don't test which type of deletion should
|
||||
// occur. Therefore, their result depends on browser's key bindings,
|
||||
// system settings and running OS.
|
||||
|
||||
function getFirstDifferentOffset(currentString, originalString) {
|
||||
for (let i = 0; i < currentString.length; i++) {
|
||||
if (currentString.charAt(i) !== originalString.charAt(i) &&
|
||||
(originalString.charAt(i) !== " " || !currentString.charAt("\u00A0"))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return currentString.length;
|
||||
}
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc def".length);
|
||||
await sendBackspaceKey(kShift);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Shift + Backspace at "<p>abc def[] ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc def".length);
|
||||
await sendBackspaceKey(kControl);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Control + Backspace at "<p>abc def[] ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc def".length);
|
||||
await sendBackspaceKey(kAlt);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Alt + Backspace at "<p>abc def[] ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc def".length);
|
||||
await sendBackspaceKey(kMeta);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Meta + Backspace at "<p>abc def[] ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p> ${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc".length);
|
||||
await sendBackspaceKey(kShift);
|
||||
let visibleText = p.firstChild.data.replace(/^\s+/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Shift + Backspace at "<p> abc[] def</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p> ${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc".length);
|
||||
await sendBackspaceKey(kControl);
|
||||
let visibleText = p.firstChild.data.replace(/^\s+/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Control + Backspace at "<p> abc[] def</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p> ${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc".length);
|
||||
await sendBackspaceKey(kAlt);
|
||||
let visibleText = p.firstChild.data.replace(/^\s+/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Alt + Backspace at "<p> abc[] def</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p> ${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc".length);
|
||||
await sendBackspaceKey(kMeta);
|
||||
let visibleText = p.firstChild.data.replace(/^\s+/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${invisibleWhiteSpaces + kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInput();
|
||||
}, 'Meta + Backspace at "<p> abc[] def</p>"');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,808 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>InputEvent.getTargetRanges() at Delete (forward delete)</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>
|
||||
<div contenteditable></div>
|
||||
<script>
|
||||
const kDeleteKey = "\uE017";
|
||||
const kShift = "\uE008";
|
||||
const kMeta = "\uE03d";
|
||||
const kControl = "\uE009";
|
||||
const kAlt = "\uE00A";
|
||||
|
||||
let selection = getSelection();
|
||||
let editor = document.querySelector("div[contenteditable]");
|
||||
let beforeinput = [];
|
||||
let input = [];
|
||||
editor.addEventListener("beforeinput", (e) => {
|
||||
// NOTE: Blink makes `getTargetRanges()` return empty range after propagaion,
|
||||
// but this test wants to check the result during propagation.
|
||||
// Therefore, we need to cache the result, but will assert if
|
||||
// `getTargetRanges()` returns different ranges after checking the
|
||||
// cached ranges.
|
||||
e.cachedRanges = e.getTargetRanges();
|
||||
beforeinput.push(e);
|
||||
});
|
||||
editor.addEventListener("input", (e) => {
|
||||
e.cachedRanges = e.getTargetRanges();
|
||||
input.push(e);
|
||||
});
|
||||
|
||||
function reset() {
|
||||
editor.focus();
|
||||
beforeinput = [];
|
||||
input = [];
|
||||
}
|
||||
|
||||
function getRangeDescription(range) {
|
||||
function getNodeDescription(node) {
|
||||
if (!node) {
|
||||
return "null";
|
||||
}
|
||||
switch (node.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
case Node.COMMENT_NODE:
|
||||
case Node.CDATA_SECTION_NODE:
|
||||
return `${node.nodeName} "${node.data}"`;
|
||||
case Node.ELEMENT_NODE:
|
||||
return `<${node.nodeName.toLowerCase()}>`;
|
||||
default:
|
||||
return `${node.nodeName}`;
|
||||
}
|
||||
}
|
||||
if (range === null) {
|
||||
return "null";
|
||||
}
|
||||
if (range === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
return range.startContainer == range.endContainer && range.startOffset == range.endOffset
|
||||
? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})`
|
||||
: `(${getNodeDescription(range.startContainer)}, ${range.startOffset}) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`;
|
||||
}
|
||||
|
||||
function getArrayOfRangesDescription(arrayOfRanges) {
|
||||
if (arrayOfRanges === null) {
|
||||
return "null";
|
||||
}
|
||||
if (arrayOfRanges === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
if (!Array.isArray(arrayOfRanges)) {
|
||||
return "Unknown Object";
|
||||
}
|
||||
if (arrayOfRanges.length === 0) {
|
||||
return "[]";
|
||||
}
|
||||
let result = "[";
|
||||
for (let range of arrayOfRanges) {
|
||||
result += `{${getRangeDescription(range)}},`;
|
||||
}
|
||||
result += "]";
|
||||
return result;
|
||||
}
|
||||
|
||||
function sendDeleteKey(modifier) {
|
||||
if (!modifier) {
|
||||
return new test_driver.Actions()
|
||||
.keyDown(kDeleteKey)
|
||||
.keyUp(kDeleteKey)
|
||||
.send();
|
||||
}
|
||||
return new test_driver.Actions()
|
||||
.keyDown(modifier)
|
||||
.keyDown(kDeleteKey)
|
||||
.keyUp(kDeleteKey)
|
||||
.keyUp(modifier)
|
||||
.send();
|
||||
}
|
||||
|
||||
function checkGetTargetRangesKeepReturningSameValue(event) {
|
||||
// https://github.com/w3c/input-events/issues/114
|
||||
assert_equals(getArrayOfRangesDescription(event.getTargetRanges()),
|
||||
getArrayOfRangesDescription(event.cachedRanges),
|
||||
`${event.type}.getTargetRanges() should keep returning the same array of ranges even after its propagation finished`);
|
||||
}
|
||||
|
||||
function checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedRange) {
|
||||
assert_equals(beforeinput.length, 1,
|
||||
"One beforeinput event should be fired if the key operation deletes something");
|
||||
assert_true(Array.isArray(beforeinput[0].cachedRanges),
|
||||
"beforeinput[0].getTargetRanges() should return an array of StaticRange instances during propagation");
|
||||
// Before checking the length of array of ranges, we should check the first
|
||||
// range first because the first range data is more important than whether
|
||||
// there are additional unexpected ranges.
|
||||
if (beforeinput[0].cachedRanges.length > 0) {
|
||||
assert_equals(
|
||||
getRangeDescription(beforeinput[0].cachedRanges[0]),
|
||||
getRangeDescription(expectedRange),
|
||||
`beforeinput.getTargetRanges() should return expected range (inputType is "${beforeinput[0].inputType}")`);
|
||||
assert_equals(beforeinput[0].cachedRanges.length, 1,
|
||||
"beforeinput.getTargetRanges() should return one range within an array");
|
||||
}
|
||||
assert_equals(beforeinput[0].cachedRanges, 1,
|
||||
"One range should be returned from getTargetRanges() when the key operation deletes something");
|
||||
checkGetTargetRangesKeepReturningSameValue(beforeinput[0]);
|
||||
}
|
||||
|
||||
function checkGetTargetRangesOfInputOnDeleteSomething() {
|
||||
assert_equals(input.length, 1,
|
||||
"One input event should be fired if the key operation deletes something");
|
||||
// https://github.com/w3c/input-events/issues/113
|
||||
assert_true(Array.isArray(input[0].cachedRanges),
|
||||
"input[0].getTargetRanges() should return an array of StaticRange instances during propagation");
|
||||
assert_equals(input[0].cachedRanges.length, 0,
|
||||
"input[0].getTargetRanges() should return empty array during propagation");
|
||||
checkGetTargetRangesKeepReturningSameValue(input[0]);
|
||||
}
|
||||
|
||||
function checkBeforeinputAndInputEventsOnNOOP() {
|
||||
assert_equals(beforeinput.length, 0,
|
||||
"beforeinput event shouldn't be fired when the key operation does not cause modifying the DOM tree");
|
||||
assert_equals(input.length, 0,
|
||||
"input event shouldn't be fired when the key operation does not cause modifying the DOM tree");
|
||||
}
|
||||
|
||||
// Simply deletes the next ASCII character of caret position.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 2);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>ab</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 2,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>ab[]c</p>"');
|
||||
|
||||
// Simply deletes the next ASCII character of caret position.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 1);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>ac</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>a[]bc</p>"');
|
||||
|
||||
// Simply deletes the next ASCII character of caret position.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc</p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 0);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>bc</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 0,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: 1,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>[]abc</p>"');
|
||||
|
||||
// Should delete the `<span>` element becase it becomes empty.
|
||||
// However, we need discussion whether the `<span>` element should be
|
||||
// contained by a range of `getTargetRanges()`.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>a<span>b</span>c</p>";
|
||||
let a = editor.querySelector("span").previousSibling;
|
||||
selection.collapse(a, 1);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>ac</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: a,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>a[]<span>b</span>c</p>"');
|
||||
|
||||
// Should delete the `<span>` element becase it becomes empty.
|
||||
// However, we need discussion whether the `<span>` element should be
|
||||
// contained by a range of `getTargetRanges()`.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>a<span>b</span>c</p>";
|
||||
let b = editor.querySelector("span").firstChild;
|
||||
selection.collapse(b, 0);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>ac</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>a<span>[]b</span>c</p>"');
|
||||
|
||||
// Invisible trailing white-space may be deleted when the last visible
|
||||
// character is deleted. If it's deleted, it should be contained by
|
||||
// the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p>";
|
||||
selection.collapse(editor.firstChild.firstChild, 2);
|
||||
await sendDeleteKey();
|
||||
assert_in_array(editor.innerHTML, ["<p>ab</p>", "<p>ab </p>"]);
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild.firstChild,
|
||||
startOffset: 2,
|
||||
endContainer: editor.firstChild.firstChild,
|
||||
endOffset: editor.firstChild.firstChild.data.length == 2 ? 4 : 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>ab[]c </p>"');
|
||||
|
||||
// Invisible trailing white-spaces in current block and invisible leading
|
||||
// white-spaces in the following block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(abc, 3);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc[] </p><p> def</p>"');
|
||||
|
||||
// Invisible trailing white-spaces in current block and invisible leading
|
||||
// white-spaces in the following block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(abc, 4);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc [] </p><p> def</p>"');
|
||||
|
||||
// Invisible trailing white-spaces in current block and invisible leading
|
||||
// white-spaces in the following block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(abc, 5);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc [] </p><p> def</p>"');
|
||||
|
||||
// Invisible trailing white-spaces in current block and invisible leading
|
||||
// white-spaces in the following block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(abc, 6);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc []</p><p> def</p>"');
|
||||
|
||||
// Invisible trailing white-spaces in current block and invisible leading
|
||||
// white-spaces in the following block should be deleted for avoiding they
|
||||
// becoming visible when the blocks are joined. Perhaps, they should be
|
||||
// contained by the range of `getTargetRanges()`, but needs discussion.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><p> def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.setBaseAndExtent(abc, 6, def, 0);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc [</p><p>] def</p>"');
|
||||
|
||||
// Invisible leading white-spaces in the following block should be deleted
|
||||
// for avoiding they becoming visible when the blocks are joined, but
|
||||
// preformatted trailing white-spaces in the first block shouldn't be
|
||||
// deleted. Perhaps, the invisible white-spaces should be contained by
|
||||
// the range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<pre>abc </pre><p> def</p>";
|
||||
let pre = editor.firstChild;
|
||||
let abc = pre.firstChild;
|
||||
let p = pre.nextSibling;
|
||||
let def = p.firstChild;
|
||||
selection.collapse(abc, 6);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<pre>abc def</pre>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 6,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<pre>abc []</pre><p> def</p>"');
|
||||
|
||||
// Invisible leading/trailing white-spaces in the following block should be
|
||||
// deleted for avoiding they becoming visible when the blocks are joined, but
|
||||
// preformatted trailing white-spaces in the first block shouldn't be
|
||||
// deleted. Perhaps, the invisible leading white-spaces should be contained
|
||||
// by the range of `getTargetRanges()`, but needs discussion.
|
||||
// And also not sure whether the trailing white-spaces should be contained
|
||||
// by additional range of `getTargetRanges()` or not because of the
|
||||
// implementation cost and runtime cost. Needs discuss.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<pre>abc </pre><p> def</p>";
|
||||
let pre = editor.firstChild;
|
||||
let abc = pre.firstChild;
|
||||
let p = pre.nextSibling;
|
||||
let def = p.firstChild;
|
||||
selection.collapse(abc, 6);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<pre>abc def</pre>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 6,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<pre>abc []</pre><p> def </p>"');
|
||||
|
||||
// Invisible trailing white-spaces in the first block should be deleted
|
||||
// when the block is joined with the preformated following block, but
|
||||
// the leading white-spaces in the preformatted block shouldn't be
|
||||
// removed. So, in this case, the invisible trailing white-spaces should
|
||||
// be in the range of `getTargetRanges()`, but not so for the preformatted
|
||||
// visible leading white-spaces. But needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc </p><pre> def</pre>";
|
||||
let p = editor.firstChild;
|
||||
let abc = p.firstChild;
|
||||
let pre = p.nextSibling;
|
||||
let def = pre.firstChild;
|
||||
selection.collapse(abc, 3);
|
||||
await sendDeleteKey();
|
||||
assert_in_array(editor.innerHTML, ["<p>abc def</p>",
|
||||
"<p>abc def</p>",
|
||||
"<p>abc def</p>",
|
||||
"<p>abc def</p>"]);
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc[] </p><pre> def</pre>"');
|
||||
|
||||
// Deleting from before invisible trailing `<br>` element of a block
|
||||
// should delete the `<br>` element and join the blocks. Therefore,
|
||||
// the target range should contain the `<br>` element and block boundaries.
|
||||
// But maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br></p><p>def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(abc, 3);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc[]<br></p><p>def</p>"');
|
||||
|
||||
// Deleting from last empty line in the first block should delete the
|
||||
// invisible `<br>` element for the last empty line and join the blocks.
|
||||
// In this case, the invisible `<br>` element should be contained in the
|
||||
// range of `getTargetRanges()`, but needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br><br></p><p>def</p>";
|
||||
let p1 = editor.firstChild;
|
||||
let abc = p1.firstChild;
|
||||
let p2 = p1.nextSibling;
|
||||
let def = p2.firstChild;
|
||||
selection.collapse(p1, 2);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abc<br>def</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p1,
|
||||
startOffset: 2,
|
||||
endContainer: def,
|
||||
endOffset: 0,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc<br>{}<br></p><p>def</p>"');
|
||||
|
||||
// Deleting visible `<br>` element should be contained by a range of
|
||||
// `getTargetRanges()`.
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br>def</p>";
|
||||
let abc = editor.firstChild.firstChild;
|
||||
selection.collapse(abc, 3);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: editor.querySelector("p"),
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc[]<br>def</p>"');
|
||||
|
||||
// Deleting visible `<br>` element should be contained by a range of
|
||||
// `getTargetRanges()`. However, when only the `<br>` element is selected,
|
||||
// the range shouldn't start from nor end by surrounding text nodes?
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<p>abc<br>def</p>";
|
||||
selection.setBaseAndExtent(editor.firstChild, 1, editor.firstChild, 2);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<p>abcdef</p>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: editor.firstChild,
|
||||
startOffset: 1,
|
||||
endContainer: editor.firstChild,
|
||||
endOffset: 2,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<p>abc{<br>}def</p>"');
|
||||
|
||||
// Joining parent block and child block should remove invisible preceding
|
||||
// white-spaces of the child block and invisible leading white-spaces in
|
||||
// the child block, and they should be contained in a range of
|
||||
// `getTargetRanges()`, but maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<div>abc <p> def<br>ghi</p></div>";
|
||||
let p = editor.querySelector("p");
|
||||
let def = p.firstChild;
|
||||
let abc = editor.firstChild.firstChild;
|
||||
selection.collapse(abc, 3);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<div>abcdef<p>ghi</p></div>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<div>abc[] <p> def<br>ghi</p></div>"');
|
||||
|
||||
// Joining child block and parent block should remove invisible trailing
|
||||
// white-spaces of the child block and invisible following white-spaces
|
||||
// in the parent block, and they should be contained by a range of
|
||||
// `getTaregetRanges()`, but maybe needs discussion.
|
||||
// https://github.com/w3c/input-events/issues/112
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
editor.innerHTML = "<div><p>abc </p> def</div>";
|
||||
let abc = editor.querySelector("p").firstChild;
|
||||
let def = editor.querySelector("p").nextSibling;
|
||||
selection.collapse(abc, 3);
|
||||
await sendDeleteKey();
|
||||
assert_equals(editor.innerHTML, "<div><p>abcdef</p></div>");
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: abc,
|
||||
startOffset: 3,
|
||||
endContainer: def,
|
||||
endOffset: 3,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Delete at "<div><p>abc[] </p> def</div>"');
|
||||
|
||||
// The following tests check whether the range returned from
|
||||
// `beforeinput[0].getTargetRanges()` is modified or different range is
|
||||
// modified instead. I.e., they don't test which type of deletion should
|
||||
// occur. Therefore, their result depends on browser's key bindings,
|
||||
// system settings and running OS.
|
||||
|
||||
function getFirstDifferentOffset(currentString, originalString) {
|
||||
for (let i = 0; i < currentString.length; i++) {
|
||||
if (currentString.charAt(i) !== originalString.charAt(i) &&
|
||||
(originalString.charAt(i) !== " " || !currentString.charAt("\u00A0"))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return currentString.length;
|
||||
}
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kShift);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Shift + Delete at "<p>abc []def ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kControl);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Control + Delete at "<p>abc []def ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kAlt);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Alt + Delete at "<p>abc []def ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def ghi";
|
||||
editor.innerHTML = `<p>${kText}</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kMeta);
|
||||
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
||||
let length = kText.length - p.firstChild.data.length;
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Meta + Delete at "<p>abc []def ghi</p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p>${kText} </p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kShift);
|
||||
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Shift + Delete at "<p>abc []def </p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p>${kText} </p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kControl);
|
||||
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Control + Delete at "<p>abc []def </p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p>${kText} </p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kAlt);
|
||||
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Alt + Delete at "<p>abc []def </p>"');
|
||||
|
||||
promise_test(async () => {
|
||||
reset();
|
||||
const kText = "abc def";
|
||||
editor.innerHTML = `<p>${kText} s</p>`;
|
||||
let p = editor.querySelector("p");
|
||||
selection.collapse(p.firstChild, "abc ".length);
|
||||
await sendDeleteKey(kMeta);
|
||||
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
||||
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
||||
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
||||
let length = kText.length + 3 - p.firstChild.data.length;
|
||||
// If invisible white-spaces are deleted, they should be contained in the target range.
|
||||
assert_equals(editor.innerHTML.replace(/ /g, " "),
|
||||
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`);
|
||||
if (startOffset === kText.length) {
|
||||
checkBeforeinputAndInputEventsOnNOOP();
|
||||
return;
|
||||
}
|
||||
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
||||
startContainer: p.firstChild,
|
||||
startOffset: startOffset,
|
||||
endContainer: p.firstChild,
|
||||
endOffset: startOffset + length,
|
||||
});
|
||||
checkGetTargetRangesOfInputOnDeleteSomething();
|
||||
}, 'Meta + Delete at "<p>abc []def</p>"');
|
||||
|
||||
</script>
|
|
@ -8,7 +8,7 @@ partial interface Navigator {
|
|||
};
|
||||
|
||||
dictionary ShareData {
|
||||
FrozenArray<File> files;
|
||||
sequence<File> files;
|
||||
USVString title;
|
||||
USVString text;
|
||||
USVString url;
|
||||
|
|
|
@ -13,13 +13,17 @@
|
|||
.displayNone {
|
||||
display: none;
|
||||
}
|
||||
.composited {
|
||||
.willChangeTransform {
|
||||
will-change: transform;
|
||||
}
|
||||
.willChangeOpacity {
|
||||
will-change: opacity;
|
||||
}
|
||||
</style>
|
||||
<img src='/images/blue.png' class='opacity0 composited' id='opacity0'/>
|
||||
<img src='/images/green.png' class='visibilityHidden composited' id='visibilityHidden'/>
|
||||
<img src='/images/red.png' class='displayNone composited' id='displayNone'/>
|
||||
<img src='/images/blue.png' class='opacity0 willChangeTransform' id='opacity0-willChangeTransform'/>
|
||||
<img src='/images/green.png' class='visibilityHidden willChangeTransform' id='visibilityHidden'/>
|
||||
<img src='/images/red.png' class='displayNone willChangeTransform' id='displayNone'/>
|
||||
<img src='/images/blue.png' class='opacity0 willChangeOpacity' id='opacity0-willChangeOpacity'/>
|
||||
<div class='opacity0 composited'><img src='/images/yellow.png' id='divOpacity0'/></div>
|
||||
<div class='visibilityHidden composited'><img src='/images/yellow.png' id='divVisibilityHidden'/></div>
|
||||
<div class='displayNone composited'><img src='/images/yellow.png' id='divDisplayNone'/></div>
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Layout Instability: simple block movement is detected</title>
|
||||
<link rel="help" href="https://wicg.github.io/layout-instability/" />
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/util.js"></script>
|
||||
<body style="writing-mode: vertical-rl">
|
||||
<div style="height: 200px; font-size: 20px; line-height: 25px">
|
||||
1AAAAAAA<br>
|
||||
2AAAAAAA<br>
|
||||
3AAAAAAA<br>
|
||||
<div id="inline-block" style="display: inline-block; width: 50px">4AAAAAAA</div><br>
|
||||
5AAAAAAA<br>
|
||||
6AAAAAAA<br>
|
||||
7AAAAAAA<br>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
promise_test(async () => {
|
||||
const watcher = new ScoreWatcher;
|
||||
|
||||
// Wait for the initial render to complete.
|
||||
await waitForAnimationFrames(2);
|
||||
|
||||
// Modify the position of the div.
|
||||
const inline_block = document.querySelector("#inline-block");
|
||||
inline_block.style.width = '100px';
|
||||
|
||||
// The lines below the inline-block are shifted down by 50px.
|
||||
// The implementation may measure the real width of the shifted text
|
||||
// or use the available width (i.e. width of the containing block).
|
||||
// Also tolerate extra 10% error.
|
||||
const text_width = inline_block.offsetWidth;
|
||||
const expectedScoreMin = computeExpectedScore(text_width * (30 * 3 + 50), 50) * 0.9;
|
||||
const expectedScoreMax = computeExpectedScore(200 * (30 * 3 + 50), 50) * 1.1;
|
||||
|
||||
// Observer fires after the frame is painted.
|
||||
assert_equals(watcher.score, 0);
|
||||
await watcher.promise;
|
||||
assert_between_exclusive(watcher.score, expectedScoreMin, expectedScoreMax);
|
||||
}, 'Inline flow movement.');
|
||||
|
||||
</script>
|
||||
</body>
|
|
@ -1,42 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Layout Instability: simple block movement is detected</title>
|
||||
<link rel="help" href="https://wicg.github.io/layout-instability/" />
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/util.js"></script>
|
||||
<div style="width: 200px; font-size: 20px; line-height: 25px">
|
||||
1AAAAAAA<br>
|
||||
2AAAAAAA<br>
|
||||
3AAAAAAA<br>
|
||||
<div id="inline-block" style="display: inline-block; height: 50px">4AAAAAAA</div><br>
|
||||
5AAAAAAA<br>
|
||||
6AAAAAAA<br>
|
||||
7AAAAAAA<br>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
promise_test(async () => {
|
||||
const watcher = new ScoreWatcher;
|
||||
|
||||
// Wait for the initial render to complete.
|
||||
await waitForAnimationFrames(2);
|
||||
|
||||
// Modify the position of the div.
|
||||
const inline_block = document.querySelector("#inline-block");
|
||||
inline_block.style.height = '100px';
|
||||
|
||||
// The lines below the inline-block are shifted down by 50px.
|
||||
// The implementation may measure the real width of the shifted text
|
||||
// or use the available width (i.e. width of the containing block).
|
||||
// Also tolerate extra 10% error.
|
||||
const text_width = inline_block.offsetWidth;
|
||||
const expectedScoreMin = computeExpectedScore(text_width * (30 * 3 + 50), 50) * 0.9;
|
||||
const expectedScoreMax = computeExpectedScore(200 * (30 * 3 + 50), 50) * 1.1;
|
||||
|
||||
// Observer fires after the frame is painted.
|
||||
assert_equals(watcher.score, 0);
|
||||
await watcher.promise;
|
||||
assert_between_exclusive(watcher.score, expectedScoreMin, expectedScoreMax);
|
||||
}, 'Inline flow movement.');
|
||||
|
||||
</script>
|
|
@ -1,21 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Layout Instability: outline doesn't contribute to layout shift</title>
|
||||
<link rel="help" href="https://wicg.github.io/layout-instability/" />
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/util.js"></script>
|
||||
<div id="target" style="width: 300px; height: 300px"></div>
|
||||
<script>
|
||||
promise_test(async () => {
|
||||
const watcher = new ScoreWatcher;
|
||||
|
||||
// Wait for the initial render to complete.
|
||||
await waitForAnimationFrames(2);
|
||||
|
||||
// Add outline for target. This should not generate a shift.
|
||||
target.style.outline = "10px solid blue";
|
||||
|
||||
await waitForAnimationFrames(3);
|
||||
assert_equals(watcher.score, 0);
|
||||
}, "Outline.");
|
||||
</script>
|
|
@ -84,6 +84,9 @@ def main(product, commit_range, wpt_args):
|
|||
command = ["python", "./wpt", "run"] + wpt_args + [product]
|
||||
|
||||
logger.info("Executing command: %s" % " ".join(command))
|
||||
with open("/home/test/artifacts/checkrun.md", "a") as f:
|
||||
f.write("\n**WPT Command:** `%s`\n\n" % " ".join(command))
|
||||
|
||||
retcode = subprocess.call(command, env=dict(os.environ, TERM="dumb"))
|
||||
if retcode != 0:
|
||||
sys.exit(retcode)
|
||||
|
|
|
@ -241,6 +241,8 @@ def create_tc_task(event, task, taskgroup_id, depends_on_ids, env_extra=None):
|
|||
},
|
||||
"routes": ["checks"]
|
||||
}
|
||||
if "extra" in task:
|
||||
task_data["extra"].update(task["extra"])
|
||||
if env_extra:
|
||||
task_data["payload"]["env"].update(env_extra)
|
||||
if depends_on_ids:
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
class GitHubChecksOutputter(object):
|
||||
"""Provides a method to output data to be shown in the GitHub Checks UI.
|
||||
|
||||
This can be useful to provide a summary of a given check (e.g. the lint)
|
||||
to enable developers to quickly understand what has gone wrong. The output
|
||||
supports markdown format.
|
||||
|
||||
See https://docs.taskcluster.net/docs/reference/integrations/github/checks#custom-text-output-in-checks
|
||||
"""
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def output(self, line):
|
||||
with open(self.path, 'a') as f:
|
||||
f.write(line)
|
||||
f.write('\n')
|
||||
|
||||
|
||||
__outputter = None
|
||||
def get_gh_checks_outputter(kwargs):
|
||||
"""Return the outputter for GitHub Checks output, if enabled.
|
||||
|
||||
:param kwargs: The arguments passed to the program (to look for the
|
||||
--github_checks_text_file flag)
|
||||
"""
|
||||
global __outputter
|
||||
if kwargs['github_checks_text_file'] and __outputter is None:
|
||||
__outputter = GitHubChecksOutputter(kwargs['github_checks_text_file'])
|
||||
return __outputter
|
|
@ -10,6 +10,13 @@ components:
|
|||
public/results:
|
||||
path: /home/test/artifacts
|
||||
type: directory
|
||||
extra:
|
||||
github:
|
||||
customCheckRun:
|
||||
# We set both textArtifactName and annotationsArtifactName due
|
||||
# to https://github.com/taskcluster/taskcluster/issues/3191
|
||||
textArtifactName: public/results/checkrun.md
|
||||
annotationsArtifactName: public/results/checkrun.md
|
||||
|
||||
wpt-testharness:
|
||||
chunks: 16
|
||||
|
@ -296,6 +303,7 @@ tasks:
|
|||
--channel=${vars.channel}
|
||||
--verify
|
||||
--verify-no-chaos-mode
|
||||
--github-checks-text-file="/home/test/artifacts/checkrun.md"
|
||||
|
||||
- wpt-${vars.browser}-${vars.channel}-results:
|
||||
use:
|
||||
|
|
|
@ -13,6 +13,7 @@ from mozlog.handlers import BaseHandler, StreamHandler, LogLevelFilter
|
|||
|
||||
here = os.path.dirname(__file__)
|
||||
localpaths = imp.load_source("localpaths", os.path.abspath(os.path.join(here, os.pardir, os.pardir, "localpaths.py")))
|
||||
from ci.tc.github_checks_output import get_gh_checks_outputter
|
||||
from wpt.markdown import markdown_adjust, table
|
||||
|
||||
|
||||
|
@ -178,8 +179,32 @@ def err_string(results_dict, iterations):
|
|||
return rv
|
||||
|
||||
|
||||
def write_github_checks_summary_inconsistent(log, inconsistent, iterations):
|
||||
"""Outputs a summary of inconsistent tests for GitHub Checks."""
|
||||
log("Some affected tests had inconsistent (flaky) results:\n")
|
||||
write_inconsistent(log, inconsistent, iterations)
|
||||
log("\n")
|
||||
log("These may be pre-existing or new flakes. Please try to reproduce (see "
|
||||
"the above WPT command, though some flags may not be needed when "
|
||||
"running locally) and determine if your change introduced the flake. "
|
||||
"If you are unable to reproduce the problem, please tag "
|
||||
"`@web-platform-tests/wpt-core-team` in a comment for help.\n")
|
||||
|
||||
|
||||
def write_github_checks_summary_slow_tests(log, slow):
|
||||
"""Outputs a summary of slow tests for GitHub Checks."""
|
||||
log("Some affected tests had slow results:\n")
|
||||
write_slow_tests(log, slow)
|
||||
log("\n")
|
||||
log("These may be pre-existing or newly slow tests. Slow tests indicate "
|
||||
"that a test ran very close to the test timeout limit and so may "
|
||||
"become TIMEOUT-flaky in the future. Consider speeding up the test or "
|
||||
"breaking it into multiple tests. For help, please tag "
|
||||
"`@web-platform-tests/wpt-core-team` in a comment.\n")
|
||||
|
||||
|
||||
def write_inconsistent(log, inconsistent, iterations):
|
||||
"""Output inconsistent tests to logger.error."""
|
||||
"""Output inconsistent tests to the passed in logging function."""
|
||||
log("## Unstable results ##\n")
|
||||
strings = [(
|
||||
"`%s`" % markdown_adjust(test),
|
||||
|
@ -191,6 +216,7 @@ def write_inconsistent(log, inconsistent, iterations):
|
|||
|
||||
|
||||
def write_slow_tests(log, slow):
|
||||
"""Output slow tests to the passed in logging function."""
|
||||
log("## Slow tests ##\n")
|
||||
strings = [(
|
||||
"`%s`" % markdown_adjust(test),
|
||||
|
@ -321,6 +347,8 @@ def check_stability(logger, repeat_loop=10, repeat_restart=5, chaos_mode=True, m
|
|||
start_time = datetime.now()
|
||||
step_results = []
|
||||
|
||||
github_checks_outputter = get_gh_checks_outputter(kwargs)
|
||||
|
||||
for desc, step_func in steps:
|
||||
if max_time and datetime.now() - start_time > max_time:
|
||||
logger.info("::: Test verification is taking too long: Giving up!")
|
||||
|
@ -337,12 +365,16 @@ def check_stability(logger, repeat_loop=10, repeat_restart=5, chaos_mode=True, m
|
|||
|
||||
if inconsistent:
|
||||
step_results.append((desc, "FAIL"))
|
||||
if github_checks_outputter:
|
||||
write_github_checks_summary_inconsistent(github_checks_outputter.output, inconsistent, iterations)
|
||||
write_inconsistent(logger.info, inconsistent, iterations)
|
||||
write_summary(logger, step_results, "FAIL")
|
||||
return 1
|
||||
|
||||
if slow:
|
||||
step_results.append((desc, "FAIL"))
|
||||
if github_checks_outputter:
|
||||
write_github_checks_summary_slow_tests(github_checks_outputter.output, slow)
|
||||
write_slow_tests(logger.info, slow)
|
||||
write_summary(logger, step_results, "FAIL")
|
||||
return 1
|
||||
|
|
|
@ -348,6 +348,11 @@ scheme host and port.""")
|
|||
help="Command-line argument to forward to the "
|
||||
"Sauce Connect binary (repeatable)")
|
||||
|
||||
taskcluster_group = parser.add_argument_group("Taskcluster-specific")
|
||||
taskcluster_group.add_argument("--github-checks-text-file",
|
||||
dest="github_checks_text_file",
|
||||
help="Path to GitHub checks output file")
|
||||
|
||||
webkit_group = parser.add_argument_group("WebKit-specific")
|
||||
webkit_group.add_argument("--webkit-port", dest="webkit_port",
|
||||
help="WebKit port")
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
test(function () {
|
||||
assert_equals(typeof self.performance, "object");
|
||||
assert_equals(typeof self.performance.getEntriesByType, "function");
|
||||
|
||||
self.performance.mark("mark1");
|
||||
self.performance.measure("measure1");
|
||||
|
||||
const type = [
|
||||
'mark',
|
||||
'measure',
|
||||
];
|
||||
type.forEach(function(entryType) {
|
||||
if (PerformanceObserver.supportedEntryTypes.includes(entryType)) {
|
||||
const entryTypeUpperCased = entryType.toUpperCase();
|
||||
const entryTypeCapitalized = entryType[0].toUpperCase() + entryType.substring(1);
|
||||
const lowerList = self.performance.getEntriesByType(entryType);
|
||||
const upperList = self.performance.getEntriesByType(entryTypeUpperCased);
|
||||
const mixedList = self.performance.getEntriesByType(entryTypeCapitalized);
|
||||
|
||||
assert_greater_than(lowerList.length, 0, "Entries exist");
|
||||
assert_equals(upperList.length, 0, "getEntriesByType('" + entryTypeCapitalized + "').length");
|
||||
assert_equals(mixedList.length, 0, "getEntriesByType('" + entryTypeCapitalized + "').length");
|
||||
}
|
||||
});
|
||||
}, "getEntriesByType values are case sensitive");
|
|
@ -1,7 +1,7 @@
|
|||
import uuid
|
||||
import pytest
|
||||
|
||||
from six import text_type
|
||||
from six import string_types
|
||||
|
||||
from tests.support.asserts import assert_success
|
||||
|
||||
|
@ -9,21 +9,21 @@ from tests.support.asserts import assert_success
|
|||
def test_sessionid(new_session, add_browser_capabilities):
|
||||
response, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilities({})}})
|
||||
value = assert_success(response)
|
||||
assert isinstance(value["sessionId"], text_type)
|
||||
assert isinstance(value["sessionId"], string_types)
|
||||
uuid.UUID(hex=value["sessionId"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("capability, type", [
|
||||
("browserName", text_type),
|
||||
("browserVersion", text_type),
|
||||
("platformName", text_type),
|
||||
("browserName", string_types),
|
||||
("browserVersion", string_types),
|
||||
("platformName", string_types),
|
||||
("acceptInsecureCerts", bool),
|
||||
("pageLoadStrategy", text_type),
|
||||
("pageLoadStrategy", string_types),
|
||||
("proxy", dict),
|
||||
("setWindowRect", bool),
|
||||
("timeouts", dict),
|
||||
("strictFileInteractability", bool),
|
||||
("unhandledPromptBehavior", text_type),
|
||||
("unhandledPromptBehavior", string_types),
|
||||
])
|
||||
def test_capability_type(session, capability, type):
|
||||
assert isinstance(session.capabilities, dict)
|
||||
|
|
|
@ -209,3 +209,12 @@
|
|||
[WebGL test #44: attachment 7 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 0,0,255,0]
|
||||
expected: FAIL
|
||||
|
||||
[WebGL test #43: attachment 6 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 0,0,0,255]
|
||||
expected: FAIL
|
||||
|
||||
[WebGL test #44: attachment 7 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 255,0,0,255]
|
||||
expected: FAIL
|
||||
|
||||
[WebGL test #52: attachment 7 should be 0,255,0,255\nat (0, 0) expected: 0,255,0,255 was 255,0,0,255]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue