Update web-platform-tests to revision ad99a9e949c6006cc0f609501de77a0edb1e593a

This commit is contained in:
WPT Sync Bot 2020-08-05 08:22:29 +00:00
parent 6e28d7b3ec
commit f1ca6b4be4
89 changed files with 2406 additions and 267 deletions

View file

@ -1,4 +0,0 @@
[hit-test-floats-002.html]
[Hit test float]
expected: FAIL

View file

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

View file

@ -324,15 +324,9 @@
[<iframe>: separate response Content-Type: text/html */*;charset=gbk] [<iframe>: separate response Content-Type: text/html */*;charset=gbk]
expected: FAIL 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] [<iframe>: combined response Content-Type: text/html */*;charset=gbk]
expected: FAIL 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 expected: FAIL

View file

@ -53,6 +53,6 @@
[combined text/javascript ] [combined text/javascript ]
expected: FAIL expected: FAIL
[separate text/javascript x/x] [separate text/javascript; charset=windows-1252 text/javascript]
expected: FAIL expected: FAIL

View file

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

View file

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

View file

@ -0,0 +1,4 @@
[creating_browsing_context_test_01.html]
[first argument: absolute url]
expected: FAIL

View file

@ -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

View file

@ -1,16 +1,20 @@
[supported-elements.html] [supported-elements.html]
expected: TIMEOUT
[Contenteditable element should support autofocus] [Contenteditable element should support autofocus]
expected: FAIL expected: FAIL
[Host element with delegatesFocus including no focusable descendants should be skipped] [Host element with delegatesFocus including no focusable descendants should be skipped]
expected: FAIL expected: NOTRUN
[Element with tabindex should support autofocus] [Element with tabindex should support autofocus]
expected: FAIL expected: FAIL
[Area element should support autofocus] [Area element should support autofocus]
expected: FAIL expected: NOTRUN
[Host element with delegatesFocus should support autofocus] [Host element with delegatesFocus should support autofocus]
expected: FAIL expected: NOTRUN
[Non-HTMLElement should not support autofocus]
expected: TIMEOUT

View file

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

View file

@ -1,4 +1,5 @@
[iframe_sandbox_popups_escaping-2.html] [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] [Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: FAIL expected: FAIL

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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

View file

@ -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

View file

@ -1,4 +0,0 @@
[iframe_005.html]
[document.write external script into iframe write back into parent]
expected: FAIL

View file

@ -1,9 +1,10 @@
[promise-job-entry.html] [promise-job-entry.html]
expected: TIMEOUT
[Fulfillment handler on fulfilled promise] [Fulfillment handler on fulfilled promise]
expected: FAIL expected: FAIL
[Rejection handler on pending-then-rejected promise] [Rejection handler on pending-then-rejected promise]
expected: FAIL expected: TIMEOUT
[Sanity check: this all works as expected with no promises involved] [Sanity check: this all works as expected with no promises involved]
expected: FAIL expected: FAIL
@ -15,5 +16,5 @@
expected: FAIL expected: FAIL
[Fulfillment handler on pending-then-fulfilled promise] [Fulfillment handler on pending-then-fulfilled promise]
expected: FAIL expected: TIMEOUT

View file

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

View file

@ -1,7 +1,8 @@
[shared-worker-in-data-url-context.window.html] [shared-worker-in-data-url-context.window.html]
expected: TIMEOUT
[Create a shared worker in a data url frame] [Create a shared worker in a data url frame]
expected: FAIL expected: FAIL
[Create a data url shared worker in a data url frame] [Create a data url shared worker in a data url frame]
expected: FAIL expected: TIMEOUT

View file

@ -17086,6 +17086,41 @@
null, 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", "6d1eedb1fcbfda2bf27f74af1b34763adc62d599",
[] []
], ],
"not-embeddable-frame.html": [
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
[]
],
"not-embeddable-frame.html.sub.headers": [
"beecdb765cd02cc6f15700d773e66e8844b941da",
[]
],
"redirect-throw-function.sub.py": [ "redirect-throw-function.sub.py": [
"1bc89abf7176bbada8f0c8c35fd699f52bb0e8a9", "1bc89abf7176bbada8f0c8c35fd699f52bb0e8a9",
[] []
@ -270710,6 +270753,10 @@
}, },
"sandbox": { "sandbox": {
"support": { "support": {
"post-origin-on-load-worker.js": [
"21ce5748ab8b1edbfd04c8f77a3fba54739a73d5",
[]
],
"sandboxed-data-iframe.sub.html": [ "sandboxed-data-iframe.sub.html": [
"fafd4dc7707ab0d26ed2c67f34c26920649795f8", "fafd4dc7707ab0d26ed2c67f34c26920649795f8",
[] []
@ -322644,7 +322691,7 @@
[] []
], ],
"from-local-system.md": [ "from-local-system.md": [
"8c71e535baa907f1ef86641ee6211adb7d0c2423", "91823444d5d4813afb020d00b2fca188f4a22f21",
[] []
], ],
"from-web.md": [ "from-web.md": [
@ -337409,6 +337456,36 @@
[] []
], ],
"dynamic-import": { "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": [ "propagate-nonce-external.js": [
"3b97d2f40e914af5d22ecc338913dcb0591927ba", "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": { "the-windoworworkerglobalscope-mixin": {
"README.md": [ "README.md": [
"10ae3e5f03601a67e247f771cf73fdfddfdda12f", "10ae3e5f03601a67e247f771cf73fdfddfdda12f",
@ -340437,7 +340532,7 @@
[] []
], ],
"web-share.idl": [ "web-share.idl": [
"c29a29d0b4ede94153a75860344ab4824e91b6d5", "b66bcd81fe9c951c2e70a58596380353b7046d97",
[] []
], ],
"webaudio.idl": [ "webaudio.idl": [
@ -350532,7 +350627,7 @@
[] []
], ],
"taskcluster-run.py": [ "taskcluster-run.py": [
"61d05689287a33c3470089e929d0c8871b6a46ef", "d228e21990a1960bd19b3a1ea16207cc3fcfad55",
[] []
], ],
"tc": { "tc": {
@ -350545,13 +350640,17 @@
[] []
], ],
"decision.py": [ "decision.py": [
"0820a6798b5b233581eb561a973cb97ff2af44e1", "f52f5b093f0f41632613578f449188f82bc03ab9",
[] []
], ],
"download.py": [ "download.py": [
"359ec33405048c134ddcfac7a564ea9a17ac1b14", "359ec33405048c134ddcfac7a564ea9a17ac1b14",
[] []
], ],
"github_checks_output.py": [
"d799be911660f566701be5ebc3b90caf117075e2",
[]
],
"sink_task.py": [ "sink_task.py": [
"ba76d27640c86197736d7edc9e8ed86fe8ec4bd0", "ba76d27640c86197736d7edc9e8ed86fe8ec4bd0",
[] []
@ -350562,7 +350661,7 @@
], ],
"tasks": { "tasks": {
"test.yml": [ "test.yml": [
"dd14fc71b915e90f0625dc1120aed3c86a787e53", "2fc11e0b27b853c5af507581ebd44772741d20d0",
[] []
] ]
}, },
@ -357563,7 +357662,7 @@
[] []
], ],
"stability.py": [ "stability.py": [
"3f8989729fde0ee45cf783bc698307e38c844d90", "605b40281a1b559e47d6aa795bb5cbd4b8715177",
[] []
], ],
"testdriver-extra.js": [ "testdriver-extra.js": [
@ -357697,7 +357796,7 @@
[] []
], ],
"wptcommandline.py": [ "wptcommandline.py": [
"f322d77fbddefabc8fd187ebbc8cadaea8ea1086", "ea586825616132b410127124ad2152ae88554cde",
[] []
], ],
"wptlogging.py": [ "wptlogging.py": [
@ -384835,6 +384934,13 @@
} }
] ]
], ],
"report-frame-ancestors.sub.html": [
"a5aa1661c1085a61bedfe88b41ee389f62f577d2",
[
null,
{}
]
],
"report-multiple-violations-01.html": [ "report-multiple-violations-01.html": [
"7a92f1b955639eb26bfd4a737ee1a930fdec6592", "7a92f1b955639eb26bfd4a737ee1a930fdec6592",
[ [
@ -385004,6 +385110,13 @@
{} {}
] ]
], ],
"meta-element.sub.html": [
"cd8da8f14c4ad775b9034131315867dec08cd2e8",
[
null,
{}
]
],
"sandbox-allow-scripts-subframe.sub.html": [ "sandbox-allow-scripts-subframe.sub.html": [
"1d6db3cde71cddb66f5536720a632b537465cbff", "1d6db3cde71cddb66f5536720a632b537465cbff",
[ [
@ -457945,7 +458058,7 @@
] ]
], ],
"reporting-redirect-with-same-origin-allow-popups.https.html": [ "reporting-redirect-with-same-origin-allow-popups.https.html": [
"7dba76c4ef5434d49d7800da14eb980f79728f44", "bb76df811da5949c2d6f5196428a4a09d8bd9a56",
[ [
null, null,
{ {
@ -469554,6 +469667,29 @@
] ]
], ],
"dynamic-import": { "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": [ "dynamic-imports-credentials.sub.html": [
"b939a3ef1639db8027519ac004cd3197e254c0b9", "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": [ "input-events-typing.html": [
"a894beea9bd381313b999e45abe0b4b8f61c804b", "a894beea9bd381313b999e45abe0b4b8f61c804b",
[ [
@ -477048,7 +477202,7 @@
] ]
], ],
"invisible-images-composited-1.html": [ "invisible-images-composited-1.html": [
"495645ab41eccb80464a2ceb7de83a2136ecfbf7", "7723d2f2bea5b622395e09ae1bd7fd4bb6cf87bc",
[ [
null, 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": [ "local-shift-without-viewport-shift.html": [
"37729f1c13c298b5a2d95c46b7a4f199d8943022", "37729f1c13c298b5a2d95c46b7a4f199d8943022",
[ [
@ -477261,13 +477401,6 @@
{} {}
] ]
], ],
"outline.html": [
"1fed8e92f5e4b60cd83646405b6bd77e673c076f",
[
null,
{}
]
],
"partially-clipped-visual-rect.html": [ "partially-clipped-visual-rect.html": [
"3b18b98dd93312c37b9e2f25918df50266a09243", "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": [ "clearMarks.html": [
"92c60a3bbb856bd05bf13f12bde09dac7eefb6e6", "92c60a3bbb856bd05bf13f12bde09dac7eefb6e6",
[ [
@ -561705,7 +561849,7 @@
] ]
], ],
"response.py": [ "response.py": [
"dc1328998810faacf74f1b94b54ed59f48e84e4d", "cbe9e7d7fb14680f027d6fdc15d409ac19a7320c",
[ [
null, null,
{} {}

View file

@ -1,4 +0,0 @@
[hit-test-floats-002.html]
[Hit test float]
expected: FAIL

View file

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

View file

@ -324,15 +324,9 @@
[<iframe>: separate response Content-Type: text/html */*;charset=gbk] [<iframe>: separate response Content-Type: text/html */*;charset=gbk]
expected: FAIL 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] [<iframe>: combined response Content-Type: text/html */*;charset=gbk]
expected: FAIL 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 expected: FAIL

View file

@ -53,6 +53,6 @@
[combined text/javascript ] [combined text/javascript ]
expected: FAIL expected: FAIL
[separate text/javascript x/x] [separate text/javascript; charset=windows-1252 text/javascript]
expected: FAIL expected: FAIL

View file

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

View file

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

View file

@ -0,0 +1,4 @@
[creating_browsing_context_test_01.html]
[first argument: absolute url]
expected: FAIL

View file

@ -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

View file

@ -1,4 +1,5 @@
[supported-elements.html] [supported-elements.html]
expected: TIMEOUT
[Contenteditable element should support autofocus] [Contenteditable element should support autofocus]
expected: FAIL expected: FAIL
@ -6,11 +7,14 @@
expected: FAIL expected: FAIL
[Host element with delegatesFocus including no focusable descendants should be skipped] [Host element with delegatesFocus including no focusable descendants should be skipped]
expected: FAIL expected: NOTRUN
[Area element should support autofocus] [Area element should support autofocus]
expected: FAIL expected: NOTRUN
[Host element with delegatesFocus should support autofocus] [Host element with delegatesFocus should support autofocus]
expected: FAIL expected: NOTRUN
[Non-HTMLElement should not support autofocus]
expected: TIMEOUT

View file

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

View file

@ -1,4 +1,5 @@
[iframe_sandbox_popups_escaping-2.html] [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] [Check that popups from a sandboxed iframe escape the sandbox if\n allow-popups-to-escape-sandbox is used]
expected: FAIL expected: FAIL

View file

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

View file

@ -1,6 +1,6 @@
[iframe_sandbox_popups_nonescaping-1.html] [iframe_sandbox_popups_nonescaping-1.html]
type: testharness type: testharness
expected: TIMEOUT expected: CRASH
[Check that popups from a sandboxed iframe do not escape the sandbox] [Check that popups from a sandboxed iframe do not escape the sandbox]
expected: NOTRUN expected: NOTRUN

View file

@ -1,6 +1,5 @@
[iframe_sandbox_popups_nonescaping-2.html] [iframe_sandbox_popups_nonescaping-2.html]
type: testharness type: testharness
expected: CRASH
[Check that popups from a sandboxed iframe do not escape the sandbox] [Check that popups from a sandboxed iframe do not escape the sandbox]
expected: FAIL expected: FAIL

View file

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

View file

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

View file

@ -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

View file

@ -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

View file

@ -1,4 +0,0 @@
[iframe_005.html]
[document.write external script into iframe write back into parent]
expected: FAIL

View file

@ -1,9 +1,10 @@
[promise-job-entry.html] [promise-job-entry.html]
expected: TIMEOUT
[Fulfillment handler on fulfilled promise] [Fulfillment handler on fulfilled promise]
expected: FAIL expected: FAIL
[Rejection handler on pending-then-rejected promise] [Rejection handler on pending-then-rejected promise]
expected: FAIL expected: TIMEOUT
[Sanity check: this all works as expected with no promises involved] [Sanity check: this all works as expected with no promises involved]
expected: FAIL expected: FAIL
@ -15,5 +16,5 @@
expected: FAIL expected: FAIL
[Fulfillment handler on pending-then-fulfilled promise] [Fulfillment handler on pending-then-fulfilled promise]
expected: FAIL expected: TIMEOUT

View file

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

View file

@ -1,7 +1,8 @@
[shared-worker-in-data-url-context.window.html] [shared-worker-in-data-url-context.window.html]
expected: TIMEOUT
[Create a shared worker in a data url frame] [Create a shared worker in a data url frame]
expected: FAIL expected: FAIL
[Create a data url shared worker in a data url frame] [Create a data url shared worker in a data url frame]
expected: FAIL expected: TIMEOUT

View file

@ -1,4 +0,0 @@
[hit_test_multiple_sc.html]
[Hit testing works for following stacking contexts]
expected: FAIL

View file

@ -1,4 +0,0 @@
[hit-test-background.html]
[Hit testing backgrounds of content should report the same element as the content]
expected: FAIL

View file

@ -1,4 +0,0 @@
[hit_test_multiple_sc.html]
[Hit testing works for following stacking contexts]
expected: FAIL

View file

@ -1,4 +0,0 @@
[hit_test_pos_fixed.html]
[Hit-test of an element with position: fixed should discard scroll offset]
expected: FAIL

View file

@ -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>

View file

@ -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]}}

View file

@ -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>

View file

@ -0,0 +1 @@
postMessage(self.origin);

View file

@ -39,9 +39,6 @@ wherever you currently set your PATH.
See also [additional setup required to run Safari](safari.md). See also [additional setup required to run Safari](safari.md).
### Windows Setup ### 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 Download and install [Python 2.7](https://www.python.org/downloads). The
installer includes `pip` by default. installer includes `pip` by default.
@ -63,6 +60,15 @@ started using:
python wpt serve 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 ### `hosts` File Setup
To get the tests running, you need to set up the test domains in your To get the tests running, you need to set up the test domains in your

View file

@ -8,7 +8,6 @@
<script src=/common/get-host-info.sub.js></script> <script src=/common/get-host-info.sub.js></script>
<script src="/common/utils.js"></script> <script src="/common/utils.js"></script>
<script src="../resources/dispatcher.js"></script> <script src="../resources/dispatcher.js"></script>
<script src="../resources/try-access.js"></script>
<script> <script>
const directory = "/html/cross-origin-opener-policy/reporting"; const directory = "/html/cross-origin-opener-policy/reporting";

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -0,0 +1 @@
export const A = { "from": "alpha/import.js" };

View file

@ -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();

View file

@ -0,0 +1 @@
export const A = { "from": "beta/import.js" };

View file

@ -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)

View file

@ -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();

View file

@ -0,0 +1 @@
export const A = { "from": "gamma/import.js" };

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -0,0 +1,3 @@
onfetch = e => {
e.respondWith(fetch("handler.html"));
}

View file

@ -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));
}

View file

@ -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>

View file

@ -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 &nbsp; def</p>",
"<p>abc&nbsp;&nbsp; def</p>",
"<p>abc&nbsp; &nbsp;def</p>",
"<p>abc &nbsp;&nbsp;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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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>

View file

@ -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 &nbsp; def</p>",
"<p>abc&nbsp;&nbsp; def</p>",
"<p>abc&nbsp; &nbsp;def</p>",
"<p>abc &nbsp;&nbsp;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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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(/&nbsp;/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>

View file

@ -8,7 +8,7 @@ partial interface Navigator {
}; };
dictionary ShareData { dictionary ShareData {
FrozenArray<File> files; sequence<File> files;
USVString title; USVString title;
USVString text; USVString text;
USVString url; USVString url;

View file

@ -13,13 +13,17 @@
.displayNone { .displayNone {
display: none; display: none;
} }
.composited { .willChangeTransform {
will-change: transform; will-change: transform;
} }
.willChangeOpacity {
will-change: opacity;
}
</style> </style>
<img src='/images/blue.png' class='opacity0 composited' id='opacity0'/> <img src='/images/blue.png' class='opacity0 willChangeTransform' id='opacity0-willChangeTransform'/>
<img src='/images/green.png' class='visibilityHidden composited' id='visibilityHidden'/> <img src='/images/green.png' class='visibilityHidden willChangeTransform' id='visibilityHidden'/>
<img src='/images/red.png' class='displayNone composited' id='displayNone'/> <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='opacity0 composited'><img src='/images/yellow.png' id='divOpacity0'/></div>
<div class='visibilityHidden composited'><img src='/images/yellow.png' id='divVisibilityHidden'/></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> <div class='displayNone composited'><img src='/images/yellow.png' id='divDisplayNone'/></div>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -84,6 +84,9 @@ def main(product, commit_range, wpt_args):
command = ["python", "./wpt", "run"] + wpt_args + [product] command = ["python", "./wpt", "run"] + wpt_args + [product]
logger.info("Executing command: %s" % " ".join(command)) 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")) retcode = subprocess.call(command, env=dict(os.environ, TERM="dumb"))
if retcode != 0: if retcode != 0:
sys.exit(retcode) sys.exit(retcode)

View file

@ -241,6 +241,8 @@ def create_tc_task(event, task, taskgroup_id, depends_on_ids, env_extra=None):
}, },
"routes": ["checks"] "routes": ["checks"]
} }
if "extra" in task:
task_data["extra"].update(task["extra"])
if env_extra: if env_extra:
task_data["payload"]["env"].update(env_extra) task_data["payload"]["env"].update(env_extra)
if depends_on_ids: if depends_on_ids:

View file

@ -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

View file

@ -10,6 +10,13 @@ components:
public/results: public/results:
path: /home/test/artifacts path: /home/test/artifacts
type: directory 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: wpt-testharness:
chunks: 16 chunks: 16
@ -296,6 +303,7 @@ tasks:
--channel=${vars.channel} --channel=${vars.channel}
--verify --verify
--verify-no-chaos-mode --verify-no-chaos-mode
--github-checks-text-file="/home/test/artifacts/checkrun.md"
- wpt-${vars.browser}-${vars.channel}-results: - wpt-${vars.browser}-${vars.channel}-results:
use: use:

View file

@ -13,6 +13,7 @@ from mozlog.handlers import BaseHandler, StreamHandler, LogLevelFilter
here = os.path.dirname(__file__) here = os.path.dirname(__file__)
localpaths = imp.load_source("localpaths", os.path.abspath(os.path.join(here, os.pardir, os.pardir, "localpaths.py"))) 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 from wpt.markdown import markdown_adjust, table
@ -178,8 +179,32 @@ def err_string(results_dict, iterations):
return rv 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): 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") log("## Unstable results ##\n")
strings = [( strings = [(
"`%s`" % markdown_adjust(test), "`%s`" % markdown_adjust(test),
@ -191,6 +216,7 @@ def write_inconsistent(log, inconsistent, iterations):
def write_slow_tests(log, slow): def write_slow_tests(log, slow):
"""Output slow tests to the passed in logging function."""
log("## Slow tests ##\n") log("## Slow tests ##\n")
strings = [( strings = [(
"`%s`" % markdown_adjust(test), "`%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() start_time = datetime.now()
step_results = [] step_results = []
github_checks_outputter = get_gh_checks_outputter(kwargs)
for desc, step_func in steps: for desc, step_func in steps:
if max_time and datetime.now() - start_time > max_time: if max_time and datetime.now() - start_time > max_time:
logger.info("::: Test verification is taking too long: Giving up!") 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: if inconsistent:
step_results.append((desc, "FAIL")) 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_inconsistent(logger.info, inconsistent, iterations)
write_summary(logger, step_results, "FAIL") write_summary(logger, step_results, "FAIL")
return 1 return 1
if slow: if slow:
step_results.append((desc, "FAIL")) 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_slow_tests(logger.info, slow)
write_summary(logger, step_results, "FAIL") write_summary(logger, step_results, "FAIL")
return 1 return 1

View file

@ -348,6 +348,11 @@ scheme host and port.""")
help="Command-line argument to forward to the " help="Command-line argument to forward to the "
"Sauce Connect binary (repeatable)") "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 = parser.add_argument_group("WebKit-specific")
webkit_group.add_argument("--webkit-port", dest="webkit_port", webkit_group.add_argument("--webkit-port", dest="webkit_port",
help="WebKit port") help="WebKit port")

View file

@ -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");

View file

@ -1,7 +1,7 @@
import uuid import uuid
import pytest import pytest
from six import text_type from six import string_types
from tests.support.asserts import assert_success 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): def test_sessionid(new_session, add_browser_capabilities):
response, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilities({})}}) response, _ = new_session({"capabilities": {"alwaysMatch": add_browser_capabilities({})}})
value = assert_success(response) value = assert_success(response)
assert isinstance(value["sessionId"], text_type) assert isinstance(value["sessionId"], string_types)
uuid.UUID(hex=value["sessionId"]) uuid.UUID(hex=value["sessionId"])
@pytest.mark.parametrize("capability, type", [ @pytest.mark.parametrize("capability, type", [
("browserName", text_type), ("browserName", string_types),
("browserVersion", text_type), ("browserVersion", string_types),
("platformName", text_type), ("platformName", string_types),
("acceptInsecureCerts", bool), ("acceptInsecureCerts", bool),
("pageLoadStrategy", text_type), ("pageLoadStrategy", string_types),
("proxy", dict), ("proxy", dict),
("setWindowRect", bool), ("setWindowRect", bool),
("timeouts", dict), ("timeouts", dict),
("strictFileInteractability", bool), ("strictFileInteractability", bool),
("unhandledPromptBehavior", text_type), ("unhandledPromptBehavior", string_types),
]) ])
def test_capability_type(session, capability, type): def test_capability_type(session, capability, type):
assert isinstance(session.capabilities, dict) assert isinstance(session.capabilities, dict)

View file

@ -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] [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 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