mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Update web-platform-tests to revision b9d4748d6a7f9b21bd420486955b44349aa005ea
This commit is contained in:
parent
0a9a222356
commit
28ed236c3a
76 changed files with 2158 additions and 581 deletions
|
@ -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,6 +37,3 @@
|
|||
[Revoke blob URL after creating Request, will fetch]
|
||||
expected: FAIL
|
||||
|
||||
[Revoke blob URL after calling fetch, fetch should succeed]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -12205,18 +12205,36 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-twice-manual.tentative.html": [
|
||||
[
|
||||
"fullscreen/api/element-request-fullscreen-twice-manual.tentative.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-elements-manual.html": [
|
||||
[
|
||||
"fullscreen/api/element-request-fullscreen-two-elements-manual.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-elements-manual.tentative.html": [
|
||||
[
|
||||
"fullscreen/api/element-request-fullscreen-two-elements-manual.tentative.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-iframes-manual.html": [
|
||||
[
|
||||
"fullscreen/api/element-request-fullscreen-two-iframes-manual.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-iframes-manual.tentative.html": [
|
||||
[
|
||||
"fullscreen/api/element-request-fullscreen-two-iframes-manual.tentative.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"fullscreen/api/promises-resolve-manual.html": [
|
||||
[
|
||||
"fullscreen/api/promises-resolve-manual.html",
|
||||
|
@ -69501,6 +69519,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/CSS2/normal-flow/margin-collapse-through-percentage-padding.html": [
|
||||
[
|
||||
"css/CSS2/normal-flow/margin-collapse-through-percentage-padding.html",
|
||||
[
|
||||
[
|
||||
"/css/reference/ref-filled-green-100px-square-only.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html": [
|
||||
[
|
||||
"css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html",
|
||||
|
@ -109365,6 +109395,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-backgrounds/border-radius-dynamic-from-no-radius.html": [
|
||||
[
|
||||
"css/css-backgrounds/border-radius-dynamic-from-no-radius.html",
|
||||
[
|
||||
[
|
||||
"/css/css-backgrounds/border-radius-dynamic-from-no-radius-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-backgrounds/border-radius-horizontal-value-is-zero.html": [
|
||||
[
|
||||
"css/css-backgrounds/border-radius-horizontal-value-is-zero.html",
|
||||
|
@ -178009,6 +178051,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/motion/animation/reftests/offset-distance-interpolation-001.html": [
|
||||
[
|
||||
"css/motion/animation/reftests/offset-distance-interpolation-001.html",
|
||||
[
|
||||
[
|
||||
"/css/motion/animation/reftests/offset-path-path-interpolation-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/motion/animation/reftests/offset-path-path-interpolation-001.html": [
|
||||
[
|
||||
"css/motion/animation/reftests/offset-path-path-interpolation-001.html",
|
||||
|
@ -178021,6 +178075,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/motion/animation/reftests/offset-rotate-interpolation-001.html": [
|
||||
[
|
||||
"css/motion/animation/reftests/offset-rotate-interpolation-001.html",
|
||||
[
|
||||
[
|
||||
"/css/motion/animation/reftests/offset-path-path-interpolation-ref.html",
|
||||
"=="
|
||||
]
|
||||
],
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/motion/offset-anchor-transform-box-fill-box.html": [
|
||||
[
|
||||
"css/motion/offset-anchor-transform-box-fill-box.html",
|
||||
|
@ -261366,6 +261432,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-backgrounds/border-radius-dynamic-from-no-radius-ref.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-backgrounds/border-radius-shorthand-002-ref.html": [
|
||||
[
|
||||
{}
|
||||
|
@ -294646,6 +294717,26 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/python-handlers/index.md": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/python-handlers/request.md": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/python-handlers/response.md": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/python-handlers/stash.md": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/reftests.md": [
|
||||
[
|
||||
{}
|
||||
|
@ -294661,6 +294752,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/server-pipes.md": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"docs/writing-tests/submission-process.md": [
|
||||
[
|
||||
{}
|
||||
|
@ -307646,6 +307742,21 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/resources/image.png": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/resources/image.png.headers": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/resources/resized.html": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/embedded-content/the-object-element/test0.html": [
|
||||
[
|
||||
{}
|
||||
|
@ -322116,6 +322227,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"service-workers/service-worker/resources/update-during-installation-worker.py": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"service-workers/service-worker/resources/update-fetch-worker.py": [
|
||||
[
|
||||
{}
|
||||
|
@ -330671,6 +330787,11 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/backends/base.py": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py": [
|
||||
[
|
||||
{}
|
||||
|
@ -358769,6 +358890,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-box/box-chrome-crash-001.html": [
|
||||
[
|
||||
"css/css-box/box-chrome-crash-001.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-box/inheritance.html": [
|
||||
[
|
||||
"css/css-box/inheritance.html",
|
||||
|
@ -362465,6 +362592,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/inheritance.html": [
|
||||
[
|
||||
"css/css-logical/inheritance.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/logical-box-border-color.html": [
|
||||
[
|
||||
"css/css-logical/logical-box-border-color.html",
|
||||
|
@ -362609,6 +362742,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-block-valid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-block-valid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-block-width-computed.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-block-width-computed.html",
|
||||
|
@ -362627,6 +362766,66 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-color-computed.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-color-computed.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-color-invalid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-color-invalid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-color-valid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-color-valid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-style-computed.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-style-computed.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-style-invalid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-style-invalid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-style-valid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-style-valid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-valid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-valid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-width-computed.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-width-computed.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-width-invalid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-width-invalid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-width-valid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/border-inline-width-valid.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"css/css-logical/parsing/inline-size-invalid.html": [
|
||||
[
|
||||
"css/css-logical/parsing/inline-size-invalid.html",
|
||||
|
@ -398515,6 +398714,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/avoid-reload-on-resize.html": [
|
||||
[
|
||||
"html/semantics/embedded-content/the-img-element/srcset/avoid-reload-on-resize.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html": [
|
||||
[
|
||||
"html/semantics/embedded-content/the-img-element/srcset/parse-a-srcset-attribute.html",
|
||||
|
@ -451870,6 +452075,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webrtc/RTCRtpSender-setStreams.https.html": [
|
||||
[
|
||||
"webrtc/RTCRtpSender-setStreams.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"webrtc/RTCRtpSender-transport.https.html": [
|
||||
[
|
||||
"webrtc/RTCRtpSender-transport.https.html",
|
||||
|
@ -456786,6 +456997,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"webxr/xrWebGLLayer_viewports.https.html": [
|
||||
[
|
||||
"webxr/xrWebGLLayer_viewports.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"workers/SharedWorker-MessageEvent-source.any.js": [
|
||||
[
|
||||
"workers/SharedWorker-MessageEvent-source.any.sharedworker.html",
|
||||
|
@ -514849,7 +515066,7 @@
|
|||
"support"
|
||||
],
|
||||
"cookies/http-state/resources/iframe-expectation-doc.html.py-str": [
|
||||
"f2cf31312d7f6f5c1d1b406ff23ba4a48e6bf084",
|
||||
"9b782a15f8451dada48b73e836f1dd716dd4f2d7",
|
||||
"support"
|
||||
],
|
||||
"cookies/http-state/resources/test-files/0001-expected": [
|
||||
|
@ -549144,6 +549361,10 @@
|
|||
"0248ccb910a8de03bf5d0f989b0844cf4bd2cc45",
|
||||
"reftest"
|
||||
],
|
||||
"css/CSS2/normal-flow/margin-collapse-through-percentage-padding.html": [
|
||||
"dfd5015d050689c3c3a01d785ab7b75025794505",
|
||||
"reftest"
|
||||
],
|
||||
"css/CSS2/normal-flow/margin-collapse-through-zero-height-block.html": [
|
||||
"471a4c7f5a4c054b1141162f88fdda9416343a5b",
|
||||
"reftest"
|
||||
|
@ -580220,6 +580441,14 @@
|
|||
"ceb41be975c90380e6def93961169b5082b9a3d6",
|
||||
"visual"
|
||||
],
|
||||
"css/css-backgrounds/border-radius-dynamic-from-no-radius-ref.html": [
|
||||
"72ada88416255c18c4e6606bee4b6cf8dc353698",
|
||||
"support"
|
||||
],
|
||||
"css/css-backgrounds/border-radius-dynamic-from-no-radius.html": [
|
||||
"335548f33ad4bb9d7c42b4b07323c0a398aa28fc",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-backgrounds/border-radius-horizontal-value-is-zero.html": [
|
||||
"3a461699b2375d62e63b35e5437d871272e73870",
|
||||
"reftest"
|
||||
|
@ -581416,6 +581645,10 @@
|
|||
"dde409360faf79a301c3ae3ea34a995d154d7bb4",
|
||||
"support"
|
||||
],
|
||||
"css/css-box/box-chrome-crash-001.html": [
|
||||
"351df37f1550ab40818b7f7f1c51191cfae5583e",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-box/inheritance.html": [
|
||||
"5047b8b1df07cb1c774b5f579101d69b2482058a",
|
||||
"testharness"
|
||||
|
@ -600944,6 +601177,10 @@
|
|||
"653925552f870f740d3c9fc397b4dc2267994103",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-logical/inheritance.html": [
|
||||
"5546a20d6cd8aa3887735c1f9955929dedbadaab",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/logical-box-border-color.html": [
|
||||
"b33528d9cd16b6de169cbd03e98b867403f090a6",
|
||||
"testharness"
|
||||
|
@ -601044,6 +601281,10 @@
|
|||
"860a1052b8346aadbbbf18faf818ab9248f35535",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-block-valid.html": [
|
||||
"973a1199c285f99713c4ef3790b77a391bf09926",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-block-width-computed.html": [
|
||||
"3b4d934f8b23b29cd5d7b3aae039ac51ac4ab410",
|
||||
"testharness"
|
||||
|
@ -601056,6 +601297,46 @@
|
|||
"98987df9a703ef38d20c6bc1581b2ca136342615",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-color-computed.html": [
|
||||
"e9eff2419fea7bfdbf204aca4879910bae103ebf",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-color-invalid.html": [
|
||||
"f0070c787bcd7c71d1a61d11b22265dd49f9ef6e",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-color-valid.html": [
|
||||
"6bf240006e1995af716dad92b3d4927cebe928d4",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-style-computed.html": [
|
||||
"adcd6d02976fca309f0479aa522128e704e92f60",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-style-invalid.html": [
|
||||
"6684dc19ecb426508a86fbce9d1db4c3b00eb10d",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-style-valid.html": [
|
||||
"4fd0cbbb0946d380ff0f78edfec85e7688f8b53e",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-valid.html": [
|
||||
"b7207c0f23541e958eeea0bbe0a8c527af67af23",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-width-computed.html": [
|
||||
"d421329bb28a3da8d70218ba4c13fc0498d0f202",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-width-invalid.html": [
|
||||
"8624fcf0fe104ec9703dda31390ff2518c0d1b94",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/border-inline-width-valid.html": [
|
||||
"03c3e0fca2fb56b7116aae6b25eae020538ecf57",
|
||||
"testharness"
|
||||
],
|
||||
"css/css-logical/parsing/inline-size-invalid.html": [
|
||||
"d3d5d3f84d9d01392533e787b9e6755d592ec96e",
|
||||
"testharness"
|
||||
|
@ -626069,7 +626350,7 @@
|
|||
"reftest"
|
||||
],
|
||||
"css/css-ui/appearance-menulist-button-002.html": [
|
||||
"0477f2d52ef16a44c16833d919c12c07014eae4c",
|
||||
"60a4312b16cdc02f79a9592d446177954ac0d5b2",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-ui/appearance-meter-001.html": [
|
||||
|
@ -628641,7 +628922,7 @@
|
|||
"reftest"
|
||||
],
|
||||
"css/css-ui/webkit-appearance-menulist-button-002.html": [
|
||||
"c8d61508d28fea5269bee40d016cd45fac79b20a",
|
||||
"078d568faa1795e3b86b7e623c2abc1d667b1c66",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-ui/webkit-appearance-meter-001.html": [
|
||||
|
@ -629013,7 +629294,7 @@
|
|||
"reftest"
|
||||
],
|
||||
"css/css-values/initial-background-color.html": [
|
||||
"7a6c6173c4f6998f56bbcb7f992ad38fca45ce58",
|
||||
"01543397ab6138f06acfcd85ec65d44f9fb7a54d",
|
||||
"reftest"
|
||||
],
|
||||
"css/css-values/lh-rlh-on-root-001.html": [
|
||||
|
@ -639049,9 +639330,13 @@
|
|||
"testharness"
|
||||
],
|
||||
"css/motion/animation/offset-rotate-interpolation.html": [
|
||||
"a73c1a41dc86a532c8f6431c73065f1b4d6ace65",
|
||||
"3b3d755f4f1faec257abd1a75eba11f8d4616d05",
|
||||
"testharness"
|
||||
],
|
||||
"css/motion/animation/reftests/offset-distance-interpolation-001.html": [
|
||||
"88441f5b547646274d95e8cf59e8bf29982f279e",
|
||||
"reftest"
|
||||
],
|
||||
"css/motion/animation/reftests/offset-path-path-interpolation-001.html": [
|
||||
"0f2765189684c345cc173868ecd612952d1ab6ca",
|
||||
"reftest"
|
||||
|
@ -639060,6 +639345,10 @@
|
|||
"9bc2409061d0ca3df287d33fdfb84bdecf522d01",
|
||||
"support"
|
||||
],
|
||||
"css/motion/animation/reftests/offset-rotate-interpolation-001.html": [
|
||||
"360caeea68242cc80cbdb131884c633a6f3f7b47",
|
||||
"reftest"
|
||||
],
|
||||
"css/motion/animation/resources/interpolation-testcommon.js": [
|
||||
"6933733e1970d06fd5473b74f7ba63a9a821624a",
|
||||
"support"
|
||||
|
@ -651313,7 +651602,7 @@
|
|||
"support"
|
||||
],
|
||||
"docs/conf.py": [
|
||||
"b3bce7971129bc2b4f62a86f4798ec69c49d7cc8",
|
||||
"73777025cbdc648dbb6fe0944eabd867ce9af6aa",
|
||||
"support"
|
||||
],
|
||||
"docs/index.rst": [
|
||||
|
@ -651420,6 +651709,22 @@
|
|||
"122a22b3f367d36d749c567c62c09ae9454c2aee",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/python-handlers/index.md": [
|
||||
"174f79aad900a5e3c1a873b26e2c060c22709db1",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/python-handlers/request.md": [
|
||||
"e2e4efc87410f157e5233dc32f2a6cdfb08bdc29",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/python-handlers/response.md": [
|
||||
"0db95e57bf608a6717cdd35c6d4c3e6c4c81bde3",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/python-handlers/stash.md": [
|
||||
"fdf50b216f7cf79f2ca0a84eb4ce788297cd5978",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/reftests.md": [
|
||||
"577b27d0db57cf0c6a6d49c89529611d507ca9f6",
|
||||
"support"
|
||||
|
@ -651429,7 +651734,11 @@
|
|||
"support"
|
||||
],
|
||||
"docs/writing-tests/server-features.md": [
|
||||
"16bf4e0ccdcfa0ce46aa3febf7a8b689ee3b39bb",
|
||||
"17fa1a887a779cedc8fdbbf40758ae0b1f26f68e",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/server-pipes.md": [
|
||||
"a2a09854a98ada790032fe31a2f5829322c37d87",
|
||||
"support"
|
||||
],
|
||||
"docs/writing-tests/submission-process.md": [
|
||||
|
@ -653265,7 +653574,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"domxpath/interfaces.tentative.html": [
|
||||
"780844ee7b11ce6ea1ee051d63166f1700cee3bf",
|
||||
"9036ad834a764798d2871a71a8b5734051949d8d",
|
||||
"testharness"
|
||||
],
|
||||
"domxpath/xml_xpath_runner.html": [
|
||||
|
@ -659652,14 +659961,26 @@
|
|||
"06641deb48b119f8236f391adae6ef252dcdcb1b",
|
||||
"manual"
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-twice-manual.tentative.html": [
|
||||
"a8b5531fa1835af333c7faab4ce041ce429cc4ca",
|
||||
"manual"
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-elements-manual.html": [
|
||||
"3291664c63ab4880dd844e5f75046d2f93c8f92f",
|
||||
"manual"
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-elements-manual.tentative.html": [
|
||||
"f46fb80490e2d626f2217777a6a75d1f546e54a3",
|
||||
"manual"
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-iframes-manual.html": [
|
||||
"c581a1575b77052f67d153e140613f91ba42e57b",
|
||||
"manual"
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen-two-iframes-manual.tentative.html": [
|
||||
"5dce676910f6d0c7a02efdb5a9bd15d2001f5b9e",
|
||||
"manual"
|
||||
],
|
||||
"fullscreen/api/element-request-fullscreen.html": [
|
||||
"23b4d2f5bfbed1f84f0b51494bdc394fe56ebcb8",
|
||||
"testharness"
|
||||
|
@ -670557,7 +670878,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html": [
|
||||
"9495bfc3c89ee27e6d81d074b5fd39ae820af376",
|
||||
"df0985d6fb435c25dce510f924b1470878c5602f",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html": [
|
||||
|
@ -671369,7 +671690,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/track/track-element/track-text-track-cue-list.html": [
|
||||
"5b11bfdea4cf935d96b21505b8681288793ee2c4",
|
||||
"73241ce0d4a1b82f9763f8410420ac59fa14d379",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/media-elements/track/track-element/track-texttracks.html": [
|
||||
|
@ -673092,6 +673413,10 @@
|
|||
"c564a5845d5d44c477e57c6f1d8eb6e8c0f457b0",
|
||||
"support"
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/avoid-reload-on-resize.html": [
|
||||
"a8038e5605760b4bcdd4c8bdca47cede880ad7a9",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/common.js": [
|
||||
"d4d2c7534c7fadac56a59a09455180f57697a6d9",
|
||||
"support"
|
||||
|
@ -673100,6 +673425,18 @@
|
|||
"ce1e4cebe5fac34441081915eddc9ab2514770ef",
|
||||
"testharness"
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/resources/image.png": [
|
||||
"d26878c9f22d53bb44be515fa9f0ffbb90a71cbd",
|
||||
"support"
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/resources/image.png.headers": [
|
||||
"edaec7ad154133f0d8ae4e69c2933a2905e82e87",
|
||||
"support"
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/resources/resized.html": [
|
||||
"6fb6847a66bdc33e2e3fbb6e5ddf86dfe313f343",
|
||||
"support"
|
||||
],
|
||||
"html/semantics/embedded-content/the-img-element/srcset/select-an-image-source.html": [
|
||||
"292395d3aef45b01dec8d9db576b42b4cde61749",
|
||||
"testharness"
|
||||
|
@ -680557,7 +680894,7 @@
|
|||
"support"
|
||||
],
|
||||
"interfaces/dedicated-workers.idl": [
|
||||
"eaed7af3d20c2ac2ca41bd3e2307363005855c0e",
|
||||
"8d7255f2a564e3dd648592db59e84dc3529359d1",
|
||||
"support"
|
||||
],
|
||||
"interfaces/dom.idl": [
|
||||
|
@ -681421,7 +681758,7 @@
|
|||
"support"
|
||||
],
|
||||
"lifecycle/resources/subframe.html": [
|
||||
"2f1d70a80a792401891d93f6ddebaea0876400b3",
|
||||
"b80ba9540a804bb326407935410d50c5fa2cfdbd",
|
||||
"support"
|
||||
],
|
||||
"lifecycle/resources/subframe_worker.html": [
|
||||
|
@ -682425,7 +682762,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"media-source/mediasource-getvideoplaybackquality.html": [
|
||||
"1823d0b34a342a80395e420c49486d0e86d38de4",
|
||||
"ec5894304040d401e12fb98773027eeae86b17e6",
|
||||
"testharness"
|
||||
],
|
||||
"media-source/mediasource-invalid-codec.html": [
|
||||
|
@ -682949,7 +683286,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"mediacapture-image/resources/imagecapture-helpers.js": [
|
||||
"6d5ffa1695d807a05edeb75a21d472856bdda252",
|
||||
"8252f42a637eb7f9c24917d63113f0adc1bf415a",
|
||||
"support"
|
||||
],
|
||||
"mediacapture-image/setOptions-reject.html": [
|
||||
|
@ -709189,7 +709526,7 @@
|
|||
"support"
|
||||
],
|
||||
"service-workers/service-worker/resources/test-helpers.sub.js": [
|
||||
"14101319fa9d9e4c76f33a471098d280f117a15f",
|
||||
"af8dad3a5be8aa831900b183ad7ee9a10417ba1a",
|
||||
"support"
|
||||
],
|
||||
"service-workers/service-worker/resources/test-request-headers-worker.js": [
|
||||
|
@ -709217,7 +709554,11 @@
|
|||
"support"
|
||||
],
|
||||
"service-workers/service-worker/resources/update-during-installation-worker.js": [
|
||||
"dabeec077f77d5e8d1924eb5f3bd5d8667b129f5",
|
||||
"3f89881c04384590b8b132c392977256bfb847ed",
|
||||
"support"
|
||||
],
|
||||
"service-workers/service-worker/resources/update-during-installation-worker.py": [
|
||||
"95e4522007c1d2be14045f7582ebe2b5347abd87",
|
||||
"support"
|
||||
],
|
||||
"service-workers/service-worker/resources/update-fetch-worker.py": [
|
||||
|
@ -709453,7 +709794,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"service-workers/service-worker/update-not-allowed.https.html": [
|
||||
"71fe1730e0d68e4e7e0949cfa408d3c2d4ed9d39",
|
||||
"0a54aa9350382bb082f407a1ea30b265575baae9",
|
||||
"testharness"
|
||||
],
|
||||
"service-workers/service-worker/update-on-navigation.https.html": [
|
||||
|
@ -710265,7 +710606,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"shape-detection/resources/shapedetection-helpers.js": [
|
||||
"09cea09c6fe0c1fb20c707a766e746b8246cfc02",
|
||||
"91d36658aab0bf9435cfc9d283be45ef1292e2ed",
|
||||
"support"
|
||||
],
|
||||
"shape-detection/shapedetection-cross-origin.sub.html": [
|
||||
|
@ -715825,7 +716166,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/manifest/vcs.py": [
|
||||
"d900012212eb32b2a4df01c781cabf0b48968bad",
|
||||
"5c3b118216ce3cfc1ff1096dd8c8bd4b112cc76a",
|
||||
"support"
|
||||
],
|
||||
"tools/mypy.ini": [
|
||||
|
@ -720281,7 +720622,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wpt/browser.py": [
|
||||
"ddc7837f192ae9307be0028636e92d4faf9b9ced",
|
||||
"1b883b93bbffc5e76cb59bed3b140cd25e020598",
|
||||
"support"
|
||||
],
|
||||
"tools/wpt/commands.json": [
|
||||
|
@ -720309,7 +720650,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wpt/run.py": [
|
||||
"98bcc2111ec45161c907581a4455730e98e33cfa",
|
||||
"0b306aee2554385e86c5ed042d030c3b2c3b78d0",
|
||||
"support"
|
||||
],
|
||||
"tools/wpt/testfiles.py": [
|
||||
|
@ -720345,7 +720686,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wpt/virtualenv.py": [
|
||||
"b99d15d1f6a466b975312b0ffde4f3161ae200c2",
|
||||
"4b7aa71a505734e48650064e7a2fd876c5a3d4e9",
|
||||
"support"
|
||||
],
|
||||
"tools/wpt/wpt.py": [
|
||||
|
@ -720785,7 +721126,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/manifestexpected.py": [
|
||||
"7a93fe41ec7a81e223c51fb6a0f57ac890b51f7a",
|
||||
"0ea4082efc2afecc63ee00504edb7e1b44e0d4d8",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/manifestinclude.py": [
|
||||
|
@ -720837,7 +721178,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/testrunner.py": [
|
||||
"9228af6369654f9e63e58c8cce2c1905ab11e458",
|
||||
"44b5401e4f8410b8ed68940b6845c6db590b68c5",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/tests/__init__.py": [
|
||||
|
@ -720925,7 +721266,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptlogging.py": [
|
||||
"9e3ff54593ffe27daf604694e8a9d5b486fa9f7c",
|
||||
"2070f77591dd7ba2dc9690e5f06809299a9eeb50",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/__init__.py": [
|
||||
|
@ -720936,12 +721277,16 @@
|
|||
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/backends/base.py": [
|
||||
"45e2147fc4ca509a9de28fcdcbb707d823459711",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py": [
|
||||
"5719a859fa4bc7e4ab4d1e9329ca74b2af6666f7",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/backends/static.py": [
|
||||
"7b4f5613c384929cfd48196f4412ffc9d1824e88",
|
||||
"6efad1c0e47b114b51259bb369a4ad15971268d7",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptmanifest/node.py": [
|
||||
|
@ -720981,7 +721326,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wptrunner.py": [
|
||||
"79ec2844ebfe79b24ab1bba533976082569e2173",
|
||||
"42712f6bc753575a3beaf37639df72e134477508",
|
||||
"support"
|
||||
],
|
||||
"tools/wptrunner/wptrunner/wpttest.py": [
|
||||
|
@ -721013,7 +721358,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptserve/docs/handlers.rst": [
|
||||
"c15aab635d96976af59c606d84d0a5750743544b",
|
||||
"f35a7b983ed89d43cd1a546f4715c00e18a395b5",
|
||||
"support"
|
||||
],
|
||||
"tools/wptserve/docs/index.rst": [
|
||||
|
@ -721029,7 +721374,7 @@
|
|||
"support"
|
||||
],
|
||||
"tools/wptserve/docs/pipes.rst": [
|
||||
"507631c51986cc0fdea1c0cd5ec273a48fc7b3b7",
|
||||
"2c9966d0b238d249944140681a02fc671c48c3e6",
|
||||
"support"
|
||||
],
|
||||
"tools/wptserve/docs/request.rst": [
|
||||
|
@ -727285,7 +727630,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webrtc/RTCPeerConnection-onnegotiationneeded.html": [
|
||||
"336b100de058200ab49400fac9ae00f8524b9da9",
|
||||
"3e31c327ac2480bb9d526e5c6665c3486449ff31",
|
||||
"testharness"
|
||||
],
|
||||
"webrtc/RTCPeerConnection-onsignalingstatechanged.https.html": [
|
||||
|
@ -727440,6 +727785,10 @@
|
|||
"1278737414c418a2b1604eae32590c0999e0d645",
|
||||
"testharness"
|
||||
],
|
||||
"webrtc/RTCRtpSender-setStreams.https.html": [
|
||||
"08592da4d528889565825f9147d789c89b7e18fc",
|
||||
"testharness"
|
||||
],
|
||||
"webrtc/RTCRtpSender-transport.https.html": [
|
||||
"8c0552dd68aba8c707c6cbe2c7d6f9f3c5f64f17",
|
||||
"testharness"
|
||||
|
@ -732053,7 +732402,7 @@
|
|||
"support"
|
||||
],
|
||||
"webxr/resources/webxr_util.js": [
|
||||
"3b010a43598af1dff31f501df0beb530ca729e07",
|
||||
"505a9281f57ecd13443dfff380e0028d74708990",
|
||||
"support"
|
||||
],
|
||||
"webxr/resources/xr-test-asserts.js": [
|
||||
|
@ -732180,6 +732529,10 @@
|
|||
"8090bcebadb39902189c716b8434de949e9c5ae9",
|
||||
"testharness"
|
||||
],
|
||||
"webxr/xrWebGLLayer_viewports.https.html": [
|
||||
"f789e473354890e39bc0ffa5abc410daea7615cf",
|
||||
"testharness"
|
||||
],
|
||||
"workers/META.yml": [
|
||||
"a7297d3844728b8bb2f7c82a2c4f32d65040a919",
|
||||
"support"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[margin-collapse-through-percentage-padding.html]
|
||||
expected: FAIL
|
|
@ -0,0 +1,2 @@
|
|||
[border-radius-dynamic-from-no-radius.html]
|
||||
expected: TIMEOUT
|
|
@ -2,7 +2,6 @@
|
|||
type: testharness
|
||||
|
||||
[single-byte-decoder.html?document]
|
||||
expected: TIMEOUT
|
||||
[ISO-8859-4: iso_8859-4:1988 (document.characterSet and document.inputEncoding)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -315,21 +315,21 @@
|
|||
[<iframe>: combined response Content-Type: */* text/html]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: combined response Content-Type: text/html */*;charset=gbk]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: combined response Content-Type: text/html;" text/plain]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html;charset=gbk text/plain text/html]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: */* text/html]
|
||||
[<iframe>: combined response Content-Type: text/html */*]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html;x=" text/plain]
|
||||
[<iframe>: separate response Content-Type: text/html;" text/plain]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: separate response Content-Type: text/html;" \\" text/plain]
|
||||
[<iframe>: separate response Content-Type: text/html */*;charset=gbk]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: combined response Content-Type: text/html;" \\" text/plain]
|
||||
expected: FAIL
|
||||
|
||||
[<iframe>: combined response Content-Type: text/html;x=" text/plain]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -11,6 +11,3 @@
|
|||
[X-Content-Type-Options%3A%20nosniff%0C]
|
||||
expected: FAIL
|
||||
|
||||
[X-Content-Type-Options%3A%20%22nosniFF%22]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[traverse_the_history_2.html]
|
||||
[traverse_the_history_5.html]
|
||||
[Multiple history traversals, last would be aborted]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[DOMContentLoaded-defer.html]
|
||||
[The end: DOMContentLoaded and defer scripts]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
[realtimeanalyser-fft-scaling.html]
|
||||
expected: TIMEOUT
|
||||
[X 2048-point FFT peak position is not equal to 64. Got 0.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[transition_calc_implicit.html]
|
||||
expected: TIMEOUT
|
|
@ -5,7 +5,7 @@
|
|||
<title>Cookie Test Expectation Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="data">{data}</div>
|
||||
<div id="data" style="white-space: pre">{data}</div>
|
||||
<script src="iframe-content-pushing.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
|
||||
<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#collapsing-margins">
|
||||
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=967193">
|
||||
<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
|
||||
<meta name="assert" content="A vertical percentage padding that resolves to 0 shouldn't prevent margins from collapsing through the box">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div style="float:left; width:100px; background:green;">
|
||||
<div id="container" style="width:100px;">
|
||||
<div style="width:100px; margin-bottom:100px;"></div>
|
||||
<div style="padding:100% 0;"></div>
|
||||
<div style="width:100px; margin-top:100px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.body.offsetTop;
|
||||
container.style.width = "0";
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<title>CSS Test Reference</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<style>
|
||||
#outer {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
#inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: green;
|
||||
border-radius: 50px;
|
||||
}
|
||||
</style>
|
||||
<p>Should be a green circle below</p>
|
||||
<div id="outer">
|
||||
<div id="inner"></div>
|
||||
</div>
|
|
@ -0,0 +1,36 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<title>CSS Test: Relative dynamic border-radius change</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://drafts.csswg.org/css-backgrounds/#border-radius">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1554755">
|
||||
<link rel="match" href="border-radius-dynamic-from-no-radius-ref.html">
|
||||
<style>
|
||||
#outer {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
#inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: green;
|
||||
/* The key is that this starts off computing to zero */
|
||||
border-radius: calc(100% - 1px);
|
||||
}
|
||||
</style>
|
||||
<p>Should be a green circle below</p>
|
||||
<div id="outer" style="width: 1px; height: 1px;">
|
||||
<div id="inner"></div>
|
||||
</div>
|
||||
<script>
|
||||
onload = function() {
|
||||
requestAnimationFrame(function() {
|
||||
requestAnimationFrame(function() {
|
||||
outer.style.height = "";
|
||||
outer.style.width = "";
|
||||
document.documentElement.className = "";
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<title>CSS Box: chrome crash</title>
|
||||
<link rel="author" href="mailto:atotic@google.com">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="help" href="https://crbug.com/967361">
|
||||
<meta name="assert" content="Chrome does not crash on narrow div with scrollbars.">
|
||||
<style>
|
||||
body {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
#target {
|
||||
overflow-y: scroll;
|
||||
max-height: 5px;
|
||||
background: gray;
|
||||
}
|
||||
</style>
|
||||
<!-- -->
|
||||
<div>
|
||||
<span>
|
||||
<div id="container">
|
||||
<div id="target">anon</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
test(() => {
|
||||
}, 'test passes if it does not crash');
|
||||
</script>
|
|
@ -0,0 +1,95 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Inheritance of CSS Logical Properties and Values properties</title>
|
||||
<link rel="help" href="https://www.w3.org/TR/css-logical-1/#property-index">
|
||||
<meta name="assert" content="Properties do not inherit.">
|
||||
<meta name="assert" content="Properties have initial values according to the spec.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/inheritance-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="reference-container">
|
||||
<div id="reference"></div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="target"></div>
|
||||
</div>
|
||||
<style>
|
||||
#reference-container {
|
||||
width: 300px;
|
||||
}
|
||||
#reference-container, #reference {
|
||||
border-style: solid; /* Avoid border-top-width computed style 0 */
|
||||
border-top-width: medium;
|
||||
}
|
||||
|
||||
#container, #target {
|
||||
border-block-end-style: solid; /* Avoid border-block-end-width computed style 0 */
|
||||
border-block-start-style: solid;
|
||||
border-inline-end-style: solid;
|
||||
border-inline-start-style: solid;
|
||||
}
|
||||
|
||||
#container {
|
||||
color: blue;
|
||||
width: 300px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
'use strict';
|
||||
const blue = "rgb(0, 0, 255)";
|
||||
const green = "rgb(0, 128, 0)";
|
||||
const mediumWidth = getComputedStyle(reference).borderTopWidth; // e.g. 3px
|
||||
const referenceWidth = getComputedStyle(reference).width; // e.g. 294px
|
||||
|
||||
assert_not_inherited('block-size', '0px', '10px');
|
||||
|
||||
assert_not_inherited('border-block-end-color', blue, green);
|
||||
assert_not_inherited('border-block-end-style', 'none', 'dotted');
|
||||
assert_not_inherited('border-block-end-width', mediumWidth, '10px');
|
||||
|
||||
assert_not_inherited('border-block-start-color', blue, green);
|
||||
assert_not_inherited('border-block-start-style', 'none', 'dotted');
|
||||
assert_not_inherited('border-block-start-width', mediumWidth, '10px');
|
||||
|
||||
assert_not_inherited('border-end-end-radius', '0px', '10px 20px');
|
||||
assert_not_inherited('border-end-start-radius', '0px', '10px 20px');
|
||||
|
||||
assert_not_inherited('border-inline-end-color', blue, green);
|
||||
assert_not_inherited('border-inline-end-style', 'none', 'dotted');
|
||||
assert_not_inherited('border-inline-end-width', mediumWidth, '10px');
|
||||
|
||||
assert_not_inherited('border-inline-start-color', blue, green);
|
||||
assert_not_inherited('border-inline-start-style', 'none', 'dotted');
|
||||
assert_not_inherited('border-inline-start-width', mediumWidth, '10px');
|
||||
|
||||
assert_not_inherited('border-start-end-radius', '0px', '10px 20px');
|
||||
assert_not_inherited('border-start-start-radius', '0px', '10px 20px');
|
||||
|
||||
assert_not_inherited('inline-size', referenceWidth, '10px');
|
||||
|
||||
assert_not_inherited('inset-block-end', 'auto', '10px');
|
||||
assert_not_inherited('inset-block-start', 'auto', '10px');
|
||||
assert_not_inherited('inset-inline-end', 'auto', '10px');
|
||||
assert_not_inherited('inset-inline-start', 'auto', '10px');
|
||||
|
||||
assert_not_inherited('margin-block-end', '0px', '10px');
|
||||
assert_not_inherited('margin-block-start', '0px', '10px');
|
||||
assert_not_inherited('margin-inline-end', '0px', '10px');
|
||||
assert_not_inherited('margin-inline-start', '0px', '10px');
|
||||
|
||||
assert_not_inherited('max-block-size', 'none', '10px');
|
||||
assert_not_inherited('max-inline-size', 'none', '10px');
|
||||
assert_not_inherited('min-block-size', '0px', '10px');
|
||||
assert_not_inherited('min-inline-size', '0px', '10px');
|
||||
|
||||
assert_not_inherited('padding-block-end', '0px', '10px');
|
||||
assert_not_inherited('padding-block-start', '0px', '10px');
|
||||
assert_not_inherited('padding-inline-end', '0px', '10px');
|
||||
assert_not_inherited('padding-inline-start', '0px', '10px');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-block with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-block">
|
||||
<meta name="assert" content="border-block supports the full grammar '<line-width> || <line-style> || <color>'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// Similar to css-backgrounds/parsing/border-valid.html
|
||||
|
||||
test_valid_value("border-block", "1px dotted red");
|
||||
test_valid_value("border-block", "double", ["double", "medium double"]);
|
||||
|
||||
test_valid_value("border-block-start", "green double thin", "thin double green");
|
||||
test_valid_value("border-block-start", "green", ["green", "medium none green"]);
|
||||
test_valid_value("border-block-end", "thin", ["thin", "thin none"]);
|
||||
test_valid_value("border-block-end", "calc(10px - 0.5em) dotted red");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: getComputedValue().borderInlineColor</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-color">
|
||||
<meta name="assert" content="border-inline-color is computed color(s).">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/computed-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="box"></div>
|
||||
<div id="target"></div>
|
||||
<style>
|
||||
#target {
|
||||
color: lime;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
test_computed_value("border-inline-start-color", "currentcolor", 'rgb(0, 255, 0)');
|
||||
test_computed_value("border-inline-start-color", "rgb(2, 3, 4)");
|
||||
test_computed_value("border-inline-end-color", "rgb(34, 51, 68)");
|
||||
test_computed_value("border-inline-end-color", "transparent", "rgba(0, 0, 0, 0)");
|
||||
test_computed_value("border-inline-color", "rgb(34, 51, 68)");
|
||||
test_computed_value("border-inline-color", "transparent rgb(2, 3, 4)", "rgba(0, 0, 0, 0) rgb(2, 3, 4)");
|
||||
test_computed_value("border-inline-color", "rgb(2, 3, 4) rgb(2, 3, 4)", "rgb(2, 3, 4)");
|
||||
test_computed_value("border-inline-color", "currentcolor lime", 'rgb(0, 255, 0)');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline-color with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-color">
|
||||
<meta name="assert" content="border-inline-color supports only the grammar '<color>{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("border-inline-start-color", "#12");
|
||||
test_invalid_value("border-inline-start-color", "auto");
|
||||
test_invalid_value("border-inline-start-color", "red green");
|
||||
test_invalid_value("border-inline-start-color", "rgb");
|
||||
test_invalid_value("border-inline-start-color", "rgb(1,2,3,4,5)");
|
||||
test_invalid_value("border-inline-start-color", "rgb(10%, 20, 30%)");
|
||||
test_invalid_value("border-inline-end-color", "#123456789");
|
||||
test_invalid_value("border-inline-end-color", "123");
|
||||
test_invalid_value("border-inline-end-color", "hsla(1,2,3,4,5)");
|
||||
test_invalid_value("border-inline-end-color", "red, green");
|
||||
test_invalid_value("border-inline-end-color", "rgb(1)");
|
||||
test_invalid_value("border-inline-end-color", "rgba(-2, 300, 400%, -0.5)");
|
||||
test_invalid_value("border-inline-color", "auto");
|
||||
test_invalid_value("border-inline-color", "lime, transparent");
|
||||
test_invalid_value("border-inline-color", "red green blue");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline-color with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-color">
|
||||
<meta name="assert" content="border-inline-color supports the full grammar '<color>{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_valid_value("border-inline-start-color", "currentcolor");
|
||||
test_valid_value("border-inline-start-color", "rgb(2, 3, 4)");
|
||||
test_valid_value("border-inline-end-color", "#234", "rgb(34, 51, 68)");
|
||||
test_valid_value("border-inline-end-color", "transparent");
|
||||
test_valid_value("border-inline-color", "#234", "rgb(34, 51, 68)");
|
||||
test_valid_value("border-inline-color", "transparent rgb(2, 3, 4)");
|
||||
test_valid_value("border-inline-color", "rgb(2, 3, 4) rgb(2, 3, 4)", "rgb(2, 3, 4)");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: getComputedValue().borderInlineStyle</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-style">
|
||||
<meta name="assert" content="border-inline-style is specified keyword(s).">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/computed-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
test_computed_value("border-inline-start-style", "dotted");
|
||||
test_computed_value("border-inline-start-style", "groove");
|
||||
test_computed_value("border-inline-start-style", "inset");
|
||||
test_computed_value("border-inline-start-style", "none");
|
||||
test_computed_value("border-inline-start-style", "solid");
|
||||
test_computed_value("border-inline-end-style", "dashed");
|
||||
test_computed_value("border-inline-end-style", "double");
|
||||
test_computed_value("border-inline-end-style", "hidden");
|
||||
test_computed_value("border-inline-end-style", "outset");
|
||||
test_computed_value("border-inline-end-style", "ridge");
|
||||
test_computed_value("border-inline-style", "dotted");
|
||||
test_computed_value("border-inline-style", "double groove");
|
||||
test_computed_value("border-inline-style", "hidden hidden", "hidden");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline-style with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-style">
|
||||
<meta name="assert" content="border-inline-style supports only the grammar '<line-style>{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("border-inline-start-style", "auto");
|
||||
test_invalid_value("border-inline-start-style", "hidden, outset");
|
||||
test_invalid_value("border-inline-end-style", "solid double");
|
||||
test_invalid_value("border-inline-style", "auto");
|
||||
test_invalid_value("border-inline-style", "groove, ridge");
|
||||
test_invalid_value("border-inline-style", "hidden inset dashed");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline-style with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-block">
|
||||
<meta name="assert" content="border-inline-style supports the full grammar '<line-style>{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset
|
||||
test_valid_value("border-inline-start-style", "dotted");
|
||||
test_valid_value("border-inline-start-style", "groove");
|
||||
test_valid_value("border-inline-start-style", "inset");
|
||||
test_valid_value("border-inline-start-style", "none");
|
||||
test_valid_value("border-inline-start-style", "solid");
|
||||
test_valid_value("border-inline-end-style", "dashed");
|
||||
test_valid_value("border-inline-end-style", "double");
|
||||
test_valid_value("border-inline-end-style", "hidden");
|
||||
test_valid_value("border-inline-end-style", "outset");
|
||||
test_valid_value("border-inline-end-style", "ridge");
|
||||
test_valid_value("border-inline-style", "dotted");
|
||||
test_valid_value("border-inline-style", "double groove");
|
||||
test_valid_value("border-inline-style", "hidden hidden", "hidden");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline">
|
||||
<meta name="assert" content="border-inline supports the full grammar '<line-width> || <line-style> || <color>'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// Similar to css-backgrounds/parsing/border-valid.html
|
||||
|
||||
test_valid_value("border-inline", "1px dotted red");
|
||||
test_valid_value("border-inline", "double", ["double", "medium double"]);
|
||||
|
||||
test_valid_value("border-inline-start", "green double thin", "thin double green");
|
||||
test_valid_value("border-inline-start", "green", ["green", "medium none green"]);
|
||||
test_valid_value("border-inline-end", "thin", ["thin", "thin none"]);
|
||||
test_valid_value("border-inline-end", "calc(10px - 0.5em) dotted red");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,76 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: getComputedValue().borderInlineWidth</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-width">
|
||||
<meta name="assert" content="border-inline-width is absolute length; zero if the border block style is none or hidden.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/computed-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="box"></div>
|
||||
<div id="target"></div>
|
||||
<style>
|
||||
#box {
|
||||
border-style: dotted; /* Avoid border-*-width computed style 0 */
|
||||
border-top-width: thin;
|
||||
border-right-width: medium;
|
||||
border-bottom-width: thick;
|
||||
}
|
||||
#target {
|
||||
font-size: 40px;
|
||||
border-inline-style: dotted; /* Avoid border-inline-*-width computed style 0 */
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
'use strict';
|
||||
const box = document.getElementById('box');
|
||||
const thinWidth = getComputedStyle(box).borderTopWidth;
|
||||
const mediumWidth = getComputedStyle(box).borderRightWidth;
|
||||
const thickWidth = getComputedStyle(box).borderBottomWidth;
|
||||
|
||||
test_computed_value("border-inline-start-width", "calc(10px + 0.5em)", "30px");
|
||||
test_computed_value("border-inline-start-width", "calc(10px - 0.5em)", "0px");
|
||||
test_computed_value("border-inline-start-width", "thin", thinWidth);
|
||||
test_computed_value("border-inline-start-width", "medium", mediumWidth);
|
||||
|
||||
test_computed_value("border-inline-end-width", "calc(10px + 0.5em)", "30px");
|
||||
test_computed_value("border-inline-end-width", "calc(10px - 0.5em)", "0px");
|
||||
test_computed_value("border-inline-end-width", "thick", thickWidth);
|
||||
|
||||
test_computed_value("border-inline-width", "10px");
|
||||
test_computed_value("border-inline-width", "10px 20px");
|
||||
test_computed_value("border-inline-width", "10px 10px", "10px");
|
||||
test(() => {
|
||||
box.style.borderInlineStartWidth = '10px';
|
||||
box.style.borderInlineEndWidth = '10px';
|
||||
|
||||
box.style.borderInlineStartStyle = 'groove';
|
||||
box.style.borderInlineEndStyle = 'solid';
|
||||
assert_equals(getComputedStyle(box).borderInlineStartWidth, '10px');
|
||||
assert_equals(getComputedStyle(box).borderInlineEndWidth, '10px');
|
||||
assert_equals(getComputedStyle(box).borderInlineWidth, '10px');
|
||||
|
||||
box.style.borderInlineStartStyle = 'hidden';
|
||||
box.style.borderInlineEndStyle = 'dashed';
|
||||
assert_equals(getComputedStyle(box).borderInlineStartWidth, '0px');
|
||||
assert_equals(getComputedStyle(box).borderInlineEndWidth, '10px');
|
||||
assert_equals(getComputedStyle(box).borderInlineWidth, '0px 10px');
|
||||
|
||||
box.style.borderInlineStartStyle = 'inset';
|
||||
box.style.borderInlineEndStyle = 'none';
|
||||
assert_equals(getComputedStyle(box).borderInlineStartWidth, '10px');
|
||||
assert_equals(getComputedStyle(box).borderInlineEndWidth, '0px');
|
||||
assert_equals(getComputedStyle(box).borderInlineWidth, '10px 0px');
|
||||
|
||||
box.style.borderInlineStartStyle = 'none';
|
||||
box.style.borderInlineEndStyle = 'hidden';
|
||||
assert_equals(getComputedStyle(box).borderInlineStartWidth, '0px');
|
||||
assert_equals(getComputedStyle(box).borderInlineEndWidth, '0px');
|
||||
assert_equals(getComputedStyle(box).borderInlineWidth, '0px');
|
||||
}, 'width is zero if the border block style is none or hidden');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline-width with invalid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-width">
|
||||
<meta name="assert" content="border-inline-width supports only the grammar '<line-width>{1,2}'.">
|
||||
<meta name="assert" content="Negative lengths are not allowed.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
test_invalid_value("border-inline-start-width", "-20px");
|
||||
test_invalid_value("border-inline-start-width", "auto");
|
||||
test_invalid_value("border-inline-start-width", "medium 40px");
|
||||
test_invalid_value("border-inline-end-width", "10");
|
||||
test_invalid_value("border-inline-end-width", "30%");
|
||||
|
||||
test_invalid_value("border-inline-width", "thick, thin");
|
||||
test_invalid_value("border-inline-width", "10px 20px 30px");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Logical Properties and Values: parsing border-inline-width with valid values</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-logical/#propdef-border-inline-width">
|
||||
<meta name="assert" content="border-inline-width supports the full grammar '<line-width>{1,2}'.">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/css/support/parsing-testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
// <length> | thin | medium | thick
|
||||
test_valid_value("border-inline-start-width", "10px");
|
||||
test_valid_value("border-inline-start-width", "calc(10px + 0.5em)");
|
||||
test_valid_value("border-inline-start-width", "thick");
|
||||
test_valid_value("border-inline-start-width", "thin");
|
||||
test_valid_value("border-inline-end-width", "0", "0px");
|
||||
test_valid_value("border-inline-end-width", "calc(10px - 0.5em)");
|
||||
test_valid_value("border-inline-end-width", "medium");
|
||||
test_valid_value("border-inline-width", "10px");
|
||||
test_valid_value("border-inline-width", "medium calc(10px + 0.5em)");
|
||||
test_valid_value("border-inline-width", "10px 10px", "10px");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="mismatch" href="appearance-auto-ref.html">
|
||||
<style>
|
||||
#container { width: 500px; }
|
||||
#container > #drop-down-select { -webkit-appearance: none; -webkit-appearance: menulist-button; }
|
||||
#container > #drop-down-select { appearance: none; appearance: menulist-button; }
|
||||
</style>
|
||||
<div id="container">
|
||||
<a>a</a>
|
||||
|
|
|
@ -10,7 +10,7 @@ Edit the appearance-* file instead and then run:
|
|||
<link rel="mismatch" href="appearance-auto-ref.html">
|
||||
<style>
|
||||
#container { width: 500px; }
|
||||
#container > #drop-down-select { -webkit--webkit-appearance: none; -webkit--webkit-appearance: menulist-button; }
|
||||
#container > #drop-down-select { -webkit-appearance: none; -webkit-appearance: menulist-button; }
|
||||
</style>
|
||||
<div id="container">
|
||||
<a>a</a>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
html, body { margin: 0px; padding: 0px; }
|
||||
|
||||
html { background: green; overflow: hidden; }
|
||||
#outer { position: absolute; top: 0px; left: 0px; red; width: 100%; height: 100%; }
|
||||
#outer { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; }
|
||||
#outer { background: red; background-color: initial; }
|
||||
|
||||
</style>
|
||||
|
|
|
@ -25,6 +25,45 @@
|
|||
{at: 2, expect: '260deg'}
|
||||
]);
|
||||
|
||||
test_interpolation({
|
||||
property: 'offset-rotate',
|
||||
from: 'auto 45deg',
|
||||
to: 'auto 125deg',
|
||||
}, [
|
||||
{at: -1, expect: 'auto -35deg'},
|
||||
{at: 0, expect: 'auto 45deg'},
|
||||
{at: 0.125, expect: 'auto 55deg'},
|
||||
{at: 0.875, expect: 'auto 115deg'},
|
||||
{at: 1, expect: 'auto 125deg'},
|
||||
{at: 2, expect: 'auto 205deg'}
|
||||
]);
|
||||
|
||||
test_interpolation({
|
||||
property: 'offset-rotate',
|
||||
from: 'auto 170deg',
|
||||
to: '100grad auto',
|
||||
}, [
|
||||
{at: -1, expect: 'auto 250deg'},
|
||||
{at: 0, expect: 'auto 170deg'},
|
||||
{at: 0.125, expect: 'auto 160deg'},
|
||||
{at: 0.875, expect: 'auto 100deg'},
|
||||
{at: 1, expect: '100grad auto'},
|
||||
{at: 2, expect: 'auto 10deg'}
|
||||
]);
|
||||
|
||||
test_interpolation({
|
||||
property: 'offset-rotate',
|
||||
from: 'auto -280deg',
|
||||
to: 'auto calc(90deg - 0.5turn - 300grad + 0rad)',
|
||||
}, [
|
||||
{at: -1, expect: 'auto -200deg'},
|
||||
{at: 0, expect: 'auto -280deg'},
|
||||
{at: 0.125, expect: 'auto -290deg'},
|
||||
{at: 0.875, expect: 'auto -350deg'},
|
||||
{at: 1, expect: 'auto calc(90deg - 0.5turn - 300grad + 0rad)'},
|
||||
{at: 2, expect: 'auto -440deg'}
|
||||
]);
|
||||
|
||||
test_interpolation({
|
||||
property: 'offset-rotate',
|
||||
from: 'auto 100deg',
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<title>offset-distance interpolation</title>
|
||||
<link rel="help" href="https://drafts.fxtf.org/motion-1/#offset-distance-property">
|
||||
<link rel="match" href="offset-path-path-interpolation-ref.html">
|
||||
<meta name="assert" content="offset-distance supports animation.">
|
||||
<style>
|
||||
@keyframes anim {
|
||||
from { offset-distance: 0%; }
|
||||
to { offset-distance: 100%; }
|
||||
}
|
||||
#target {
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
top: 0px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-color: lime;
|
||||
transform-origin: 0px 0px;
|
||||
offset-path: path("m 50 150 h 100");
|
||||
animation: anim 10s -5s paused linear;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
<script>
|
||||
requestAnimationFrame(() => {
|
||||
document.documentElement.classList.remove('reftest-wait');
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<title>offset-rotate interpolation</title>
|
||||
<link rel="help" href="https://drafts.fxtf.org/motion-1/#offset-rotate-property">
|
||||
<link rel="match" href="offset-path-path-interpolation-ref.html">
|
||||
<meta name="assert" content="offset-rotate supports animation.">
|
||||
<style>
|
||||
@keyframes anim {
|
||||
from { offset-rotate: auto; }
|
||||
to { offset-rotate: reverse; }
|
||||
}
|
||||
#target {
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
top: 0px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-color: lime;
|
||||
transform-origin: 0px 0px;
|
||||
offset-path: path("m 100 150 v -100");
|
||||
animation: anim 10s -5s paused linear;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
<script>
|
||||
requestAnimationFrame(() => {
|
||||
document.documentElement.classList.remove('reftest-wait');
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -42,7 +42,8 @@ release = u''
|
|||
# ones.
|
||||
extensions = [
|
||||
'recommonmark',
|
||||
'sphinxarg.ext'
|
||||
'sphinxarg.ext',
|
||||
'sphinx.ext.autodoc'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# Python Handlers
|
||||
|
||||
Python file handlers are Python files which the server executes in response to
|
||||
requests made to the corresponding URL. This is hooked up to a route like
|
||||
`("*", "*.py", python_file_handler)`, meaning that any .py file will be
|
||||
treated as a handler file (note that this makes it easy to write unsafe
|
||||
handlers, particularly when running the server in a web-exposed setting).
|
||||
|
||||
The Python files must define a single function `main` with the signature::
|
||||
|
||||
main(request, response)
|
||||
|
||||
The wptserver implements a number of Python APIs for controlling traffic.
|
||||
|
||||
```eval_rst
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
request
|
||||
response
|
||||
stash
|
||||
```
|
|
@ -0,0 +1,3 @@
|
|||
```eval_rst
|
||||
.. include:: ../../../tools/wptserve/docs/request.rst
|
||||
```
|
|
@ -0,0 +1,3 @@
|
|||
```eval_rst
|
||||
.. include:: ../../../tools/wptserve/docs/response.rst
|
||||
```
|
|
@ -0,0 +1,3 @@
|
|||
```eval_rst
|
||||
.. include:: ../../../tools/wptserve/docs/stash.rst
|
||||
```
|
|
@ -82,12 +82,20 @@ the file e.g. `test.html.sub.headers`.
|
|||
|
||||
### Tests Requiring Full Control Over The HTTP Response
|
||||
|
||||
```eval_rst
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
python-handlers/index
|
||||
server-pipes
|
||||
```
|
||||
|
||||
For full control over the request and response the server provides the
|
||||
ability to write `.asis` files; these are served as literal HTTP
|
||||
responses. It also provides the ability to write Python scripts that
|
||||
have access to request data and can manipulate the content and timing
|
||||
of the response. For details see the
|
||||
[wptserve documentation](https://wptserve.readthedocs.org).
|
||||
responses. It also provides the ability to write [Python
|
||||
"handlers"](python-handlers/index)--Python scripts that have access to request
|
||||
data and can manipulate the content and timing of the response. Responses are
|
||||
also influenced by [the `pipe` query string parameter](server-pipes).
|
||||
|
||||
|
||||
### Writing tests for HTTP/2.0
|
||||
|
|
136
tests/wpt/web-platform-tests/docs/writing-tests/server-pipes.md
Normal file
136
tests/wpt/web-platform-tests/docs/writing-tests/server-pipes.md
Normal file
|
@ -0,0 +1,136 @@
|
|||
# wptserve Pipes
|
||||
|
||||
## Enabling
|
||||
|
||||
Pipes are functions that may be used when serving files to alter parts
|
||||
of the response. These are invoked by adding a pipe= query parameter
|
||||
taking a | separated list of pipe functions and parameters. The pipe
|
||||
functions are applied to the response from left to right. For example:
|
||||
|
||||
GET /sample.txt?pipe=slice(1,200)|status(404).
|
||||
|
||||
This would serve bytes 1 to 199, inclusive, of foo.txt with the HTTP status
|
||||
code 404.
|
||||
|
||||
Note: If you write directly to the response socket using ResponseWriter, or
|
||||
when using the asis handler, only the trickle pipe will affect the response.
|
||||
|
||||
There are several built-in pipe functions, and it is possible to add
|
||||
more using the `@pipe` decorator on a function, if required.
|
||||
|
||||
Note: Because of the way pipes compose, using some pipe functions prevents the
|
||||
content-length of the response from being known in advance. In these cases the
|
||||
server will close the connection to indicate the end of the response,
|
||||
preventing the use of HTTP 1.1 keepalive.
|
||||
|
||||
## Built-In Pipes
|
||||
|
||||
### `sub`
|
||||
|
||||
Used to substitute variables from the server environment, or from the
|
||||
request into the response.
|
||||
|
||||
Substitutions are marked in a file using a block delimited by `{{`
|
||||
and `}}`. Inside the block the following variables are available:
|
||||
|
||||
- `{{host}}` - The host name of the server excluding any subdomain part.
|
||||
- `{{domains[]}}` - The domain name of a particular subdomain e.g.
|
||||
`{{domains[www]}}` for the `www` subdomain.
|
||||
- `{{ports[][]}}` - The port number of servers, by protocol e.g.
|
||||
`{{ports[http][0]}}` for the first (and, depending on setup, possibly only)
|
||||
http server
|
||||
- `{{headers[]}}` The HTTP headers in the request e.g. `{{headers[X-Test]}}`
|
||||
for a hypothetical `X-Test` header.
|
||||
- `{{header_or_default(header, default)}}` The value of an HTTP header, or a
|
||||
default value if it is absent. e.g. `{{header_or_default(X-Test,
|
||||
test-header-absent)}}`
|
||||
- `{{GET[]}}` The query parameters for the request e.g. `{{GET[id]}}` for an id
|
||||
parameter sent with the request.
|
||||
|
||||
So, for example, to write a JavaScript file called `xhr.js` that
|
||||
depends on the host name of the server, without hardcoding, one might
|
||||
write:
|
||||
|
||||
var server_url = http://{{host}}:{{ports[http][0]}}/path/to/resource;
|
||||
//Create the actual XHR and so on
|
||||
|
||||
The file would then be included as:
|
||||
|
||||
<script src="xhr.js?pipe=sub"></script>
|
||||
|
||||
This pipe can also be enabled by using a filename `*.sub.ext`, e.g. the file above could be called `xhr.sub.js`.
|
||||
|
||||
### `status`
|
||||
|
||||
Used to set the HTTP status of the response, for example:
|
||||
|
||||
example.js?pipe=status(410)
|
||||
|
||||
### `headers`
|
||||
|
||||
Used to add or replace http headers in the response. Takes two or
|
||||
three arguments; the header name, the header value and whether to
|
||||
append the header rather than replace an existing header (default:
|
||||
False). So, for example, a request for:
|
||||
|
||||
example.html?pipe=header(Content-Type,text/plain)
|
||||
|
||||
causes example.html to be returned with a text/plain content type
|
||||
whereas:
|
||||
|
||||
example.html?pipe=header(Content-Type,text/plain,True)
|
||||
|
||||
Will cause example.html to be returned with both text/html and
|
||||
text/plain content-type headers.
|
||||
|
||||
### `slice`
|
||||
|
||||
Used to send only part of a response body. Takes the start and,
|
||||
optionally, end bytes as arguments, although either can be null to
|
||||
indicate the start or end of the file, respectively. So for example:
|
||||
|
||||
example.txt?pipe=slice(10,20)
|
||||
|
||||
Would result in a response with a body containing 10 bytes of
|
||||
example.txt including byte 10 but excluding byte 20.
|
||||
|
||||
example.txt?pipe=slice(10)
|
||||
|
||||
Would cause all bytes from byte 10 of example.txt to be sent, but:
|
||||
|
||||
example.txt?pipe=slice(null,20)
|
||||
|
||||
Would send the first 20 bytes of example.txt.
|
||||
|
||||
### `trickle`
|
||||
|
||||
Note: Using this function will force a connection close.
|
||||
|
||||
Used to send the body of a response in chunks with delays. Takes a
|
||||
single argument that is a microsyntax consisting of colon-separated
|
||||
commands. There are three types of commands:
|
||||
|
||||
* Bare numbers represent a number of bytes to send
|
||||
|
||||
* Numbers prefixed `d` indicate a delay in seconds
|
||||
|
||||
* Numbers prefixed `r` must only appear at the end of the command, and
|
||||
indicate that the preceding N items must be repeated until there is
|
||||
no more content to send. The number of items to repeat must be even.
|
||||
|
||||
In the absence of a repetition command, the entire remainder of the content is
|
||||
sent at once when the command list is exhausted. So for example:
|
||||
|
||||
example.txt?pipe=trickle(d1)
|
||||
|
||||
causes a 1s delay before sending the entirety of example.txt.
|
||||
|
||||
example.txt?pipe=trickle(100:d1)
|
||||
|
||||
causes 100 bytes of example.txt to be sent, followed by a 1s delay,
|
||||
and then the remainder of the file to be sent. On the other hand:
|
||||
|
||||
example.txt?pipe=trickle(100:d1:r2)
|
||||
|
||||
Will cause the file to be sent in 100 byte chunks separated by a 1s
|
||||
delay until the whole content has been sent.
|
|
@ -8,26 +8,7 @@
|
|||
<script src='/resources/WebIDLParser.js'></script>
|
||||
<script src='/resources/idlharness.js'></script>
|
||||
<script type='text/plain'>
|
||||
[Constructor] interface XPathEvaluator {
|
||||
[NewObject] XPathExpression createExpression(DOMString expression,
|
||||
optional XPathNSResolver? resolver);
|
||||
Node createNSResolver(Node nodeResolver);
|
||||
XPathResult evaluate(DOMString expression, Node contextNode,
|
||||
optional XPathNSResolver? resolver,
|
||||
optional unsigned short type,
|
||||
optional object? result);
|
||||
};
|
||||
|
||||
interface XPathExpression {
|
||||
XPathResult evaluate(Node contextNode,
|
||||
optional unsigned short type,
|
||||
optional object? result);
|
||||
};
|
||||
|
||||
callback interface XPathNSResolver {
|
||||
DOMString? lookupNamespaceURI(DOMString? prefix);
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface XPathResult {
|
||||
const unsigned short ANY_TYPE = 0;
|
||||
const unsigned short NUMBER_TYPE = 1;
|
||||
|
@ -39,8 +20,10 @@ interface XPathResult {
|
|||
const unsigned short ORDERED_NODE_SNAPSHOT_TYPE = 7;
|
||||
const unsigned short ANY_UNORDERED_NODE_TYPE = 8;
|
||||
const unsigned short FIRST_ORDERED_NODE_TYPE = 9;
|
||||
|
||||
readonly attribute unsigned short resultType;
|
||||
readonly attribute double numberValue;
|
||||
readonly attribute unrestricted double numberValue;
|
||||
// Maybe "DOMString?".
|
||||
readonly attribute DOMString stringValue;
|
||||
readonly attribute boolean booleanValue;
|
||||
readonly attribute Node? singleNodeValue;
|
||||
|
@ -49,10 +32,37 @@ interface XPathResult {
|
|||
Node? iterateNext();
|
||||
Node? snapshotItem(unsigned long index);
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface XPathExpression {
|
||||
XPathResult evaluate(Node contextNode,
|
||||
optional unsigned short type,
|
||||
optional XPathResult? result);
|
||||
};
|
||||
|
||||
callback interface XPathNSResolver {
|
||||
DOMString? lookupNamespaceURI(DOMString? prefix);
|
||||
};
|
||||
|
||||
interface mixin XPathEvaluatorBase {
|
||||
[NewObject] XPathExpression createExpression(DOMString expression,
|
||||
optional XPathNSResolver? resolver);
|
||||
XPathNSResolver createNSResolver(Node nodeResolver);
|
||||
XPathResult evaluate(DOMString expression,
|
||||
Node contextNode,
|
||||
optional XPathNSResolver? resolver,
|
||||
optional unsigned short type,
|
||||
optional XPathResult? result);
|
||||
};
|
||||
|
||||
[Exposed=Window, Constructor]
|
||||
interface XPathEvaluator {};
|
||||
|
||||
XPathEvaluator includes XPathEvaluatorBase;
|
||||
</script>
|
||||
<script type='text/plain' class='untested'>
|
||||
interface Document {};
|
||||
Document implements XPathEvaluator;
|
||||
Document includes XPathEvaluatorBase;
|
||||
</script>
|
||||
<script>
|
||||
"use strict";
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Tentative due to:
|
||||
https://github.com/whatwg/fullscreen/issues/152
|
||||
|
||||
-->
|
||||
<title>Element#requestFullscreen() twice</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../trusted-click.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
promise_test(async (test) => {
|
||||
const div = document.querySelector("div");
|
||||
|
||||
const fullscreenChangePromise = new Promise((resolve, reject) => {
|
||||
document.onfullscreenchange = test.step_func(() => {
|
||||
assert_equals(document.fullscreenElement, div);
|
||||
// Ensure that there's only one fullscreenchange event.
|
||||
document.onfullscreenchange = test.unreached_func("second fullscreenchange event");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const fullscreenErrorPromise = new Promise((resolve, reject) => {
|
||||
document.onfullscreenerror = test.step_func(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
trusted_click(test, () => {
|
||||
// Request fullscreen twice.
|
||||
div.requestFullscreen();
|
||||
assert_equals(document.fullscreenElement, null, "fullscreenElement after first requestFullscreen()");
|
||||
var p = div.requestFullscreen();
|
||||
if (p) {
|
||||
p.then(test.unreached_func("promise unexpectedly resolved"), ()=>{});
|
||||
}
|
||||
}, document.body);
|
||||
|
||||
await Promise.all([
|
||||
fullscreenChangePromise,
|
||||
fullscreenErrorPromise,
|
||||
]);
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Tentative due to:
|
||||
https://github.com/whatwg/fullscreen/issues/152
|
||||
|
||||
-->
|
||||
<title>Element#requestFullscreen() on two elements in the same document</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../trusted-click.js"></script>
|
||||
<div id="log"></div>
|
||||
<div id="a"></div>
|
||||
<div id="b"></div>
|
||||
<script>
|
||||
promise_test(async (test) => {
|
||||
// Request fullscreen on both elements, but in reverse tree order.
|
||||
const a = document.getElementById('a');
|
||||
const b = document.getElementById('b');
|
||||
|
||||
// Expect two fullscreenchange events, with document.fullscreenElement
|
||||
// changing in the same order as the requests.
|
||||
const order = [];
|
||||
const fullscreenChangePromise = new Promise((resolve, reject) => {
|
||||
document.onfullscreenchange = test.step_func(() => {
|
||||
assert_in_array(document.fullscreenElement, [a, b]);
|
||||
order.push(document.fullscreenElement.id);
|
||||
if (order.length == 2) {
|
||||
// Since fullscreenchange event occurs at animation frame timing we might
|
||||
// have not seen the transition from null -> 'b' but just see the
|
||||
// resulting 'a' transition twice.
|
||||
assert_true(order[0] == 'a' || order[0] == 'b', 'first id seen is a or b');
|
||||
assert_true(order[1] == 'a', 'second id seen is b');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
const fullscreenErrorPromise = new Promise((resolve, reject) => {
|
||||
document.onfullscreenerror = test.step_func(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
trusted_click(test, () => {
|
||||
b.requestFullscreen();
|
||||
var p = a.requestFullscreen();
|
||||
if (p) {
|
||||
p.then(test.unreached_func("promise unexpectedly resolved"), ()=>{});
|
||||
}
|
||||
}, document.body);
|
||||
|
||||
await Promise.all([
|
||||
fullscreenChangePromise,
|
||||
fullscreenErrorPromise,
|
||||
]);
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Tentative due to:
|
||||
https://github.com/whatwg/fullscreen/issues/152
|
||||
|
||||
-->
|
||||
<title>Element#requestFullscreen() on two elements in different iframes</title>
|
||||
<meta name="timeout" content="long">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../trusted-click.js"></script>
|
||||
<div id="log"></div>
|
||||
<iframe id="a" allowfullscreen></iframe>
|
||||
<iframe id="b" allowfullscreen></iframe>
|
||||
<script>
|
||||
promise_test(async (test) => {
|
||||
// Request fullscreen on the body elements of both iframes, but in reverse
|
||||
// tree order.
|
||||
const a = document.getElementById('a');
|
||||
const b = document.getElementById('b');
|
||||
var rejected = false;
|
||||
|
||||
// Expect two fullscreenchange events, with document.fullscreenElement
|
||||
// changing in the same order as the requests. (Events should also fire on the
|
||||
// iframes' documents, but this is not covered by this test.)
|
||||
const order = [];
|
||||
const fullscreenChangePromise = new Promise((resolve, reject) => {
|
||||
document.onfullscreenchange = test.step_func(() => {
|
||||
assert_in_array(document.fullscreenElement, [a, b]);
|
||||
order.push(document.fullscreenElement.id);
|
||||
if (order.length == 2) {
|
||||
// When the second event arrived, the fullscreen element may still be the
|
||||
// old one.
|
||||
//
|
||||
// TODO(mustaq): We need a better explanation here to cover the tree-order
|
||||
// idea of the spec.
|
||||
assert_true(order[0] == 'a' || order[0] == 'b', 'first id seen is a or b');
|
||||
assert_true(order[1] == 'a', 'second id seen is a');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
const fullscreenErrorPromise = new Promise((resolve, reject) => {
|
||||
document.onfullscreenerror = test.step_func(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Make a trusted click on frame 'b' to activate it.
|
||||
trusted_click(test, () => {
|
||||
// Now queue a trusted click on frame 'a' to make back-to-back calls.
|
||||
setTimeout(() => {
|
||||
trusted_click(test, () => {
|
||||
b.contentDocument.body.requestFullscreen();
|
||||
a.contentDocument.body.requestFullscreen().catch(test.step_func_done());
|
||||
}, a.contentDocument.body);
|
||||
}, 0);
|
||||
}, b.contentDocument.body);
|
||||
|
||||
await Promise.all([
|
||||
fullscreenChangePromise,
|
||||
fullscreenErrorPromise,
|
||||
]);
|
||||
});
|
||||
</script>
|
|
@ -7,16 +7,21 @@
|
|||
<video hidden></video>
|
||||
<script>
|
||||
// Negative test for the specified behavior prior to HTML r8447.
|
||||
async_test(function(t) {
|
||||
promise_test(async function(t) {
|
||||
var v = document.querySelector('video');
|
||||
v.play();
|
||||
t.step_timeout(function() {
|
||||
var watcher = new EventWatcher(t, v, [ 'pause' ]);
|
||||
var p = v.play();
|
||||
|
||||
await new Promise(resolve => t.step_timeout(resolve, 0));
|
||||
assert_equals(v.networkState, v.NETWORK_EMPTY,
|
||||
'networkState after stable state');
|
||||
assert_false(v.paused, 'paused after stable state');
|
||||
v.parentNode.removeChild(v);
|
||||
assert_false(v.paused, 'paused after removing');
|
||||
v.onpause = t.step_func_done();
|
||||
}, 0);
|
||||
|
||||
await watcher.wait_for('pause');
|
||||
|
||||
await promise_rejects(t, 'AbortError', p, 'We expect promise being rejected');
|
||||
assert_true(v.paused, 'paused after removing and stable state');
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
// Testing TextTrackCueList [] operator.
|
||||
assert_equals(cues[0].id, "1");
|
||||
assert_equals(cues[3].id, "4");
|
||||
assert_object_equals(cues[4], undefined);
|
||||
assert_equals(cues[4], undefined);
|
||||
|
||||
// Testing TextTrackCueList getCueById().
|
||||
assert_equals(cues.getCueById("1").startTime, 0);
|
||||
assert_equals(cues.getCueById("4").startTime, 121);
|
||||
assert_object_equals(cues.getCueById("junk"), undefined);
|
||||
assert_equals(cues.getCueById("junk"), null);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<title>Avoid srcset image reloads when viewport resizes</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
setup({explicit_done:true});
|
||||
const image_was_loaded = () => {
|
||||
const iframe = document.getElementById("iframe");
|
||||
// Resize the iframe
|
||||
iframe.width="400";
|
||||
// Wait 500 ms
|
||||
step_timeout(() => {
|
||||
// Check that the iframe only loaded a single resource
|
||||
const entries = iframe.contentWindow.performance.getEntriesByType("resource");
|
||||
assert_equals(entries.length, 1);
|
||||
done();
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
<iframe id=iframe width="401" src="resources/resized.html" onload="image_was_loaded()"></iframe>
|
Binary file not shown.
After Width: | Height: | Size: 268 B |
|
@ -0,0 +1,3 @@
|
|||
Cache-Control: no-store
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<img srcset="image.png?400 400w, image.png?800 800w, image.png?1600 1600w" sizes="50vw">
|
|
@ -61,8 +61,8 @@ interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
|
|||
|
||||
typedef (DOMString or Function) TimerHandler;
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface WindowOrWorkerGlobalScope {
|
||||
[Exposed=(Window,Worker)]
|
||||
interface mixin WindowOrWorkerGlobalScope {
|
||||
[Replaceable] readonly attribute USVString origin;
|
||||
|
||||
// base64 utility methods
|
||||
|
@ -79,17 +79,17 @@ interface WindowOrWorkerGlobalScope {
|
|||
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, optional ImageBitmapOptions options);
|
||||
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options);
|
||||
};
|
||||
WorkerGlobalScope implements WindowOrWorkerGlobalScope;
|
||||
WorkerGlobalScope includes WindowOrWorkerGlobalScope;
|
||||
|
||||
[Exposed=Worker]
|
||||
interface WorkerNavigator {};
|
||||
WorkerNavigator implements NavigatorID;
|
||||
WorkerNavigator implements NavigatorLanguage;
|
||||
WorkerNavigator implements NavigatorOnLine;
|
||||
WorkerNavigator implements NavigatorConcurrentHardware;
|
||||
WorkerNavigator includes NavigatorID;
|
||||
WorkerNavigator includes NavigatorLanguage;
|
||||
WorkerNavigator includes NavigatorOnLine;
|
||||
WorkerNavigator includes NavigatorConcurrentHardware;
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface NavigatorID {
|
||||
[Exposed=(Window,Worker)]
|
||||
interface mixin NavigatorID {
|
||||
readonly attribute DOMString appCodeName; // constant "Mozilla"
|
||||
readonly attribute DOMString appName; // constant "Netscape"
|
||||
readonly attribute DOMString appVersion;
|
||||
|
@ -103,19 +103,19 @@ interface NavigatorID {
|
|||
// also has additional members in a partial interface
|
||||
};
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface NavigatorLanguage {
|
||||
[Exposed=(Window,Worker)]
|
||||
interface mixin NavigatorLanguage {
|
||||
readonly attribute DOMString language;
|
||||
readonly attribute FrozenArray<DOMString> languages;
|
||||
};
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface NavigatorOnLine {
|
||||
[Exposed=(Window,Worker)]
|
||||
interface mixin NavigatorOnLine {
|
||||
readonly attribute boolean onLine;
|
||||
};
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface NavigatorConcurrentHardware {
|
||||
[Exposed=(Window,Worker)]
|
||||
interface mixin NavigatorConcurrentHardware {
|
||||
readonly attribute unsigned long long hardwareConcurrency;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<img src="/common/slow.py">
|
||||
<script>
|
||||
window.addEventListener('load', () => {
|
||||
window.parent.postMessage('load');
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
assert_false(sourceBuffer.updating, "updating");
|
||||
mediaSource.endOfStream();
|
||||
assert_less_than(mediaSource.duration, 10, "duration");
|
||||
mediaElement.play();
|
||||
mediaElement.play().catch(test.unreached_func("Unexpected promise rejection"));;
|
||||
test.expectEvent(mediaElement, 'ended', 'mediaElement');
|
||||
});
|
||||
|
||||
|
@ -103,7 +103,7 @@
|
|||
mediaSource.endOfStream();
|
||||
assert_less_than(mediaSource.duration, 10, "duration");
|
||||
startTime = window.performance.now();
|
||||
mediaElement.play();
|
||||
mediaElement.play().catch(test.unreached_func("Unexpected promise rejection"));
|
||||
test.expectEvent(mediaElement, 'ended', 'mediaElement');
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// --enable-blink-features=MojoJS,MojoJSTest
|
||||
|
||||
let loadChromiumResources = Promise.resolve().then(() => {
|
||||
if (!MojoInterfaceInterceptor) {
|
||||
if (!('MojoInterfaceInterceptor' in self)) {
|
||||
// Do nothing on non-Chromium-based browsers or when the Mojo bindings are
|
||||
// not present in the global namespace.
|
||||
return;
|
||||
|
|
|
@ -75,9 +75,11 @@ function wait_for_update(test, registration) {
|
|||
}
|
||||
|
||||
return new Promise(test.step_func(function(resolve) {
|
||||
registration.addEventListener('updatefound', test.step_func(function() {
|
||||
var handler = test.step_func(function() {
|
||||
registration.removeEventListener('updatefound', handler);
|
||||
resolve(registration.installing);
|
||||
}));
|
||||
});
|
||||
registration.addEventListener('updatefound', handler);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,57 @@
|
|||
'use strict';
|
||||
|
||||
const installMayFinish = new Promise(resolve => {
|
||||
const installEventFired = new Promise(resolve => {
|
||||
self.fireInstallEvent = resolve;
|
||||
});
|
||||
|
||||
const installFinished = new Promise(resolve => {
|
||||
self.finishInstall = resolve;
|
||||
});
|
||||
|
||||
let report = { installEventFired: false };
|
||||
|
||||
addEventListener('install', event => {
|
||||
report.installEventFired = true;
|
||||
let attemptUpdate = registration.update().catch(exception => {
|
||||
report.exception = exception.name;
|
||||
});
|
||||
event.waitUntil(Promise.all([installMayFinish, attemptUpdate]));
|
||||
fireInstallEvent();
|
||||
event.waitUntil(installFinished);
|
||||
});
|
||||
|
||||
addEventListener('message', event => {
|
||||
if (event.data === 'finishInstall') {
|
||||
// Use a dedicated MessageChannel for every request so senders can wait for
|
||||
// individual requests to finish, and concurrent requests (to different
|
||||
// workers) don't cause race conditions.
|
||||
const port = event.data;
|
||||
port.onmessage = (event) => {
|
||||
switch (event.data) {
|
||||
case 'awaitInstallEvent':
|
||||
installEventFired.then(() => {
|
||||
port.postMessage('installEventFired');
|
||||
});
|
||||
break;
|
||||
|
||||
case 'finishInstall':
|
||||
installFinished.then(() => {
|
||||
port.postMessage('installFinished');
|
||||
});
|
||||
finishInstall();
|
||||
} else {
|
||||
event.source.postMessage(report);
|
||||
break;
|
||||
|
||||
case 'callUpdate': {
|
||||
const channel = new MessageChannel();
|
||||
registration.update().then(() => {
|
||||
channel.port2.postMessage({
|
||||
success: true,
|
||||
});
|
||||
}).catch((exception) => {
|
||||
channel.port2.postMessage({
|
||||
success: false,
|
||||
exception: exception.name,
|
||||
});
|
||||
});
|
||||
port.postMessage(channel.port1, [channel.port1]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
port.postMessage('Unexpected command ' + event.data);
|
||||
break;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import time
|
||||
|
||||
def main(request, response):
|
||||
headers = [('Content-Type', 'application/javascript'),
|
||||
('Cache-Control', 'max-age=0')]
|
||||
# Add timestamp to the worker so update() finds a new worker every time.
|
||||
body = '''
|
||||
// %s
|
||||
importScripts('update-during-installation-worker.js');
|
||||
'''.strip() % time.clock()
|
||||
return headers, body
|
|
@ -5,16 +5,85 @@
|
|||
<script>
|
||||
'use strict';
|
||||
|
||||
function send_message_to_worker_and_wait_for_response(worker, message) {
|
||||
return new Promise(resolve => {
|
||||
// Use a dedicated channel for every request to avoid race conditions on
|
||||
// concurrent requests.
|
||||
const channel = new MessageChannel();
|
||||
worker.postMessage(channel.port1, [channel.port1]);
|
||||
|
||||
let messageReceived = false;
|
||||
channel.port2.onmessage = event => {
|
||||
assert_false(messageReceived, 'Already received response for ' + message);
|
||||
messageReceived = true;
|
||||
resolve(event.data);
|
||||
};
|
||||
channel.port2.postMessage(message);
|
||||
});
|
||||
}
|
||||
|
||||
async function ensure_install_event_fired(worker) {
|
||||
const response = await send_message_to_worker_and_wait_for_response(worker, 'awaitInstallEvent');
|
||||
assert_equals('installEventFired', response);
|
||||
assert_equals('installing', worker.state, 'Expected worker to be installing.');
|
||||
}
|
||||
|
||||
async function finish_install(worker) {
|
||||
await ensure_install_event_fired(worker);
|
||||
const response = await send_message_to_worker_and_wait_for_response(worker, 'finishInstall');
|
||||
assert_equals('installFinished', response);
|
||||
}
|
||||
|
||||
async function activate_service_worker(t, worker) {
|
||||
await finish_install(worker);
|
||||
// By waiting for both states at the same time, the test fails
|
||||
// quickly if the installation fails, avoiding a timeout.
|
||||
await Promise.race([wait_for_state(t, worker, 'activated'),
|
||||
wait_for_state(t, worker, 'redundant')]);
|
||||
assert_equals('activated', worker.state, 'Service worker should be activated.');
|
||||
}
|
||||
|
||||
async function update_within_service_worker(worker) {
|
||||
// This function returns a Promise that resolves when update()
|
||||
// has been called but is not necessarily finished yet.
|
||||
// Call finish() on the returned object to wait for update() settle.
|
||||
const port = await send_message_to_worker_and_wait_for_response(worker, 'callUpdate');
|
||||
let messageReceived = false;
|
||||
return {
|
||||
finish: () => {
|
||||
return new Promise(resolve => {
|
||||
port.onmessage = event => {
|
||||
assert_false(messageReceived, 'Update already finished.');
|
||||
messageReceived = true;
|
||||
resolve(event.data);
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function update_from_client_and_await_installing_version(test, registration) {
|
||||
const updatefound = wait_for_update(test, registration);
|
||||
registration.update();
|
||||
await updatefound;
|
||||
return registration.installing;
|
||||
}
|
||||
|
||||
async function spin_up_service_worker(test) {
|
||||
const script = 'resources/update-during-installation-worker.js';
|
||||
const script = 'resources/update-during-installation-worker.py';
|
||||
const scope = 'resources/blank.html';
|
||||
|
||||
let registration = await service_worker_unregister_and_register(test, script, scope);
|
||||
test.add_cleanup(() => {
|
||||
const registration = await service_worker_unregister_and_register(test, script, scope);
|
||||
test.add_cleanup(async () => {
|
||||
if (registration.installing) {
|
||||
registration.installing.postMessage('finishInstall');
|
||||
// If there is an installing worker, we need to finish installing it.
|
||||
// Otherwise, the tests fails with an timeout because unregister() blocks
|
||||
// until the install-event-handler finishes.
|
||||
const worker = registration.installing;
|
||||
await send_message_to_worker_and_wait_for_response(worker, 'awaitInstallEvent');
|
||||
await send_message_to_worker_and_wait_for_response(worker, 'finishInstall');
|
||||
}
|
||||
registration.unregister();
|
||||
return registration.unregister();
|
||||
});
|
||||
|
||||
return registration;
|
||||
|
@ -23,36 +92,49 @@ async function spin_up_service_worker(test) {
|
|||
promise_test(async t => {
|
||||
const registration = await spin_up_service_worker(t);
|
||||
const worker = registration.installing;
|
||||
await ensure_install_event_fired(worker);
|
||||
|
||||
// spin_up_service_worker installs a cleanup hook that ensures the
|
||||
// worker finished its installation by sending it a
|
||||
// 'finishInstall' message, thus making sure that the registration
|
||||
// will be cleanly removed at the end of the test.
|
||||
assert_equals(worker.state, 'installing');
|
||||
promise_rejects(t, 'InvalidStateError', registration.update());
|
||||
}, 'ServiceWorkerRegistration.update() from client throws while installing service worker.')
|
||||
const result = registration.update();
|
||||
await activate_service_worker(t, worker);
|
||||
return result;
|
||||
}, 'ServiceWorkerRegistration.update() from client succeeds while installing service worker.');
|
||||
|
||||
promise_test(async t => {
|
||||
const registration = await spin_up_service_worker(t);
|
||||
const worker = registration.installing;
|
||||
worker.postMessage('finishInstall');
|
||||
await ensure_install_event_fired(worker);
|
||||
|
||||
// By waiting for both states at the same time, the test fails
|
||||
// quickly if the installation fails, avoiding a timeout.
|
||||
await Promise.race([wait_for_state(t, worker, 'activated'),
|
||||
wait_for_state(t, worker, 'redundant')]);
|
||||
assert_equals(worker.state, 'activated', 'Service worker should be activated.');
|
||||
|
||||
const response = await new Promise(resolve => {
|
||||
navigator.serviceWorker.onmessage = event => { resolve(event.data); };
|
||||
worker.postMessage('PING');
|
||||
// Add event listener to fail the test if update() succeeds.
|
||||
const updatefound = t.step_func(async () => {
|
||||
registration.removeEventListener('updatefound', updatefound);
|
||||
// Activate new worker so non-compliant browsers don't fail with timeout.
|
||||
await activate_service_worker(t, registration.installing);
|
||||
assert_unreached("update() should have failed");
|
||||
});
|
||||
registration.addEventListener('updatefound', updatefound);
|
||||
|
||||
// We check that the service worker instance that replied to the
|
||||
// message is the same one that received the 'install' event since
|
||||
// it's possible for them to be two distinct execution
|
||||
// environments.
|
||||
assert_true(response.installEventFired, 'Service worker should have been installed.');
|
||||
assert_equals(response.exception, 'InvalidStateError', 'update() should have thrown.');
|
||||
const update = await update_within_service_worker(worker);
|
||||
// Activate worker to ensure update() finishes and the test doesn't timeout
|
||||
// in non-compliant browsers.
|
||||
await activate_service_worker(t, worker);
|
||||
|
||||
const response = await update.finish();
|
||||
assert_false(response.success, 'update() should have failed.');
|
||||
assert_equals('InvalidStateError', response.exception, 'update() should have thrown InvalidStateError.');
|
||||
}, 'ServiceWorkerRegistration.update() from installing service worker throws.');
|
||||
|
||||
promise_test(async t => {
|
||||
const registration = await spin_up_service_worker(t);
|
||||
const worker1 = registration.installing;
|
||||
await activate_service_worker(t, worker1);
|
||||
|
||||
const worker2 = await update_from_client_and_await_installing_version(t, registration);
|
||||
await ensure_install_event_fired(worker2);
|
||||
|
||||
const update = await update_within_service_worker(worker1);
|
||||
// Activate the new version so that update() finishes and the test doesn't timeout.
|
||||
await activate_service_worker(t, worker2);
|
||||
const response = await update.finish();
|
||||
assert_true(response.success, 'update() from active service worker should have succeeded.');
|
||||
}, 'ServiceWorkerRegistration.update() from active service worker succeeds while installing service worker.');
|
||||
</script>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// --enable-blink-features=MojoJS,MojoJSTest
|
||||
|
||||
let loadChromiumResources = Promise.resolve().then(() => {
|
||||
if (!MojoInterfaceInterceptor) {
|
||||
if (!('MojoInterfaceInterceptor' in self)) {
|
||||
// Do nothing on non-Chromium-based browsers or when the Mojo bindings are
|
||||
// not present in the global namespace.
|
||||
return;
|
||||
|
|
|
@ -153,7 +153,7 @@ class MtimeCache(CacheFile):
|
|||
|
||||
def __init__(self, cache_root, tests_root, manifest_path, rebuild=False):
|
||||
self.manifest_path = manifest_path
|
||||
super(MtimeCache, self).__init__(cache_root, tests_root, rebuild=False)
|
||||
super(MtimeCache, self).__init__(cache_root, tests_root, rebuild)
|
||||
|
||||
def updated(self, rel_path, stat):
|
||||
"""Return a boolean indicating whether the file changed since the cache was last updated.
|
||||
|
|
|
@ -179,7 +179,11 @@ class Firefox(Browser):
|
|||
binary = find_executable("firefox", os.path.join(path, "firefox"))
|
||||
elif self.platform == "win":
|
||||
import mozinstall
|
||||
try:
|
||||
binary = mozinstall.get_binary(path, "firefox")
|
||||
except mozinstall.InvalidBinary:
|
||||
# ignore the case where we fail to get a binary
|
||||
pass
|
||||
elif self.platform == "macos":
|
||||
binary = find_executable("firefox", os.path.join(path, self.application_name.get(channel, "Firefox Nightly.app"),
|
||||
"Contents", "MacOS"))
|
||||
|
|
|
@ -125,6 +125,11 @@ def check_environ(product):
|
|||
else:
|
||||
hosts_path = "/etc/hosts"
|
||||
|
||||
if os.path.abspath(os.curdir) == wpt_root:
|
||||
wpt_path = "wpt"
|
||||
else:
|
||||
wpt_path = os.path.join(wpt_root, "wpt")
|
||||
|
||||
with open(hosts_path, "r") as f:
|
||||
for line in f:
|
||||
line = line.split("#", 1)[0].strip()
|
||||
|
@ -136,13 +141,14 @@ def check_environ(product):
|
|||
if is_windows:
|
||||
message = """Missing hosts file configuration. Run
|
||||
|
||||
python wpt make-hosts-file | Out-File %s -Encoding ascii -Append
|
||||
python %s make-hosts-file | Out-File %s -Encoding ascii -Append
|
||||
|
||||
in PowerShell with Administrator privileges.""" % hosts_path
|
||||
in PowerShell with Administrator privileges.""" % (wpt_path, hosts_path)
|
||||
else:
|
||||
message = """Missing hosts file configuration. Run
|
||||
|
||||
./wpt make-hosts-file | sudo tee -a %s""" % hosts_path
|
||||
%s make-hosts-file | sudo tee -a %s""" % ("./wpt" if wpt_path == "wpt" else wpt_path,
|
||||
hosts_path)
|
||||
raise WptrunError(message)
|
||||
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class Virtualenv(object):
|
|||
def install(self, *requirements):
|
||||
try:
|
||||
self.working_set.require(*requirements)
|
||||
except pkg_resources.ResolutionError:
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
@ -98,7 +98,7 @@ class Virtualenv(object):
|
|||
with open(requirements_path) as f:
|
||||
try:
|
||||
self.working_set.require(f.read())
|
||||
except pkg_resources.ResolutionError:
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
|
|
@ -3,7 +3,7 @@ from six.moves.urllib.parse import urljoin
|
|||
from collections import deque
|
||||
|
||||
from wptmanifest.backends import static
|
||||
from wptmanifest.backends.static import ManifestItem
|
||||
from wptmanifest.backends.base import ManifestItem
|
||||
|
||||
import expected
|
||||
|
||||
|
@ -198,7 +198,7 @@ def fuzzy_prop(node):
|
|||
|
||||
|
||||
class ExpectedManifest(ManifestItem):
|
||||
def __init__(self, name, test_path, url_base):
|
||||
def __init__(self, node, test_path, url_base):
|
||||
"""Object representing all the tests in a particular manifest
|
||||
|
||||
:param name: Name of the AST Node associated with this object.
|
||||
|
@ -207,13 +207,14 @@ class ExpectedManifest(ManifestItem):
|
|||
:param test_path: Path of the test file associated with this manifest.
|
||||
:param url_base: Base url for serving the tests in this manifest
|
||||
"""
|
||||
name = node.data
|
||||
if name is not None:
|
||||
raise ValueError("ExpectedManifest should represent the root node")
|
||||
if test_path is None:
|
||||
raise ValueError("ExpectedManifest requires a test path")
|
||||
if url_base is None:
|
||||
raise ValueError("ExpectedManifest requires a base url")
|
||||
ManifestItem.__init__(self, name)
|
||||
ManifestItem.__init__(self, node)
|
||||
self.child_map = {}
|
||||
self.test_path = test_path
|
||||
self.url_base = url_base
|
||||
|
@ -339,12 +340,12 @@ class DirectoryManifest(ManifestItem):
|
|||
|
||||
|
||||
class TestNode(ManifestItem):
|
||||
def __init__(self, name):
|
||||
def __init__(self, node, **kwargs):
|
||||
"""Tree node associated with a particular test in a manifest
|
||||
|
||||
:param name: name of the test"""
|
||||
assert name is not None
|
||||
ManifestItem.__init__(self, name)
|
||||
assert node.data is not None
|
||||
ManifestItem.__init__(self, node, **kwargs)
|
||||
self.updated_expected = []
|
||||
self.new_expected = []
|
||||
self.subtests = {}
|
||||
|
@ -431,12 +432,6 @@ class TestNode(ManifestItem):
|
|||
|
||||
|
||||
class SubtestNode(TestNode):
|
||||
def __init__(self, name):
|
||||
"""Tree node associated with a particular subtest in a manifest
|
||||
|
||||
:param name: name of the subtest"""
|
||||
TestNode.__init__(self, name)
|
||||
|
||||
@property
|
||||
def is_empty(self):
|
||||
if self._data:
|
||||
|
|
|
@ -7,9 +7,7 @@ from six.moves.queue import Empty
|
|||
from collections import namedtuple
|
||||
from multiprocessing import Process, current_process, Queue
|
||||
|
||||
from mozlog import structuredlog
|
||||
|
||||
import wptlogging
|
||||
from mozlog import structuredlog, capture
|
||||
|
||||
# Special value used as a sentinal in various commands
|
||||
Stop = object()
|
||||
|
@ -142,7 +140,7 @@ def start_runner(runner_command_queue, runner_result_queue,
|
|||
|
||||
logger = MessageLogger(send_message)
|
||||
|
||||
with wptlogging.CaptureIO(logger, capture_stdio):
|
||||
with capture.CaptureIO(logger, capture_stdio):
|
||||
try:
|
||||
browser = executor_browser_cls(**executor_browser_kwargs)
|
||||
executor = executor_cls(browser, **executor_kwargs)
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import logging
|
||||
import sys
|
||||
import threading
|
||||
from six import StringIO
|
||||
from multiprocessing import Queue
|
||||
|
||||
from mozlog import commandline, stdadapter, set_default_logger
|
||||
from mozlog.structuredlog import StructuredLogger
|
||||
|
||||
|
||||
def setup(args, defaults):
|
||||
logger = args.pop('log', None)
|
||||
if logger:
|
||||
|
@ -49,86 +46,3 @@ class LogLevelRewriter(object):
|
|||
data = data.copy()
|
||||
data["level"] = self.to_level
|
||||
return self.inner(data)
|
||||
|
||||
|
||||
class LogThread(threading.Thread):
|
||||
def __init__(self, queue, logger, level):
|
||||
self.queue = queue
|
||||
self.log_func = getattr(logger, level)
|
||||
threading.Thread.__init__(self, name="Thread-Log")
|
||||
self.daemon = True
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
msg = self.queue.get()
|
||||
except (EOFError, IOError):
|
||||
break
|
||||
if msg is None:
|
||||
break
|
||||
else:
|
||||
self.log_func(msg)
|
||||
|
||||
|
||||
class LoggingWrapper(StringIO):
|
||||
"""Wrapper for file like objects to redirect output to logger
|
||||
instead"""
|
||||
|
||||
def __init__(self, queue, prefix=None):
|
||||
StringIO.__init__(self)
|
||||
self.queue = queue
|
||||
self.prefix = prefix
|
||||
|
||||
def write(self, data):
|
||||
if isinstance(data, str):
|
||||
try:
|
||||
data = data.decode("utf8")
|
||||
except UnicodeDecodeError:
|
||||
data = data.encode("string_escape").decode("ascii")
|
||||
|
||||
if data.endswith("\n"):
|
||||
data = data[:-1]
|
||||
if data.endswith("\r"):
|
||||
data = data[:-1]
|
||||
if not data:
|
||||
return
|
||||
if self.prefix is not None:
|
||||
data = "%s: %s" % (self.prefix, data)
|
||||
self.queue.put(data)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
|
||||
class CaptureIO(object):
|
||||
def __init__(self, logger, do_capture):
|
||||
self.logger = logger
|
||||
self.do_capture = do_capture
|
||||
self.logging_queue = None
|
||||
self.logging_thread = None
|
||||
self.original_stdio = None
|
||||
|
||||
def __enter__(self):
|
||||
if self.do_capture:
|
||||
self.original_stdio = (sys.stdout, sys.stderr)
|
||||
self.logging_queue = Queue()
|
||||
self.logging_thread = LogThread(self.logging_queue, self.logger, "info")
|
||||
sys.stdout = LoggingWrapper(self.logging_queue, prefix="STDOUT")
|
||||
sys.stderr = LoggingWrapper(self.logging_queue, prefix="STDERR")
|
||||
self.logging_thread.start()
|
||||
|
||||
def __exit__(self, *args, **kwargs):
|
||||
if self.do_capture:
|
||||
sys.stdout, sys.stderr = self.original_stdio
|
||||
if self.logging_queue is not None:
|
||||
self.logger.info("Closing logging queue")
|
||||
self.logging_queue.put(None)
|
||||
if self.logging_thread is not None:
|
||||
self.logging_thread.join(10)
|
||||
while not self.logging_queue.empty():
|
||||
try:
|
||||
self.logger.warning("Dropping log message: %r", self.logging_queue.get())
|
||||
except Exception:
|
||||
pass
|
||||
self.logging_queue.close()
|
||||
self.logger.info("queue closed")
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
import abc
|
||||
|
||||
from ..node import NodeVisitor
|
||||
from ..parser import parse
|
||||
|
||||
|
||||
class Compiler(NodeVisitor):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def compile(self, tree, data_cls_getter=None, **kwargs):
|
||||
self._kwargs = kwargs
|
||||
return self._compile(tree, data_cls_getter, **kwargs)
|
||||
|
||||
def _compile(self, tree, data_cls_getter=None, **kwargs):
|
||||
"""Compile a raw AST into a form where conditional expressions
|
||||
are represented by ConditionalValue objects that can be evaluated
|
||||
at runtime.
|
||||
|
||||
tree - The root node of the wptmanifest AST to compile
|
||||
|
||||
data_cls_getter - A function taking two parameters; the previous
|
||||
output node and the current ast node and returning
|
||||
the class of the output node to use for the current
|
||||
ast node
|
||||
"""
|
||||
if data_cls_getter is None:
|
||||
self.data_cls_getter = lambda x, y: ManifestItem
|
||||
else:
|
||||
self.data_cls_getter = data_cls_getter
|
||||
|
||||
self.tree = tree
|
||||
self.output_node = self._initial_output_node(tree, **kwargs)
|
||||
self.visit(tree)
|
||||
if hasattr(self.output_node, "set_defaults"):
|
||||
self.output_node.set_defaults()
|
||||
assert self.output_node is not None
|
||||
return self.output_node
|
||||
|
||||
def _initial_output_node(self, node, **kwargs):
|
||||
return self.data_cls_getter(None, None)(node, **kwargs)
|
||||
|
||||
def visit_DataNode(self, node):
|
||||
if node != self.tree:
|
||||
output_parent = self.output_node
|
||||
self.output_node = self.data_cls_getter(self.output_node, node)(node, **self._kwargs)
|
||||
else:
|
||||
output_parent = None
|
||||
|
||||
assert self.output_node is not None
|
||||
|
||||
for child in node.children:
|
||||
self.visit(child)
|
||||
|
||||
if output_parent is not None:
|
||||
# Append to the parent *after* processing all the node data
|
||||
output_parent.append(self.output_node)
|
||||
self.output_node = self.output_node.parent
|
||||
|
||||
assert self.output_node is not None
|
||||
|
||||
@abc.abstractmethod
|
||||
def visit_KeyValueNode(self, node):
|
||||
pass
|
||||
|
||||
def visit_ListNode(self, node):
|
||||
return [self.visit(child) for child in node.children]
|
||||
|
||||
def visit_ValueNode(self, node):
|
||||
return node.data
|
||||
|
||||
def visit_AtomNode(self, node):
|
||||
return node.data
|
||||
|
||||
@abc.abstractmethod
|
||||
def visit_ConditionalNode(self, node):
|
||||
pass
|
||||
|
||||
def visit_StringNode(self, node):
|
||||
indexes = [self.visit(child) for child in node.children]
|
||||
|
||||
def value(x):
|
||||
rv = node.data
|
||||
for index in indexes:
|
||||
rv = rv[index(x)]
|
||||
return rv
|
||||
return value
|
||||
|
||||
def visit_NumberNode(self, node):
|
||||
if "." in node.data:
|
||||
return float(node.data)
|
||||
else:
|
||||
return int(node.data)
|
||||
|
||||
def visit_VariableNode(self, node):
|
||||
indexes = [self.visit(child) for child in node.children]
|
||||
|
||||
def value(x):
|
||||
data = x[node.data]
|
||||
for index in indexes:
|
||||
data = data[index(x)]
|
||||
return data
|
||||
return value
|
||||
|
||||
def visit_IndexNode(self, node):
|
||||
assert len(node.children) == 1
|
||||
return self.visit(node.children[0])
|
||||
|
||||
@abc.abstractmethod
|
||||
def visit_UnaryExpressionNode(self, node):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def visit_BinaryExpressionNode(self, node):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def visit_UnaryOperatorNode(self, node):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def visit_BinaryOperatorNode(self, node):
|
||||
pass
|
||||
|
||||
|
||||
class ManifestItem(object):
|
||||
def __init__(self, node, **kwargs):
|
||||
self.parent = None
|
||||
self.node = node
|
||||
self.children = []
|
||||
self._data = {}
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s %s>" % (self.__class__, self.node.data)
|
||||
|
||||
def __str__(self):
|
||||
rv = [repr(self)]
|
||||
for item in self.children:
|
||||
rv.extend(" %s" % line for line in str(item).split("\n"))
|
||||
return "\n".join(rv)
|
||||
|
||||
def set_defaults(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def is_empty(self):
|
||||
if self._data:
|
||||
return False
|
||||
return all(child.is_empty for child in self.children)
|
||||
|
||||
@property
|
||||
def root(self):
|
||||
node = self
|
||||
while node.parent is not None:
|
||||
node = node.parent
|
||||
return node
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.node.data
|
||||
|
||||
def get(self, key):
|
||||
for node in [self, self.root]:
|
||||
if key in node._data:
|
||||
return node._data[key]
|
||||
raise KeyError
|
||||
|
||||
def set(self, name, value):
|
||||
self._data[name] = value
|
||||
|
||||
def remove(self):
|
||||
if self.parent:
|
||||
self.parent.children.remove(self)
|
||||
self.parent = None
|
||||
|
||||
def iterchildren(self, name=None):
|
||||
for item in self.children:
|
||||
if item.name == name or name is None:
|
||||
yield item
|
||||
|
||||
def has_key(self, key):
|
||||
for node in [self, self.root]:
|
||||
if key in node._data:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _flatten(self):
|
||||
rv = {}
|
||||
for node in [self, self.root]:
|
||||
for name, value in node._data.iteritems():
|
||||
if name not in rv:
|
||||
rv[name] = value
|
||||
return rv
|
||||
|
||||
def iteritems(self):
|
||||
for item in self._flatten().iteritems():
|
||||
yield item
|
||||
|
||||
def iterkeys(self):
|
||||
for item in self._flatten().iterkeys():
|
||||
yield item
|
||||
|
||||
def itervalues(self):
|
||||
for item in self._flatten().itervalues():
|
||||
yield item
|
||||
|
||||
def append(self, child):
|
||||
child.parent = self
|
||||
self.children.append(child)
|
||||
return child
|
||||
|
||||
|
||||
def compile_ast(compiler, ast, data_cls_getter=None, **kwargs):
|
||||
return compiler().compile(ast,
|
||||
data_cls_getter=data_cls_getter,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def compile(compiler, stream, data_cls_getter=None, **kwargs):
|
||||
return compile_ast(compiler,
|
||||
parse(stream),
|
||||
data_cls_getter=data_cls_getter,
|
||||
**kwargs)
|
|
@ -1,10 +1,10 @@
|
|||
import operator
|
||||
|
||||
from ..node import NodeVisitor
|
||||
from . import base
|
||||
from ..parser import parse
|
||||
|
||||
|
||||
class Compiler(NodeVisitor):
|
||||
class Compiler(base.Compiler):
|
||||
"""Compiler backend that evaluates conditional expressions
|
||||
to give static output"""
|
||||
|
||||
|
@ -26,29 +26,7 @@ class Compiler(NodeVisitor):
|
|||
self._kwargs = kwargs
|
||||
self.expr_data = expr_data
|
||||
|
||||
if data_cls_getter is None:
|
||||
self.data_cls_getter = lambda x, y: ManifestItem
|
||||
else:
|
||||
self.data_cls_getter = data_cls_getter
|
||||
|
||||
self.output_node = None
|
||||
self.visit(tree)
|
||||
return self.output_node
|
||||
|
||||
def visit_DataNode(self, node):
|
||||
output_parent = self.output_node
|
||||
if self.output_node is None:
|
||||
assert node.parent is None
|
||||
self.output_node = self.data_cls_getter(None, None)(None, **self._kwargs)
|
||||
else:
|
||||
self.output_node = self.data_cls_getter(self.output_node, node)(node.data)
|
||||
|
||||
for child in node.children:
|
||||
self.visit(child)
|
||||
|
||||
if output_parent is not None:
|
||||
output_parent.append(self.output_node)
|
||||
self.output_node = self.output_node.parent
|
||||
return self._compile(tree, data_cls_getter, **kwargs)
|
||||
|
||||
def visit_KeyValueNode(self, node):
|
||||
key_name = node.data
|
||||
|
@ -61,15 +39,6 @@ class Compiler(NodeVisitor):
|
|||
if key_value is not None:
|
||||
self.output_node.set(key_name, key_value)
|
||||
|
||||
def visit_ValueNode(self, node):
|
||||
return node.data
|
||||
|
||||
def visit_AtomNode(self, node):
|
||||
return node.data
|
||||
|
||||
def visit_ListNode(self, node):
|
||||
return [self.visit(child) for child in node.children]
|
||||
|
||||
def visit_ConditionalNode(self, node):
|
||||
assert len(node.children) == 2
|
||||
if self.visit(node.children[0]):
|
||||
|
@ -81,12 +50,6 @@ class Compiler(NodeVisitor):
|
|||
value = self.visit(child)(value)
|
||||
return value
|
||||
|
||||
def visit_NumberNode(self, node):
|
||||
if "." in node.data:
|
||||
return float(node.data)
|
||||
else:
|
||||
return int(node.data)
|
||||
|
||||
def visit_VariableNode(self, node):
|
||||
value = self.expr_data[node.data]
|
||||
for child in node.children:
|
||||
|
@ -123,92 +86,6 @@ class Compiler(NodeVisitor):
|
|||
"!=": operator.ne}[node.data]
|
||||
|
||||
|
||||
class ManifestItem(object):
|
||||
def __init__(self, name, **kwargs):
|
||||
self.parent = None
|
||||
self.name = name
|
||||
self.children = []
|
||||
self._data = {}
|
||||
|
||||
def __repr__(self):
|
||||
return "<static.ManifestItem %s>" % (self.name)
|
||||
|
||||
def __str__(self):
|
||||
rv = [repr(self)]
|
||||
for item in self.children:
|
||||
rv.extend(" %s" % line for line in str(item).split("\n"))
|
||||
return "\n".join(rv)
|
||||
|
||||
def set_defaults(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def is_empty(self):
|
||||
if self._data:
|
||||
return False
|
||||
return all(child.is_empty for child in self.children)
|
||||
|
||||
@property
|
||||
def root(self):
|
||||
node = self
|
||||
while node.parent is not None:
|
||||
node = node.parent
|
||||
return node
|
||||
|
||||
def has_key(self, key):
|
||||
for node in [self, self.root]:
|
||||
if key in node._data:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get(self, key):
|
||||
for node in [self, self.root]:
|
||||
if key in node._data:
|
||||
return node._data[key]
|
||||
raise KeyError
|
||||
|
||||
def set(self, name, value):
|
||||
self._data[name] = value
|
||||
|
||||
def remove(self):
|
||||
if self.parent:
|
||||
self.parent._remove_child(self)
|
||||
|
||||
def _remove_child(self, child):
|
||||
self.children.remove(child)
|
||||
child.parent = None
|
||||
|
||||
def iterchildren(self, name=None):
|
||||
for item in self.children:
|
||||
if item.name == name or name is None:
|
||||
yield item
|
||||
|
||||
def _flatten(self):
|
||||
rv = {}
|
||||
for node in [self, self.root]:
|
||||
for name, value in node._data.iteritems():
|
||||
if name not in rv:
|
||||
rv[name] = value
|
||||
return rv
|
||||
|
||||
def iteritems(self):
|
||||
for item in self._flatten().iteritems():
|
||||
yield item
|
||||
|
||||
def iterkeys(self):
|
||||
for item in self._flatten().iterkeys():
|
||||
yield item
|
||||
|
||||
def itervalues(self):
|
||||
for item in self._flatten().itervalues():
|
||||
yield item
|
||||
|
||||
def append(self, child):
|
||||
child.parent = self
|
||||
self.children.append(child)
|
||||
return child
|
||||
|
||||
|
||||
def compile_ast(ast, expr_data, data_cls_getter=None, **kwargs):
|
||||
return Compiler().compile(ast,
|
||||
expr_data,
|
||||
|
|
|
@ -12,6 +12,7 @@ import testloader
|
|||
import wptcommandline
|
||||
import wptlogging
|
||||
import wpttest
|
||||
from mozlog import capture
|
||||
from font import FontInstaller
|
||||
from testrunner import ManagerGroup
|
||||
from browsers.base import NullBrowser
|
||||
|
@ -132,7 +133,7 @@ def get_pause_after_test(test_loader, **kwargs):
|
|||
|
||||
|
||||
def run_tests(config, test_paths, product, **kwargs):
|
||||
with wptlogging.CaptureIO(logger, not kwargs["no_capture_stdio"]):
|
||||
with capture.CaptureIO(logger, not kwargs["no_capture_stdio"]):
|
||||
env.do_delayed_imports(logger, test_paths)
|
||||
|
||||
product = products.load_product(config, product, load_cls=True)
|
||||
|
|
|
@ -71,16 +71,13 @@ decorator::
|
|||
Python File Handlers
|
||||
--------------------
|
||||
|
||||
Python file handlers are designed to provide a vaguely PHP-like interface
|
||||
where each resource corresponds to a particular python file on the
|
||||
filesystem. Typically this is hooked up to a route like ``("*",
|
||||
"*.py", python_file_handler)``, meaning that any .py file will be
|
||||
treated as a handler file (note that this makes python files unsafe in
|
||||
much the same way that .php files are when using PHP).
|
||||
Python file handlers are Python files which the server executes in response to
|
||||
requests made to the corresponding URL. This is hooked up to a route like
|
||||
``("*", "*.py", python_file_handler)``, meaning that any .py file will be
|
||||
treated as a handler file (note that this makes it easy to write unsafe
|
||||
handlers, particularly when running the server in a web-exposed setting).
|
||||
|
||||
Unlike PHP, the python files don't work by outputting text to stdout
|
||||
from the global scope. Instead they must define a single function
|
||||
`main` with the signature::
|
||||
The Python files must define a single function `main` with the signature::
|
||||
|
||||
main(request, response)
|
||||
|
||||
|
|
|
@ -1,163 +1,6 @@
|
|||
Pipes
|
||||
======
|
||||
|
||||
Pipes are functions that may be used when serving files to alter parts
|
||||
of the response. These are invoked by adding a pipe= query parameter
|
||||
taking a | separated list of pipe functions and parameters. The pipe
|
||||
functions are applied to the response from left to right. For example::
|
||||
|
||||
GET /sample.txt?pipe=slice(1,200)|status(404).
|
||||
|
||||
This would serve bytes 1 to 199, inclusive, of foo.txt with the HTTP status
|
||||
code 404.
|
||||
|
||||
.. note::
|
||||
If you write directly to the response socket using ResponseWriter,
|
||||
or when using the asis handler, only the trickle pipe will affect the response.
|
||||
|
||||
There are several built-in pipe functions, and it is possible to add
|
||||
more using the `@pipe` decorator on a function, if required.
|
||||
|
||||
.. note::
|
||||
Because of the way pipes compose, using some pipe functions prevents the
|
||||
content-length of the response from being known in advance. In these cases
|
||||
the server will close the connection to indicate the end of the response,
|
||||
preventing the use of HTTP 1.1 keepalive.
|
||||
|
||||
Built-In Pipes
|
||||
--------------
|
||||
|
||||
sub
|
||||
~~~
|
||||
|
||||
Used to substitute variables from the server environment, or from the
|
||||
request into the response.
|
||||
|
||||
Substitutions are marked in a file using a block delimited by `{{`
|
||||
and `}}`. Inside the block the following variables are available:
|
||||
|
||||
`{{host}}`
|
||||
The host name of the server excluding any subdomain part.
|
||||
|
||||
`{{domains[]}}`
|
||||
The domain name of a particular subdomain
|
||||
e.g. `{{domains[www]}}` for the `www` subdomain.
|
||||
|
||||
`{{ports[][]}}`
|
||||
The port number of servers, by protocol
|
||||
e.g. `{{ports[http][0]}}` for the first (and, depending on setup,
|
||||
possibly only) http server
|
||||
|
||||
`{{headers[]}}`
|
||||
The HTTP headers in the request
|
||||
e.g. `{{headers[X-Test]}}` for a hypothetical `X-Test` header.
|
||||
|
||||
`{{header_or_default(header, default)}}`
|
||||
The value of an HTTP header, or a default value if it is absent.
|
||||
e.g. `{{header_or_default(X-Test, test-header-absent)}}`
|
||||
|
||||
`{{GET[]}}`
|
||||
The query parameters for the request
|
||||
e.g. `{{GET[id]}}` for an id parameter sent with the request.
|
||||
|
||||
So, for example, to write a JavaScript file called `xhr.js` that
|
||||
depends on the host name of the server, without hardcoding, one might
|
||||
write::
|
||||
|
||||
var server_url = http://{{host}}:{{ports[http][0]}}/path/to/resource;
|
||||
//Create the actual XHR and so on
|
||||
|
||||
The file would then be included as:
|
||||
|
||||
<script src="xhr.js?pipe=sub"></script>
|
||||
|
||||
This pipe can also be enabled by using a filename `*.sub.ext`, e.g. the file above could be called `xhr.sub.js`.
|
||||
|
||||
status
|
||||
~~~~~~
|
||||
|
||||
Used to set the HTTP status of the response, for example::
|
||||
|
||||
example.js?pipe=status(410)
|
||||
|
||||
headers
|
||||
~~~~~~~
|
||||
|
||||
Used to add or replace http headers in the response. Takes two or
|
||||
three arguments; the header name, the header value and whether to
|
||||
append the header rather than replace an existing header (default:
|
||||
False). So, for example, a request for::
|
||||
|
||||
example.html?pipe=header(Content-Type,text/plain)
|
||||
|
||||
causes example.html to be returned with a text/plain content type
|
||||
whereas::
|
||||
|
||||
example.html?pipe=header(Content-Type,text/plain,True)
|
||||
|
||||
Will cause example.html to be returned with both text/html and
|
||||
text/plain content-type headers.
|
||||
|
||||
slice
|
||||
~~~~~
|
||||
|
||||
Used to send only part of a response body. Takes the start and,
|
||||
optionally, end bytes as arguments, although either can be null to
|
||||
indicate the start or end of the file, respectively. So for example::
|
||||
|
||||
example.txt?pipe=slice(10,20)
|
||||
|
||||
Would result in a response with a body containing 10 bytes of
|
||||
example.txt including byte 10 but excluding byte 20.
|
||||
|
||||
::
|
||||
|
||||
example.txt?pipe=slice(10)
|
||||
|
||||
Would cause all bytes from byte 10 of example.txt to be sent, but::
|
||||
|
||||
example.txt?pipe=slice(null,20)
|
||||
|
||||
Would send the first 20 bytes of example.txt.
|
||||
|
||||
trickle
|
||||
~~~~~~~
|
||||
|
||||
.. note::
|
||||
Using this function will force a connection close.
|
||||
|
||||
Used to send the body of a response in chunks with delays. Takes a
|
||||
single argument that is a microsyntax consisting of colon-separated
|
||||
commands. There are three types of commands:
|
||||
|
||||
* Bare numbers represent a number of bytes to send
|
||||
|
||||
* Numbers prefixed `d` indicate a delay in seconds
|
||||
|
||||
* Numbers prefixed `r` must only appear at the end of the command, and
|
||||
indicate that the preceding N items must be repeated until there is
|
||||
no more content to send. The number of items to repeat must be even.
|
||||
|
||||
In the absence of a repetition command, the entire remainder of the content is
|
||||
sent at once when the command list is exhausted. So for example::
|
||||
|
||||
example.txt?pipe=trickle(d1)
|
||||
|
||||
causes a 1s delay before sending the entirety of example.txt.
|
||||
|
||||
::
|
||||
|
||||
example.txt?pipe=trickle(100:d1)
|
||||
|
||||
causes 100 bytes of example.txt to be sent, followed by a 1s delay,
|
||||
and then the remainder of the file to be sent. On the other hand::
|
||||
|
||||
example.txt?pipe=trickle(100:d1:r2)
|
||||
|
||||
Will cause the file to be sent in 100 byte chunks separated by a 1s
|
||||
delay until the whole content has been sent.
|
||||
|
||||
|
||||
:mod:`Interface <pipes>`
|
||||
------------------------
|
||||
|
||||
|
|
|
@ -327,6 +327,27 @@
|
|||
await new Promise(resolve => pc.onnegotiationneeded = resolve);
|
||||
}, 'Updating the direction of the transceiver should cause negotiationneeded to fire');
|
||||
|
||||
/*
|
||||
5.2. RTCRtpSender Interface
|
||||
|
||||
setStreams
|
||||
7. Update the negotiation-needed flag for connection.
|
||||
*/
|
||||
promise_test(async t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const transceiver = pc.addTransceiver('audio', {direction:'sendrecv'});
|
||||
const offer = await pc.createOffer();
|
||||
await pc.setLocalDescription(offer);
|
||||
const answer = await generateAnswer(offer);
|
||||
await pc.setRemoteDescription(answer);
|
||||
|
||||
const stream = new MediaStream();
|
||||
transceiver.sender.setStreams(stream);
|
||||
await new Promise(resolve => pc.onnegotiationneeded = resolve);
|
||||
}, 'Calling setStreams should cause negotiationneeded to fire');
|
||||
|
||||
/*
|
||||
TODO
|
||||
4.7.3. Updating the Negotiation-Needed flag
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>RTCRtpSender.prototype.setStreams</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="RTCPeerConnection-helper.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
promise_test(async t => {
|
||||
const caller = new RTCPeerConnection();
|
||||
t.add_cleanup(() => caller.close());
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track] = stream.getTracks();
|
||||
|
||||
const sender = caller.addTrack(track);
|
||||
const stream1 = new MediaStream();
|
||||
const stream2 = new MediaStream();
|
||||
sender.setStreams(stream1, stream2);
|
||||
|
||||
const offer = await caller.createOffer();
|
||||
callee.setRemoteDescription(offer);
|
||||
return new Promise(resolve => callee.ontrack = t.step_func(event =>{
|
||||
assert_equals(event.streams.length, 2);
|
||||
const calleeStreamIds = event.streams.map(s => s.id);
|
||||
assert_in_array(stream1.id, calleeStreamIds);
|
||||
assert_in_array(stream2.id, calleeStreamIds);
|
||||
resolve();
|
||||
}));
|
||||
}, 'setStreams causes streams to be reported via ontrack on callee');
|
||||
|
||||
promise_test(async t => {
|
||||
const caller = new RTCPeerConnection();
|
||||
t.add_cleanup(() => caller.close());
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track] = stream.getTracks();
|
||||
|
||||
const sender = caller.addTrack(track);
|
||||
sender.setStreams(stream);
|
||||
|
||||
const offer = await caller.createOffer();
|
||||
callee.setRemoteDescription(offer);
|
||||
return new Promise(resolve => callee.ontrack = t.step_func(event =>{
|
||||
assert_equals(event.streams.length, 1);
|
||||
assert_equals(stream.id, event.streams[0].id);
|
||||
assert_equals(track.id, event.track.id);
|
||||
assert_equals(event.streams[0].getTracks()[0], event.track);
|
||||
resolve();
|
||||
}));
|
||||
}, 'setStreams can be used to reconstruct a stream with a track on the remote side');
|
||||
|
||||
|
||||
promise_test(async t => {
|
||||
const caller = new RTCPeerConnection();
|
||||
t.add_cleanup(() => caller.close());
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
|
||||
callee.ontrack = t.unreached_func();
|
||||
const transceiver = caller.addTransceiver('audio', {direction: 'inactive'});
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
|
||||
const stream1 = new MediaStream();
|
||||
const stream2 = new MediaStream();
|
||||
transceiver.direction = 'sendrecv';
|
||||
transceiver.sender.setStreams(stream1, stream2);
|
||||
|
||||
const offer = await caller.createOffer();
|
||||
callee.setRemoteDescription(offer);
|
||||
return new Promise(resolve => callee.ontrack = t.step_func(event =>{
|
||||
assert_equals(event.streams.length, 2);
|
||||
const calleeStreamIds = event.streams.map(s => s.id);
|
||||
assert_in_array(stream1.id, calleeStreamIds);
|
||||
assert_in_array(stream2.id, calleeStreamIds);
|
||||
assert_in_array(event.track, event.streams[0].getTracks());
|
||||
assert_in_array(event.track, event.streams[1].getTracks());
|
||||
resolve();
|
||||
}));
|
||||
}, 'Adding streams and changing direction causes new streams to be reported via ontrack on callee');
|
||||
|
||||
promise_test(async t => {
|
||||
const caller = new RTCPeerConnection();
|
||||
t.add_cleanup(() => caller.close());
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
|
||||
const stream1 = new MediaStream();
|
||||
const stream2 = new MediaStream();
|
||||
let calleeTrack = null;
|
||||
callee.ontrack = t.step_func(event => {
|
||||
assert_equals(event.streams.length, 0);
|
||||
calleeTrack = event.track;
|
||||
});
|
||||
const transceiver = caller.addTransceiver('audio', {direction: 'sendrecv'});
|
||||
await exchangeOfferAnswer(caller, callee);
|
||||
assert_true(calleeTrack instanceof MediaStreamTrack);
|
||||
|
||||
transceiver.sender.setStreams(stream1, stream2);
|
||||
const offer = await caller.createOffer();
|
||||
callee.setRemoteDescription(offer);
|
||||
return new Promise(resolve => callee.ontrack = t.step_func(event =>{
|
||||
assert_equals(event.streams.length, 2);
|
||||
const calleeStreamIds = event.streams.map(s => s.id);
|
||||
assert_in_array(stream1.id, calleeStreamIds);
|
||||
assert_in_array(stream2.id, calleeStreamIds);
|
||||
assert_in_array(event.track, event.streams[0].getTracks());
|
||||
assert_in_array(event.track, event.streams[1].getTracks());
|
||||
assert_equals(event.track, calleeTrack);
|
||||
resolve();
|
||||
}));
|
||||
}, 'Adding streams to an active transceiver causes new streams to be reported via ontrack on callee');
|
||||
|
||||
test(t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const stream1 = new MediaStream();
|
||||
const stream2 = new MediaStream();
|
||||
const transceiver = pc.addTransceiver('audio');
|
||||
|
||||
pc.close();
|
||||
assert_throws('InvalidStateError', () => transceiver.sender.setStreams(stream1, stream2));
|
||||
}, 'setStreams() fires InvalidStateError on a closed peer connection.');
|
||||
</script>
|
|
@ -116,7 +116,7 @@ function forEachWebxrObject(callback) {
|
|||
|
||||
// Code for loading test api in chromium.
|
||||
let loadChromiumResources = Promise.resolve().then(() => {
|
||||
if (!MojoInterfaceInterceptor) {
|
||||
if (!('MojoInterfaceInterceptor' in self)) {
|
||||
// Do nothing on non-Chromium-based browsers or when the Mojo bindings are
|
||||
// not present in the global namespace.
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="resources/test-constants.js"></script>
|
||||
<script src="resources/webxr_util.js"></script>
|
||||
<script src="resources/xr-test-asserts.js"></script>
|
||||
<canvas></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
let immersiveTestName = "XRWebGLLayer reports a valid viewports for immersive sessions";
|
||||
let inlineTestName = "XRWebGLLayer reports a valid viewports for inline sessions";
|
||||
|
||||
let fakeDeviceInitParams = { supportsImmersive:true };
|
||||
|
||||
let testFunction = function(session, fakeDeviceController, t) {
|
||||
// Need to have a valid pose.
|
||||
fakeDeviceController.setXRPresentationFrameData(VALID_POSE_MATRIX, [{
|
||||
eye:"left",
|
||||
projectionMatrix: VALID_PROJECTION_MATRIX,
|
||||
viewMatrix: VALID_VIEW_MATRIX
|
||||
}, {
|
||||
eye:"right",
|
||||
projectionMatrix: VALID_PROJECTION_MATRIX,
|
||||
viewMatrix: VALID_VIEW_MATRIX
|
||||
}]);
|
||||
|
||||
return session.requestReferenceSpace('viewer')
|
||||
.then((space) => new Promise((resolve) => {
|
||||
function onFrame(time, xrFrame) {
|
||||
let viewer_pose = xrFrame.getViewerPose(space);
|
||||
|
||||
let layer = xrFrame.session.renderState.baseLayer;
|
||||
for (view of viewer_pose.views) {
|
||||
let viewport = layer.getViewport(view);
|
||||
|
||||
// Ensure the returned object is an XRViewport object
|
||||
assert_not_equals(viewport, null);
|
||||
assert_true(viewport instanceof XRViewport);
|
||||
|
||||
// Ensure the viewport dimensions are valid
|
||||
assert_greater_than_equal(viewport.x, 0);
|
||||
assert_greater_than_equal(viewport.y, 0);
|
||||
assert_greater_than_equal(viewport.width, 1);
|
||||
assert_greater_than_equal(viewport.height, 1);
|
||||
}
|
||||
|
||||
// Finished test.
|
||||
resolve();
|
||||
}
|
||||
|
||||
session.requestAnimationFrame(onFrame);
|
||||
}));
|
||||
};
|
||||
|
||||
xr_session_promise_test(immersiveTestName, testFunction,
|
||||
fakeDeviceInitParams, 'immersive-vr');
|
||||
xr_session_promise_test(inlineTestName, testFunction,
|
||||
fakeDeviceInitParams, 'inline');
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue