summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/appmanifest
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/appmanifest
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/appmanifest')
-rw-r--r--testing/web-platform/tests/appmanifest/META.yml6
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-browser-manual.html36
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-fullscreen-manual.html36
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-minimal-ui-manual.html36
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-service-worker.js55
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-standalone-manual.html36
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-member/resources/icon.pngbin0 -> 9612 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-app-region-window-controls-overlay-manual.tentative.html73
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html67
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-browser-manual.tentative.html35
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-fullscreen-manual.tentative.html35
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-minimal-ui-manual.tentative.html35
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-service-worker.js59
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-manual.tentative.html35
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-overrides-browser-manual.tentative.html37
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html43
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/display-override-member/resources/icon.pngbin0 -> 8565 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html42
-rw-r--r--testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-service-worker.js52
-rw-r--r--testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.js39
-rw-r--r--testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest21
-rw-r--r--testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-sample-file.txt1
-rw-r--r--testing/web-platform/tests/appmanifest/file_handlers-member/resources/icon.pngbin0 -> 3799 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-fail-manual.sub.html16
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-manual.sub.html16
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-fail-manual.sub.html17
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-manual.sub.html17
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-last-matching-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-next-appropriate-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/icons-member-service-worker.js59
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/fail.pngbin0 -> 5957 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.sub.webmanifest10
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.sub.webmanifest10
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest10
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.sub.webmanifest10
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest14
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest13
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest10
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/pass.pngbin0 -> 5684 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/icons-member/resources/pass.png.sub.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/icon.pngbin0 -> 14565 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v1.html29
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v2.html25
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual.tentative.html22
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest13
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest13
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update.js34
-rw-r--r--testing/web-platform/tests/appmanifest/id-member/id-member-service-worker.js8
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/name-member-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/name-member-service-worker.js52
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/resources/icon.pngbin0 -> 9836 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/resources/name-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/orientation-member-landscape-manual.html25
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/orientation-member-portrait-manual.html25
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/orientation-member-service-worker.js53
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/resources/icon.pngbin0 -> 9871 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-manual.tentative.html34
-rw-r--r--testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-service-worker.js52
-rw-r--r--testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/icon.pngbin0 -> 1520 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest18
-rw-r--r--testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers_entry.html19
-rw-r--r--testing/web-platform/tests/appmanifest/short_name-member/resources/icon.pngbin0 -> 8321 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/short_name-member/short_name-member-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/short_name-member/short_name-member-service-worker.js52
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.pngbin0 -> 5684 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png.sub.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.sub.webmanifest22
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.sub.webmanifest22
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest22
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.sub.webmanifest22
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest27
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest27
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest27
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest26
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest26
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest22
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_fail.html4
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_pass.html4
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub.html17
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub.html17
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub.html18
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub.html18
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-manual.html10
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-service-worker.js61
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-empty-name-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-invalid-url-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-out-of-scope-url-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-name-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-url-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/fail.html4
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/pass.html5
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/resources/icon.pngbin0 -> 8364 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest11
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/start_url-member-fail-manual.sub.html16
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/start_url-member-pass-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/start_url-member/start_url-member-service-worker.js55
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/icon.pngbin0 -> 6591 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest12
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-hsl-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-named-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgb-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex3-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex6-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgblegacy-manual.html9
-rw-r--r--testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-service-worker.js57
-rw-r--r--testing/web-platform/tests/appmanifest/unrecognized-member/resources/icon.pngbin0 -> 9836 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest15
-rw-r--r--testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-manual.html10
-rw-r--r--testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-service-worker.js52
-rw-r--r--testing/web-platform/tests/appmanifest/user_preferences-member/resources/icon.pngbin0 -> 104 bytes
-rw-r--r--testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member-manual.js4
-rw-r--r--testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest22
-rw-r--r--testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest.headers1
-rw-r--r--testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-manual.html13
-rw-r--r--testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-service-worker.js52
194 files changed, 2681 insertions, 0 deletions
diff --git a/testing/web-platform/tests/appmanifest/META.yml b/testing/web-platform/tests/appmanifest/META.yml
new file mode 100644
index 0000000000..bef14c3c79
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/META.yml
@@ -0,0 +1,6 @@
+spec: https://w3c.github.io/manifest/
+suggested_reviewers:
+ - kenchris
+ - marcoscaceres
+ - mgiuca
+ - christianliebel
diff --git a/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-browser-manual.html b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-browser-manual.html
new file mode 100644
index 0000000000..690b4ba521
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-browser-manual.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test "browser" value of display member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest#display-member" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-browser" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="manifest" href="resources/display-member-media-feature-browser.webmanifest" />
+<script src="resources/display-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Testing support for "browser" value of display member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: browser) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const browser = matchMedia("(display-mode: browser)");
+
+browser.onchange = () => {
+ if (browser.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!browser.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-fullscreen-manual.html b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-fullscreen-manual.html
new file mode 100644
index 0000000000..a6db66679c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-fullscreen-manual.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test "fullscreen" value of display member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest#display-member" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-fullscreen" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="manifest" href="resources/display-member-media-feature-fullscreen.webmanifest" />
+<script src="resources/display-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Testing support for "fullscreen" value of display member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: fullscreen) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const fullscreen = matchMedia("(display-mode: fullscreen)");
+
+fullscreen.onchange = () => {
+ if (fullscreen.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!fullscreen.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-minimal-ui-manual.html b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-minimal-ui-manual.html
new file mode 100644
index 0000000000..b645d6cd7f
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-minimal-ui-manual.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test "minimal-ui" value of display member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest#display-member" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-minimal-ui" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="manifest" href="resources/display-member-media-feature-minimal-ui.webmanifest" />
+<script src="resources/display-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Testing support for "minimal-ui" value of display member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: minimal-ui) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const minimalUi = matchMedia("(display-mode: minimal-ui)");
+
+minimalUi.onchange = () => {
+ if (minimalUi.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!minimalUi.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-service-worker.js b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-service-worker.js
new file mode 100644
index 0000000000..5720e3cbc3
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-service-worker.js
@@ -0,0 +1,55 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "display-member-media-feature-browser-manual.html",
+ "display-member-media-feature-fullscreen-manual.html",
+ "display-member-media-feature-minimal-ui-manual.html",
+ "display-member-media-feature-standalone-manual.html",
+ "display-member-media-feature-service-worker.js",
+ "resources/display-member-media-feature-manual.js",
+ "resources/icon.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-standalone-manual.html b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-standalone-manual.html
new file mode 100644
index 0000000000..c820091f0f
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/display-member-media-feature-standalone-manual.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test "standalone" value of display member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest#display-member" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-standalone" />
+<link rel="manifest" href="resources/display-member-media-feature-standalone.webmanifest" />
+<script src="resources/display-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Testing support for "standalone" value of display member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: standalone) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const standalone = matchMedia("(display-mode: standalone)");
+
+standalone.onchange = () => {
+ if (standalone.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!standalone.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest
new file mode 100644
index 0000000000..9e1f6a3350
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-member-media-feature-browser-manual.html",
+ "display": "browser"
+}
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-browser.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest
new file mode 100644
index 0000000000..3954538e50
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-member-media-feature-fullscreen-manual.html",
+ "display": "fullscreen"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-fullscreen.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-manual.js b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-manual.js
new file mode 100644
index 0000000000..60723d5afe
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'display-member-media-feature-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest
new file mode 100644
index 0000000000..9463941aa4
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-member-media-feature-minimal-ui-manual.html",
+ "display": "minimal-ui"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-minimal-ui.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest
new file mode 100644
index 0000000000..a8269e977c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-member-media-feature-standalone-manual.html",
+ "display": "standalone"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/display-member-media-feature-standalone.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-member/resources/icon.png b/testing/web-platform/tests/appmanifest/display-member/resources/icon.png
new file mode 100644
index 0000000000..267cba8d1e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-app-region-window-controls-overlay-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-app-region-window-controls-overlay-manual.tentative.html
new file mode 100644
index 0000000000..c802ba67fa
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-app-region-window-controls-overlay-manual.tentative.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Test app-region CSS property when "window-controls-overlay" in display-override member</title>
+ <link rel="manifest" href="resources/display-override-member-app-region-window-controls-overlay.webmanifest" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <h1>Test app-region CSS property when "window-controls-overlay" in display-override member</h1>
+ <style>
+ #draggableRectangle {
+ app-region: drag;
+ background-color: blue;
+ position: absolute;
+ top: 25px;
+ left: 25px;
+ width: 250px;
+ height: 250px;
+ color: white;
+ }
+
+ #outerRectangle {
+ background-color: green;
+ position: relative;
+ width: 300px;
+ height: 300px;
+ text-align: center;
+ }
+
+ #innerRectangle {
+ app-region: no-drag;
+ background-color: red;
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 150px;
+ height: 150px;
+ }
+ </style>
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/display-override-member-media-feature-manual.js"></script>
+
+ <script>
+ setup({ explicit_timeout: true })
+ var manual_test = async_test("app-region element drags window");
+
+ window.addEventListener('DOMContentLoaded', function () {
+ document.getElementById('outerRectangle').addEventListener('click', manual_test.unreached_func('click event fired on outer rectangle'));
+ document.getElementById('innerRectangle').addEventListener('click', (e) => {e.stopPropagation();}, true);
+ });
+ </script>
+</head>
+
+<body>
+ <h1>Description</h1>
+ <p>This test validates that an element will drag the window around when running in "window-controls-overlay" mode.</p>
+ <h1>Manual Test Steps:</h1>
+ <p>
+ <ol>
+ <li> Install this app, and toggle into "window-controls-overlay" mode.</li>
+ <li> Click and drag the blue rectangle containing the text "Drag Me". This element has the app-region:drag CSS property set.</li>
+ <li> If the app window moves around as you drag the blue rectangle, <button onclick="manual_test.done()">Click Here</button>.</li>
+ </ol>
+ </p>
+ <div id="outerRectangle">
+ <div id="draggableRectangle">
+ Drag Me
+ <div id="innerRectangle">Not Draggable</div>
+ </div>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html
new file mode 100644
index 0000000000..a49b4f6f98
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Test CSS environment variables when "window-controls-overlay" in display-override member</title>
+ <link rel="manifest" href="resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <h1>Test CSS environment variables when "window-controls-overlay" in display-override member</h1>
+ <style>
+ #windowControlsOverlayElementStyle {
+ padding-left: env(titlebar-area-x);
+ padding-right: env(titlebar-area-width);
+ padding-top: env(titlebar-area-y);
+ padding-bottom: env(titlebar-area-height);
+ }
+ </style>
+
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/display-override-member-media-feature-manual.js"></script>
+
+ <script>
+ setup({ explicit_timeout: true });
+ var manual_test = async_test("titlebar-area CSS environment variables");
+ manual_test.step_timeout(() => {
+ manual_test.force_timeout();
+ manual_test.done();
+ }, 60000);
+ manual_test.step(() => {
+ navigator.windowControlsOverlay.addEventListener('geometrychange', (event) => {
+ if (navigator.windowControlsOverlay.visible) {
+ const windowControlsOverlayElementStyle = document.getElementById('windowControlsOverlayElementStyle');
+ const x = getComputedStyle(windowControlsOverlayElementStyle).getPropertyValue('padding-left');
+ const w = getComputedStyle(windowControlsOverlayElementStyle).getPropertyValue('padding-right');
+ const y = getComputedStyle(windowControlsOverlayElementStyle).getPropertyValue('padding-top');
+ const h = getComputedStyle(windowControlsOverlayElementStyle).getPropertyValue('padding-bottom');
+ const boundingClientRect = navigator.windowControlsOverlay.getTitlebarAreaRect();
+ manual_test.step(() => {
+ assert_equals(x, boundingClientRect.x + 'px', 'CSS environment "titlebar-area-x" does not equal navigator.windowControlsOverlay.getTitlebarAreaRect().x');
+ assert_equals(y, boundingClientRect.y + 'px', 'CSS environment "titlebar-area-x" does not equal navigator.windowControlsOverlay.getTitlebarAreaRect().y');
+ assert_equals(w, boundingClientRect.width + 'px', 'CSS environment "titlebar-area-x" does not equal navigator.windowControlsOverlay.getTitlebarAreaRect().width');
+ assert_equals(h, boundingClientRect.height + 'px', 'CSS environment "titlebar-area-x" does not equal navigator.windowControlsOverlay.getTitlebarAreaRect().height');
+ });
+ manual_test.done();
+ }
+ });
+ });
+ </script>
+</head>
+
+<body>
+ <h1>Description</h1>
+ <p>This test validates that when in "window-controls-overlay" mode, the 'titlebar-area-*' CSS environment variables
+ match the values returned by navigator.windowControlsOverlay.getTitlebarAreaRect().</p>
+ <h1>Manual Test Steps:</h1>
+ <p>
+ <ol>
+ <li> Install this app, and toggle into "window-controls-overlay" mode.</li>
+ <li> Upon toggling into "window-controls-overlay" mode, the test will validate that the CSS enviroment variable
+ values match the JavaScript API.</li>
+ </ol>
+ Note: This test will automatically timeout and fail if not completed within 60 seconds.
+ </p>
+ <div id="windowControlsOverlayElementStyle"></div>
+</body>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-browser-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-browser-manual.tentative.html
new file mode 100644
index 0000000000..d13d0986ad
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-browser-manual.tentative.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Test "browser" in display-override member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-browser" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="manifest" href="resources/display-override-member-media-feature-browser.webmanifest" />
+<script src="resources/display-override-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Test "browser" in display-override member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: browser) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const browser = matchMedia("(display-mode: browser)");
+
+browser.onchange = () => {
+ if (browser.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!browser.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-fullscreen-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-fullscreen-manual.tentative.html
new file mode 100644
index 0000000000..0b9923f8bd
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-fullscreen-manual.tentative.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Test "fullscreen" in display-override member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-fullscreen" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="manifest" href="resources/display-override-member-media-feature-fullscreen.webmanifest" />
+<script src="resources/display-override-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Test "fullscreen" in display-override member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: fullscreen) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const fullscreen = matchMedia("(display-mode: fullscreen)");
+
+fullscreen.onchange = () => {
+ if (fullscreen.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!fullscreen.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-minimal-ui-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-minimal-ui-manual.tentative.html
new file mode 100644
index 0000000000..5b9d63977d
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-minimal-ui-manual.tentative.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Test "minimal-ui" in display-override member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-minimal-ui" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="manifest" href="resources/display-override-member-media-feature-minimal-ui.webmanifest" />
+<script src="resources/display-override-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Test "minimal-ui" in display-override member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: minimal-ui) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const minimalUi = matchMedia("(display-mode: minimal-ui)");
+
+minimalUi.onchange = () => {
+ if (minimalUi.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!minimalUi.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-service-worker.js b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-service-worker.js
new file mode 100644
index 0000000000..02818dc665
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-service-worker.js
@@ -0,0 +1,59 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "display-override-member-app-region-window-controls-overlay-manual.tentative.html",
+ "display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html",
+ "display-override-member-media-feature-browser-manual.tentative.html",
+ "display-override-member-media-feature-fullscreen-manual.tentative.html",
+ "display-override-member-media-feature-minimal-ui-manual.tentative.html",
+ "display-override-member-media-feature-standalone-manual.tentative.html",
+ "display-override-member-media-feature-standalone-overrides-browser-manual.tentative.html",
+ "display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html",
+ "display-override-member-media-feature-service-worker.js",
+ "resources/display-override-member-media-feature-manual.js",
+ "resources/icon.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-manual.tentative.html
new file mode 100644
index 0000000000..db1ed38929
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-manual.tentative.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Test "standalone" in display-override member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-standalone" />
+<link rel="manifest" href="resources/display-override-member-media-feature-standalone.webmanifest" />
+<script src="resources/display-override-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Test "standalone" in display-override member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: standalone) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const standalone = matchMedia("(display-mode: standalone)");
+
+standalone.onchange = () => {
+ if (standalone.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!standalone.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-overrides-browser-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-overrides-browser-manual.tentative.html
new file mode 100644
index 0000000000..d42feb3fe2
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-standalone-overrides-browser-manual.tentative.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Test "standalone" in display-override member + "browser" in display member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest#display-member" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-browser" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-standalone" />
+<link rel="manifest" href="resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest" />
+<script src="resources/display-override-member-media-feature-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Test "standalone" in display-override member + "browser" in display member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: standalone) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const standalone = matchMedia("(display-mode: standalone)");
+
+standalone.onchange = () => {
+ if (standalone.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!standalone.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+<p>
+ To pass, the background color must be green after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html
new file mode 100644
index 0000000000..0929b43dec
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>Test "window-controls-overlay" in display-override member + "browser" in display member + media feature</title>
+<link rel="help" href="https://w3c.github.io/manifest#display-member" />
+<link rel="help" href="https://w3c.github.io/manifest/#the-display-mode-media-feature" />
+<link rel="help" href="https://w3c.github.io/manifest/#dom-displaymodetype-browser" />
+<link rel="manifest" href="resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest" />
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src="resources/display-override-member-media-feature-manual.js"></script>
+<h1>Test "window-controls-overlay" in display-override member + "browser" in display member + media feature</h1>
+<style>
+ .fail {
+ background-color: red;
+ }
+
+ @media all and (display-mode: standalone) {
+ body {
+ background-color: green;
+ }
+ }
+</style>
+<script>
+const standalone = matchMedia("(display-mode: standalone)");
+
+standalone.onchange = () => {
+ if (standalone.matches) {
+ document.body.classList.remove("fail");
+ }
+}
+
+if (!standalone.matches) {
+ document.body.classList.add("fail");
+}
+</script>
+
+<p>This test validates that the display-mode property is 'standalone' when the
+ installed app is running in "window-controls-overlay" mode.</p>
+<h2>Manual Test Steps:</h2>
+<p>
+ <ol>
+ <li>Install this app, and toggle into "window-controls-overlay" mode.</li>
+ <li>The background will be green if the test pases, otherwise red.</li>
+ </ol>
+</p>
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest
new file mode 100644
index 0000000000..a5f3af06b7
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "Window Controls Overlay - app-region",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-app-region-window-controls-overlay-manual.tentative.html",
+ "display": "browser",
+ "display_override": [ "window-controls-overlay" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-app-region-window-controls-overlay.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest
new file mode 100644
index 0000000000..ebfc0a0bd9
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "Window Controls Overlay - CSS environment variables",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html",
+ "display": "browser",
+ "display_override": [ "window-controls-overlay" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-css-environment-variables-window-controls-overlay.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest
new file mode 100644
index 0000000000..a384f6f2c8
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display override member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-media-feature-browser-manual.tentative.html",
+ "display_override": [ "browser" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-browser.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest
new file mode 100644
index 0000000000..70cad0a0ca
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display override member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-media-feature-fullscreen-manual.tentative.html",
+ "display_override": [ "fullscreen" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-fullscreen.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-manual.js b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-manual.js
new file mode 100644
index 0000000000..eca350245f
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'display-override-member-media-feature-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest
new file mode 100644
index 0000000000..474f58526b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display override member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-media-feature-browser-manual.tentative.html",
+ "display_override": [ "minimal-ui" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-minimal-ui.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest
new file mode 100644
index 0000000000..dcdd293ab7
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "Display override member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-media-feature-browser-manual.tentative.html",
+ "display": "browser",
+ "display_override": [ "standalone" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone-overrides-browser.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest
new file mode 100644
index 0000000000..dfd6b77a25
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "Display override member media feature WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-media-feature-browser-manual.tentative.html",
+ "display_override": [ "standalone" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-standalone.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest
new file mode 100644
index 0000000000..75e91eaf87
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "Window Controls Overlay - CSS environment variables",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html",
+ "display": "browser",
+ "display_override": [ "window-controls-overlay" ]
+}
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest.headers b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/display-override-member/resources/icon.png b/testing/web-platform/tests/appmanifest/display-override-member/resources/icon.png
new file mode 100644
index 0000000000..637cc8daf4
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/display-override-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html b/testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html
new file mode 100644
index 0000000000..f6384b6dda
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-manual.tentative.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <link rel="manifest" href="resources/file_handlers-member.webmanifest" />
+ <title>File Handling Web Platform Test</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/file_handlers-member.js" type="module"></script>
+ <style>
+ body {
+ margin: 2em;
+ }
+
+ ol {
+ line-height: 200%;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>
+ File Handling Test
+ </h1>
+ <div class="section">
+ <h2>
+ Instructions (details may be OS-dependent)
+ </h2>
+ <ol>
+ <li>Install this site as a PWA</li>
+ <li>Download <a href="resources/file_handlers-sample-file.txt" download>this file</a></li>
+ <li>
+ In your file browser, right click the downloaded file (<code>file_handlers-sample-file.txt</code>)
+ </li>
+ <li>Select <b>"Open with"</b> &gt; <b>"File Handling WPT"</b></li>
+ <li>
+ If your browser prompts you to allow <b>File Handling WPT</b> to open
+ the file, choose allow
+ </li>
+ <li>The app window that opens should indicate success of this test.</li>
+ </ol>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-service-worker.js b/testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-service-worker.js
new file mode 100644
index 0000000000..972b65304b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/file_handlers-member/file_handlers-member-service-worker.js
@@ -0,0 +1,52 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.1";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "file_handlers-member-service-worker.js",
+ "file_handlers-member-manual.tentative.html",
+ "resources/file_handlers-member.js",
+ "resources/icon.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.js b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.js
new file mode 100644
index 0000000000..87ec82ef9a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.js
@@ -0,0 +1,39 @@
+// Since this is a manual test, disable the automatic timeout.
+setup({explicit_timeout: true});
+
+// Redirect to https if using http, because File System Access API (previously
+// Native FileSystem API) isn't supported in http.
+if (location.protocol !== 'https:') {
+ location.replace(
+ `https:${location.href.substring(location.protocol.length)}`
+ );
+}
+
+test(function() {
+ assert_true('serviceWorker' in navigator);
+}, 'serviceWorker exists')
+
+navigator.serviceWorker.register(
+ 'file_handlers-member-service-worker.js');
+
+test(function() {
+ assert_true('launchQueue' in window);
+}, 'File Handling API enabled');
+
+test(function() {
+ assert_true('showOpenFilePicker' in window);
+}, 'File System Access API enabled');
+
+promise_test(async t => {
+ const launchParams = await new Promise(resolve => {
+ window.launchQueue.setConsumer(resolve);
+ });
+
+ assert_equals(launchParams.files.length, 1, 'Wrong number of files found');
+
+ const readHandle = await launchParams.files[0].getFile();
+ assert_equals(readHandle.name, 'file_handlers-sample-file.txt');
+
+ const fileContents = await readHandle.text();
+ assert_equals(fileContents, 'File handling WPT - Hello world!\n');
+}, 'launchQueue works as expected');
diff --git a/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest
new file mode 100644
index 0000000000..1cc5bf4aa9
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-member.webmanifest
@@ -0,0 +1,21 @@
+{
+ "name": "File Handling WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "144x144"
+ }
+ ],
+ "start_url": "../file_handlers-member-manual.tentative.html",
+ "display": "standalone",
+ "scope": "../../file_handlers-member/",
+ "file_handlers": [
+ {
+ "action": "../file_handlers-member-manual.tentative.html",
+ "name": "Plain Text",
+ "accept": {
+ "text/plain": [".txt"]
+ }
+ }
+ ]
+}
diff --git a/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-sample-file.txt b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-sample-file.txt
new file mode 100644
index 0000000000..5c8a71969c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/file_handlers-sample-file.txt
@@ -0,0 +1 @@
+File handling WPT - Hello world!
diff --git a/testing/web-platform/tests/appmanifest/file_handlers-member/resources/icon.png b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/icon.png
new file mode 100644
index 0000000000..c177ad8dbd
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/file_handlers-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-fail-manual.sub.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-fail-manual.sub.html
new file mode 100644
index 0000000000..f49dac6057
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-fail-manual.sub.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Test that icons member is supported (CORS violation)</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member-cors-fail.sub.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member (CORS violation)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the icon <strong>must not</strong> show a white cross on a red background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-manual.sub.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-manual.sub.html
new file mode 100644
index 0000000000..aa0fe89db6
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-cors-manual.sub.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Test that icons member is supported (via CORS)</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member-cors.sub.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member (via CORS)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the icon must show a white check mark on a green background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-fail-manual.sub.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-fail-manual.sub.html
new file mode 100644
index 0000000000..e4706011f8
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-fail-manual.sub.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="img-src {{host}}:{{ports[https][1]}}">
+<title>Test that icons member is supported (CSP violation)</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member-csp-fail.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member (CSP violation)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the icon <strong>must not</strong> show a white cross on a red background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-manual.sub.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-manual.sub.html
new file mode 100644
index 0000000000..c76364b83f
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-csp-manual.sub.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="img-src {{host}}:{{ports[https][1]}}">
+<title>Test that icons member is supported (CSP check)</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member-csp.sub.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member (CSP check)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the icon must show a white check mark on a green background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-last-matching-manual.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-last-matching-manual.html
new file mode 100644
index 0000000000..a02ddc3a50
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-last-matching-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that icons member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member-last-matching.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member</h1>
+<p>
+ To pass, the icon must show a white check mark on a green background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-manual.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-manual.html
new file mode 100644
index 0000000000..6a9b7620ed
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that icons member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member</h1>
+<p>
+ To pass, the icon should must a white check mark on a green background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-next-appropriate-manual.html b/testing/web-platform/tests/appmanifest/icons-member/icons-member-next-appropriate-manual.html
new file mode 100644
index 0000000000..8e87fc1062
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-next-appropriate-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that icons member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#icons-member" />
+<link rel="manifest" href="resources/icons-member-next-appropriate.webmanifest" />
+<script src="resources/icons-member-manual.js"></script>
+<h1>Testing support for icons member</h1>
+<p>
+ To pass, the icon must show a white check mark on a green background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/icons-member/icons-member-service-worker.js b/testing/web-platform/tests/appmanifest/icons-member/icons-member-service-worker.js
new file mode 100644
index 0000000000..21b07f8515
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/icons-member-service-worker.js
@@ -0,0 +1,59 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "icons-member-cors-fail-manual.sub.html",
+ "icons-member-cors-manual.sub.html",
+ "icons-member-csp-fail-manual.sub.html",
+ "icons-member-csp-manual.sub.html",
+ "icons-member-last-matching-manual.html",
+ "icons-member-manual.html",
+ "icons-member-next-appropriate-manual.html",
+ "icons-member-service-worker.js",
+ "resources/icons-member-manual.js",
+ "resources/fail.png",
+ "resources/pass.png"
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/fail.png b/testing/web-platform/tests/appmanifest/icons-member/resources/fail.png
new file mode 100644
index 0000000000..1d596c6ba6
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/fail.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.sub.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.sub.webmanifest
new file mode 100644
index 0000000000..24e2214365
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.sub.webmanifest
@@ -0,0 +1,10 @@
+{
+ "name": "Icons member (CORS violation) WPT",
+ "icons": [{
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/fail.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }],
+ "start_url": "../icons-member-cors-fail-manual.sub.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors-fail.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.sub.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.sub.webmanifest
new file mode 100644
index 0000000000..33cb12654b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.sub.webmanifest
@@ -0,0 +1,10 @@
+{
+ "name": "Icons member (via CORS) WPT",
+ "icons": [{
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/pass.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }],
+ "start_url": "../icons-member-cors-manual.sub.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-cors.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest
new file mode 100644
index 0000000000..2b614ebb01
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest
@@ -0,0 +1,10 @@
+{
+ "name": "Icons member (CSP violation) WPT",
+ "icons": [{
+ "src": "fail.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }],
+ "start_url": "../icons-member-csp-fail-manual.sub.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp-fail.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.sub.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.sub.webmanifest
new file mode 100644
index 0000000000..f1089bba3c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.sub.webmanifest
@@ -0,0 +1,10 @@
+{
+ "name": "Icons member (CSP check) WPT",
+ "icons": [{
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/pass.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }],
+ "start_url": "../icons-member-csp-manual.sub.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-csp.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest
new file mode 100644
index 0000000000..04ac33112d
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest
@@ -0,0 +1,14 @@
+{
+ "name": "Icons member WPT",
+ "icons": [{
+ "src": "fail.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }, {
+ "src": "pass.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }],
+ "start_url": "../icons-member-last-matching-manual.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-last-matching.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-manual.js b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-manual.js
new file mode 100644
index 0000000000..cf149792a3
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'icons-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest
new file mode 100644
index 0000000000..e65169b06a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest
@@ -0,0 +1,13 @@
+{
+ "name": "Icons member WPT",
+ "icons": [{
+ "src": "pass.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }, {
+ "src": "../icons-member-manual.html",
+ "sizes": "256x256"
+ }],
+ "start_url": "../icons-member-next-appropriate-manual.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member-next-appropriate.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest
new file mode 100644
index 0000000000..8e7a2c3426
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest
@@ -0,0 +1,10 @@
+{
+ "name": "Icons member WPT",
+ "icons": [{
+ "src": "pass.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }],
+ "start_url": "../icons-member-manual.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/icons-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/pass.png b/testing/web-platform/tests/appmanifest/icons-member/resources/pass.png
new file mode 100644
index 0000000000..be7433a3e2
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/pass.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/icons-member/resources/pass.png.sub.headers b/testing/web-platform/tests/appmanifest/icons-member/resources/pass.png.sub.headers
new file mode 100644
index 0000000000..adf190aa8e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/icons-member/resources/pass.png.sub.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: https://{{host}}:{{ports[https][0]}}
diff --git a/testing/web-platform/tests/appmanifest/id-member/icon.png b/testing/web-platform/tests/appmanifest/id-member/icon.png
new file mode 100644
index 0000000000..4b9c7c8f32
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v1.html b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v1.html
new file mode 100644
index 0000000000..3f4a331e0b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v1.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Manifest Id Web Platform Test</title>
+ <style>
+ body {
+ margin: 2em;
+ }
+
+ ol {
+ line-height: 200%;
+ }
+ </style>
+ <!-- This points to manifest v2 with a different start_url, but the
+ id is url-equivalent to manifest v1. -->
+ <link rel="manifest" href="id-member-manifest-update-v2.webmanifest" />
+ <script src="id-member-manifest-update.js"></script>
+
+ </head>
+ <body>
+ <h1>
+ Manifest Id Test
+ </h1>
+ <h2 style="color: red">
+ start_url v1
+ </h2>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v2.html b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v2.html
new file mode 100644
index 0000000000..4454017eaf
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual-v2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>Manifest Id Web Platform Test</title>
+ <style>
+ body {
+ margin: 2em;
+ }
+
+ ol {
+ line-height: 200%;
+ }
+ </style>
+ <link rel="manifest" href="id-member-manifest-update-v1.webmanifest" />
+ <script src="id-member-manifest-update.js"></script>
+ </head>
+ <body>
+ <h1>
+ Manifest Id Test
+ </h1>
+ <h2 style="color: green">
+ start_url v2
+ </h2>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual.tentative.html b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual.tentative.html
new file mode 100644
index 0000000000..c534d7404a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-manual.tentative.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>Manifest Id Web Platform Test</title>
+ <style>
+ body {
+ margin: 2em;
+ }
+
+ ol {
+ line-height: 200%;
+ }
+ </style>
+ <link rel="manifest" href="id-member-manifest-update-v1.webmanifest" />
+ <script src="id-member-manifest-update.js"></script>
+ </head>
+ <body>
+ <h1>
+ Manifest Id Test
+ </h1>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest
new file mode 100644
index 0000000000..5d02d2b10a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest
@@ -0,0 +1,13 @@
+{
+ "name": "id member test",
+ "id": "/testId",
+ "start_url": "id-member-manifest-update-manual-v1.html",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }
+ ],
+ "display": "standalone"
+}
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest.headers b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v1.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest
new file mode 100644
index 0000000000..582620186e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest
@@ -0,0 +1,13 @@
+{
+ "name": "id member test",
+ "id": "testId",
+ "start_url": "id-member-manifest-update-manual-v2.html",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }
+ ],
+ "display": "standalone"
+}
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest.headers b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update-v2.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update.js b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update.js
new file mode 100644
index 0000000000..7d6e344ed9
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-manifest-update.js
@@ -0,0 +1,34 @@
+window.onload = () => {
+ const instruction = document.createElement("div");
+ instruction.innerHTML = `
+ <h2>
+ Instructions
+ </h2>
+ <ol>
+ <li>Install <a href="id-member-manifest-update-manual.html ">id-member-manifest-update-manual.html </a> as a PWA</li>
+ <li>
+ Launch the app from OS. The page should be launched to start_url v1.
+ </li>
+ <li>
+ Close the app window.
+ </li>
+ <li>
+ Trigger a manifest update event.
+ <p>
+ This step is specific to each browser implementation.
+ On Chrome, trigger the update by restarting the browser through chrome://restart.
+ </p>
+ </li>
+ <li>
+ Launch the app from OS again, start_url should be updated to v2.
+ </li>
+ </ol>
+`;
+
+ document.body.appendChild(instruction);
+};
+async function main() {
+ await navigator.serviceWorker.register("id-member-service-worker.js");
+ await navigator.serviceWorker.ready;
+}
+main(); \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/id-member/id-member-service-worker.js b/testing/web-platform/tests/appmanifest/id-member/id-member-service-worker.js
new file mode 100644
index 0000000000..c0a16c4a46
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/id-member/id-member-service-worker.js
@@ -0,0 +1,8 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+self.addEventListener("fetch", e => {
+ e.respondWith(fetch(e.request).catch(_ => {
+ return new Response('Offline test.');
+ }));
+});
diff --git a/testing/web-platform/tests/appmanifest/name-member/name-member-manual.html b/testing/web-platform/tests/appmanifest/name-member/name-member-manual.html
new file mode 100644
index 0000000000..577c821c3b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/name-member-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that name member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest" />
+<link rel="manifest" href="resources/name-member.webmanifest" />
+<script src="resources/name-member-manual.js"></script>
+<h1>Testing support for name member</h1>
+<p>
+ To pass, the application name must be "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/name-member/name-member-service-worker.js b/testing/web-platform/tests/appmanifest/name-member/name-member-service-worker.js
new file mode 100644
index 0000000000..5733f35636
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/name-member-service-worker.js
@@ -0,0 +1,52 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "name-member-manual.html",
+ "name-member-service-worker.js",
+ "resources/name-member-manual.js",
+ "resources/icon.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/name-member/resources/icon.png b/testing/web-platform/tests/appmanifest/name-member/resources/icon.png
new file mode 100644
index 0000000000..6a06550023
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest b/testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest
new file mode 100644
index 0000000000..e1b2979207
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "fail",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../name-member-manual.html",
+ "display": "fullscreen"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest.headers b/testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/resources/name-member-fail.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/name-member/resources/name-member-manual.js b/testing/web-platform/tests/appmanifest/name-member/resources/name-member-manual.js
new file mode 100644
index 0000000000..042b94f85b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/resources/name-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'name-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest b/testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest
new file mode 100644
index 0000000000..366044f09e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "pass",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../name-member-manual.html",
+ "display": "fullscreen"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/name-member/resources/name-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-landscape-manual.html b/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-landscape-manual.html
new file mode 100644
index 0000000000..8df1117964
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-landscape-manual.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Test that orientation member with landscape value is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#orientation-member" />
+<link rel="manifest" href="resources/orientation-member-landscape.webmanifest" />
+<script src="resources/orientation-member-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Testing support for orientation member with "landscape" value</h1>
+<style>
+ @media all and (orientation: landscape) {
+ body {
+ background-color: green;
+ }
+ }
+ @media all and (orientation: portrait) {
+ body {
+ background-color: red;
+ }
+ }
+</style>
+<p>
+ Please set the phone orientation to portrait.
+</p>
+<p>
+ To pass, after installing the display orientation must be landscape and the background must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-portrait-manual.html b/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-portrait-manual.html
new file mode 100644
index 0000000000..ed866f3561
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-portrait-manual.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Test that orientation member with portrait value is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#orientation-member" />
+<link rel="manifest" href="resources/orientation-member-portrait.webmanifest" />
+<script src="resources/orientation-member-manual.js"></script>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<h1>Testing support for orientation member with "portrait" value</h1>
+<style>
+ @media all and (orientation: portrait) {
+ body {
+ background-color: green;
+ }
+ }
+ @media all and (orientation: landscape) {
+ body {
+ background-color: red;
+ }
+ }
+</style>
+<p>
+ Please set the phone orientation to landscape.
+</p>
+<p>
+ To pass, after installing the display orientation must be portrait and the background must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-service-worker.js b/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-service-worker.js
new file mode 100644
index 0000000000..26f53c9816
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/orientation-member-service-worker.js
@@ -0,0 +1,53 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "orientation-member-landscape-manual.html",
+ "orientation-member-portrait-manual.html",
+ "orientation-member-service-worker.js",
+ "resources/orientation-member-manual.js",
+ "resources/icon.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/resources/icon.png b/testing/web-platform/tests/appmanifest/orientation-member/resources/icon.png
new file mode 100644
index 0000000000..fecb1d2da4
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest
new file mode 100644
index 0000000000..c930d292e5
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "Orientation member with landscape value WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../orientation-member-landscape-manual.html",
+ "display": "standalone",
+ "orientation": "landscape"
+}
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest.headers b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-landscape.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-manual.js b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-manual.js
new file mode 100644
index 0000000000..6929c997a4
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'orientation-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest
new file mode 100644
index 0000000000..7ddf0851ac
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "Orientation member with portrait value WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../orientation-member-portrait-manual.html",
+ "display": "standalone",
+ "orientation": "portrait"
+}
diff --git a/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest.headers b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/orientation-member/resources/orientation-member-portrait.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-manual.tentative.html b/testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-manual.tentative.html
new file mode 100644
index 0000000000..fa9c958e0e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-manual.tentative.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <link rel="manifest" href="resources/protocol_handlers-member.webmanifest" />
+ <title>Protocol Handling Web Platform Test</title>
+ <script>
+ navigator.serviceWorker.register(
+ 'protocol_handlers-member-service-worker.js');
+ </script>
+</head>
+<body>
+ <h1>Protocol Handling Web Platform Test</h1>
+ <p>This test validates that an install application can register URL protocol
+ handlers via a property in the web app manifest. The app should open
+ directly when the 'web+testing' custom-scheme URL is visited.
+ </p>
+ <h2>Manual Test Steps:</h2>
+ <p>
+ <ol>
+ <li>Install this app.</li>
+ <li>Launch 'web+testing://test-url/'. Instructions will vary by OS.
+ <ul>
+ <li>On Windows - open a command prompt, and run "start web+testing://test-url/".</li>
+ <li>On MacOS - open a terminal, and "open web+testing://test-url/".</li>
+ <li>On Linux - open a terminal, and "xgd-open web+testing://test-url/".</li>
+ </ul>
+ </li>
+ <li>If your browser prompts you, allow the app to open.</li>
+ <li>The app window that opens should indicate success of this test.</li>
+ </ol>
+ </p>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-service-worker.js b/testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-service-worker.js
new file mode 100644
index 0000000000..e502e2a985
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/protocol_handlers-member/protocol_handlers-member-service-worker.js
@@ -0,0 +1,52 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.1";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "protocol_handlers-member-service-worker.js",
+ "protocol_handlers-member-manual.tentative.html",
+ "resources/icon.png",
+ "resources/protocol_handlers_entry.html",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/icon.png b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/icon.png
new file mode 100644
index 0000000000..9255547fae
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest
new file mode 100644
index 0000000000..cce6ae1e22
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest
@@ -0,0 +1,18 @@
+{
+ "name": "Protocol_handlers test",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "144x144"
+ }
+ ],
+ "start_url": "../protocol_handlers-member-manual.tentative.html",
+ "display": "standalone",
+ "scope": "../../protocol_handlers-member/",
+ "protocol_handlers": [
+ {
+ "protocol": "web+testing",
+ "url": "protocol_handlers_entry.html?value=%s"
+ }
+ ]
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers_entry.html b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers_entry.html
new file mode 100644
index 0000000000..c5fa629f22
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/protocol_handlers-member/resources/protocol_handlers_entry.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Protocol Handling Web Platform Test - Pass</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script>
+ setup({ single_test: true });
+ const urlParams = new URLSearchParams(window.location.search);
+ assert_equals(urlParams.get('value'), "web+testing://test-url/");
+ done();
+ </script>
+</head>
+<body>
+ <h1>Protocol Handling Page</h1>
+ <p>This test validates that the app was launched with the web+testing://test-url/ URL.</p>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/short_name-member/resources/icon.png b/testing/web-platform/tests/appmanifest/short_name-member/resources/icon.png
new file mode 100644
index 0000000000..1798a17481
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/short_name-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member-manual.js b/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member-manual.js
new file mode 100644
index 0000000000..7420e66c31
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'short_name-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest b/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest
new file mode 100644
index 0000000000..e456f55d60
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest
@@ -0,0 +1,11 @@
+{
+ "short_name": "pass",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../short_name-member-manual.html",
+ "display": "fullscreen"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/short_name-member/resources/short_name-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/short_name-member/short_name-member-manual.html b/testing/web-platform/tests/appmanifest/short_name-member/short_name-member-manual.html
new file mode 100644
index 0000000000..ce5f8029fe
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/short_name-member/short_name-member-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that short_name member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest/#short_name-member" />
+<link rel="manifest" href="resources/short_name-member.webmanifest" />
+<script src="resources/short_name-member-manual.js"></script>
+<h1>Testing support for short_name member</h1>
+<p>
+ To pass, the application name must be "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/short_name-member/short_name-member-service-worker.js b/testing/web-platform/tests/appmanifest/short_name-member/short_name-member-service-worker.js
new file mode 100644
index 0000000000..ed8cadb9af
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/short_name-member/short_name-member-service-worker.js
@@ -0,0 +1,52 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "short_name-member-manual.html",
+ "short_name-member-service-worker.js",
+ "resources/short_name-member-manual.js",
+ "resources/icon.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png
new file mode 100644
index 0000000000..be7433a3e2
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png.sub.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png.sub.headers
new file mode 100644
index 0000000000..adf190aa8e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/pass.png.sub.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: https://{{host}}:{{ports[https][0]}}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.sub.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.sub.webmanifest
new file mode 100644
index 0000000000..a4975b03df
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.sub.webmanifest
@@ -0,0 +1,22 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/fail.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-cors-fail-manual.sub.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/fail.png",
+ "sizes": "256x256"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors-fail.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.sub.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.sub.webmanifest
new file mode 100644
index 0000000000..94f0e0388c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.sub.webmanifest
@@ -0,0 +1,22 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "https://{{host}}:{{ports[https][0]}}/appmanifest/shortcuts-member/resources/pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-cors-manual.sub.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/pass.png",
+ "sizes": "256x256"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-cors.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest
new file mode 100644
index 0000000000..7efe564c9d
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest
@@ -0,0 +1,22 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-csp-fail-manual.sub.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "fail.png",
+ "sizes": "256x256"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp-fail.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.sub.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.sub.webmanifest
new file mode 100644
index 0000000000..55b0afb3ed
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.sub.webmanifest
@@ -0,0 +1,22 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "https://{{host}}:{{ports[https][0]}}/appmanifest/shortcuts-member/resources/pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-csp-manual.sub.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "https://{{host}}:{{ports[https][1]}}/appmanifest/icons-member/resources/pass.png",
+ "sizes": "256x256"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-csp.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-manual.js b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-manual.js
new file mode 100644
index 0000000000..5fdfde1bd6
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'shortcuts-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest
new file mode 100644
index 0000000000..6e17899c65
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest
@@ -0,0 +1,27 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-skip-for-empty-name-manual.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_fail.html",
+ "icons": []
+ }, {
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "pass.png"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-empty-name.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest
new file mode 100644
index 0000000000..573bbdc8c0
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest
@@ -0,0 +1,27 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-skip-for-invalid-url-manual.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "fail",
+ "short_name": "",
+ "description": "",
+ "url": "http://foo:660000",
+ "icons": []
+ }, {
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "pass.png"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-invalid-url.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest
new file mode 100644
index 0000000000..79ac5130fb
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest
@@ -0,0 +1,27 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-skip-for-out-of-scope-url-manual.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "fail",
+ "short_name": "",
+ "description": "",
+ "url": "https://example.com",
+ "icons": []
+ }, {
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "pass.png"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest
new file mode 100644
index 0000000000..14521109c2
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest
@@ -0,0 +1,26 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-skip-for-undefined-name-manual.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "short_name": "fail",
+ "description": "",
+ "url": "../shortcut_fail.html",
+ "icons": []
+ }, {
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "pass.png"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-name.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest
new file mode 100644
index 0000000000..e272c4cae5
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest
@@ -0,0 +1,26 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-skip-for-undefined-url-manual.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "fail",
+ "short_name": "",
+ "description": "",
+ "icons": []
+ }, {
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "pass.png"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member-skip-for-undefined-url.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest
new file mode 100644
index 0000000000..68c3e99d70
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest
@@ -0,0 +1,22 @@
+{
+ "name": "Shortcut test",
+ "icons": [
+ {
+ "src": "pass.png",
+ "sizes": "256x256"
+ }
+ ],
+ "start_url": "../shortcuts-member-manual.html",
+ "display": "fullscreen",
+ "scope": "../",
+ "shortcuts": [{
+ "name": "pass",
+ "short_name": "",
+ "description": "",
+ "url": "../shortcut_pass.html",
+ "icons": [{
+ "src": "pass.png",
+ "sizes": "256x256"
+ }]
+ }]
+}
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/resources/shortcuts-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_fail.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_fail.html
new file mode 100644
index 0000000000..d3259744d3
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_fail.html
@@ -0,0 +1,4 @@
+<html>
+<meta charset="utf-8">
+<body style="background: red">
+<h1>Fail</h1>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_pass.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_pass.html
new file mode 100644
index 0000000000..f15bfe1141
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcut_pass.html
@@ -0,0 +1,4 @@
+<html>
+<meta charset="utf-8">
+<body style="background: green">
+<h1>Pass</h1>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub.html
new file mode 100644
index 0000000000..5b1bd84dca
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-fail-manual.sub.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test that shortcuts member is supported (icon violates CORS)</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-cors-fail.sub.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing support for shortcuts member (icon violates CORS)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the application <strong>must not</strong> show a shortcut with
+ a white cross on red background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub.html
new file mode 100644
index 0000000000..73b47c4336
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-cors-manual.sub.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Test that shortcuts member is supported (icon via CORS)</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-cors.sub.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing support for shortcuts member (icon via CORS)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the application must show a shortcut named "pass" with a check
+ mark icon. Clicking it must open this document again.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub.html
new file mode 100644
index 0000000000..228c9782c0
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-fail-manual.sub.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="img-src {{host}}:{{ports[https][1]}}">
+<title>Test that shortcuts member is supported (icon CSP violation)</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-csp-fail.sub.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing support for shortcuts member (icon CSP violation)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the application <strong>must not</strong> show a shortcut with
+ a white cross on red background.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub.html
new file mode 100644
index 0000000000..68c5f0107d
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-csp-manual.sub.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="img-src {{host}}:{{ports[https][0]}}">
+<title>Test that shortcuts member is supported (icon CSP check)</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-csp.sub.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing support for shortcuts member (icon CSP check)</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the application must show a shortcut named "pass" with a check
+ mark icon. Clicking it must open this document again.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-manual.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-manual.html
new file mode 100644
index 0000000000..f2a7d6742d
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-manual.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>Test that shortcuts member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing support for shortcuts member</h1>
+<p>
+ To pass, the application must show a shortcut named "pass" with a check
+ mark icon. Clicking it must open this document again.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-service-worker.js b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-service-worker.js
new file mode 100644
index 0000000000..bd9995202e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-service-worker.js
@@ -0,0 +1,61 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "shortcuts-member-cors-fail-manual.sub.html",
+ "shortcuts-member-cors-manual.sub.html",
+ "shortcuts-member-csp-fail-manual.sub.html",
+ "shortcuts-member-csp-manual.sub.html",
+ "shortcuts-member-manual.html",
+ "shortcuts-member-skip-for-empty-name-manual.html",
+ "shortcuts-member-skip-for-invalid-url-manual.html",
+ "shortcuts-member-skip-for-out-of-scope-url-manual.html",
+ "shortcuts-member-skip-for-undefined-name-manual.html",
+ "shortcuts-member-skip-for-undefined-url-manual.html",
+ "shortcuts-member-service-worker.js",
+ "resources/shortcuts-member-manual.js",
+ "resources/pass.png",
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-empty-name-manual.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-empty-name-manual.html
new file mode 100644
index 0000000000..48f4af7ba5
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-empty-name-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that shortcut items with an empty name are skipped</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-skip-for-empty-name.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing if shortcut items with an empty name are skipped</h1>
+<p>
+ To pass, the application must provide a single shortcut named "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-invalid-url-manual.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-invalid-url-manual.html
new file mode 100644
index 0000000000..6967f8dca2
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-invalid-url-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that shortcut items with an invalid URL are skipped</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-skip-for-invalid-url.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing if shortcut items with an invalid URL are skipped</h1>
+<p>
+ To pass, the application must provide a single shortcut named "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-out-of-scope-url-manual.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-out-of-scope-url-manual.html
new file mode 100644
index 0000000000..64f3d0fe15
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-out-of-scope-url-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that shortcut items with an out-of-scope URL are skipped</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-skip-for-out-of-scope-url.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing if shortcut items with an out-of-scope URL are skipped</h1>
+<p>
+ To pass, the application must provide a single shortcut named "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-name-manual.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-name-manual.html
new file mode 100644
index 0000000000..c0a7768eee
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-name-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that shortcut items with an undefined name are skipped</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-skip-for-undefined-name.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing if shortcut items with an undefined name are skipped</h1>
+<p>
+ To pass, the application must provide a single shortcut named "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-url-manual.html b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-url-manual.html
new file mode 100644
index 0000000000..ffeb6af9a0
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/shortcuts-member/shortcuts-member-skip-for-undefined-url-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that shortcut items with an undefined URL are skipped</title>
+<link rel="help" href="https://w3c.github.io/manifest/#shortcuts-member" />
+<link rel="manifest" href="resources/shortcuts-member-skip-for-undefined-url.webmanifest" />
+<script src="resources/shortcuts-member-manual.js"></script>
+<h1>Testing if shortcut items with an undefined URL are skipped</h1>
+<p>
+ To pass, the application must provide a single shortcut named "pass".
+</p>
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/fail.html b/testing/web-platform/tests/appmanifest/start_url-member/fail.html
new file mode 100644
index 0000000000..4c6c599b5a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/fail.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<meta charset="utf-8">
+<body style="background-color: red">
+<h1>FAIL</h1>
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/pass.html b/testing/web-platform/tests/appmanifest/start_url-member/pass.html
new file mode 100644
index 0000000000..caecc70f6d
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/pass.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<title>PASS</title>
+<meta charset="utf-8">
+<body style="background-color: green">
+<h1>PASS</h1>
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/resources/icon.png b/testing/web-platform/tests/appmanifest/start_url-member/resources/icon.png
new file mode 100644
index 0000000000..b8845ac098
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest
new file mode 100644
index 0000000000..9cfb0b815b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "start_url member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "https://{{host}}:{{ports[https][1]}}/appmanifest/start_url-member/fail.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest.headers b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-manual.js b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-manual.js
new file mode 100644
index 0000000000..302ce45aeb
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'start_url-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest
new file mode 100644
index 0000000000..2afae97566
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest
@@ -0,0 +1,11 @@
+{
+ "name": "start_url member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../pass.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/resources/start_url-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-fail-manual.sub.html b/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-fail-manual.sub.html
new file mode 100644
index 0000000000..079f048b55
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-fail-manual.sub.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Test that start_url member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest/#start_url-member" />
+<link rel="manifest" href="https://{{host}}:{{ports[https][0]}}/appmanifest/start_url-member/resources/start_url-member-fail.sub.webmanifest" />
+<script src="resources/start_url-member-manual.js"></script>
+<h1>Cross-origin start URLs are invalid</h1>
+<script>
+ // Force the port of the origin to be ports[https][0] (likely :8443)
+ // we treat the start_url's port ports[https][1] (likely :8444) to be another origin that we fail against
+ if (window.location.origin !== "https://{{host}}:{{ports[https][0]}}") {
+ window.location = new URL(window.location.pathname, "https://{{host}}:{{ports[https][0]}}")
+ }
+</script>
+<p>
+ To pass, the start URL must not be fail.html because it's not same origin.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-pass-manual.html b/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-pass-manual.html
new file mode 100644
index 0000000000..34be2d6263
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-pass-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that start_url member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest/#start_url-member" />
+<link rel="manifest" href="resources/start_url-member.webmanifest" />
+<script src="resources/start_url-member-manual.js"></script>
+<h1>Testing support for start_url member</h1>
+<p>
+ To pass, the start URL must be pass.html after installing.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-service-worker.js b/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-service-worker.js
new file mode 100644
index 0000000000..6ffe893e13
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/start_url-member/start_url-member-service-worker.js
@@ -0,0 +1,55 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "fail.html",
+ "pass.html",
+ "start_url-member-fail-manual.sub.html",
+ "start_url-member-pass-manual.html",
+ "start_url-member-service-worker.js",
+ "resources/start_url-member-manual.js",
+ "resources/icon.png"
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/icon.png b/testing/web-platform/tests/appmanifest/theme_color-member/resources/icon.png
new file mode 100644
index 0000000000..341f824d9b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest
new file mode 100644
index 0000000000..d3ddbf1c16
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "theme_color member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../theme_color-member-hsl-manual.html",
+ "display": "fullscreen",
+ "theme_color": "hsl(120 100% 50%)"
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest.headers b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-hsl.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-manual.js b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-manual.js
new file mode 100644
index 0000000000..0cef8baa4c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'theme_color-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest
new file mode 100644
index 0000000000..efa621b57c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "theme_color member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../theme_color-member-named-manual.html",
+ "display": "fullscreen",
+ "theme_color": "green"
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest.headers b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-named.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest
new file mode 100644
index 0000000000..1a0a51debe
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "theme_color member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../theme_color-member-rgb-manual.html",
+ "display": "fullscreen",
+ "theme_color": "rgb(0 255 0)"
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest.headers b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgb.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest
new file mode 100644
index 0000000000..0d01d1d5fe
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "theme_color member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../theme_color-member-rgbhex3-manual.html",
+ "display": "fullscreen",
+ "theme_color": "#0F0"
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest.headers b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex3.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest
new file mode 100644
index 0000000000..74e71bb9b4
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "theme_color member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../theme_color-member-rgbhex6-manual.html",
+ "display": "fullscreen",
+ "theme_color": "#00FF00"
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest.headers b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgbhex6.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest
new file mode 100644
index 0000000000..5679b302be
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest
@@ -0,0 +1,12 @@
+{
+ "name": "theme_color member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../theme_color-member-rgblegacy-manual.html",
+ "display": "fullscreen",
+ "theme_color": "rgb(0, 255, 0)"
+}
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest.headers b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest.headers
new file mode 100644
index 0000000000..2bab061d43
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/resources/theme_color-member-rgblegacy.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-hsl-manual.html b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-hsl-manual.html
new file mode 100644
index 0000000000..b5327e8a4b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-hsl-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that theme_color member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#theme_color-member" />
+<link rel="manifest" href="resources/theme_color-member-hsl.webmanifest" />
+<script src="resources/theme_color-member-manual.js"></script>
+<h1>Testing support for theme_color member</h1>
+<p>
+ To pass, the theme_color must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-named-manual.html b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-named-manual.html
new file mode 100644
index 0000000000..28156f5a7b
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-named-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that theme_color member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#theme_color-member" />
+<link rel="manifest" href="resources/theme_color-member-named.webmanifest" />
+<script src="resources/theme_color-member-manual.js"></script>
+<h1>Testing support for theme_color member</h1>
+<p>
+ To pass, the theme_color must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgb-manual.html b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgb-manual.html
new file mode 100644
index 0000000000..c1a23d15d4
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgb-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that theme_color member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#theme_color-member" />
+<link rel="manifest" href="resources/theme_color-member-rgb.webmanifest" />
+<script src="resources/theme_color-member-manual.js"></script>
+<h1>Testing support for theme_color member</h1>
+<p>
+ To pass, the theme_color must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex3-manual.html b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex3-manual.html
new file mode 100644
index 0000000000..bd2d6bc28e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex3-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that theme_color member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#theme_color-member" />
+<link rel="manifest" href="resources/theme_color-member-rgbhex3.webmanifest" />
+<script src="resources/theme_color-member-manual.js"></script>
+<h1>Testing support for theme_color member</h1>
+<p>
+ To pass, the theme_color must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex6-manual.html b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex6-manual.html
new file mode 100644
index 0000000000..65a2d369ae
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgbhex6-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that theme_color member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#theme_color-member" />
+<link rel="manifest" href="resources/theme_color-member-rgbhex6.webmanifest" />
+<script src="resources/theme_color-member-manual.js"></script>
+<h1>Testing support for theme_color member</h1>
+<p>
+ To pass, the theme_color must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgblegacy-manual.html b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgblegacy-manual.html
new file mode 100644
index 0000000000..4df73b0d67
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-rgblegacy-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Test that theme_color member is supported</title>
+<link rel="help" href="https://w3c.github.io/manifest#theme_color-member" />
+<link rel="manifest" href="resources/theme_color-member-rgblegacy.webmanifest" />
+<script src="resources/theme_color-member-manual.js"></script>
+<h1>Testing support for theme_color member</h1>
+<p>
+ To pass, the theme_color must be green.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-service-worker.js b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-service-worker.js
new file mode 100644
index 0000000000..f087117e10
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/theme_color-member/theme_color-member-service-worker.js
@@ -0,0 +1,57 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "theme_color-member-hsl-manual.html",
+ "theme_color-member-named-manual.html",
+ "theme_color-member-rgb-manual.html",
+ "theme_color-member-rgbhex3-manual.html",
+ "theme_color-member-rgbhex6-manual.html",
+ "theme_color-member-rgblegacy-manual.html",
+ "theme_color-member-service-worker.js",
+ "resources/theme_color-member-manual.js",
+ "resources/icon.png"
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/unrecognized-member/resources/icon.png b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/icon.png
new file mode 100644
index 0000000000..deea71918a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member-manual.js b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member-manual.js
new file mode 100644
index 0000000000..9be8fb602e
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'unrecognized-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest
new file mode 100644
index 0000000000..1eb7b6285a
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest
@@ -0,0 +1,15 @@
+{
+ "this member name is not expected to be recognized": "ok",
+ "this object is not expected to be recognized": {
+ "this sub-field is not expected to be recognized": []
+ },
+ "short_name": "pass",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "192x192"
+ }
+ ],
+ "start_url": "../unrecognized-member-manual.html",
+ "display": "fullscreen"
+}
diff --git a/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/unrecognized-member/resources/unrecognized-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-manual.html b/testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-manual.html
new file mode 100644
index 0000000000..d22b5bacd7
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-manual.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>Test that an unrecognized member is ignored</title>
+<link rel="help" href="https://www.w3.org/TR/appmanifest/#processing" />
+<link rel="manifest" href="resources/unrecognized-member.webmanifest" />
+<script src="resources/unrecognized-member-manual.js"></script>
+<h1>Testing support for ignoring an unrecognized member</h1>
+<p>
+ To pass, the application name must be "pass". Parsing must not fail due to the
+ presence of the unrecognized members in the manifest.
+</p>
diff --git a/testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-service-worker.js b/testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-service-worker.js
new file mode 100644
index 0000000000..5364b09ffd
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/unrecognized-member/unrecognized-member-service-worker.js
@@ -0,0 +1,52 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "unrecognized-member-manual.html",
+ "unrecognized-member-service-worker.js",
+ "resources/unrecognized-member-manual.js",
+ "resources/icon.png"
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});
diff --git a/testing/web-platform/tests/appmanifest/user_preferences-member/resources/icon.png b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/icon.png
new file mode 100644
index 0000000000..d6dd4860ae
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/icon.png
Binary files differ
diff --git a/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member-manual.js b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member-manual.js
new file mode 100644
index 0000000000..bf1bc8d24c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member-manual.js
@@ -0,0 +1,4 @@
+if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'user_preferences-member-service-worker.js');
+}
diff --git a/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest
new file mode 100644
index 0000000000..3d92202bf7
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest
@@ -0,0 +1,22 @@
+{
+ "name": "user_preferences member WPT",
+ "icons": [
+ {
+ "src": "icon.png",
+ "sizes": "144x144"
+ }
+ ],
+ "start_url": "../user_preferences-member-manual.html",
+ "display": "fullscreen",
+ "user_preferences": {
+ "color_scheme": {
+ "dark": {
+ "theme_color": "green"
+ },
+ "light": {
+ "theme_color": "green"
+ }
+ }
+ },
+ "theme_color": "red"
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest.headers b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest.headers
new file mode 100644
index 0000000000..23f36ea27c
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/user_preferences-member/resources/user_preferences-member.webmanifest.headers
@@ -0,0 +1 @@
+Content-Type: application/manifest+json; charset=utf-8 \ No newline at end of file
diff --git a/testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-manual.html b/testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-manual.html
new file mode 100644
index 0000000000..c864d3dfd5
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-manual.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>Test that user_preferences member is supported</title>
+<link rel="manifest" href="resources/user_preferences-member.webmanifest" />
+<script src="resources/user_preferences-member-manual.js"></script>
+<h1>Testing support for user_preferences member</h1>
+<ol>
+ <li>Install this site as a PWA</li>
+ <li>Enable the OS dark mode setting</li>
+ <li>To pass, the theme_color must be green. This can be observed by looking
+ at the top of the window. On failure, this will be red.
+ </li>
+</ol>
+
diff --git a/testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-service-worker.js b/testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-service-worker.js
new file mode 100644
index 0000000000..24d575a917
--- /dev/null
+++ b/testing/web-platform/tests/appmanifest/user_preferences-member/user_preferences-member-service-worker.js
@@ -0,0 +1,52 @@
+// Some user agents only offer app installation if there is a SW and it handles
+// offline requests.
+
+const cacheVersion = "1.2";
+const CACHE_NAME = `cache-v${cacheVersion}`;
+
+// The resources cached by this service worker.
+const resources = [
+ "user_preferences-member-manual.html",
+ "user_preferences-member-service-worker.js",
+ "resources/user_preferences-member-manual.js",
+ "resources/icon.png"
+];
+
+// Load all resources for this service worker.
+const precache = async () => {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.addAll(resources);
+};
+
+// Get a resource from the cache.
+const fromCache = async request => {
+ const cache = await caches.open(CACHE_NAME);
+ return await cache.match(request.url);
+};
+
+// Attempt to get resources from the network first, fallback to the cache if we're
+// offline.
+const networkFallbackToCache = async request => {
+ try {
+ const response = await fetch(request);
+ if (response.ok) return response;
+ } catch (err) {}
+ return await fromCache(request);
+};
+
+// When we have a new service worker, update the caches and swap immediately.
+self.addEventListener("install", e => {
+ e.waitUntil(precache().then(() => self.skipWaiting()));
+});
+
+// Claim existing clients.
+self.addEventListener("activate", e => {
+ e.waitUntil(self.clients.claim());
+});
+
+// When a resource need to be fetched, check whether it is
+// contained in the cache and return the cached version, otherwise
+// get it from the network.
+self.addEventListener("fetch", e => {
+ e.respondWith(networkFallbackToCache(e.request));
+});