mirror of
https://github.com/servo/servo.git
synced 2025-06-27 18:43:40 +01:00
Update web-platform-tests to revision b704e37ec97fe90b3a3d59c10f78c21907b5b576
This commit is contained in:
parent
cc0ac89e1a
commit
9f516d3717
70 changed files with 1688 additions and 806 deletions
|
@ -1,4 +1,5 @@
|
|||
[url-in-tags-revoke.window.html]
|
||||
expected: TIMEOUT
|
||||
[Fetching a blob URL immediately before revoking it works in an iframe.]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -14,3 +15,6 @@
|
|||
[Opening a blob URL in a new window by clicking an <a> tag works immediately before revoking the URL.]
|
||||
expected: FAIL
|
||||
|
||||
[Fetching a blob URL immediately before revoking it works in <script> tags.]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
[Revoke blob URL after creating Request, will fetch]
|
||||
expected: FAIL
|
||||
|
||||
[Revoke blob URL after calling fetch, fetch should succeed]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[url-with-fetch.any.html]
|
||||
[Untitled]
|
||||
|
@ -34,3 +37,6 @@
|
|||
[Revoke blob URL after creating Request, will fetch]
|
||||
expected: FAIL
|
||||
|
||||
[Revoke blob URL after calling fetch, fetch should succeed]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -147133,6 +147133,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-transforms/text-perspective-001.html": [
|
||||
[
|
||||
"/css/css-transforms/text-perspective-001.html",
|
||||
[
|
||||
[
|
||||
"about:blank",
|
||||
"!="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-transforms/transform-3d-rotateY-stair-above-001.xht": [
|
||||
[
|
||||
"/css/css-transforms/transform-3d-rotateY-stair-above-001.xht",
|
||||
|
@ -188569,6 +188581,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-block-size.html": [
|
||||
[
|
||||
"/html/rendering/replaced-elements/the-select-element/select-1-block-size.html",
|
||||
[
|
||||
[
|
||||
"/html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-line-height.html": [
|
||||
[
|
||||
"/html/rendering/replaced-elements/the-select-element/select-1-line-height.html",
|
||||
|
@ -188581,6 +188605,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-empty.html": [
|
||||
[
|
||||
"/html/rendering/replaced-elements/the-select-element/select-empty.html",
|
||||
[
|
||||
[
|
||||
"/html/rendering/replaced-elements/the-select-element/select-empty-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/the-css-user-agent-style-sheet-and-presentational-hints/body-bgcolor-attribute-change.html": [
|
||||
[
|
||||
"/html/rendering/the-css-user-agent-style-sheet-and-presentational-hints/body-bgcolor-attribute-change.html",
|
||||
|
@ -197254,6 +197290,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-common.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/nested-cloning-common.js": [
|
||||
[
|
||||
{}
|
||||
|
@ -280139,6 +280180,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/support/blue-32x32.png": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/variables/reftest.list": [
|
||||
[
|
||||
{}
|
||||
|
@ -291834,11 +291880,21 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-line-height-ref.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-empty-ref.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/rendering/replaced-elements/tools/gen-svgsizing-tests.py": [
|
||||
[
|
||||
{}
|
||||
|
@ -316839,6 +316895,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webdriver/tests/support/fixtures.py": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webdriver/tests/support/helpers.py": [
|
||||
[
|
||||
{}
|
||||
|
@ -316849,6 +316910,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webdriver/tests/support/image.py": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webdriver/tests/support/inline.py": [
|
||||
[
|
||||
{}
|
||||
|
@ -326161,6 +326227,16 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/get-databases.any.js": [
|
||||
[
|
||||
"/IndexedDB/get-databases.any.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/get-databases.any.worker.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/globalscope-indexedDB-SameObject.html": [
|
||||
[
|
||||
"/IndexedDB/globalscope-indexedDB-SameObject.html",
|
||||
|
@ -327949,6 +328025,78 @@
|
|||
}
|
||||
]
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.js": [
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.serviceworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.sharedworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.worker.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-indexes.any.js": [
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes.any.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes.any.serviceworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes.any.sharedworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-indexes.any.worker.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-store-cursors.any.js": [
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.serviceworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.sharedworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store-cursors.any.worker.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-store.any.js": [
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store.any.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store.any.serviceworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store.any.sharedworker.html",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"/IndexedDB/key-generators/reading-autoincrement-store.any.worker.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"IndexedDB/key_invalid.htm": [
|
||||
[
|
||||
"/IndexedDB/key_invalid.htm",
|
||||
|
@ -400575,6 +400723,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"service-workers/service-worker/postmessage-to-client-message-queue.https.html": [
|
||||
[
|
||||
"/service-workers/service-worker/postmessage-to-client-message-queue.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"service-workers/service-worker/postmessage-to-client.https.html": [
|
||||
[
|
||||
"/service-workers/service-worker/postmessage-to-client.https.html",
|
||||
|
@ -436035,7 +436189,7 @@
|
|||
"support"
|
||||
],
|
||||
".travis.yml": [
|
||||
"b14cfafbdf7a3b4380e746e939d1512ef55785ea",
|
||||
"9d3431bc444a2da1dc674ef6673f692742191ad6",
|
||||
"support"
|
||||
],
|
||||
".well-known/README.md": [
|
||||
|
@ -440750,6 +440904,10 @@
|
|||
"5db452ebafe68a095f083b65a713ba3e0ad40cf5",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/get-databases.any.js": [
|
||||
"f054e0fec2f0543eae7978303ae2a24858bdf245",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/globalscope-indexedDB-SameObject.html": [
|
||||
"7263aaaace5331310558e3f80b8509ac8246ed69",
|
||||
"testharness"
|
||||
|
@ -441343,7 +441501,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"IndexedDB/idbindex-rename-abort.html": [
|
||||
"b14d30122610bc7025a478c146fbac42128f7428",
|
||||
"b61988e9b5c764b5b72b4937b8d76fd3aed15e67",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/idbindex-rename-errors.html": [
|
||||
|
@ -441523,7 +441681,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"IndexedDB/idbobjectstore-rename-abort.html": [
|
||||
"6e16c31e339f731e218044ee9320edba3d965661",
|
||||
"75893cd84c012d4bc662ba11fd79ef1eacaf49cc",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/idbobjectstore-rename-errors.html": [
|
||||
|
@ -441926,6 +442084,26 @@
|
|||
"4dd5d9005b6cb6e4c2c7dccaef62804bfcdb73ec",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-common.js": [
|
||||
"45c8ffef923870909cb9b0e2af128081e5bce41a",
|
||||
"support"
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-indexes-cursors.any.js": [
|
||||
"d7938768fa152c20b4b58538350a51b78b38e445",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-indexes.any.js": [
|
||||
"d945b78bf3743bccd632dabdcb846af52c183110",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-store-cursors.any.js": [
|
||||
"05971098fa893ebe58de4b2ad05d84a4965b6e0d",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/key-generators/reading-autoincrement-store.any.js": [
|
||||
"bbba6a335139d5b2946b5f6d71a635fd5ee014c3",
|
||||
"testharness"
|
||||
],
|
||||
"IndexedDB/key_invalid.htm": [
|
||||
"30759d5ef3e594852990808621ce75c840d0ac39",
|
||||
"testharness"
|
||||
|
@ -442035,7 +442213,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"IndexedDB/support-promises.js": [
|
||||
"21e2163ec60eb3eee05269b83f583f77fad780eb",
|
||||
"433af5092701d617e2964f7d1ea3ea089b50c441",
|
||||
"support"
|
||||
],
|
||||
"IndexedDB/support.js": [
|
||||
|
@ -442131,7 +442309,7 @@
|
|||
"support"
|
||||
],
|
||||
"WebCryptoAPI/META.yml": [
|
||||
"ec95611b3fed980e2897a5fe2bedc6bb7fa2913d",
|
||||
"8f27e484996c51eb9ebbbd96902fa1f885af7be0",
|
||||
"support"
|
||||
],
|
||||
"WebCryptoAPI/README.md": [
|
||||
|
@ -445311,7 +445489,7 @@
|
|||
"manual"
|
||||
],
|
||||
"annotation-vocab/META.yml": [
|
||||
"030df88318ccaec889feaee3e25134f5504a678d",
|
||||
"f99f921d352cbffa724fb0fa031eb60d2ceb2b83",
|
||||
"support"
|
||||
],
|
||||
"annotation-vocab/tools/.gitignore": [
|
||||
|
@ -549075,7 +549253,7 @@
|
|||
"manual"
|
||||
],
|
||||
"css/css-grid/META.yml": [
|
||||
"f8482e16f983ca24e3333ae8989277f82b297ad1",
|
||||
"18c574ac68bac7e5b95085d96c49347d5eb36814",
|
||||
"support"
|
||||
],
|
||||
"css/css-grid/README.md": [
|
||||
|
@ -555963,7 +556141,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"css/css-properties-values-api/registered-property-computation.html": [
|
||||
"180cdf601edd4a82398d29239141bf38e55bd0c1",
|
||||
"2525e43ef51e1e5af94426346e51a68b87fea055",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-properties-values-api/registered-property-cssom.html": [
|
||||
|
@ -555971,15 +556149,15 @@
|
|||
"testharness"
|
||||
],
|
||||
"css/css-properties-values-api/registered-property-initial.html": [
|
||||
"24543d5c5fdc84706a28502d8cf8c2c7f925978e",
|
||||
"77aa9cd11a3eabfd154cc98869699e6f24c64c5c",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-properties-values-api/resources/utils.js": [
|
||||
"c4dc3fd5a8d98106395e3e99566f05d6d9a30c0c",
|
||||
"bef59560f68d84ed0d681bb22e0611ea2466024f",
|
||||
"support"
|
||||
],
|
||||
"css/css-properties-values-api/self-utils.html": [
|
||||
"530c5f677ad25858a06281a9e526584e57081af5",
|
||||
"05aa4b2fb03b29feee47177624715230768a44a0",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-properties-values-api/support/alt/alt.css": [
|
||||
|
@ -568398,6 +568576,10 @@
|
|||
"2145190fec4cddb59f18a5ac1d5bfead0ce548fa",
|
||||
"support"
|
||||
],
|
||||
"css/css-transforms/text-perspective-001.html": [
|
||||
"e98b3e73b36a323a60ad5ef74e090ff193ad41b9",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-transforms/transform-2d-getComputedStyle-001.html": [
|
||||
"a085b794fc4dbd01abd8cf779b691b541d0bf8e3",
|
||||
"testharness"
|
||||
|
@ -584891,7 +585073,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"css/geometry/META.yml": [
|
||||
"9e3a7979ed80210ccba78da767526aad875e00c2",
|
||||
"98a2ae9860b2d682220dbf21eb2f3606ca68ff61",
|
||||
"support"
|
||||
],
|
||||
"css/geometry/WebKitCSSMatrix.html": [
|
||||
|
@ -595359,19 +595541,19 @@
|
|||
"reftest"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/calc-background-position-1-ref.html": [
|
||||
"a9d8056ccab98b795824ab62f7ca86175bc46c39",
|
||||
"b64aa46bf2eeddfc89791c13f1cea946faefece5",
|
||||
"support"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/calc-background-position-1.html": [
|
||||
"2a8bfdf65b0d08eef12775c1abe0698615ddbb7d",
|
||||
"68351aef6e57dff3f065bad14630e81db171c0a6",
|
||||
"reftest"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/calc-background-size-1-ref.html": [
|
||||
"16b89c1d805078574f3557b3c7791cb2ebef3d21",
|
||||
"5385c46ef52592fa4535608ee09be865bff719ef",
|
||||
"support"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/calc-background-size-1.html": [
|
||||
"e91f8c26ce1ec937f5225eb570b104033edfc26a",
|
||||
"f52ceeeabe16a0011beb170d3bcc75852ae4e0cb",
|
||||
"reftest"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/calc-border-radius-1-ref.html": [
|
||||
|
@ -595570,6 +595752,10 @@
|
|||
"0f236cb3df999e9fb7d90ebf5ad05e97b3c269a1",
|
||||
"reftest"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/values3/support/blue-32x32.png": [
|
||||
"deefd19b2ac53bef91c82ed2f6f4ea5f53a9e34f",
|
||||
"support"
|
||||
],
|
||||
"css/vendor-imports/mozilla/mozilla-central-reftests/variables/reftest.list": [
|
||||
"baa90e4e9000c2df1f6bc487e25ecdf999a99cf5",
|
||||
"support"
|
||||
|
@ -608659,7 +608845,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/dom/elements/the-innertext-idl-attribute/getter-tests.js": [
|
||||
"5139ec97b05ce6d3cd9b84a20770065e9f81adb0",
|
||||
"4dd2b6be20619cde5f244ca76d239aa9bbc50044",
|
||||
"support"
|
||||
],
|
||||
"html/dom/elements/the-innertext-idl-attribute/getter.html": [
|
||||
|
@ -614194,6 +614380,14 @@
|
|||
"3b8d992cc2a07dfd902dbb1011e2c348e862baaa",
|
||||
"reftest"
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-block-size-ref.html": [
|
||||
"3e437494c0ad8dadd4d58b630194678753516fde",
|
||||
"support"
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-block-size.html": [
|
||||
"4aecc596ce693a6cff3f6ffd5dbac1fa4911dfe8",
|
||||
"reftest"
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-1-line-height-ref.html": [
|
||||
"26e5f33282192b10f56cd66fefeda2c1b9d9b389",
|
||||
"support"
|
||||
|
@ -614202,6 +614396,14 @@
|
|||
"e6383f089ffa5550005f99257ecac7984dd09110",
|
||||
"reftest"
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-empty-ref.html": [
|
||||
"31ba23a5cf86f161b1204ea3f4c9fef4585af909",
|
||||
"support"
|
||||
],
|
||||
"html/rendering/replaced-elements/the-select-element/select-empty.html": [
|
||||
"6568a6de34985a7fc201ce0bd530b86b145083e8",
|
||||
"reftest"
|
||||
],
|
||||
"html/rendering/replaced-elements/tools/gen-svgsizing-tests.py": [
|
||||
"5ba69f8ab5ba0a74810c570d9a4f3d7ddd90a3ba",
|
||||
"support"
|
||||
|
@ -636931,7 +637133,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"pointerevents/META.yml": [
|
||||
"ef94157ef9a9df762f940f1c6b04128dd69f4f3b",
|
||||
"be61ddddaf62acb3396ada6779ad3f50e6caa709",
|
||||
"support"
|
||||
],
|
||||
"pointerevents/README.md": [
|
||||
|
@ -649762,8 +649964,12 @@
|
|||
"29c056080c79d581975e0929dcebd84d63b86a20",
|
||||
"testharness"
|
||||
],
|
||||
"service-workers/service-worker/postmessage-to-client-message-queue.https.html": [
|
||||
"caa4f9445d3d8ad0ab92ba73713da17a33af185c",
|
||||
"testharness"
|
||||
],
|
||||
"service-workers/service-worker/postmessage-to-client.https.html": [
|
||||
"b1dc41a018f273832f4ac90c17b4b981f095b0ef",
|
||||
"15d2e889337078869e3c3e97d312649e6a8bd8b2",
|
||||
"testharness"
|
||||
],
|
||||
"service-workers/service-worker/postmessage.https.html": [
|
||||
|
@ -651987,7 +652193,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"speech-api/META.yml": [
|
||||
"17263d91d367f5571ac7df3616aa026bdb4f6433",
|
||||
"ac4b89b03490dbb46c257a2e5fdec3a741acdd52",
|
||||
"support"
|
||||
],
|
||||
"speech-api/SpeechRecognition-abort-manual.https.html": [
|
||||
|
@ -653319,7 +653525,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"subresource-integrity/META.yml": [
|
||||
"740ad1412f671ad86d88098ae437a817cbd620d5",
|
||||
"2b8891ec6b498cc6b24df46e21fffad437732b54",
|
||||
"support"
|
||||
],
|
||||
"subresource-integrity/alternate.css": [
|
||||
|
@ -661615,7 +661821,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wpt/run.py": [
|
||||
"a2cd1c0b115dff81a4cc0f356eb351fab51998f1",
|
||||
"b977d8a0cd68ccb00b299c7840415f843c16f949",
|
||||
"support"
|
||||
],
|
||||
"tools/wpt/testfiles.py": [
|
||||
|
@ -661643,7 +661849,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wpt/utils.py": [
|
||||
"1e622a63859ac5da0d1aa0015a971083b23adbc9",
|
||||
"fa60230389deb56686f6753171482b69ac28983c",
|
||||
"support"
|
||||
],
|
||||
"tools/wpt/virtualenv.py": [
|
||||
|
@ -662111,7 +662317,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/testrunner.py": [
|
||||
"2b7c091c84722c750b46d6143c74c8d329a7fd99",
|
||||
"e819f242e2df532d6e9c62e9292e1f563047c148",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/tests/__init__.py": [
|
||||
|
@ -662255,7 +662461,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptrunner.py": [
|
||||
"0a5b1352e212fcb702f1824293a774ea48d78ef1",
|
||||
"d0c1106b0f9bb1f2aa727e263cd1e74ab1b04c01",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wpttest.py": [
|
||||
|
@ -663307,7 +663513,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"url/META.yml": [
|
||||
"459152f6f078042714905b3e1d2eaba1c415807b",
|
||||
"3a789a0d513f0a78bf362dd73c8a807d0cd55a50",
|
||||
"support"
|
||||
],
|
||||
"url/README.md": [
|
||||
|
@ -665667,7 +665873,7 @@
|
|||
"support"
|
||||
],
|
||||
"webaudio/META.yml": [
|
||||
"37276da53345515f79453de8c5ade6037ff6f9eb",
|
||||
"e8f8cc59489e381dba1fd35e9d088a6de86a3783",
|
||||
"support"
|
||||
],
|
||||
"webaudio/README.md": [
|
||||
|
@ -666755,7 +666961,7 @@
|
|||
"wdspec"
|
||||
],
|
||||
"webdriver/tests/conftest.py": [
|
||||
"d16883256aca4f600400f060719d0a7ac8d16dfd",
|
||||
"42b82c9ecf29a1aed48bfa959c20aba6edd1319e",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/delete_all_cookies/__init__.py": [
|
||||
|
@ -666819,7 +667025,7 @@
|
|||
"wdspec"
|
||||
],
|
||||
"webdriver/tests/element_click/center_point.py": [
|
||||
"b3d2ea7a1098266530cb6e835861dcc7336b7091",
|
||||
"21bf8f31fd8dd1c961008ab74330956dd11e14f2",
|
||||
"wdspec"
|
||||
],
|
||||
"webdriver/tests/element_click/click.py": [
|
||||
|
@ -667475,23 +667681,31 @@
|
|||
"support"
|
||||
],
|
||||
"webdriver/tests/support/asserts.py": [
|
||||
"cdf313bc04b3e96e999b559de506b5595efe8419",
|
||||
"1dea6ce68779269b005061a391f7553a6741157f",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/defaults.py": [
|
||||
"c2020527a6f38a628b2c1a4199caaff46cf0c36b",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/fixtures.py": [
|
||||
"d16883256aca4f600400f060719d0a7ac8d16dfd",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/helpers.py": [
|
||||
"b2db3e7b0d338f1325214cd8019b7cac613dd8b1",
|
||||
"5dd7a323d8cc1a166acdb1b6445015b8b19d8c76",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/http_request.py": [
|
||||
"5e46d97017e14ba009d4d1ed6d62bb5012f48d15",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/image.py": [
|
||||
"1eb3a187a43b86ffe752d4d73f6e639bdd9e96da",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/inline.py": [
|
||||
"3bf56c84bedb47e024a88983fa15c232ddba7899",
|
||||
"8b4f1657cffb193511da346bc4c236aac1d70308",
|
||||
"support"
|
||||
],
|
||||
"webdriver/tests/support/merge_dictionaries.py": [
|
||||
|
@ -675751,7 +675965,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"xhr/send-content-type-charset.htm": [
|
||||
"4e75df234682c91b7effa0de52f5f95a3ac438a4",
|
||||
"0a91e1fbd7e061df3123163e049cc8aab90a67e2",
|
||||
"testharness"
|
||||
],
|
||||
"xhr/send-content-type-string.htm": [
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
[Matching font-weight: '500' should prefer '501 550' over '502 560']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-weight: '501' should prefer '501' over '502 510']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-weight: '501' should prefer '502 510' over '503 520']
|
||||
expected: FAIL
|
||||
|
||||
|
@ -137,9 +134,6 @@
|
|||
[Matching font-style: 'oblique 21deg' should prefer 'oblique -50deg -20deg' over 'oblique -40deg -30deg']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 10deg' over 'oblique 5deg']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-style: 'oblique 10deg' should prefer 'oblique 5deg' over 'oblique 15deg 20deg']
|
||||
expected: FAIL
|
||||
|
||||
|
@ -203,9 +197,6 @@
|
|||
[Matching font-style: 'oblique -10deg' should prefer 'oblique 0deg 10deg' over 'oblique 40deg 50deg']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -20deg' over 'oblique -60deg -40deg']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-style: 'oblique -20deg' should prefer 'oblique -10deg' over 'italic']
|
||||
expected: FAIL
|
||||
|
||||
|
@ -332,3 +323,6 @@
|
|||
[Matching font-weight: '399' should prefer '350 399' over '340 360']
|
||||
expected: FAIL
|
||||
|
||||
[Matching font-weight: '500' should prefer '450 460' over '400']
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -71,51 +71,9 @@
|
|||
[text-indent intermediate]
|
||||
expected: FAIL
|
||||
|
||||
[clip end]
|
||||
[opacity end]
|
||||
expected: FAIL
|
||||
|
||||
[border-top-width end]
|
||||
expected: FAIL
|
||||
|
||||
[border-left-width end]
|
||||
expected: FAIL
|
||||
|
||||
[font-size end]
|
||||
expected: FAIL
|
||||
|
||||
[vertical-align end]
|
||||
expected: FAIL
|
||||
|
||||
[border-right-color end]
|
||||
expected: FAIL
|
||||
|
||||
[margin-right end]
|
||||
expected: FAIL
|
||||
|
||||
[max-width end]
|
||||
expected: FAIL
|
||||
|
||||
[height end]
|
||||
expected: FAIL
|
||||
|
||||
[bottom end]
|
||||
expected: FAIL
|
||||
|
||||
[top end]
|
||||
expected: FAIL
|
||||
|
||||
[font-weight end]
|
||||
expected: FAIL
|
||||
|
||||
[border-left-color end]
|
||||
expected: FAIL
|
||||
|
||||
[margin-bottom end]
|
||||
expected: FAIL
|
||||
|
||||
[border-right-width end]
|
||||
expected: FAIL
|
||||
|
||||
[padding-bottom intermediate]
|
||||
[z-index end]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
type: testharness
|
||||
|
||||
[single-byte-decoder.html?document]
|
||||
expected: TIMEOUT
|
||||
expected: CRASH
|
||||
[windows-1254: iso_8859-9 (document.characterSet and document.inputEncoding)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -509,6 +509,7 @@
|
|||
|
||||
|
||||
[single-byte-decoder.html?XMLHttpRequest]
|
||||
expected: CRASH
|
||||
[ISO-8859-2: iso_8859-2:1987 (XMLHttpRequest)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[beforeunload-canceling.html]
|
||||
expected: TIMEOUT
|
||||
[Returning 0 with a real iframe unloading; setting returnValue to foo]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[traverse_the_history_1.html]
|
||||
[Multiple history traversals from the same task]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
[traverse_the_history_5.html]
|
||||
[traverse_the_history_4.html]
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
|
@ -24,9 +24,6 @@
|
|||
[Set HTTP URL frame location.protocol to gopher]
|
||||
expected: FAIL
|
||||
|
||||
[Set HTTP URL frame location.protocol to x]
|
||||
expected: FAIL
|
||||
|
||||
[Set HTTP URL frame location.protocol to http+x]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -266,3 +266,15 @@
|
|||
[Whitespace around <img> should not be collapsed ("<div>abc <img width=1 height=1> def")]
|
||||
expected: FAIL
|
||||
|
||||
[text-transform handles Turkish casing ("<div><div lang='tr' style='text-transform:uppercase'>i ı")]
|
||||
expected: FAIL
|
||||
|
||||
[display:table-row on the element itself ("<div style='display:table-row'>")]
|
||||
expected: FAIL
|
||||
|
||||
[display:table-cell on the element itself ("<div style='display:table-cell'>")]
|
||||
expected: FAIL
|
||||
|
||||
[<br> ("<br>")]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[select-1-block-size.html]
|
||||
expected: FAIL
|
|
@ -0,0 +1,2 @@
|
|||
[select-empty.html]
|
||||
expected: FAIL
|
|
@ -5,5 +5,5 @@
|
|||
expected: NOTRUN
|
||||
|
||||
[calling play() on a sufficiently long video should trigger timeupdate event]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[toggleEvent.html]
|
||||
[Calling open twice on 'details' fires only one toggle event]
|
||||
expected: FAIL
|
||||
|
||||
[Setting open=true to opened 'details' element should not fire a toggle event at the 'details' element]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[script-onerror-insertion-point-2.html]
|
||||
expected: TIMEOUT
|
|
@ -2,6 +2,3 @@
|
|||
[document.open() after parser is aborted]
|
||||
expected: FAIL
|
||||
|
||||
[async document.open() after parser is aborted]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
[request.formData() with input: &&&a=b&&&&c=d&]
|
||||
expected: FAIL
|
||||
|
||||
[response.formData() with input: a&b&c]
|
||||
[request.formData() with input: a&b&c]
|
||||
expected: FAIL
|
||||
|
||||
[request.formData() with input: a&b&c]
|
||||
[request.formData() with input: _charset_=windows-1252&test=%C2x]
|
||||
expected: FAIL
|
||||
|
||||
[response.formData() with input: _charset_=windows-1252&test=%C2x]
|
||||
expected: FAIL
|
||||
|
||||
[request.formData() with input: a=b&c=d&]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
|
@ -25,6 +31,6 @@
|
|||
[request.formData() with input: &&&a=b&&&&c=d&]
|
||||
expected: FAIL
|
||||
|
||||
[response.formData() with input: _charset_=windows-1252&test=%C2x]
|
||||
[request.formData() with input: a=b&c=d&]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[import-in-moduleworker.html]
|
||||
expected: ERROR
|
||||
[Base URL in module dedicated workers: import]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -45,3 +45,21 @@
|
|||
[unknown parameters need to be preserved]
|
||||
expected: FAIL
|
||||
|
||||
[charset with space that is UTF-8 does not change]
|
||||
expected: FAIL
|
||||
|
||||
[charset in double quotes with backslashes that is UTF-8 does not change]
|
||||
expected: FAIL
|
||||
|
||||
[If charset= param is UTF-8 (case-insensitive), it should not be changed (bogus charset)]
|
||||
expected: FAIL
|
||||
|
||||
[Multiple non-UTF-8 charset parameters deduplicate, bogus parameter dropped]
|
||||
expected: FAIL
|
||||
|
||||
[If charset= param is UTF-8 (case-insensitive), it should not be changed]
|
||||
expected: FAIL
|
||||
|
||||
[charset in double quotes that is UTF-8 does not change]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[transition_calc_implicit.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[unitless-length.html]
|
||||
expected: TIMEOUT
|
|
@ -74,7 +74,7 @@ matrix:
|
|||
os: linux
|
||||
python: "3.6"
|
||||
env: JOB=tools_unittest TOXENV=py36 HYPOTHESIS_PROFILE=ci SCRIPT=tools/ci/ci_tools_unittest.sh
|
||||
- name: "tools/wpt/ unittests"
|
||||
- name: "tools/wpt/ tests"
|
||||
if: type = pull_request
|
||||
os: linux
|
||||
python: "2.7"
|
||||
|
|
62
tests/wpt/web-platform-tests/IndexedDB/get-databases.any.js
Normal file
62
tests/wpt/web-platform-tests/IndexedDB/get-databases.any.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
// META: script=support-promises.js
|
||||
|
||||
promise_test(async testCase => {
|
||||
// Delete any databases that may not have been cleaned up after
|
||||
// previous test runs.
|
||||
await deleteAllDatabases(testCase);
|
||||
|
||||
const db_name = "TestDatabase";
|
||||
const db = await createNamedDatabase(testCase, db_name, ()=>{});
|
||||
const databases_promise = await indexedDB.databases();
|
||||
const expected_result = [
|
||||
{"name": db_name, "version": 1},
|
||||
];
|
||||
assert_object_equals(
|
||||
databases_promise,
|
||||
expected_result,
|
||||
"Call to databases() did not retrieve the single expected result.");
|
||||
}, "Enumerate one database.");
|
||||
|
||||
promise_test(async testCase => {
|
||||
// Delete any databases that may not have been cleaned up after previous test
|
||||
// runs.
|
||||
await deleteAllDatabases(testCase);
|
||||
|
||||
const db_name1 = "TestDatabase1";
|
||||
const db_name2 = "TestDatabase2";
|
||||
const db_name3 = "TestDatabase3";
|
||||
const db1 = await createNamedDatabase(testCase, db_name1, ()=>{});
|
||||
const db2 = await createNamedDatabase(testCase, db_name2, ()=>{});
|
||||
const db3 = await createNamedDatabase(testCase, db_name3, ()=>{});
|
||||
const databases_promise = await indexedDB.databases();
|
||||
const expected_result = [
|
||||
{"name": db_name1, "version": 1},
|
||||
{"name": db_name2, "version": 1},
|
||||
{"name": db_name3, "version": 1},
|
||||
];
|
||||
assert_object_equals(
|
||||
databases_promise,
|
||||
expected_result,
|
||||
"Call to databases() did not retrieve the multiple expected results");
|
||||
}, "Enumerate multiple databases.");
|
||||
|
||||
promise_test(async testCase => {
|
||||
// Add some databases and close their connections.
|
||||
const db1 = await createNamedDatabase(testCase, "DB1", ()=>{});
|
||||
const db2 = await createNamedDatabase(testCase, "DB2", ()=>{});
|
||||
db1.onversionchange = () => { db1.close() };
|
||||
db2.onversionchange = () => { db2.close() };
|
||||
|
||||
// Delete any databases that may not have been cleaned up after previous test
|
||||
// runs as well as the two databases made above.
|
||||
await deleteAllDatabases(testCase);
|
||||
|
||||
// Make sure the databases are no longer returned.
|
||||
const databases_promise = await indexedDB.databases();
|
||||
assert_object_equals(
|
||||
databases_promise,
|
||||
[],
|
||||
"Call to databases() found database it should not have.")
|
||||
}, "Make sure an empty list is returned for the case of no databases.");
|
||||
|
||||
done();
|
|
@ -39,9 +39,8 @@ promise_test(testCase => {
|
|||
'versionchange transaction is aborted');
|
||||
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
return promiseForRequest(testCase, request);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
|
@ -95,9 +94,8 @@ promise_test(testCase => {
|
|||
'versionchange transaction is aborted');
|
||||
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
return promiseForRequest(testCase, request);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('not_books', 'readonly');
|
||||
const store = transaction.objectStore('not_books');
|
||||
assert_array_equals(
|
||||
|
|
|
@ -40,9 +40,8 @@ promise_test(testCase => {
|
|||
'IDBObjectStore.name should not reflect the rename any more ' +
|
||||
'after the versionchange transaction is aborted');
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
return promiseForRequest(testCase, request);
|
||||
}).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not reflect the rename ' +
|
||||
|
@ -107,9 +106,8 @@ promise_test(testCase => {
|
|||
'should be empty after the versionchange transaction is aborted ' +
|
||||
'returns');
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
return promiseForRequest(testCase, request);
|
||||
}).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, [],
|
||||
'IDBDatabase.objectStoreNames should not reflect the creation or ' +
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
// Returns the "name" property written to the object with the given ID.
|
||||
function nameForId(id) {
|
||||
return `Object ${id}`;
|
||||
}
|
||||
|
||||
// Initial database setup used by all the reading-autoincrement tests.
|
||||
async function setupAutoincrementDatabase(testCase) {
|
||||
const database = await createDatabase(testCase, database => {
|
||||
const store = database.createObjectStore(
|
||||
'store', { autoIncrement: true, keyPath: 'id' });
|
||||
store.createIndex('by_name', 'name', { unique: true });
|
||||
store.createIndex('by_id', 'id', { unique: true });
|
||||
|
||||
// Cover writing from the initial upgrade transaction.
|
||||
for (let i = 1; i <= 16; ++i) {
|
||||
if (i % 2 == 0) {
|
||||
store.put({name: nameForId(i), id: i});
|
||||
} else {
|
||||
store.put({name: nameForId(i)});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Cover writing from a subsequent transaction.
|
||||
const transaction = database.transaction(['store'], 'readwrite');
|
||||
const store = transaction.objectStore('store');
|
||||
for (let i = 17; i <= 32; ++i) {
|
||||
if (i % 2 == 0) {
|
||||
store.put({name: nameForId(i), id: i});
|
||||
} else {
|
||||
store.put({name: nameForId(i)});
|
||||
}
|
||||
}
|
||||
await promiseForTransaction(testCase, transaction);
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
// Returns the IDs used by the object store, sorted as strings.
|
||||
//
|
||||
// This is used to determine the correct order of records when retrieved from an
|
||||
// index that uses stringified IDs.
|
||||
function idsSortedByStringCompare() {
|
||||
const stringIds = [];
|
||||
for (let i = 1; i <= 32; ++i)
|
||||
stringIds.push(i);
|
||||
stringIds.sort((a, b) => indexedDB.cmp(`${a}`, `${b}`));
|
||||
return stringIds;
|
||||
}
|
||||
|
||||
async function iterateCursor(testCase, cursorRequest, callback) {
|
||||
// This uses requestWatcher() directly instead of using promiseForRequest()
|
||||
// inside the loop to avoid creating multiple EventWatcher instances. In turn,
|
||||
// this avoids ending up with O(N) listeners for the request and O(N^2)
|
||||
// dispatched events.
|
||||
const eventWatcher = requestWatcher(testCase, cursorRequest);
|
||||
while (true) {
|
||||
const event = await eventWatcher.wait_for('success');
|
||||
const cursor = event.target.result;
|
||||
if (cursor === null)
|
||||
return;
|
||||
callback(cursor);
|
||||
cursor.continue();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns equivalent information to getAllKeys() by iterating a cursor.
|
||||
//
|
||||
// Returns an array with one dictionary per entry in the source. The dictionary
|
||||
// has the properties "key" and "primaryKey".
|
||||
async function getAllKeysViaCursor(testCase, cursorSource) {
|
||||
const results = [];
|
||||
await iterateCursor(testCase, cursorSource.openKeyCursor(), cursor => {
|
||||
results.push({ key: cursor.key, primaryKey: cursor.primaryKey });
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
// Returns equivalent information to getAll() by iterating a cursor.
|
||||
//
|
||||
// Returns an array with one dictionary per entry in the source. The dictionary
|
||||
// has the properties "key", "primaryKey" and "value".
|
||||
async function getAllViaCursor(testCase, cursorSource) {
|
||||
const results = [];
|
||||
await iterateCursor(testCase, cursorSource.openCursor(), cursor => {
|
||||
results.push({
|
||||
key: cursor.key,
|
||||
primaryKey: cursor.primaryKey,
|
||||
value: cursor.value,
|
||||
});
|
||||
});
|
||||
return results;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// META: global=window,dedicatedworker,sharedworker,serviceworker
|
||||
// META: script=../support-promises.js
|
||||
// META: script=./reading-autoincrement-common.js
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_id');
|
||||
|
||||
const result = await getAllViaCursor(testCase, index);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].key, i, 'Autoincrement index key');
|
||||
assert_equals(result[i - 1].primaryKey, i, 'Autoincrement primary key');
|
||||
assert_equals(result[i - 1].value.id, i, 'Autoincrement key in value');
|
||||
assert_equals(result[i - 1].value.name, nameForId(i),
|
||||
'String property in value');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.openCursor() iterates over an index on the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_id');
|
||||
|
||||
const result = await getAllKeysViaCursor(testCase, index);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].key, i, 'Autoincrement index key');
|
||||
assert_equals(result[i - 1].primaryKey, i, 'Autoincrement primary key');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.openKeyCursor() iterates over an index on the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_name');
|
||||
|
||||
const stringSortedIds = idsSortedByStringCompare();
|
||||
|
||||
const result = await getAllViaCursor(testCase, index);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].key, nameForId(stringSortedIds[i - 1]),
|
||||
'Index key');
|
||||
assert_equals(result[i - 1].primaryKey, stringSortedIds[i - 1],
|
||||
'Autoincrement primary key');
|
||||
assert_equals(result[i - 1].value.id, stringSortedIds[i - 1],
|
||||
'Autoincrement key in value');
|
||||
assert_equals(result[i - 1].value.name, nameForId(stringSortedIds[i - 1]),
|
||||
'String property in value');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.openCursor() iterates over an index not covering the ' +
|
||||
'autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_name');
|
||||
|
||||
const stringSortedIds = idsSortedByStringCompare();
|
||||
|
||||
const result = await getAllKeysViaCursor(testCase, index);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].key, nameForId(stringSortedIds[i - 1]),
|
||||
'Index key');
|
||||
assert_equals(result[i - 1].primaryKey, stringSortedIds[i - 1],
|
||||
'Autoincrement primary key');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.openKeyCursor() iterates over an index not covering the ' +
|
||||
'autoincrement key');
|
|
@ -0,0 +1,108 @@
|
|||
// META: global=window,dedicatedworker,sharedworker,serviceworker
|
||||
// META: script=../support-promises.js
|
||||
// META: script=./reading-autoincrement-common.js
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_id');
|
||||
const request = index.getAll();
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].id, i, 'Autoincrement key');
|
||||
assert_equals(result[i - 1].name, nameForId(i), 'String property');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.getAll() for an index on the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_id');
|
||||
const request = index.getAllKeys();
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i)
|
||||
assert_equals(result[i - 1], i, 'Autoincrement key');
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.getAllKeys() for an index on the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_id');
|
||||
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
const request = index.get(i);
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.id, i, 'autoincrement key');
|
||||
assert_equals(result.name, nameForId(i), 'string property');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.get() for an index on the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const stringSortedIds = idsSortedByStringCompare();
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_name');
|
||||
const request = index.getAll();
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].id, stringSortedIds[i - 1],
|
||||
'autoincrement key');
|
||||
assert_equals(result[i - 1].name, nameForId(stringSortedIds[i - 1]),
|
||||
'string property');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.getAll() for an index not covering the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const stringSortedIds = idsSortedByStringCompare();
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_name');
|
||||
const request = index.getAllKeys();
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i)
|
||||
assert_equals(result[i - 1], stringSortedIds[i - 1], 'String property');
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.getAllKeys() returns correct result for an index not covering ' +
|
||||
'the autoincrement key');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const index = store.index('by_name');
|
||||
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
const request = index.get(nameForId(i));
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.id, i, 'Autoincrement key');
|
||||
assert_equals(result.name, nameForId(i), 'String property');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBIndex.get() for an index not covering the autoincrement key');
|
|
@ -0,0 +1,38 @@
|
|||
// META: global=window,dedicatedworker,sharedworker,serviceworker
|
||||
// META: script=../support-promises.js
|
||||
// META: script=./reading-autoincrement-common.js
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
|
||||
const result = await getAllViaCursor(testCase, store);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].key, i, 'Autoincrement key');
|
||||
assert_equals(result[i - 1].primaryKey, i, 'Autoincrement primary key');
|
||||
assert_equals(result[i - 1].value.id, i, 'Autoincrement key in value');
|
||||
assert_equals(result[i - 1].value.name, nameForId(i),
|
||||
'string property in value');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBObjectStore.openCursor() iterates over an autoincrement store');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
|
||||
const result = await getAllKeysViaCursor(testCase, store);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].key, i, 'Incorrect autoincrement key');
|
||||
assert_equals(result[i - 1].primaryKey, i, 'Incorrect primary key');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBObjectStore.openKeyCursor() iterates over an autoincrement store');
|
|
@ -0,0 +1,49 @@
|
|||
// META: global=window,dedicatedworker,sharedworker,serviceworker
|
||||
// META: script=../support-promises.js
|
||||
// META: script=./reading-autoincrement-common.js
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const request = store.getAll();
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
assert_equals(result[i - 1].id, i, 'Autoincrement key');
|
||||
assert_equals(result[i - 1].name, nameForId(i), 'String property');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBObjectStore.getAll() for an autoincrement store');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
const request = store.getAllKeys();
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.length, 32);
|
||||
for (let i = 1; i <= 32; ++i)
|
||||
assert_equals(result[i - 1], i, 'Autoincrement key');
|
||||
|
||||
database.close();
|
||||
}, 'IDBObjectStore.getAllKeys() for an autoincrement store');
|
||||
|
||||
promise_test(async testCase => {
|
||||
const database = await setupAutoincrementDatabase(testCase);
|
||||
|
||||
const transaction = database.transaction(['store'], 'readonly');
|
||||
const store = transaction.objectStore('store');
|
||||
|
||||
for (let i = 1; i <= 32; ++i) {
|
||||
const request = store.get(i);
|
||||
const result = await promiseForRequest(testCase, request);
|
||||
assert_equals(result.id, i, 'Autoincrement key');
|
||||
assert_equals(result.name, nameForId(i), 'String property');
|
||||
}
|
||||
|
||||
database.close();
|
||||
}, 'IDBObjectStore.get() for an autoincrement store');
|
|
@ -5,11 +5,39 @@ function databaseName(testCase) {
|
|||
return 'db' + self.location.pathname + '-' + testCase.name;
|
||||
}
|
||||
|
||||
// Creates an EventWatcher covering all the events that can be issued by
|
||||
// IndexedDB requests and transactions.
|
||||
// EventWatcher covering all the events defined on IndexedDB requests.
|
||||
//
|
||||
// The events cover IDBRequest and IDBOpenDBRequest.
|
||||
function requestWatcher(testCase, request) {
|
||||
return new EventWatcher(testCase, request,
|
||||
['abort', 'blocked', 'complete', 'error', 'success', 'upgradeneeded']);
|
||||
['blocked', 'error', 'success', 'upgradeneeded']);
|
||||
}
|
||||
|
||||
// EventWatcher covering all the events defined on IndexedDB transactions.
|
||||
//
|
||||
// The events cover IDBTransaction.
|
||||
function transactionWatcher(testCase, request) {
|
||||
return new EventWatcher(testCase, request, ['abort', 'complete', 'error']);
|
||||
}
|
||||
|
||||
// Promise that resolves with an IDBRequest's result.
|
||||
//
|
||||
// The promise only resolves if IDBRequest receives the "success" event. Any
|
||||
// other event causes the promise to reject with an error. This is correct in
|
||||
// most cases, but insufficient for indexedDB.open(), which issues
|
||||
// "upgradeneded" events under normal operation.
|
||||
function promiseForRequest(testCase, request) {
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(event => event.target.result);
|
||||
}
|
||||
|
||||
// Promise that resolves when an IDBTransaction completes.
|
||||
//
|
||||
// The promise resolves with undefined if IDBTransaction receives the "complete"
|
||||
// event, and rejects with an error for any other event.
|
||||
function promiseForTransaction(testCase, request) {
|
||||
const eventWatcher = transactionWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('complete').then(() => {});
|
||||
}
|
||||
|
||||
// Migrates an IndexedDB database whose name is unique for the test case.
|
||||
|
@ -64,7 +92,7 @@ function migrateNamedDatabase(
|
|||
requestEventPromise = new Promise((resolve, reject) => {
|
||||
request.onerror = event => {
|
||||
event.preventDefault();
|
||||
resolve(event);
|
||||
resolve(event.target.error);
|
||||
};
|
||||
request.onsuccess = () => reject(new Error(
|
||||
'indexedDB.open should not succeed for an aborted ' +
|
||||
|
@ -79,8 +107,7 @@ function migrateNamedDatabase(
|
|||
if (!shouldBeAborted) {
|
||||
request.onerror = null;
|
||||
request.onsuccess = null;
|
||||
requestEventPromise =
|
||||
requestWatcher(testCase, request).wait_for('success');
|
||||
requestEventPromise = promiseForRequest(testCase, request);
|
||||
}
|
||||
|
||||
// requestEventPromise needs to be the last promise in the chain, because
|
||||
|
@ -95,12 +122,10 @@ function migrateNamedDatabase(
|
|||
'indexedDB.open should not succeed without creating a ' +
|
||||
'versionchange transaction'));
|
||||
};
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
if (database) {
|
||||
testCase.add_cleanup(() => { database.close(); });
|
||||
}
|
||||
return database || event.target.error;
|
||||
}).then(databaseOrError => {
|
||||
if (databaseOrError instanceof IDBDatabase)
|
||||
testCase.add_cleanup(() => { databaseOrError.close(); });
|
||||
return databaseOrError;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -126,9 +151,7 @@ function createDatabase(testCase, setupCallback) {
|
|||
// close the database.
|
||||
function createNamedDatabase(testCase, databaseName, setupCallback) {
|
||||
const request = indexedDB.deleteDatabase(databaseName);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
|
||||
return eventWatcher.wait_for('success').then(event => {
|
||||
return promiseForRequest(testCase, request).then(() => {
|
||||
testCase.add_cleanup(() => { indexedDB.deleteDatabase(databaseName); });
|
||||
return migrateNamedDatabase(testCase, databaseName, 1, setupCallback)
|
||||
});
|
||||
|
@ -152,9 +175,7 @@ function openDatabase(testCase, version) {
|
|||
// close the database.
|
||||
function openNamedDatabase(testCase, databaseName, version) {
|
||||
const request = indexedDB.open(databaseName, version);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const database = request.result;
|
||||
return promiseForRequest(testCase, request).then(database => {
|
||||
testCase.add_cleanup(() => { database.close(); });
|
||||
return database;
|
||||
});
|
||||
|
@ -215,9 +236,7 @@ function checkStoreIndexes (testCase, store, errorMessage) {
|
|||
function checkStoreGenerator(testCase, store, expectedKey, errorMessage) {
|
||||
const request = store.put(
|
||||
{ title: 'Bedrock Nights ' + expectedKey, author: 'Barney' });
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
return promiseForRequest(testCase, request).then(result => {
|
||||
assert_equals(result, expectedKey, errorMessage);
|
||||
});
|
||||
}
|
||||
|
@ -230,9 +249,7 @@ function checkStoreGenerator(testCase, store, expectedKey, errorMessage) {
|
|||
// is using it incorrectly.
|
||||
function checkStoreContents(testCase, store, errorMessage) {
|
||||
const request = store.get(123456);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
return promiseForRequest(testCase, request).then(result => {
|
||||
assert_equals(result.isbn, BOOKS_RECORD_DATA[0].isbn, errorMessage);
|
||||
assert_equals(result.author, BOOKS_RECORD_DATA[0].author, errorMessage);
|
||||
assert_equals(result.title, BOOKS_RECORD_DATA[0].title, errorMessage);
|
||||
|
@ -247,9 +264,7 @@ function checkStoreContents(testCase, store, errorMessage) {
|
|||
// is using it incorrectly.
|
||||
function checkAuthorIndexContents(testCase, index, errorMessage) {
|
||||
const request = index.get(BOOKS_RECORD_DATA[2].author);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
return promiseForRequest(testCase, request).then(result => {
|
||||
assert_equals(result.isbn, BOOKS_RECORD_DATA[2].isbn, errorMessage);
|
||||
assert_equals(result.title, BOOKS_RECORD_DATA[2].title, errorMessage);
|
||||
});
|
||||
|
@ -263,9 +278,7 @@ function checkAuthorIndexContents(testCase, index, errorMessage) {
|
|||
// is using it incorrectly.
|
||||
function checkTitleIndexContents(testCase, index, errorMessage) {
|
||||
const request = index.get(BOOKS_RECORD_DATA[2].title);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
return promiseForRequest(testCase, request).then(result => {
|
||||
assert_equals(result.isbn, BOOKS_RECORD_DATA[2].isbn, errorMessage);
|
||||
assert_equals(result.author, BOOKS_RECORD_DATA[2].author, errorMessage);
|
||||
});
|
||||
|
@ -290,3 +303,12 @@ function largeValue(size, seed) {
|
|||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
async function deleteAllDatabases(testCase) {
|
||||
const dbs_to_delete = await indexedDB.databases();
|
||||
for( const db_info of dbs_to_delete) {
|
||||
let request = indexedDB.deleteDatabase(db_info.name);
|
||||
let eventWatcher = requestWatcher(testCase, request);
|
||||
await eventWatcher.wait_for('success');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
spec: https://w3c.github.io/webcrypto/
|
||||
suggested_reviewers:
|
||||
- Wafflespeanut
|
||||
- jimsch
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
spec: https://www.w3.org/TR/annotation-vocab/
|
||||
suggested_reviewers:
|
||||
- halindrome
|
||||
- gkellogg
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
spec: https://drafts.csswg.org/css-grid/
|
||||
suggested_reviewers:
|
||||
- mrego
|
||||
- tomalec
|
||||
- plinss
|
||||
- jxs
|
||||
- tabatkins
|
||||
|
|
|
@ -18,134 +18,147 @@
|
|||
|
||||
<script>
|
||||
|
||||
for (let element of [divWithFontSizeSet, divWithFontSizeInherited]) {
|
||||
let id = element.id;
|
||||
// Generate a property and temporarily set its value. Then call 'fn' with
|
||||
// the name of the generated property.
|
||||
function with_custom_property(element, reg, value, fn) {
|
||||
if (element.id.length == 0)
|
||||
throw 'The specified element must have an ID';
|
||||
|
||||
// Generate a property and temporarily set its value. Then call 'fn' with
|
||||
// the name of the generated property.
|
||||
function with_custom_property(reg, value, fn) {
|
||||
let name = generate_property(reg);
|
||||
let name = generate_property(reg);
|
||||
|
||||
// Because we want to include the parsing step, insert a stylesheet
|
||||
// node with textContent.
|
||||
let node = document.createElement('style');
|
||||
node.textContent = `#${id} { ${name}:${value}; }`;
|
||||
document.body.append(node);
|
||||
// Because we want to include the parsing step, insert a stylesheet
|
||||
// node with textContent.
|
||||
let node = document.createElement('style');
|
||||
node.textContent = `#${element.id} { ${name}:${value}; }`;
|
||||
document.body.append(node);
|
||||
|
||||
try {
|
||||
fn(name);
|
||||
} finally {
|
||||
node.remove();
|
||||
}
|
||||
try {
|
||||
fn(name);
|
||||
} finally {
|
||||
node.remove();
|
||||
}
|
||||
|
||||
function assert_computed_value(syntax, value, expected) {
|
||||
with_custom_property(syntax, value, (name) => {
|
||||
let actual = getComputedStyle(element).getPropertyValue(name);
|
||||
assert_equals(actual, expected);
|
||||
});
|
||||
}
|
||||
|
||||
// Computes an absolute reference value for some length.
|
||||
//
|
||||
// E.g. to figure out how many pixels '10vh' is, do length_ref('10vh').
|
||||
function length_ref(value, refnode = ref) {
|
||||
try {
|
||||
// The reference property 'min-height' is chosen arbitrarily, but
|
||||
// avoid properties with "resolved value is used value"-behavior
|
||||
// [1], as it may affect rounding, and custom properties do not
|
||||
// have this behavior.
|
||||
//
|
||||
// [1] https://drafts.csswg.org/cssom/#resolved-values
|
||||
const ref_property = 'min-height';
|
||||
refnode.style = `${ref_property}: ${value}`;
|
||||
return getComputedStyle(refnode).getPropertyValue(ref_property);
|
||||
} finally {
|
||||
refnode.style = '';
|
||||
}
|
||||
}
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<length>', '12px', '12px');
|
||||
assert_computed_value('<length>', '13vw', length_ref('13vw'));
|
||||
assert_computed_value('<length>', '14em', '140px');
|
||||
assert_computed_value('<length>', '15vmin', length_ref('15vmin'));
|
||||
assert_computed_value('<length>', 'calc(16px - 7em + 10vh)', length_ref('calc(10vh - 54px)'));
|
||||
with_custom_property('<length>', '14em', (name) => {
|
||||
assert_computed_value('<length>', `var(${name})`, '140px');
|
||||
});
|
||||
}, "<length> values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<length-percentage>', '17em', '170px');
|
||||
assert_computed_value('<length-percentage>', '18%', '18%');
|
||||
assert_computed_value('<length-percentage>', 'calc(19em - 2%)', 'calc(190px + -2%)');
|
||||
}, "<length-percentage> values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<length>#', '10px, 3em', '10px, 30px');
|
||||
assert_computed_value('<length>#', '10px, 3em', '10px, 30px');
|
||||
assert_computed_value('<length>#', '4em ,9px', '40px, 9px');
|
||||
assert_computed_value('<length>#', '8em', '80px');
|
||||
}, "<length># values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<length-percentage>#', '3% , 10vmax , 22px', ['3%', length_ref('10vmax'), '22px'].join(', '));
|
||||
assert_computed_value('<length-percentage>#', 'calc(50% + 1em), 4px', 'calc(10px + 50%), 4px');
|
||||
assert_computed_value('<length-percentage>#', 'calc(13% + 37px)', 'calc(37px + 13%)');
|
||||
}, "<length-percentage># values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<length>+', '10px 3em', '10px 30px');
|
||||
assert_computed_value('<length>+', '4em 9px', '40px 9px');
|
||||
}, "<length>+ values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<length-percentage>+', '3% 10vmax 22px', ['3%', length_ref('10vmax'), '22px'].join(' '));
|
||||
assert_computed_value('<length-percentage>+', 'calc(50% + 1em) 4px', 'calc(10px + 50%) 4px');
|
||||
}, "<length-percentage>+ values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<transform-function>', 'translateX(2px)', 'translateX(2px)');
|
||||
assert_computed_value('<transform-function>', 'translateX(10em)', 'translateX(100px)');
|
||||
assert_computed_value('<transform-function>', 'translateX(calc(11em + 10%))', 'translateX(calc(110px + 10%))');
|
||||
assert_computed_value('<transform-function>+', 'translateX(10%) scale(2)', 'translateX(10%) scale(2)');
|
||||
}, "<transform-function> values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<integer>', '15', '15');
|
||||
assert_computed_value('<integer>', 'calc(15 + 15)', '30');
|
||||
assert_computed_value('<integer>', 'calc(2.4)', '2');
|
||||
assert_computed_value('<integer>', 'calc(2.6)', '3');
|
||||
assert_computed_value('<integer>', 'calc(2.6 + 3.1)', '6');
|
||||
}, "<integer> values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<integer>+', '15 calc(2.4) calc(2.6)', '15 2 3');
|
||||
}, "<integer>+ values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('<color>', '#ff0000', 'rgb(255, 0, 0)');
|
||||
assert_computed_value('<color>', '#000f00', 'rgb(0, 15, 0)');
|
||||
assert_computed_value('<color>', '#00000a', 'rgb(0, 0, 10)');
|
||||
assert_computed_value('<color>', '#badbee', 'rgb(186, 219, 238)');
|
||||
assert_computed_value('<color>', '#badbee33', 'rgba(186, 219, 238, 0.2)');
|
||||
assert_computed_value('<color>', 'tomato', 'rgb(255, 99, 71)');
|
||||
assert_computed_value('<color>', 'plum', 'rgb(221, 160, 221)');
|
||||
assert_computed_value('<color>', 'currentcolor', 'currentcolor');
|
||||
}, "<color> values are computed correctly for " + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('*', 'tomato', 'tomato');
|
||||
assert_computed_value('tomato | plum', 'plum', 'plum');
|
||||
assert_computed_value('tomato | plum | <color>', 'plum', 'plum');
|
||||
}, "ident values that look like color keywords are not converted to colors" + id);
|
||||
|
||||
test(function() {
|
||||
assert_computed_value('*', '-50grad', '-50grad');
|
||||
assert_computed_value('<angle>', '180deg', '180deg');
|
||||
assert_computed_value('<angle>', '400grad', '360deg');
|
||||
assert_computed_value('<angle>', 'calc(360deg + 400grad)', '720deg');
|
||||
}, "<angle> values computed correctly for " + id);
|
||||
}
|
||||
|
||||
function assert_computed_value(element, syntax, value, expected) {
|
||||
with_custom_property(element, syntax, value, (name) => {
|
||||
let actual = getComputedStyle(element).getPropertyValue(name);
|
||||
assert_equals(actual, expected);
|
||||
});
|
||||
}
|
||||
|
||||
// Computes an absolute reference value for some length.
|
||||
//
|
||||
// E.g. to figure out how many pixels '10vh' is, do length_ref('10vh').
|
||||
function length_ref(value, refnode = ref) {
|
||||
try {
|
||||
// The reference property 'min-height' is chosen arbitrarily, but
|
||||
// avoid properties with "resolved value is used value"-behavior
|
||||
// [1], as it may affect rounding, and custom properties do not
|
||||
// have this behavior.
|
||||
//
|
||||
// [1] https://drafts.csswg.org/cssom/#resolved-values
|
||||
const ref_property = 'min-height';
|
||||
refnode.style = `${ref_property}: ${value}`;
|
||||
return getComputedStyle(refnode).getPropertyValue(ref_property);
|
||||
} finally {
|
||||
refnode.style = '';
|
||||
}
|
||||
}
|
||||
|
||||
function test_computed_value(syntax, value, expected) {
|
||||
test(function() {
|
||||
assert_computed_value(divWithFontSizeSet, syntax, value, expected);
|
||||
}, `${syntax} values are computed correctly [${value}]`);
|
||||
}
|
||||
|
||||
test(function(){
|
||||
const element = divWithFontSizeSet;
|
||||
with_custom_property(element, '<length>', '14em', (name) => {
|
||||
assert_computed_value(element, '<length>', `var(${name})`, '140px');
|
||||
});
|
||||
}, '<length> values computed are correctly via var()-reference');
|
||||
|
||||
test(function(){
|
||||
const element = divWithFontSizeInherited;
|
||||
with_custom_property(element, '<length>', '14em', (name) => {
|
||||
assert_computed_value(element, '<length>', `var(${name})`, '140px');
|
||||
});
|
||||
}, '<length> values computed are correctly via var()-reference when font-size is inherited');
|
||||
|
||||
test(function(){
|
||||
const element = divWithFontSizeInherited;
|
||||
assert_computed_value(element, '<length>', '14em', '140px');
|
||||
}, '<length> values are computed correctly when font-size is inherited [14em]');
|
||||
|
||||
test(function(){
|
||||
const element = divWithFontSizeInherited;
|
||||
assert_computed_value(element, '<length>', 'calc(14em + 10px)', '150px');
|
||||
}, '<length> values are computed correctly when font-size is inherited [calc(14em + 10px)]');
|
||||
|
||||
test_computed_value('<length>', '12px', '12px');
|
||||
test_computed_value('<length>', '13vw', length_ref('13vw'));
|
||||
test_computed_value('<length>', '14em', '140px');
|
||||
test_computed_value('<length>', '15vmin', length_ref('15vmin'));
|
||||
test_computed_value('<length>', 'calc(16px - 7em + 10vh)', length_ref('calc(10vh - 54px)'));
|
||||
|
||||
test_computed_value('<length-percentage>', '17em', '170px');
|
||||
test_computed_value('<length-percentage>', '18%', '18%');
|
||||
test_computed_value('<length-percentage>', 'calc(19em - 2%)', 'calc(190px + -2%)');
|
||||
|
||||
test_computed_value('<length>#', '10px, 3em', '10px, 30px');
|
||||
test_computed_value('<length>#', '4em ,9px', '40px, 9px');
|
||||
test_computed_value('<length>#', '8em', '80px');
|
||||
|
||||
test_computed_value('<length-percentage>#', '3% , 10vmax , 22px', ['3%', length_ref('10vmax'), '22px'].join(', '));
|
||||
test_computed_value('<length-percentage>#', 'calc(50% + 1em), 4px', 'calc(10px + 50%), 4px');
|
||||
test_computed_value('<length-percentage>#', 'calc(13% + 37px)', 'calc(37px + 13%)');
|
||||
|
||||
test_computed_value('<length>+', '10px 3em', '10px 30px');
|
||||
test_computed_value('<length>+', '4em 9px', '40px 9px');
|
||||
|
||||
test_computed_value('<length-percentage>+', '3% 10vmax 22px', ['3%', length_ref('10vmax'), '22px'].join(' '));
|
||||
test_computed_value('<length-percentage>+', 'calc(50% + 1em) 4px', 'calc(10px + 50%) 4px');
|
||||
|
||||
test_computed_value('<transform-function>', 'translateX(2px)', 'translateX(2px)');
|
||||
test_computed_value('<transform-function>', 'translateX(10em)', 'translateX(100px)');
|
||||
test_computed_value('<transform-function>', 'translateX(calc(11em + 10%))', 'translateX(calc(110px + 10%))');
|
||||
test_computed_value('<transform-function>+', 'translateX(10%) scale(2)', 'translateX(10%) scale(2)');
|
||||
|
||||
test_computed_value('<integer>', '15', '15');
|
||||
test_computed_value('<integer>', 'calc(15 + 15)', '30');
|
||||
test_computed_value('<integer>', 'calc(2.4)', '2');
|
||||
test_computed_value('<integer>', 'calc(2.6)', '3');
|
||||
test_computed_value('<integer>', 'calc(2.6 + 3.1)', '6');
|
||||
|
||||
test_computed_value('<integer>+', '15 calc(2.4) calc(2.6)', '15 2 3');
|
||||
|
||||
test_computed_value('<color>', '#ff0000', 'rgb(255, 0, 0)');
|
||||
test_computed_value('<color>', '#000f00', 'rgb(0, 15, 0)');
|
||||
test_computed_value('<color>', '#00000a', 'rgb(0, 0, 10)');
|
||||
test_computed_value('<color>', '#badbee', 'rgb(186, 219, 238)');
|
||||
test_computed_value('<color>', '#badbee33', 'rgba(186, 219, 238, 0.2)');
|
||||
test_computed_value('<color>', 'tomato', 'rgb(255, 99, 71)');
|
||||
test_computed_value('<color>', 'plum', 'rgb(221, 160, 221)');
|
||||
test_computed_value('<color>', 'currentcolor', 'currentcolor');
|
||||
|
||||
// Custom ident values that look like color keywords should not be converted.
|
||||
test_computed_value('*', 'tomato', 'tomato');
|
||||
test_computed_value('tomato | plum', 'plum', 'plum');
|
||||
test_computed_value('tomato | plum | <color>', 'plum', 'plum');
|
||||
|
||||
test_computed_value('*', '-50grad', '-50grad');
|
||||
test_computed_value('<angle>', '180deg', '180deg');
|
||||
test_computed_value('<angle>', '400grad', '360deg');
|
||||
test_computed_value('<angle>', 'calc(360deg + 400grad)', '720deg');
|
||||
|
||||
test_computed_value('*', '50s', '50s');
|
||||
test_computed_value('<time>', '1s', '1s');
|
||||
test_computed_value('<time>', '1000ms', '1s');
|
||||
test_computed_value('<time>', 'calc(1000ms + 1s)', '2s');
|
||||
|
||||
test_computed_value('*', '50dpi', '50dpi');
|
||||
test_computed_value('<resolution>', '1dppx', '1dppx');
|
||||
test_computed_value('<resolution>', '96dpi', '1dppx');
|
||||
test_computed_value('<resolution>', 'calc(1dppx + 96dpi)', '2dppx');
|
||||
|
||||
</script>
|
||||
|
|
|
@ -1,35 +1,45 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#dom-propertydescriptor-initialvalue" />
|
||||
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api/#register-a-custom-property" />
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
#target {
|
||||
background: var(--inherited-color);
|
||||
color: var(--non-inherited-color);
|
||||
}
|
||||
</style>
|
||||
<script src="./resources/utils.js"></script>
|
||||
<div id=target></div>
|
||||
<script>
|
||||
test(function() {
|
||||
CSS.registerProperty({name: '--length', syntax: '<length>', initialValue: 'calc(10px + 15px)', inherits: false});
|
||||
CSS.registerProperty({name: '--length-percentage', syntax: '<length-percentage>', initialValue: 'calc(1in + 10% + 4px)', inherits: false});
|
||||
CSS.registerProperty({name: '--inherited-color', syntax: '<color>', initialValue: 'pink', inherits: true});
|
||||
CSS.registerProperty({name: '--non-inherited-color', syntax: '<color>', initialValue: 'purple', inherits: false});
|
||||
CSS.registerProperty({name: '--transform-function', syntax: '<transform-function>', initialValue: 'rotate(42deg)', inherits: false});
|
||||
CSS.registerProperty({name: '--single-transform-list', syntax: '<transform-list>', initialValue: 'scale(calc(2 + 2))', inherits: false});
|
||||
CSS.registerProperty({name: '--multiple-transform-list', syntax: '<transform-list>', initialValue: 'scale(calc(2 + 1)) translateX(calc(3px + 1px))', inherits: false});
|
||||
|
||||
computedStyle = getComputedStyle(target);
|
||||
assert_equals(computedStyle.getPropertyValue('--length'), '25px');
|
||||
assert_equals(computedStyle.getPropertyValue('--length-percentage'), 'calc(100px + 10%)');
|
||||
assert_equals(computedStyle.getPropertyValue('--inherited-color'), 'rgb(255, 192, 203)');
|
||||
assert_equals(computedStyle.getPropertyValue('--non-inherited-color'), 'rgb(128, 0, 128)');
|
||||
assert_equals(computedStyle.getPropertyValue('--transform-function'), 'rotate(42deg)');
|
||||
assert_equals(computedStyle.getPropertyValue('--single-transform-list'), 'scale(4)');
|
||||
assert_equals(computedStyle.getPropertyValue('--multiple-transform-list'), 'scale(3) translateX(4px)');
|
||||
function test_initial_value(reg, expected) {
|
||||
let suffix = reg.inherits === true ? ', inherits' : '';
|
||||
test(function(){
|
||||
let name = generate_property(reg);
|
||||
let actual = getComputedStyle(target).getPropertyValue(name);
|
||||
assert_equals(actual, expected);
|
||||
}, `Initial value for ${reg.syntax} correctly computed [${reg.initialValue}${suffix}]`);
|
||||
}
|
||||
|
||||
test_initial_value({ syntax: '<length>', initialValue: 'calc(10px + 15px)' }, '25px');
|
||||
test_initial_value({ syntax: '<length-percentage>', initialValue: 'calc(1in + 10% + 4px)' }, 'calc(100px + 10%)');
|
||||
test_initial_value({ syntax: '<color>', initialValue: 'pink', inherits: true }, 'rgb(255, 192, 203)');
|
||||
test_initial_value({ syntax: '<color>', initialValue: 'purple' }, 'rgb(128, 0, 128)');
|
||||
test_initial_value({ syntax: '<transform-function>', initialValue: 'rotate(42deg)' }, 'rotate(42deg)');
|
||||
test_initial_value({ syntax: '<transform-list>', initialValue: 'scale(calc(2 + 2))' }, 'scale(4)');
|
||||
test_initial_value({ syntax: '<transform-list>', initialValue: 'scale(calc(2 + 1)) translateX(calc(3px + 1px))' }, 'scale(3) translateX(4px)');
|
||||
|
||||
// Test that the initial value of the custom property 'reg' is successfully
|
||||
// substituted into 'property'.
|
||||
function test_substituted_value(reg, property, expected) {
|
||||
let inherits_text = reg.inherits === true ? 'inherited' : 'non-inherited';
|
||||
test(function(){
|
||||
try {
|
||||
let name = generate_property(reg);
|
||||
target.style = `${property}:var(${name});`;
|
||||
assert_equals(getComputedStyle(target).getPropertyValue(property), expected);
|
||||
} finally {
|
||||
target.style = '';
|
||||
}
|
||||
}, `Initial ${inherits_text} value can be substituted [${reg.initialValue}, ${property}]`);
|
||||
}
|
||||
|
||||
test_substituted_value({ syntax: '<color>', initialValue: 'purple', inherits: true }, 'color', 'rgb(128, 0, 128)');
|
||||
test_substituted_value({ syntax: '<color>', initialValue: 'pink' }, 'background-color', 'rgb(255, 192, 203)');
|
||||
|
||||
assert_equals(computedStyle.backgroundColor, 'rgb(255, 192, 203)');
|
||||
assert_equals(computedStyle.color, 'rgb(128, 0, 128)');
|
||||
}, "Initial values of registered properties can be referenced when no custom properties are explicitly set.");
|
||||
</script>
|
||||
|
|
|
@ -50,6 +50,14 @@ function any_initial_value(syntax) {
|
|||
// generated. If a single string is used as the argument, it is assumed to be
|
||||
// the syntax.
|
||||
function generate_property(reg) {
|
||||
// Verify that only valid keys are specified. This prevents the caller from
|
||||
// accidentally supplying 'inherited' instead of 'inherits', for example.
|
||||
if (typeof(reg) === 'object') {
|
||||
const permitted = new Set(['name', 'syntax', 'initialValue', 'inherits']);
|
||||
if (!Object.keys(reg).every(k => permitted.has(k)))
|
||||
throw new Error('generate_property: invalid parameter');
|
||||
}
|
||||
|
||||
let syntax = typeof(reg) === 'string' ? reg : reg.syntax;
|
||||
let initial = typeof(reg.initialValue) === 'undefined' ? any_initial_value(syntax)
|
||||
: reg.initialValue;
|
||||
|
|
|
@ -32,4 +32,10 @@ test(function(){
|
|||
}
|
||||
}, 'Generated properties respect inherits flag');
|
||||
|
||||
test(function(){
|
||||
assert_throws(new Error(), () => generate_property({syntax: '<length>', foo: 1}));
|
||||
assert_throws(new Error(), () => generate_property({syntax: '<length>', inherited: false}));
|
||||
assert_throws(new Error(), () => generate_property({syntax: '<length>', initial: '10px'}));
|
||||
}, 'Can\'t generate property with unknown fields');
|
||||
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Test: Text is not incorrectly clipped in presence of perspective.</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1494685">
|
||||
<link rel="mismatch" href="about:blank">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
perspective: 1px;
|
||||
}
|
||||
.heading {
|
||||
transform: translateZ(-9px) scale(10);
|
||||
}
|
||||
h1 {
|
||||
font-size: 100px;
|
||||
}
|
||||
</style>
|
||||
<div class="container">
|
||||
<div class="heading">
|
||||
<h1>X</h1>
|
||||
</div>
|
||||
</div>
|
|
@ -1,5 +1,4 @@
|
|||
spec: https://drafts.fxtf.org/geometry/
|
||||
suggested_reviewers:
|
||||
- peterjoel
|
||||
- tschneidereit
|
||||
- dirkschulze
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
p {
|
||||
height: 50px; width: 200px;
|
||||
border: thin solid;
|
||||
background-image: url(../backgrounds/blue-32x32.png);
|
||||
background-image: url(support/blue-32x32.png);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
p {
|
||||
height: 50px; width: 200px;
|
||||
border: thin solid;
|
||||
background-image: url(../backgrounds/blue-32x32.png);
|
||||
background-image: url(support/blue-32x32.png);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
p {
|
||||
height: 50px; width: 200px;
|
||||
border: thin solid;
|
||||
background-image: url(../backgrounds/blue-32x32.png);
|
||||
background-image: url(support/blue-32x32.png);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
p {
|
||||
height: 50px; width: 200px;
|
||||
border: thin solid;
|
||||
background-image: url(../backgrounds/blue-32x32.png);
|
||||
background-image: url(support/blue-32x32.png);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 110 B |
|
@ -273,6 +273,11 @@ testText("<div>abc<div class='itable'><span class='cell'>def</span></div>ghi", "
|
|||
testText("<div>abc<div class='itable'><span class='row'><span class='cell'>def</span></span>\n<span class='row'><span class='cell'>123</span></span></div>ghi",
|
||||
"abcdef\n123ghi", "Single newline in two-row inline-table");
|
||||
|
||||
/**** display:table-row/table-cell/table-caption ****/
|
||||
testText("<div style='display:table-row'>", "", "display:table-row on the element itself");
|
||||
testText("<div style='display:table-cell'>", "", "display:table-cell on the element itself");
|
||||
testText("<div style='display:table-caption'>", "", "display:table-caption on the element itself");
|
||||
|
||||
/**** Lists ****/
|
||||
|
||||
testText("<div><ol><li>abc", "abc", "<ol> list items get no special treatment");
|
||||
|
@ -293,6 +298,9 @@ testText("<div>abc<hr><hr>def", "abc\ndef", "<hr><hr> induces just one line brea
|
|||
testText("<div>abc<hr><hr><hr>def", "abc\ndef", "<hr><hr><hr> induces just one line break");
|
||||
testText("<div><hr class='poke'>", "abc", "<hr> content rendered");
|
||||
testText("<div>abc<!--comment-->def", "abcdef", "comment ignored");
|
||||
testText("<br>", "", "<br>");
|
||||
testText("<p>", "", "empty <p>");
|
||||
testText("<div>", "", "empty <div>");
|
||||
|
||||
/**** text-transform ****/
|
||||
|
||||
|
@ -308,11 +316,13 @@ testText("<div>abc<span>123<div>456</div>789</span>def", "abc123\n456\n789def",
|
|||
|
||||
testText("<div>abc<div style='float:left'>123</div>def", "abc\n123\ndef", "floats induce a block boundary");
|
||||
testText("<div>abc<span style='float:left'>123</span>def", "abc\n123\ndef", "floats induce a block boundary");
|
||||
testText("<div style='float:left'>123", "123", "float on the element itself");
|
||||
|
||||
/**** position ****/
|
||||
|
||||
testText("<div>abc<div style='position:absolute'>123</div>def", "abc\n123\ndef", "position:absolute induces a block boundary");
|
||||
testText("<div>abc<span style='position:absolute'>123</span>def", "abc\n123\ndef", "position:absolute induces a block boundary");
|
||||
testText("<div style='position:absolute'>123", "123", "position:absolute on the element itself");
|
||||
testText("<div>abc<div style='position:relative'>123</div>def", "abc\n123\ndef", "position:relative has no effect");
|
||||
testText("<div>abc<span style='position:relative'>123</span>def", "abc123def", "position:relative has no effect");
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Reference: Combobox block-size test</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<style>
|
||||
html,body {
|
||||
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
|
||||
}
|
||||
|
||||
select { -webkit-appearance: none; }
|
||||
|
||||
.big { font-size: 48pt; min-height: 40pt; }
|
||||
.lh { line-height: 48pt; min-height: 40pt; }
|
||||
|
||||
.mask { position:fixed; left:20px; right:0; top:0; bottom:0; background: black; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- mask off differences on the right side -->
|
||||
<div class="mask"></div>
|
||||
|
||||
<select><optgroup label="label"><option>option</option></select><br>
|
||||
<select class="big"><optgroup label="label"><option>option</option></select><br>
|
||||
<select class="lh"><optgroup label="label"><option>option</option></select><br>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test: Combobox block-size test</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<link rel="match" href="select-1-block-size-ref.html">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499578">
|
||||
<style>
|
||||
html,body {
|
||||
color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
|
||||
}
|
||||
|
||||
select { -webkit-appearance: none; }
|
||||
|
||||
optgroup { font-size: 32pt; }
|
||||
option { font-size: 24pt; }
|
||||
.big { font-size: 48pt; }
|
||||
.lh { line-height: 48pt; }
|
||||
|
||||
.mask { position:fixed; left:20px; right:0; top:0; bottom:0; background: black; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- mask off differences on the right side -->
|
||||
<div class="mask"></div>
|
||||
|
||||
<select><optgroup label="label"><option>option</option></select><br>
|
||||
<select class="big"><optgroup label="label"><option>option</option></select><br>
|
||||
<select class="lh"><optgroup label="label"><option>option</option></select><br>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Reference: empty SELECT</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<style>
|
||||
|
||||
.none { display: none; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table border="1" cellpadding="10">
|
||||
<tr>
|
||||
<td><select size="4"><option class="none"></select>
|
||||
<td><select size="4" style="-webkit-appearance: none"><option class="none">option</select>
|
||||
<td><select size="4" style="-webkit-appearance: none; border: 1px solid black"><option class="none">option</select>
|
||||
<td><select size="4" style="border: 1px solid black"><option class="none">option</select>
|
||||
</table>
|
||||
|
||||
<table border="1" cellpadding="10">
|
||||
<tr>
|
||||
<td><select size="1"><option class="none"></select>
|
||||
<td><select size="1" style="-webkit-appearance: none"><option class="none"></select>
|
||||
<td><select size="1" style="-webkit-appearance: none; border: 1px solid black"><option class="none"></select>
|
||||
<td><select size="1" style="border: 1px solid black"><option class="none"></select>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test: empty SELECT</title>
|
||||
<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
|
||||
<link rel="match" href="select-empty-ref.html">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499230">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table border="1" cellpadding="10">
|
||||
<tr>
|
||||
<td><select size="4"></select>
|
||||
<td><select size="4" style="-webkit-appearance: none"></select>
|
||||
<td><select size="4" style="-webkit-appearance: none; border: 1px solid black"></select>
|
||||
<td><select size="4" style="border: 1px solid black"></select>
|
||||
</table>
|
||||
|
||||
<table border="1" cellpadding="10">
|
||||
<tr>
|
||||
<td><select size="1"></select>
|
||||
<td><select size="1" style="-webkit-appearance: none"></select>
|
||||
<td><select size="1" style="-webkit-appearance: none; border: 1px solid black"></select>
|
||||
<td><select size="1" style="border: 1px solid black"></select>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,5 @@ suggested_reviewers:
|
|||
- jacobrossi
|
||||
- plehegar
|
||||
- scottgonzalez
|
||||
- staktrace
|
||||
- RByers
|
||||
- NavidZ
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Service Worker: postMessage to Client (message queue)</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/common/get-host-info.sub.js"></script>
|
||||
<script src="resources/test-helpers.sub.js"></script>
|
||||
<script>
|
||||
// This function creates a message listener that captures all messages
|
||||
// sent to this window and matches them with corresponding requests.
|
||||
// This frees test code from having to use clunky constructs just to
|
||||
// avoid race conditions, since the relative order of message and
|
||||
// request arrival doesn't matter.
|
||||
function create_message_listener(t) {
|
||||
const listener = {
|
||||
messages: new Set(),
|
||||
requests: new Set(),
|
||||
waitFor: function(predicate) {
|
||||
for (const event of this.messages) {
|
||||
// If a message satisfying the predicate has already
|
||||
// arrived, it gets matched to this request.
|
||||
if (predicate(event)) {
|
||||
this.messages.delete(event);
|
||||
return Promise.resolve(event);
|
||||
}
|
||||
}
|
||||
|
||||
// If no match was found, the request is stored and a
|
||||
// promise is returned.
|
||||
const request = { predicate };
|
||||
const promise = new Promise(resolve => request.resolve = resolve);
|
||||
this.requests.add(request);
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
window.onmessage = t.step_func(event => {
|
||||
for (const request of listener.requests) {
|
||||
// If the new message matches a stored request's
|
||||
// predicate, the request's promise is resolved with this
|
||||
// message.
|
||||
if (request.predicate(event)) {
|
||||
listener.requests.delete(request);
|
||||
request.resolve(event);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// No outstanding request for this message, store it in case
|
||||
// it's requested later.
|
||||
listener.messages.add(event);
|
||||
});
|
||||
return listener;
|
||||
}
|
||||
|
||||
async function service_worker_register_and_activate(t, script, scope) {
|
||||
const registration = await service_worker_unregister_and_register(t, script, scope);
|
||||
t.add_cleanup(() => registration.unregister());
|
||||
const worker = registration.installing;
|
||||
await wait_for_state(t, worker, 'activated');
|
||||
return worker;
|
||||
}
|
||||
|
||||
// Add an iframe (parent) whose document contains a nested iframe
|
||||
// (child), then set the child's src attribute to child_url and return
|
||||
// its Window (without waiting for it to finish loading).
|
||||
async function with_nested_iframes(t, child_url) {
|
||||
const parent = await with_iframe('resources/nested-iframe-parent.html?role=parent');
|
||||
t.add_cleanup(() => parent.remove());
|
||||
const child = parent.contentWindow.document.getElementById('child');
|
||||
child.setAttribute('src', child_url);
|
||||
return child.contentWindow;
|
||||
}
|
||||
|
||||
// Returns a predicate matching a fetch message with the specified
|
||||
// key.
|
||||
function fetch_message(key) {
|
||||
return event => event.data.type === 'fetch' && event.data.key === key;
|
||||
}
|
||||
|
||||
// Returns a predicate matching a ping message with the specified
|
||||
// payload.
|
||||
function ping_message(data) {
|
||||
return event => event.data.type === 'ping' && event.data.data === data;
|
||||
}
|
||||
|
||||
// A client message queue test is a testharness.js test with some
|
||||
// additional setup:
|
||||
// 1. A listener (see create_message_listener)
|
||||
// 2. An active service worker
|
||||
// 3. Two nested iframes
|
||||
// 4. A state transition function that controls the order of events
|
||||
// during the test
|
||||
function client_message_queue_test(url, test_function, description) {
|
||||
promise_test(async t => {
|
||||
t.listener = create_message_listener(t);
|
||||
|
||||
const script = 'resources/stalling-service-worker.js';
|
||||
const scope = 'resources/';
|
||||
t.service_worker = await service_worker_register_and_activate(t, script, scope);
|
||||
|
||||
// We create two nested iframes such that both are controlled by
|
||||
// the newly installed service worker.
|
||||
const child_url = url + '?role=child';
|
||||
t.frame = await with_nested_iframes(t, child_url);
|
||||
|
||||
t.state_transition = async function(from, to, scripts) {
|
||||
// A state transition begins with the child's parser
|
||||
// fetching a script due to a <script> tag. The request
|
||||
// arrives at the service worker, which notifies the
|
||||
// parent, which in turn notifies the test. Note that the
|
||||
// event loop keeps spinning while the parser is waiting.
|
||||
const request = await this.listener.waitFor(fetch_message(to));
|
||||
|
||||
// The test instructs the service worker to send two ping
|
||||
// messages through the Client interface: first to the
|
||||
// child, then to the parent.
|
||||
this.service_worker.postMessage(from);
|
||||
|
||||
// When the parent receives the ping message, it forwards
|
||||
// it to the test. Assuming that messages to both child
|
||||
// and parent are mapped to the same task queue (this is
|
||||
// not [yet] required by the spec), receiving this message
|
||||
// guarantees that the child has already dispatched its
|
||||
// message if it was allowed to do so.
|
||||
await this.listener.waitFor(ping_message(from));
|
||||
|
||||
// Finally, reply to the service worker's fetch
|
||||
// notification with the script it should use as the fetch
|
||||
// request's response. This is a defensive mechanism that
|
||||
// ensures the child's parser really is blocked until the
|
||||
// test is ready to continue.
|
||||
request.ports[0].postMessage([`state = '${to}';`].concat(scripts));
|
||||
};
|
||||
|
||||
await test_function(t);
|
||||
}, description);
|
||||
}
|
||||
|
||||
function client_message_queue_enable_test(
|
||||
install_script,
|
||||
start_script,
|
||||
earliest_dispatch,
|
||||
description)
|
||||
{
|
||||
function later_state(state1, state2) {
|
||||
const states = ['init', 'install', 'start', 'finish', 'loaded'];
|
||||
const index1 = states.indexOf(state1);
|
||||
const index2 = states.indexOf(state2);
|
||||
const max_index = Math.max(index1, index2);
|
||||
return states[max_index];
|
||||
}
|
||||
|
||||
client_message_queue_test('enable-client-message-queue.html', async t => {
|
||||
// While parsing the child's document, the child transitions
|
||||
// from the 'init' state all the way to the 'finish' state.
|
||||
// Once parsing is finished it would enter the final 'loaded'
|
||||
// state. All but the last transition require assitance from
|
||||
// the test.
|
||||
await t.state_transition('init', 'install', [install_script]);
|
||||
await t.state_transition('install', 'start', [start_script]);
|
||||
await t.state_transition('start', 'finish', []);
|
||||
|
||||
// Wait for all messages to get dispatched on the child's
|
||||
// ServiceWorkerContainer and then verify that each message
|
||||
// was dispatched while the child was in the correct state.
|
||||
const report = await t.frame.report;
|
||||
['init', 'install', 'start'].forEach(state => {
|
||||
const dispatch = later_state(state, earliest_dispatch);
|
||||
assert_equals(report[state], dispatch,
|
||||
`Message sent in state '${state}' dispatched in state '${dispatch}'`);
|
||||
});
|
||||
}, description);
|
||||
}
|
||||
|
||||
const empty_script = ``;
|
||||
|
||||
const add_event_listener =
|
||||
`navigator.serviceWorker.addEventListener('message', handle_message);`;
|
||||
|
||||
const set_onmessage = `navigator.serviceWorker.onmessage = handle_message;`;
|
||||
|
||||
const start_messages = `navigator.serviceWorker.startMessages();`;
|
||||
|
||||
client_message_queue_enable_test(add_event_listener, empty_script, 'loaded',
|
||||
'Messages from ServiceWorker to Client only received after DOMContentLoaded event.');
|
||||
|
||||
client_message_queue_enable_test(add_event_listener, start_messages, 'start',
|
||||
'Messages from ServiceWorker to Client only received after calling startMessages().');
|
||||
|
||||
client_message_queue_enable_test(set_onmessage, empty_script, 'install',
|
||||
'Messages from ServiceWorker to Client only received after setting onmessage.');
|
||||
|
||||
const resolve_manual_promise = `resolve_manual_promise();`
|
||||
|
||||
async function test_microtasks_when_client_message_queue_enabled(t, scripts) {
|
||||
await t.state_transition('init', 'start', scripts.concat([resolve_manual_promise]));
|
||||
let result = await t.frame.result;
|
||||
assert_equals(result[0], 'microtask', 'The microtask was executed first.');
|
||||
assert_equals(result[1], 'message', 'The message was dispatched.');
|
||||
}
|
||||
|
||||
client_message_queue_test('message-vs-microtask.html', t => {
|
||||
return test_microtasks_when_client_message_queue_enabled(t, [
|
||||
add_event_listener,
|
||||
start_messages,
|
||||
]);
|
||||
}, 'Microtasks run before dispatching messages after calling startMessages().');
|
||||
|
||||
client_message_queue_test('message-vs-microtask.html', t => {
|
||||
return test_microtasks_when_client_message_queue_enabled(t, [set_onmessage]);
|
||||
}, 'Microtasks run before dispatching messages after setting onmessage.');
|
||||
</script>
|
|
@ -51,208 +51,4 @@ promise_test(t => {
|
|||
})
|
||||
.then(e => { assert_equals(e.data, 'quit'); });
|
||||
}, 'postMessage from ServiceWorker to Client.');
|
||||
|
||||
// This function creates a message listener that captures all messages
|
||||
// sent to this window and matches them with corresponding requests.
|
||||
// This frees test code from having to use clunky constructs just to
|
||||
// avoid race conditions, since the relative order of message and
|
||||
// request arrival doesn't matter.
|
||||
function create_message_listener(t) {
|
||||
const listener = {
|
||||
messages: new Set(),
|
||||
requests: new Set(),
|
||||
waitFor: function(predicate) {
|
||||
for (const event of this.messages) {
|
||||
// If a message satisfying the predicate has already
|
||||
// arrived, it gets matched to this request.
|
||||
if (predicate(event)) {
|
||||
this.messages.delete(event);
|
||||
return Promise.resolve(event);
|
||||
}
|
||||
}
|
||||
|
||||
// If no match was found, the request is stored and a
|
||||
// promise is returned.
|
||||
const request = { predicate };
|
||||
const promise = new Promise(resolve => request.resolve = resolve);
|
||||
this.requests.add(request);
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
window.onmessage = t.step_func(event => {
|
||||
for (const request of listener.requests) {
|
||||
// If the new message matches a stored request's
|
||||
// predicate, the request's promise is resolved with this
|
||||
// message.
|
||||
if (request.predicate(event)) {
|
||||
listener.requests.delete(request);
|
||||
request.resolve(event);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// No outstanding request for this message, store it in case
|
||||
// it's requested later.
|
||||
listener.messages.add(event);
|
||||
});
|
||||
return listener;
|
||||
}
|
||||
|
||||
async function service_worker_register_and_activate(t, script, scope) {
|
||||
const registration = await service_worker_unregister_and_register(t, script, scope);
|
||||
t.add_cleanup(() => registration.unregister());
|
||||
const worker = registration.installing;
|
||||
await wait_for_state(t, worker, 'activated');
|
||||
return worker;
|
||||
}
|
||||
|
||||
// Add an iframe (parent) whose document contains a nested iframe
|
||||
// (child), then set the child's src attribute to child_url and return
|
||||
// its Window (without waiting for it to finish loading).
|
||||
async function with_nested_iframes(t, child_url) {
|
||||
const parent = await with_iframe('resources/nested-iframe-parent.html?role=parent');
|
||||
t.add_cleanup(() => parent.remove());
|
||||
const child = parent.contentWindow.document.getElementById('child');
|
||||
child.setAttribute('src', child_url);
|
||||
return child.contentWindow;
|
||||
}
|
||||
|
||||
// Returns a predicate matching a fetch message with the specified
|
||||
// key.
|
||||
function fetch_message(key) {
|
||||
return event => event.data.type === 'fetch' && event.data.key === key;
|
||||
}
|
||||
|
||||
// Returns a predicate matching a ping message with the specified
|
||||
// payload.
|
||||
function ping_message(data) {
|
||||
return event => event.data.type === 'ping' && event.data.data === data;
|
||||
}
|
||||
|
||||
// A client message queue test is a testharness.js test with some
|
||||
// additional setup:
|
||||
// 1. A listener (see create_message_listener)
|
||||
// 2. An active service worker
|
||||
// 3. Two nested iframes
|
||||
// 4. A state transition function that controls the order of events
|
||||
// during the test
|
||||
function client_message_queue_test(url, test_function, description) {
|
||||
promise_test(async t => {
|
||||
t.listener = create_message_listener(t);
|
||||
|
||||
const script = 'resources/stalling-service-worker.js';
|
||||
const scope = 'resources/';
|
||||
t.service_worker = await service_worker_register_and_activate(t, script, scope);
|
||||
|
||||
// We create two nested iframes such that both are controlled by
|
||||
// the newly installed service worker.
|
||||
const child_url = url + '?role=child';
|
||||
t.frame = await with_nested_iframes(t, child_url);
|
||||
|
||||
t.state_transition = async function(from, to, scripts) {
|
||||
// A state transition begins with the child's parser
|
||||
// fetching a script due to a <script> tag. The request
|
||||
// arrives at the service worker, which notifies the
|
||||
// parent, which in turn notifies the test. Note that the
|
||||
// event loop keeps spinning while the parser is waiting.
|
||||
const request = await this.listener.waitFor(fetch_message(to));
|
||||
|
||||
// The test instructs the service worker to send two ping
|
||||
// messages through the Client interface: first to the
|
||||
// child, then to the parent.
|
||||
this.service_worker.postMessage(from);
|
||||
|
||||
// When the parent receives the ping message, it forwards
|
||||
// it to the test. Assuming that messages to both child
|
||||
// and parent are mapped to the same task queue (this is
|
||||
// not [yet] required by the spec), receiving this message
|
||||
// guarantees that the child has already dispatched its
|
||||
// message if it was allowed to do so.
|
||||
await this.listener.waitFor(ping_message(from));
|
||||
|
||||
// Finally, reply to the service worker's fetch
|
||||
// notification with the script it should use as the fetch
|
||||
// request's response. This is a defensive mechanism that
|
||||
// ensures the child's parser really is blocked until the
|
||||
// test is ready to continue.
|
||||
request.ports[0].postMessage([`state = '${to}';`].concat(scripts));
|
||||
};
|
||||
|
||||
await test_function(t);
|
||||
}, description);
|
||||
}
|
||||
|
||||
function client_message_queue_enable_test(
|
||||
install_script,
|
||||
start_script,
|
||||
earliest_dispatch,
|
||||
description)
|
||||
{
|
||||
function later_state(state1, state2) {
|
||||
const states = ['init', 'install', 'start', 'finish', 'loaded'];
|
||||
const index1 = states.indexOf(state1);
|
||||
const index2 = states.indexOf(state2);
|
||||
const max_index = Math.max(index1, index2);
|
||||
return states[max_index];
|
||||
}
|
||||
|
||||
client_message_queue_test('enable-client-message-queue.html', async t => {
|
||||
// While parsing the child's document, the child transitions
|
||||
// from the 'init' state all the way to the 'finish' state.
|
||||
// Once parsing is finished it would enter the final 'loaded'
|
||||
// state. All but the last transition require assitance from
|
||||
// the test.
|
||||
await t.state_transition('init', 'install', [install_script]);
|
||||
await t.state_transition('install', 'start', [start_script]);
|
||||
await t.state_transition('start', 'finish', []);
|
||||
|
||||
// Wait for all messages to get dispatched on the child's
|
||||
// ServiceWorkerContainer and then verify that each message
|
||||
// was dispatched while the child was in the correct state.
|
||||
const report = await t.frame.report;
|
||||
['init', 'install', 'start'].forEach(state => {
|
||||
const dispatch = later_state(state, earliest_dispatch);
|
||||
assert_equals(report[state], dispatch,
|
||||
`Message sent in state '${state}' dispatched in state '${dispatch}'`);
|
||||
});
|
||||
}, description);
|
||||
}
|
||||
|
||||
const empty_script = ``;
|
||||
|
||||
const add_event_listener =
|
||||
`navigator.serviceWorker.addEventListener('message', handle_message);`;
|
||||
|
||||
const set_onmessage = `navigator.serviceWorker.onmessage = handle_message;`;
|
||||
|
||||
const start_messages = `navigator.serviceWorker.startMessages();`;
|
||||
|
||||
client_message_queue_enable_test(add_event_listener, empty_script, 'loaded',
|
||||
'Messages from ServiceWorker to Client only received after DOMContentLoaded event.');
|
||||
|
||||
client_message_queue_enable_test(add_event_listener, start_messages, 'start',
|
||||
'Messages from ServiceWorker to Client only received after calling startMessages().');
|
||||
|
||||
client_message_queue_enable_test(set_onmessage, empty_script, 'install',
|
||||
'Messages from ServiceWorker to Client only received after setting onmessage.');
|
||||
|
||||
const resolve_manual_promise = `resolve_manual_promise();`
|
||||
|
||||
async function test_microtasks_when_client_message_queue_enabled(t, scripts) {
|
||||
await t.state_transition('init', 'start', scripts.concat([resolve_manual_promise]));
|
||||
let result = await t.frame.result;
|
||||
assert_equals(result[0], 'microtask', 'The microtask was executed first.');
|
||||
assert_equals(result[1], 'message', 'The message was dispatched.');
|
||||
}
|
||||
|
||||
client_message_queue_test('message-vs-microtask.html', t => {
|
||||
return test_microtasks_when_client_message_queue_enabled(t, [
|
||||
add_event_listener,
|
||||
start_messages,
|
||||
]);
|
||||
}, 'Microtasks run before dispatching messages after calling startMessages().');
|
||||
|
||||
client_message_queue_test('message-vs-microtask.html', t => {
|
||||
return test_microtasks_when_client_message_queue_enabled(t, [set_onmessage]);
|
||||
}, 'Microtasks run before dispatching messages after setting onmessage.');
|
||||
</script>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
spec: https://w3c.github.io/speech-api/
|
||||
suggested_reviewers:
|
||||
- andrenatal
|
||||
- gshires
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
spec: https://w3c.github.io/webappsec-subresource-integrity/
|
||||
suggested_reviewers:
|
||||
- metromoxie
|
||||
- fmarier
|
||||
- jonathanKingston
|
||||
- mikewest
|
||||
- hillbrad
|
||||
- mastahyeti
|
||||
|
|
|
@ -264,6 +264,8 @@ class Chrome(BrowserSetup):
|
|||
if kwargs["browser_channel"] == "dev":
|
||||
logger.info("Automatically turning on experimental features for Chrome Dev")
|
||||
kwargs["binary_args"].append("--enable-experimental-web-platform-features")
|
||||
# TODO(foolip): remove after unified plan is enabled on Chrome stable
|
||||
kwargs["binary_args"].append("--enable-features=RTCUnifiedPlanByDefault")
|
||||
|
||||
# Allow audio autoplay without a user gesture.
|
||||
kwargs["binary_args"].append("--autoplay-policy=no-user-gesture-required")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import zipfile
|
||||
from io import BytesIO
|
||||
|
@ -49,20 +48,6 @@ def call(*args):
|
|||
raise
|
||||
|
||||
|
||||
def get_git_cmd(repo_path):
|
||||
"""Create a function for invoking git commands as a subprocess."""
|
||||
def git(cmd, *args):
|
||||
full_cmd = ["git", cmd] + list(args)
|
||||
try:
|
||||
logger.debug(" ".join(full_cmd))
|
||||
return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT).strip()
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error("Git command exited with status %i" % e.returncode)
|
||||
logger.error(e.output)
|
||||
sys.exit(1)
|
||||
return git
|
||||
|
||||
|
||||
def seekable(fileobj):
|
||||
"""Attempt to use file.seek on given file, with fallbacks."""
|
||||
try:
|
||||
|
@ -94,21 +79,6 @@ def unzip(fileobj, dest=None, limit=None):
|
|||
os.chmod(os.path.join(dest, info.filename), perm)
|
||||
|
||||
|
||||
class pwd(object):
|
||||
"""Create context for temporarily changing present working directory."""
|
||||
def __init__(self, dir):
|
||||
self.dir = dir
|
||||
self.old_dir = None
|
||||
|
||||
def __enter__(self):
|
||||
self.old_dir = os.path.abspath(os.curdir)
|
||||
os.chdir(self.dir)
|
||||
|
||||
def __exit__(self, *args, **kwargs):
|
||||
os.chdir(self.old_dir)
|
||||
self.old_dir = None
|
||||
|
||||
|
||||
def get(url):
|
||||
"""Issue GET request to a given URL and return the response."""
|
||||
import requests
|
||||
|
|
|
@ -818,14 +818,10 @@ class ManagerGroup(object):
|
|||
self.pool.add(manager)
|
||||
self.wait()
|
||||
|
||||
def is_alive(self):
|
||||
"""Boolean indicating whether any manager in the group is still alive"""
|
||||
return any(manager.is_alive() for manager in self.pool)
|
||||
|
||||
def wait(self):
|
||||
"""Wait for all the managers in the group to finish"""
|
||||
for item in self.pool:
|
||||
item.join()
|
||||
for manager in self.pool:
|
||||
manager.join()
|
||||
|
||||
def stop(self):
|
||||
"""Set the stop flag so that all managers in the group stop as soon
|
||||
|
@ -834,7 +830,7 @@ class ManagerGroup(object):
|
|||
self.logger.debug("Stop flag set in ManagerGroup")
|
||||
|
||||
def test_count(self):
|
||||
return sum(item.test_count for item in self.pool)
|
||||
return sum(manager.test_count for manager in self.pool)
|
||||
|
||||
def unexpected_count(self):
|
||||
return sum(item.unexpected_count for item in self.pool)
|
||||
return sum(manager.unexpected_count for manager in self.pool)
|
||||
|
|
|
@ -275,8 +275,8 @@ def run_tests(config, test_paths, product, **kwargs):
|
|||
logger.critical("Main thread got signal")
|
||||
manager_group.stop()
|
||||
raise
|
||||
test_count += manager_group.test_count()
|
||||
unexpected_count += manager_group.unexpected_count()
|
||||
test_count += manager_group.test_count()
|
||||
unexpected_count += manager_group.unexpected_count()
|
||||
|
||||
test_total += test_count
|
||||
unexpected_total += unexpected_count
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
spec: https://url.spec.whatwg.org/
|
||||
suggested_reviewers:
|
||||
- mikewest
|
||||
- smola
|
||||
- domenic
|
||||
- Sebmaster
|
||||
- annevk
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
spec: https://webaudio.github.io/web-audio-api/
|
||||
suggested_reviewers:
|
||||
- chrislo
|
||||
- padenot
|
||||
- rtoy
|
||||
|
|
|
@ -1,234 +1 @@
|
|||
import copy
|
||||
import json
|
||||
import os
|
||||
import urlparse
|
||||
|
||||
import pytest
|
||||
import webdriver
|
||||
|
||||
from tests.support import defaults
|
||||
from tests.support.helpers import cleanup_session
|
||||
from tests.support.http_request import HTTPRequest
|
||||
from tests.support.sync import Poll
|
||||
|
||||
|
||||
_current_session = None
|
||||
_custom_session = False
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
# register the capabilities marker
|
||||
config.addinivalue_line("markers",
|
||||
"capabilities: mark test to use capabilities")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def capabilities():
|
||||
"""Default capabilities to use for a new WebDriver session."""
|
||||
return {}
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if "capabilities" in metafunc.fixturenames:
|
||||
marker = metafunc.definition.get_closest_marker(name="capabilities")
|
||||
if marker:
|
||||
metafunc.parametrize("capabilities", marker.args, ids=None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def add_event_listeners(session):
|
||||
"""Register listeners for tracked events on element."""
|
||||
def add_event_listeners(element, tracked_events):
|
||||
element.session.execute_script("""
|
||||
let element = arguments[0];
|
||||
let trackedEvents = arguments[1];
|
||||
|
||||
if (!("events" in window)) {
|
||||
window.events = [];
|
||||
}
|
||||
|
||||
for (var i = 0; i < trackedEvents.length; i++) {
|
||||
element.addEventListener(trackedEvents[i], function (event) {
|
||||
window.events.push(event.type);
|
||||
});
|
||||
}
|
||||
""", args=(element, tracked_events))
|
||||
return add_event_listeners
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_cookie(session, url):
|
||||
"""Create a cookie"""
|
||||
def create_cookie(name, value, **kwargs):
|
||||
if kwargs.get("path", None) is not None:
|
||||
session.url = url(kwargs["path"])
|
||||
|
||||
session.set_cookie(name, value, **kwargs)
|
||||
return session.cookies(name)
|
||||
|
||||
return create_cookie
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_frame(session):
|
||||
"""Create an `iframe` element in the current browsing context and insert it
|
||||
into the document. Return a reference to the newly-created element."""
|
||||
def create_frame():
|
||||
append = """
|
||||
var frame = document.createElement('iframe');
|
||||
document.body.appendChild(frame);
|
||||
return frame;
|
||||
"""
|
||||
return session.execute_script(append)
|
||||
|
||||
return create_frame
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_window(session):
|
||||
"""Open new window and return the window handle."""
|
||||
def create_window():
|
||||
windows_before = session.handles
|
||||
name = session.execute_script("window.open()")
|
||||
assert len(session.handles) == len(windows_before) + 1
|
||||
new_windows = list(set(session.handles) - set(windows_before))
|
||||
return new_windows.pop()
|
||||
return create_window
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def http(configuration):
|
||||
return HTTPRequest(configuration["host"], configuration["port"])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def server_config():
|
||||
return json.loads(os.environ.get("WD_SERVER_CONFIG"))
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def configuration():
|
||||
host = os.environ.get("WD_HOST", defaults.DRIVER_HOST)
|
||||
port = int(os.environ.get("WD_PORT", str(defaults.DRIVER_PORT)))
|
||||
capabilities = json.loads(os.environ.get("WD_CAPABILITIES", "{}"))
|
||||
|
||||
return {
|
||||
"host": host,
|
||||
"port": port,
|
||||
"capabilities": capabilities
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def session(capabilities, configuration, request):
|
||||
"""Create and start a session for a test that does not itself test session creation.
|
||||
|
||||
By default the session will stay open after each test, but we always try to start a
|
||||
new one and assume that if that fails there is already a valid session. This makes it
|
||||
possible to recover from some errors that might leave the session in a bad state, but
|
||||
does not demand that we start a new session per test."""
|
||||
global _current_session
|
||||
|
||||
# Update configuration capabilities with custom ones from the
|
||||
# capabilities fixture, which can be set by tests
|
||||
caps = copy.deepcopy(configuration["capabilities"])
|
||||
caps.update(capabilities)
|
||||
caps = {"alwaysMatch": caps}
|
||||
|
||||
# If there is a session with different capabilities active, end it now
|
||||
if _current_session is not None and (
|
||||
caps != _current_session.requested_capabilities):
|
||||
_current_session.end()
|
||||
_current_session = None
|
||||
|
||||
if _current_session is None:
|
||||
_current_session = webdriver.Session(
|
||||
configuration["host"],
|
||||
configuration["port"],
|
||||
capabilities=caps)
|
||||
try:
|
||||
_current_session.start()
|
||||
except webdriver.error.SessionNotCreatedException:
|
||||
if not _current_session.session_id:
|
||||
raise
|
||||
|
||||
# Enforce a fixed default window size
|
||||
_current_session.window.size = defaults.WINDOW_SIZE
|
||||
|
||||
yield _current_session
|
||||
|
||||
cleanup_session(_current_session)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def current_session():
|
||||
return _current_session
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def url(server_config):
|
||||
def inner(path, protocol="http", query="", fragment=""):
|
||||
port = server_config["ports"][protocol][0]
|
||||
host = "%s:%s" % (server_config["browser_host"], port)
|
||||
return urlparse.urlunsplit((protocol, host, path, query, fragment))
|
||||
|
||||
inner.__name__ = "url"
|
||||
return inner
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_dialog(session):
|
||||
"""Create a dialog (one of "alert", "prompt", or "confirm") and provide a
|
||||
function to validate that the dialog has been "handled" (either accepted or
|
||||
dismissed) by returning some value."""
|
||||
|
||||
def create_dialog(dialog_type, text=None):
|
||||
assert dialog_type in ("alert", "confirm", "prompt"), (
|
||||
"Invalid dialog type: '%s'" % dialog_type)
|
||||
|
||||
if text is None:
|
||||
text = ""
|
||||
|
||||
assert isinstance(text, basestring), "`text` parameter must be a string"
|
||||
|
||||
# Script completes itself when the user prompt has been opened.
|
||||
# For prompt() dialogs, add a value for the 'default' argument,
|
||||
# as some user agents (IE, for example) do not produce consistent
|
||||
# values for the default.
|
||||
session.execute_async_script("""
|
||||
let dialog_type = arguments[0];
|
||||
let text = arguments[1];
|
||||
|
||||
setTimeout(function() {
|
||||
if (dialog_type == 'prompt') {
|
||||
window.dialog_return_value = window[dialog_type](text, '');
|
||||
} else {
|
||||
window.dialog_return_value = window[dialog_type](text);
|
||||
}
|
||||
}, 0);
|
||||
""", args=(dialog_type, text))
|
||||
|
||||
wait = Poll(
|
||||
session,
|
||||
timeout=15,
|
||||
ignored_exceptions=webdriver.NoSuchAlertException,
|
||||
message="No user prompt with text '{}' detected".format(text))
|
||||
wait.until(lambda s: s.alert.text == text)
|
||||
|
||||
return create_dialog
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def closed_window(session, create_window):
|
||||
original_handle = session.window_handle
|
||||
|
||||
new_handle = create_window()
|
||||
session.window_handle = new_handle
|
||||
|
||||
session.close()
|
||||
assert new_handle not in session.handles, "Unable to close window {}".format(new_handle)
|
||||
|
||||
yield new_handle
|
||||
|
||||
session.window_handle = original_handle
|
||||
|
||||
pytest_plugins = "tests.support.fixtures"
|
||||
|
|
|
@ -51,7 +51,7 @@ def square(size):
|
|||
<script>
|
||||
window.clicks = [];
|
||||
let div = document.querySelector("div");
|
||||
div.addEventListener("click", ({{clientX, clientY}}) => window.clicks.push([clientX, clientY]));
|
||||
div.addEventListener("click", function(e) {{ window.clicks.push([e.clientX, e.clientY]) }});
|
||||
</script>
|
||||
""".format(size=size))
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import base64
|
||||
import imghdr
|
||||
|
||||
from webdriver import Element, NoSuchAlertException, WebDriverException
|
||||
|
||||
|
||||
|
@ -189,3 +192,10 @@ def assert_move_to_coordinates(point, target, events):
|
|||
assert e["pageX"] == point["x"]
|
||||
assert e["pageY"] == point["y"]
|
||||
assert e["target"] == target
|
||||
|
||||
|
||||
def assert_png(screenshot):
|
||||
"""Test that screenshot is a Base64 encoded PNG file."""
|
||||
image = base64.decodestring(screenshot)
|
||||
mime_type = imghdr.what("", image)
|
||||
assert mime_type == "png", "Expected image to be PNG, but it was {}".format(mime_type)
|
||||
|
|
234
tests/wpt/web-platform-tests/webdriver/tests/support/fixtures.py
Normal file
234
tests/wpt/web-platform-tests/webdriver/tests/support/fixtures.py
Normal file
|
@ -0,0 +1,234 @@
|
|||
import copy
|
||||
import json
|
||||
import os
|
||||
import urlparse
|
||||
|
||||
import pytest
|
||||
import webdriver
|
||||
|
||||
from tests.support import defaults
|
||||
from tests.support.helpers import cleanup_session
|
||||
from tests.support.http_request import HTTPRequest
|
||||
from tests.support.sync import Poll
|
||||
|
||||
|
||||
_current_session = None
|
||||
_custom_session = False
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
# register the capabilities marker
|
||||
config.addinivalue_line("markers",
|
||||
"capabilities: mark test to use capabilities")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def capabilities():
|
||||
"""Default capabilities to use for a new WebDriver session."""
|
||||
return {}
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if "capabilities" in metafunc.fixturenames:
|
||||
marker = metafunc.definition.get_closest_marker(name="capabilities")
|
||||
if marker:
|
||||
metafunc.parametrize("capabilities", marker.args, ids=None)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def add_event_listeners(session):
|
||||
"""Register listeners for tracked events on element."""
|
||||
def add_event_listeners(element, tracked_events):
|
||||
element.session.execute_script("""
|
||||
let element = arguments[0];
|
||||
let trackedEvents = arguments[1];
|
||||
|
||||
if (!("events" in window)) {
|
||||
window.events = [];
|
||||
}
|
||||
|
||||
for (var i = 0; i < trackedEvents.length; i++) {
|
||||
element.addEventListener(trackedEvents[i], function (event) {
|
||||
window.events.push(event.type);
|
||||
});
|
||||
}
|
||||
""", args=(element, tracked_events))
|
||||
return add_event_listeners
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_cookie(session, url):
|
||||
"""Create a cookie"""
|
||||
def create_cookie(name, value, **kwargs):
|
||||
if kwargs.get("path", None) is not None:
|
||||
session.url = url(kwargs["path"])
|
||||
|
||||
session.set_cookie(name, value, **kwargs)
|
||||
return session.cookies(name)
|
||||
|
||||
return create_cookie
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_frame(session):
|
||||
"""Create an `iframe` element in the current browsing context and insert it
|
||||
into the document. Return a reference to the newly-created element."""
|
||||
def create_frame():
|
||||
append = """
|
||||
var frame = document.createElement('iframe');
|
||||
document.body.appendChild(frame);
|
||||
return frame;
|
||||
"""
|
||||
return session.execute_script(append)
|
||||
|
||||
return create_frame
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_window(session):
|
||||
"""Open new window and return the window handle."""
|
||||
def create_window():
|
||||
windows_before = session.handles
|
||||
name = session.execute_script("window.open()")
|
||||
assert len(session.handles) == len(windows_before) + 1
|
||||
new_windows = list(set(session.handles) - set(windows_before))
|
||||
return new_windows.pop()
|
||||
return create_window
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def http(configuration):
|
||||
return HTTPRequest(configuration["host"], configuration["port"])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def server_config():
|
||||
return json.loads(os.environ.get("WD_SERVER_CONFIG"))
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def configuration():
|
||||
host = os.environ.get("WD_HOST", defaults.DRIVER_HOST)
|
||||
port = int(os.environ.get("WD_PORT", str(defaults.DRIVER_PORT)))
|
||||
capabilities = json.loads(os.environ.get("WD_CAPABILITIES", "{}"))
|
||||
|
||||
return {
|
||||
"host": host,
|
||||
"port": port,
|
||||
"capabilities": capabilities
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def session(capabilities, configuration, request):
|
||||
"""Create and start a session for a test that does not itself test session creation.
|
||||
|
||||
By default the session will stay open after each test, but we always try to start a
|
||||
new one and assume that if that fails there is already a valid session. This makes it
|
||||
possible to recover from some errors that might leave the session in a bad state, but
|
||||
does not demand that we start a new session per test."""
|
||||
global _current_session
|
||||
|
||||
# Update configuration capabilities with custom ones from the
|
||||
# capabilities fixture, which can be set by tests
|
||||
caps = copy.deepcopy(configuration["capabilities"])
|
||||
caps.update(capabilities)
|
||||
caps = {"alwaysMatch": caps}
|
||||
|
||||
# If there is a session with different capabilities active, end it now
|
||||
if _current_session is not None and (
|
||||
caps != _current_session.requested_capabilities):
|
||||
_current_session.end()
|
||||
_current_session = None
|
||||
|
||||
if _current_session is None:
|
||||
_current_session = webdriver.Session(
|
||||
configuration["host"],
|
||||
configuration["port"],
|
||||
capabilities=caps)
|
||||
try:
|
||||
_current_session.start()
|
||||
except webdriver.error.SessionNotCreatedException:
|
||||
if not _current_session.session_id:
|
||||
raise
|
||||
|
||||
# Enforce a fixed default window size
|
||||
_current_session.window.size = defaults.WINDOW_SIZE
|
||||
|
||||
yield _current_session
|
||||
|
||||
cleanup_session(_current_session)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def current_session():
|
||||
return _current_session
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def url(server_config):
|
||||
def inner(path, protocol="http", query="", fragment=""):
|
||||
port = server_config["ports"][protocol][0]
|
||||
host = "%s:%s" % (server_config["browser_host"], port)
|
||||
return urlparse.urlunsplit((protocol, host, path, query, fragment))
|
||||
|
||||
inner.__name__ = "url"
|
||||
return inner
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_dialog(session):
|
||||
"""Create a dialog (one of "alert", "prompt", or "confirm") and provide a
|
||||
function to validate that the dialog has been "handled" (either accepted or
|
||||
dismissed) by returning some value."""
|
||||
|
||||
def create_dialog(dialog_type, text=None):
|
||||
assert dialog_type in ("alert", "confirm", "prompt"), (
|
||||
"Invalid dialog type: '%s'" % dialog_type)
|
||||
|
||||
if text is None:
|
||||
text = ""
|
||||
|
||||
assert isinstance(text, basestring), "`text` parameter must be a string"
|
||||
|
||||
# Script completes itself when the user prompt has been opened.
|
||||
# For prompt() dialogs, add a value for the 'default' argument,
|
||||
# as some user agents (IE, for example) do not produce consistent
|
||||
# values for the default.
|
||||
session.execute_async_script("""
|
||||
let dialog_type = arguments[0];
|
||||
let text = arguments[1];
|
||||
|
||||
setTimeout(function() {
|
||||
if (dialog_type == 'prompt') {
|
||||
window.dialog_return_value = window[dialog_type](text, '');
|
||||
} else {
|
||||
window.dialog_return_value = window[dialog_type](text);
|
||||
}
|
||||
}, 0);
|
||||
""", args=(dialog_type, text))
|
||||
|
||||
wait = Poll(
|
||||
session,
|
||||
timeout=15,
|
||||
ignored_exceptions=webdriver.NoSuchAlertException,
|
||||
message="No user prompt with text '{}' detected".format(text))
|
||||
wait.until(lambda s: s.alert.text == text)
|
||||
|
||||
return create_dialog
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def closed_window(session, create_window):
|
||||
original_handle = session.window_handle
|
||||
|
||||
new_handle = create_window()
|
||||
session.window_handle = new_handle
|
||||
|
||||
session.close()
|
||||
assert new_handle not in session.handles, "Unable to close window {}".format(new_handle)
|
||||
|
||||
yield new_handle
|
||||
|
||||
session.window_handle = original_handle
|
||||
|
|
@ -117,3 +117,11 @@ def is_element_in_viewport(session, element):
|
|||
return !(rect.right < 0 || rect.bottom < 0 ||
|
||||
rect.left > viewport.width || rect.top > viewport.height)
|
||||
""", args=(element,))
|
||||
|
||||
|
||||
def document_dimensions(session):
|
||||
return tuple(session.execute_script("""
|
||||
let {devicePixelRatio} = window;
|
||||
let {width, height} = document.documentElement.getBoundingClientRect();
|
||||
return [width * devicePixelRatio, height * devicePixelRatio];
|
||||
"""))
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import base64
|
||||
import struct
|
||||
|
||||
from tests.support.asserts import assert_png
|
||||
|
||||
|
||||
def png_dimensions(screenshot):
|
||||
assert_png(screenshot)
|
||||
image = base64.decodestring(screenshot)
|
||||
width, height = struct.unpack(">LL", image[16:24])
|
||||
return int(width), int(height)
|
|
@ -2,7 +2,7 @@ import urllib
|
|||
|
||||
|
||||
def inline(doc, doctype="html", mime="text/html;charset=utf-8", protocol="http"):
|
||||
from ..conftest import server_config, url
|
||||
from .fixtures import server_config, url
|
||||
build_url = url(server_config())
|
||||
|
||||
if doctype == "html":
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
<title>XMLHttpRequest: send() - charset parameter of Content-Type</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following::ol[1]/li[4]/p/code[contains(text(),'Content-Type')]/.. following::ol[1]/li[4]/p/code[contains(text(),'Content-Type')]/../following-sibling::p" />
|
||||
<link rel="help" href="https://xhr.spec.whatwg.org/#dom-XMLHttpRequest-send-a-string" data-tested-assertations="following::p[2]" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
|
@ -45,8 +43,8 @@
|
|||
)
|
||||
request(
|
||||
"text/plain;charset=utf-8",
|
||||
"text/plain;charset=UTF-8",
|
||||
"Correct text/plain MIME with charset"
|
||||
"text/plain;charset=utf-8",
|
||||
"If charset= param is UTF-8 (case-insensitive), it should not be changed"
|
||||
)
|
||||
request(
|
||||
"text/x-pink-unicorn",
|
||||
|
@ -70,8 +68,8 @@
|
|||
)
|
||||
request(
|
||||
"text/plain;charset=utf-8;charset=waddup",
|
||||
"text/plain;charset=UTF-8",
|
||||
"charset given but wrong, fix it (known MIME, bogus charset)"
|
||||
"text/plain;charset=utf-8;charset=waddup",
|
||||
"If charset= param is UTF-8 (case-insensitive), it should not be changed (bogus charset)"
|
||||
)
|
||||
request(
|
||||
"text/plain;charset=shift-jis",
|
||||
|
@ -81,7 +79,7 @@
|
|||
request(
|
||||
"text/x-pink-unicorn; charset=windows-1252; charset=bogus; notrelated; charset=ascii",
|
||||
"text/x-pink-unicorn;charset=UTF-8",
|
||||
"Multiple charset parameters deduplicate, bogus parameter dropped"
|
||||
"Multiple non-UTF-8 charset parameters deduplicate, bogus parameter dropped"
|
||||
)
|
||||
request(
|
||||
null,
|
||||
|
@ -90,20 +88,20 @@
|
|||
)
|
||||
request(
|
||||
"text/plain;charset= utf-8",
|
||||
"text/plain;charset=UTF-8",
|
||||
"charset with space")
|
||||
"text/plain;charset= utf-8",
|
||||
"charset with space that is UTF-8 does not change")
|
||||
request(
|
||||
"text/plain;charset=\"utf-8\"",
|
||||
"text/plain;charset=UTF-8",
|
||||
"charset in double quotes")
|
||||
"text/plain;charset=\"utf-8\"",
|
||||
"charset in double quotes that is UTF-8 does not change")
|
||||
request(
|
||||
"text/plain;charset=\" utf-8\"",
|
||||
"text/plain;charset=UTF-8",
|
||||
"charset in double quotes with space")
|
||||
request(
|
||||
"text/plain;charset=\"u\\t\\f-8\"",
|
||||
"text/plain;charset=UTF-8",
|
||||
"charset in double quotes with backslashes")
|
||||
"text/plain;charset=\"u\\t\\f-8\"",
|
||||
"charset in double quotes with backslashes that is UTF-8 does not change")
|
||||
request(
|
||||
"YO/yo;charset=x;yo=YO; X=y",
|
||||
"yo/yo;charset=UTF-8;yo=YO;x=y",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue