summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/androidTest/assets
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/androidTest/assets')
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/moz.build78
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js190
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.pngbin0 -> 1395 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.pngbin0 -> 1093 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.pngbin0 -> 1074 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js4
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json43
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.js24
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpibin0 -> 1827 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpibin0 -> 1882 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.zipbin0 -> 1882 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpibin0 -> 9221 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json23
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js44
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js8
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/download.js18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy-incompatible.xpibin0 -> 521 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpibin0 -> 544 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js5
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js2
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/langpack_signed.xpibin0 -> 4452 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js29
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json23
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js28
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.pngbin0 -> 225 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js6
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json20
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json20
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/clickToRequestPermission.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/manifest.json13
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/request-permission.js11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js39
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json25
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js4
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.sys.mjs83
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportProcessChild.sys.mjs22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js127
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json42
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js256
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json308
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js60
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js1
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-aria-comboboxes.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-checkbox.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-clipboard.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-collection.html21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-expandable.html13
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-headings.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-links.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-atomic.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-descendant.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image-labeled-by.html15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image.html15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-local-iframe.html21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-move-caret-accessibility-focus.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-mutation.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-range.html23
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-remote-iframe.html24
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-scroll.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-selectable.html22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-text-entry-node.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-tree.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/address_form.html21
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/audio/owl.mp3bin0 -> 67430 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/autoplay.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/badVideoPath.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/beforeunload.html15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/cc_form.html22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/clickToReload.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/clipboard_read.html22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/color_grid.html40
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/color_orange_background.html29
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/colors.html23
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_audio.html20
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html44
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_full.html22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_image.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_image_nested.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_link.html15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/context_menu_video.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/data_uri.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/dnd.html27
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/download.html18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fedcm_accounts_endpoint.json12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_manifest.json18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_metadata.json4
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fedcm_idtokens_endpoint.json3
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fedcm_rp.html8
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fixedbottom.html36
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fixedpercent.html25
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fixedvh.html25
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/form_blank.html20
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms.html34
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms2.html17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms2_iframe.html16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms3.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms4.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms5.html24
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete.html16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete_iframe.html15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms_id_value.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms_iframe.html58
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/forms_xorigin.html77
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/fullscreen.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_container.html58
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_iframe.html39
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/hello.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/hello2.html9
-rwxr-xr-xmobile/android/geckoview/src/androidTest/assets/www/helloPDFWorld.pdfbin0 -> 10414 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/hsts_header.sjs6
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/hungScript.html16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_no_scrollable.html60
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_scrollable.html60
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_no_scrollable.html55
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_scrollable.html55
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_hello.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_http_only.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_automation.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_local.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/iframe_unknown_protocol.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/images/test.gifbin0 -> 23961 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/inputs.html66
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/links.html28
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/loremIpsum.html17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/media_session_default1.html15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/media_session_dom1.html109
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/metatags.html19
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/mouseToReload.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/mp4.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/newSession.html22
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/newSession_child.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/no-meta-viewport.html5
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/ogg.html11
-rwxr-xr-xmobile/android/geckoview/src/androidTest/assets/www/orange.pdfbin0 -> 16829 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto-none.html28
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto.html28
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-auto.html28
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-on-non-root.html37
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/popup.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/print_content_change.html37
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/print_iframe.html39
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/prompts.html31
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/pull-to-refresh-subframe.html82
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/push/push.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/push/push.js44
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/push/sw.js30
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/red-background-body-fully-covered-by-green-element.html23
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/reflect_local_storage_into_title.html17
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/resubmit.html12
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/root_100_percent_height.html37
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/root_100vh.html36
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/root_98vh.html36
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/saveState.html18
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/scroll-handoff.html40
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/scroll.html59
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/select-listbox.html7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/select-multiple.html7
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/select.html6
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame.html6
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame_xorigin.html47
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/showDynamicToolbar.html96
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/simple_redirect.sjs4
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/titleChange.html16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/touch-action-wheel-listener.html33
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/touch-action.html48
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/touch.html58
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/touch_xorigin.html16
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/touchstart.html37
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/tracemonkey.pdfbin0 -> 178030 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/trackers.html14
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/translations-tester-en.html62
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/translations-tester-es.html83
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/transparent.gifbin0 -> 43 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/update_manifest.json40
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/videos/gizmo.webmbin0 -> 159035 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/videos/short.mp4bin0 -> 13651 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/videos/video.oggbin0 -> 285310 bytes
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/viewport.html19
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/webm.html11
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.html10
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.js15
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/worker/open_window_target.html9
-rw-r--r--mobile/android/geckoview/src/androidTest/assets/www/worker/service-worker.js15
246 files changed, 5411 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/androidTest/assets/moz.build b/mobile/android/geckoview/src/androidTest/assets/moz.build
new file mode 100644
index 0000000000..12d6550f1c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/moz.build
@@ -0,0 +1,78 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addons = {
+ "browsing-data": [
+ "background.js",
+ "manifest.json",
+ ],
+ "tabs-activate-remove": [
+ "background.js",
+ "manifest.json",
+ ],
+ "tabs-activate-remove-2": [
+ "background.js",
+ "manifest.json",
+ ],
+ "update-1": [
+ "borderify.js",
+ "manifest.json",
+ ],
+ "update-2": [
+ "borderify.js",
+ "manifest.json",
+ ],
+ "update-postpone-1": [
+ "background.js",
+ "borderify.js",
+ "manifest.json",
+ ],
+ "update-postpone-2": [
+ "borderify.js",
+ "manifest.json",
+ ],
+ "update-with-perms-1": [
+ "borderify.js",
+ "manifest.json",
+ ],
+ "update-with-perms-2": [
+ "borderify.js",
+ "manifest.json",
+ ],
+ "page-history": [
+ "page.html",
+ "manifest.json",
+ ],
+ "download-flags-true": [
+ "download.js",
+ "manifest.json",
+ ],
+ "download-flags-false": [
+ "download.js",
+ "manifest.json",
+ ],
+ "download-onChanged": [
+ "download.js",
+ "manifest.json",
+ ],
+ "permission-request": [
+ "clickToRequestPermission.html",
+ "request-permission.js",
+ "manifest.json",
+ ],
+}
+
+for addon, files in addons.items():
+ indir = "web_extensions/%s" % addon
+ xpi = "%s.xpi" % indir
+ inputs = [indir]
+ for file in files:
+ inputs.append("%s/%s" % (indir, file))
+ GeneratedFile(
+ xpi, script="/toolkit/mozapps/extensions/test/create_xpi.py", inputs=inputs
+ )
+
+ TEST_HARNESS_FILES.testing.mochitest.tests.junit += ["!%s" % xpi]
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js
new file mode 100644
index 0000000000..41c5ed8080
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/.eslintrc.js
@@ -0,0 +1,14 @@
+"use strict";
+
+module.exports = {
+ env: {
+ webextensions: true,
+ },
+ globals: {
+ ExtensionAPI: true,
+ // available to frameScripts
+ addMessageListener: false,
+ content: false,
+ sendAsyncMessage: false,
+ },
+};
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js
new file mode 100644
index 0000000000..dab0f5d897
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/background.js
@@ -0,0 +1,190 @@
+const port = browser.runtime.connectNative("browser");
+port.onMessage.addListener(message => {
+ handleMessage(message, null);
+});
+
+browser.runtime.onMessage.addListener((message, sender) => {
+ handleMessage(message, sender.tab.id);
+});
+
+browser.pageAction.onClicked.addListener(tab => {
+ port.postMessage({ method: "onClicked", tabId: tab.id, type: "pageAction" });
+});
+
+browser.browserAction.onClicked.addListener(tab => {
+ port.postMessage({
+ method: "onClicked",
+ tabId: tab.id,
+ type: "browserAction",
+ });
+});
+
+function handlePageActionMessage(message, tabId) {
+ switch (message.action) {
+ case "enable":
+ browser.pageAction.show(tabId);
+ break;
+
+ case "disable":
+ browser.pageAction.hide(tabId);
+ break;
+
+ case "setPopup":
+ browser.pageAction.setPopup({
+ tabId,
+ popup: message.popup,
+ });
+ break;
+
+ case "setPopupCheckRestrictions":
+ browser.pageAction
+ .setPopup({
+ tabId,
+ popup: message.popup,
+ })
+ .then(
+ () => {
+ port.postMessage({
+ resultFor: "setPopup",
+ type: "pageAction",
+ success: true,
+ });
+ },
+ err => {
+ port.postMessage({
+ resultFor: "setPopup",
+ type: "pageAction",
+ success: false,
+ error: String(err),
+ });
+ }
+ );
+ break;
+
+ case "setTitle":
+ browser.pageAction.setTitle({
+ tabId,
+ title: message.title,
+ });
+ break;
+
+ case "setIcon":
+ browser.pageAction.setIcon({
+ tabId,
+ imageData: message.imageData,
+ path: message.path,
+ });
+ break;
+
+ default:
+ throw new Error(`Page Action does not support ${message.action}`);
+ }
+}
+
+function handleBrowserActionMessage(message, tabId) {
+ switch (message.action) {
+ case "enable":
+ browser.browserAction.enable(tabId);
+ break;
+
+ case "disable":
+ browser.browserAction.disable(tabId);
+ break;
+
+ case "setBadgeText":
+ browser.browserAction.setBadgeText({
+ tabId,
+ text: message.text,
+ });
+ break;
+
+ case "setBadgeTextColor":
+ browser.browserAction.setBadgeTextColor({
+ tabId,
+ color: message.color,
+ });
+ break;
+
+ case "setBadgeBackgroundColor":
+ browser.browserAction.setBadgeBackgroundColor({
+ tabId,
+ color: message.color,
+ });
+ break;
+
+ case "setPopup":
+ browser.browserAction.setPopup({
+ tabId,
+ popup: message.popup,
+ });
+ break;
+
+ case "setPopupCheckRestrictions":
+ browser.browserAction
+ .setPopup({
+ tabId,
+ popup: message.popup,
+ })
+ .then(
+ () => {
+ port.postMessage({
+ resultFor: "setPopup",
+ type: "browserAction",
+ success: true,
+ });
+ },
+ err => {
+ port.postMessage({
+ resultFor: "setPopup",
+ type: "browserAction",
+ success: false,
+ error: String(err),
+ });
+ }
+ );
+ break;
+
+ case "setTitle":
+ browser.browserAction.setTitle({
+ tabId,
+ title: message.title,
+ });
+ break;
+
+ case "setIcon":
+ browser.browserAction.setIcon({
+ tabId,
+ imageData: message.imageData,
+ path: message.path,
+ });
+ break;
+
+ default:
+ throw new Error(`Browser Action does not support ${message.action}`);
+ }
+}
+
+function handleMessage(message, tabId) {
+ switch (message.type) {
+ case "ping":
+ port.postMessage({ method: "pong" });
+ return;
+
+ case "load":
+ browser.tabs.update(tabId, {
+ url: message.url,
+ });
+ return;
+
+ case "browserAction":
+ handleBrowserActionMessage(message, tabId);
+ return;
+
+ case "pageAction":
+ handlePageActionMessage(message, tabId);
+ return;
+
+ default:
+ throw new Error(`Unsupported message type ${message.type}`);
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.png
new file mode 100644
index 0000000000..dbed714c56
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32-light.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.png
new file mode 100644
index 0000000000..89863ccec7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/beasts-32.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.png
new file mode 100644
index 0000000000..aea2c19784
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/expected.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-19.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/geo-38.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg
new file mode 100644
index 0000000000..dd1fae7d15
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/button/icon.svg
@@ -0,0 +1 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 500 500" height="500px" id="Layer_1" version="1.1" viewBox="0 0 500 500" width="500px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path clip-rule="evenodd" d="M131.889,150.061v63.597h-27.256 c-20.079,0-36.343,16.263-36.343,36.342v181.711c0,20.078,16.264,36.34,36.343,36.34h290.734c20.078,0,36.345-16.262,36.345-36.34 V250c0-20.079-16.267-36.342-36.345-36.342h-27.254v-63.597c0-65.232-52.882-118.111-118.112-118.111 S131.889,84.828,131.889,150.061z M177.317,213.658v-63.597c0-40.157,32.525-72.685,72.683-72.685 c40.158,0,72.685,32.528,72.685,72.685v63.597H177.317z M213.658,313.599c0-20.078,16.263-36.341,36.342-36.341 s36.341,16.263,36.341,36.341c0,12.812-6.634,24.079-16.625,30.529c0,0,3.55,21.446,7.542,46.699 c0,7.538-6.087,13.625-13.629,13.625h-27.258c-7.541,0-13.627-6.087-13.627-13.625l7.542-46.699 C220.294,337.678,213.658,326.41,213.658,313.599z" fill="#010101" fill-rule="evenodd"/></svg> \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js
new file mode 100644
index 0000000000..eaa2467df0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/content.js
@@ -0,0 +1,4 @@
+const port = browser.runtime.connectNative("browser");
+port.onMessage.addListener(message => {
+ browser.runtime.sendMessage(message);
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json
new file mode 100644
index 0000000000..21ca7c7e07
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/manifest.json
@@ -0,0 +1,43 @@
+{
+ "manifest_version": 2,
+ "name": "actions",
+ "version": "1.0",
+ "description": "Defines Page and Browser actions",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "actions@tests.mozilla.org"
+ }
+ },
+ "browser_action": {
+ "default_title": "Test action default",
+ "theme_icons": [
+ {
+ "light": "button/beasts-32-light.png",
+ "dark": "button/beasts-32.png",
+ "size": 32
+ }
+ ]
+ },
+ "page_action": {
+ "default_title": "Test action default",
+ "default_icon": {
+ "19": "button/geo-19.png",
+ "38": "button/geo-38.png"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "content_scripts": [
+ {
+ "matches": ["<all_urls>"],
+ "js": ["content.js"]
+ }
+ ],
+ "permissions": [
+ "tabs",
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html
new file mode 100644
index 0000000000..dc388b8a7f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <script
+ type="text/javascript"
+ src="test-open-popup-browser-action.js"
+ ></script>
+ </head>
+ <body>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ </body>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js
new file mode 100644
index 0000000000..cde31235ac
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-browser-action.js
@@ -0,0 +1,7 @@
+window.addEventListener("DOMContentLoaded", init);
+
+function init() {
+ document.body.addEventListener("click", event => {
+ browser.browserAction.openPopup();
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html
new file mode 100644
index 0000000000..3fe42d0b2e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <script
+ type="text/javascript"
+ src="test-open-popup-page-action.js"
+ ></script>
+ </head>
+ <body>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ </body>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js
new file mode 100644
index 0000000000..f16d96333f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-open-popup-page-action.js
@@ -0,0 +1,7 @@
+window.addEventListener("DOMContentLoaded", init);
+
+function init() {
+ document.body.addEventListener("click", event => {
+ browser.pageAction.openPopup();
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.html
new file mode 100644
index 0000000000..f0fff977d8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <script src="test-popup-messaging.js"></script>
+ </head>
+ <body>
+ <h1>HELLO</h1>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.js
new file mode 100644
index 0000000000..479f957564
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup-messaging.js
@@ -0,0 +1,24 @@
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ const response = await browser.runtime.sendNativeMessage(
+ "browser",
+ "testPopupMessage"
+ );
+
+ browser.runtime.sendNativeMessage("browser", `response: ${response}`);
+
+ const port = browser.runtime.connectNative("browser");
+ port.onMessage.addListener(response => {
+ if (response.action === "disconnect") {
+ port.disconnect();
+ return;
+ }
+
+ port.postMessage(`response: ${response.message}`);
+ });
+
+ port.postMessage("testPopupPortMessage");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html
new file mode 100644
index 0000000000..dd98313e59
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <script src="test-popup.js"></script>
+ </head>
+ <body>
+ <h1>HELLO</h1>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js
new file mode 100644
index 0000000000..47271e744c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/actions/test-popup.js
@@ -0,0 +1,3 @@
+window.addEventListener("DOMContentLoaded", () => {
+ window.close();
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpi
new file mode 100644
index 0000000000..19ce0d7f0f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-missing-id.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpi
new file mode 100644
index 0000000000..fd395d13df
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.zip b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.zip
new file mode 100644
index 0000000000..fd395d13df
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify-unsigned.zip
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpi
new file mode 100644
index 0000000000..1ed97f1047
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/border-48.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg
new file mode 100644
index 0000000000..dd1fae7d15
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/icons/icon.svg
@@ -0,0 +1 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 500 500" height="500px" id="Layer_1" version="1.1" viewBox="0 0 500 500" width="500px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path clip-rule="evenodd" d="M131.889,150.061v63.597h-27.256 c-20.079,0-36.343,16.263-36.343,36.342v181.711c0,20.078,16.264,36.34,36.343,36.34h290.734c20.078,0,36.345-16.262,36.345-36.34 V250c0-20.079-16.267-36.342-36.345-36.342h-27.254v-63.597c0-65.232-52.882-118.111-118.112-118.111 S131.889,84.828,131.889,150.061z M177.317,213.658v-63.597c0-40.157,32.525-72.685,72.683-72.685 c40.158,0,72.685,32.528,72.685,72.685v63.597H177.317z M213.658,313.599c0-20.078,16.263-36.341,36.342-36.341 s36.341,16.263,36.341,36.341c0,12.812-6.634,24.079-16.625,30.529c0,0,3.55,21.446,7.542,46.699 c0,7.538-6.087,13.625-13.629,13.625h-27.258c-7.541,0-13.627-6.087-13.627-13.625l7.542-46.699 C220.294,337.678,213.658,326.41,213.658,313.599z" fill="#010101" fill-rule="evenodd"/></svg> \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json
new file mode 100644
index 0000000000..4e3daf6708
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/borderify/manifest.json
@@ -0,0 +1,23 @@
+{
+ "manifest_version": 2,
+ "name": "Borderify",
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "borderify@tests.mozilla.org"
+ }
+ },
+ "icons": {
+ "48": "icons/border-48.png"
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ],
+ "options_ui": {
+ "page": "dummy.html"
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js
new file mode 100644
index 0000000000..d0ae54b3dd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/background.js
@@ -0,0 +1,44 @@
+const port = browser.runtime.connectNative("browser");
+
+async function apiCall(message) {
+ const { type, since, removalOptions, dataTypes } = message;
+ switch (type) {
+ case "clear-downloads":
+ await browser.browsingData.removeDownloads({ since });
+ break;
+ case "clear-form-data":
+ await browser.browsingData.removeFormData({ since });
+ break;
+ case "clear-history":
+ await browser.browsingData.removeHistory({ since });
+ break;
+ case "clear-passwords":
+ await browser.browsingData.removePasswords({ since });
+ break;
+ case "clear":
+ await browser.browsingData.remove(removalOptions, dataTypes);
+ break;
+ case "get-settings":
+ return browser.browsingData.settings();
+ }
+ return null;
+}
+
+port.onMessage.addListener(async message => {
+ const { uuid } = message;
+ try {
+ const result = await apiCall(message);
+ port.postMessage({
+ type: "response",
+ result,
+ uuid,
+ });
+ } catch (exception) {
+ const { message } = exception;
+ port.postMessage({
+ type: "error",
+ error: message,
+ uuid,
+ });
+ }
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json
new file mode 100644
index 0000000000..23df4d8338
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data-built-in/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "BrowsingData",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "browsing-data-settings@tests.mozilla.org"
+ }
+ },
+ "version": "1.0",
+ "description": "Tests the browsingData API",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["browsingData", "geckoViewAddons", "nativeMessaging"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js
new file mode 100644
index 0000000000..4597e3328b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/background.js
@@ -0,0 +1,8 @@
+browser.browsingData.removeDownloads({ since: 10001 });
+browser.browsingData.removeFormData({ since: 10002 });
+browser.browsingData.removeHistory({ since: 10003 });
+browser.browsingData.removePasswords({ since: 10004 });
+browser.browsingData.remove(
+ { since: 10005 },
+ { downloads: true, cookies: true }
+);
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json
new file mode 100644
index 0000000000..f7af03c25e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/browsing-data/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "BrowsingData",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "browsing-data@tests.mozilla.org"
+ }
+ },
+ "version": "1.0",
+ "description": "Tests the browsingData API",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["browsingData"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js
new file mode 100644
index 0000000000..68f51ea5d8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/download.js
@@ -0,0 +1,3 @@
+browser.downloads.download({
+ url: "http://localhost:4245/assets/www/images/test.gif",
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json
new file mode 100644
index 0000000000..77b1cb5179
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-false/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "Download",
+ "version": "1.0",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "download-flags-false@tests.mozilla.org"
+ }
+ },
+ "description": "Downloads a file",
+ "background": {
+ "scripts": ["download.js"]
+ },
+ "permissions": ["downloads"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js
new file mode 100644
index 0000000000..4bb06a5cbb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/download.js
@@ -0,0 +1,16 @@
+browser.downloads.download({
+ url: "http://localhost:4245/assets/www/images/test.gif",
+ filename: "banana.gif",
+ method: "POST",
+ body: "postbody",
+ headers: [
+ {
+ name: "User-Agent",
+ value: "Mozilla Firefox",
+ },
+ ],
+ allowHttpErrors: true,
+ conflictAction: "overwrite",
+ saveAs: true,
+ incognito: true,
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json
new file mode 100644
index 0000000000..c0170dafd4
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-flags-true/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "Download",
+ "version": "1.0",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "download-flags-true@tests.mozilla.org"
+ }
+ },
+ "description": "Downloads a file",
+ "background": {
+ "scripts": ["download.js"]
+ },
+ "permissions": ["downloads"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/download.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/download.js
new file mode 100644
index 0000000000..01cd377cef
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/download.js
@@ -0,0 +1,18 @@
+async function test() {
+ browser.downloads.onChanged.addListener(async delta => {
+ const changes = { current: {}, previous: {} };
+ changes.id = delta.id;
+ delete delta.id;
+ for (const prop in delta) {
+ changes.current[prop] = delta[prop].current;
+ changes.previous[prop] = delta[prop].previous;
+ }
+ await browser.runtime.sendNativeMessage("browser", changes);
+ });
+
+ await browser.downloads.download({
+ url: "http://localhost:4245/assets/www/images/test.gif",
+ });
+}
+
+test();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/manifest.json
new file mode 100644
index 0000000000..1c1ad4cc5e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/download-onChanged/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "Download",
+ "version": "1.0",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "download-onChanged@tests.mozilla.org"
+ }
+ },
+ "description": "Downloads a file",
+ "background": {
+ "scripts": ["download.js"]
+ },
+ "permissions": ["downloads", "geckoViewAddons", "nativeMessaging"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy-incompatible.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy-incompatible.xpi
new file mode 100644
index 0000000000..93c5dbd3b2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy-incompatible.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpi
new file mode 100644
index 0000000000..0e0f549ceb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js
new file mode 100644
index 0000000000..2a49c0d665
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/dummy.js
@@ -0,0 +1 @@
+console.log("Hi, I'm a dummy.");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json
new file mode 100644
index 0000000000..f1f9b93a91
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/dummy/manifest.json
@@ -0,0 +1,21 @@
+{
+ "manifest_version": 2,
+ "name": "Dummy",
+ "version": "1.0",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "dummy@tests.mozilla.org"
+ }
+ },
+ "description": "Doesn't do anything.",
+ "options_ui": {
+ "open_in_tab": true,
+ "page": "options.html"
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["dummy.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json
new file mode 100644
index 0000000000..0fcb48bc8f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/manifest.json
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 2,
+ "name": "Test messages sent from extensions when restoring",
+ "version": "1.0",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "extension-page-restoring@tests.mozilla.org"
+ }
+ },
+ "permissions": ["geckoViewAddons", "nativeMessaging"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js
new file mode 100644
index 0000000000..66866bbd37
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab-script.js
@@ -0,0 +1,5 @@
+browser.runtime.sendNativeMessage("browser1", "HELLO_FROM_PAGE_1");
+browser.runtime.sendNativeMessage("browser2", "HELLO_FROM_PAGE_2");
+
+const port = browser.runtime.connectNative("browser1");
+port.postMessage("HELLO_FROM_PORT");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html
new file mode 100644
index 0000000000..d99a610c0c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-restore/tab.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <h1>Hello World!</h1>
+ <script src="tab-script.js"></script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js
new file mode 100644
index 0000000000..43e2b44f96
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/background-script.js
@@ -0,0 +1,7 @@
+browser.runtime.onMessage.addListener(notify);
+
+function notify(message) {
+ if (message.action == "showTab") {
+ browser.tabs.update({ url: "/tab.html" });
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json
new file mode 100644
index 0000000000..c64115e07c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/manifest.json
@@ -0,0 +1,21 @@
+{
+ "manifest_version": 2,
+ "name": "Mozilla Android Components - Tabs Update Test",
+ "version": "1.0",
+ "background": {
+ "scripts": ["background-script.js"]
+ },
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "extension-page-update@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["tabs.js"],
+ "run_at": "document_idle"
+ }
+ ],
+ "permissions": ["geckoViewAddons", "nativeMessaging", "tabs", "<all_urls>"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js
new file mode 100644
index 0000000000..011f3bb301
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab-script.js
@@ -0,0 +1,2 @@
+// Let's test privileged APIs
+browser.runtime.sendNativeMessage("browser", "HELLO_FROM_PAGE");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html
new file mode 100644
index 0000000000..d99a610c0c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tab.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <h1>Hello World!</h1>
+ <script src="tab-script.js"></script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js
new file mode 100644
index 0000000000..ef5fbf6ce3
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/extension-page-update/tabs.js
@@ -0,0 +1 @@
+browser.runtime.sendMessage({ action: "showTab" });
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/langpack_signed.xpi b/mobile/android/geckoview/src/androidTest/assets/web_extensions/langpack_signed.xpi
new file mode 100644
index 0000000000..f60d00348e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/langpack_signed.xpi
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json
new file mode 100644
index 0000000000..9a687dafbe
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/manifest.json
@@ -0,0 +1,22 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Test messaging between app and web extension",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "messaging-content@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["messaging.js"]
+ }
+ ],
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js
new file mode 100644
index 0000000000..1c8323df53
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-content/messaging.js
@@ -0,0 +1,29 @@
+// This message should not be handled
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ const response = await browser.runtime.sendNativeMessage(
+ "browser",
+ "testContentBrowserMessage"
+ );
+
+ browser.runtime.sendNativeMessage("browser", `response: ${response}`);
+
+ const port = browser.runtime.connectNative("browser");
+ port.onMessage.addListener(response => {
+ if (response.action === "disconnect") {
+ port.disconnect();
+ return;
+ }
+
+ port.postMessage(`response: ${response.message}`);
+ });
+
+ port.onDisconnect.addListener(() =>
+ browser.runtime.sendNativeMessage("browser", { type: "portDisconnected" })
+ );
+
+ port.postMessage("testContentPortMessage");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json
new file mode 100644
index 0000000000..f9039fd2e8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/manifest.json
@@ -0,0 +1,23 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Test messaging between app and web extension",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "messaging-iframe@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": ["*://localhost/*"],
+ "js": ["messaging.js"],
+ "all_frames": true
+ }
+ ],
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js
new file mode 100644
index 0000000000..eb4ad3d8f9
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging-iframe/messaging.js
@@ -0,0 +1,11 @@
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ await browser.runtime.sendNativeMessage(
+ "browser",
+ "testContentBrowserMessage"
+ );
+ browser.runtime.connectNative("browser");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js
new file mode 100644
index 0000000000..20deb53ae7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/background.js
@@ -0,0 +1,28 @@
+browser.runtime.sendNativeMessage("badNativeApi", "errorerrorerror");
+
+async function runTest() {
+ const response = await browser.runtime.sendNativeMessage(
+ "browser",
+ "testBackgroundBrowserMessage"
+ );
+
+ browser.runtime.sendNativeMessage("browser", `response: ${response}`);
+
+ const port = browser.runtime.connectNative("browser");
+ port.onMessage.addListener(response => {
+ if (response.action === "disconnect") {
+ port.disconnect();
+ return;
+ }
+
+ port.postMessage(`response: ${response.message}`);
+ });
+
+ port.onDisconnect.addListener(() =>
+ browser.runtime.sendNativeMessage("browser", { type: "portDisconnected" })
+ );
+
+ port.postMessage("testBackgroundPortMessage");
+}
+
+runTest();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.png b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.png
new file mode 100644
index 0000000000..90687de26d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/icons/border-48.png
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json
new file mode 100644
index 0000000000..d25b692f63
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/messaging/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Test messaging between app and web extension",
+ "icons": {
+ "48": "icons/border-48.png"
+ },
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "messaging@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["geckoViewAddons", "nativeMessaging"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js
new file mode 100644
index 0000000000..cdd3a7a523
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/background.js
@@ -0,0 +1,6 @@
+browser.notifications.create("cake-notification", {
+ type: "basic",
+ title: "Time for cake!",
+ iconUrl: "https://example.com/img.svg",
+ message: "Something something cake",
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json
new file mode 100644
index 0000000000..963fb51e3f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/notification-test/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "Notification test",
+ "version": "1.0",
+ "description": "Send a notification.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "notification@example.com"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["notifications"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js
new file mode 100644
index 0000000000..1872c48d00
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/background.js
@@ -0,0 +1 @@
+browser.runtime.openOptionsPage();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json
new file mode 100644
index 0000000000..487fb0fb3d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-1/manifest.json
@@ -0,0 +1,20 @@
+{
+ "manifest_version": 2,
+ "name": "openOptionsPage-1",
+ "version": "1.0",
+ "description": "Opens options page in a new tab.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "openoptionspage1@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs"],
+ "options_ui": {
+ "page": "options.html",
+ "browser_style": true,
+ "open_in_tab": true
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js
new file mode 100644
index 0000000000..1872c48d00
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/background.js
@@ -0,0 +1 @@
+browser.runtime.openOptionsPage();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json
new file mode 100644
index 0000000000..3378050197
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/openoptionspage-2/manifest.json
@@ -0,0 +1,20 @@
+{
+ "manifest_version": 2,
+ "name": "openOptionsPage-2",
+ "version": "1.0",
+ "description": "Opens options page via delegate.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "openoptionspage2@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs"],
+ "options_ui": {
+ "page": "options.html",
+ "browser_style": true,
+ "open_in_tab": false
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json
new file mode 100644
index 0000000000..9d411c8dd6
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/manifest.json
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 2,
+ "name": "Page History",
+ "version": "1.0",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "page-history@tests.mozilla.org"
+ }
+ },
+ "description": "Can load a WebExtension Page."
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html
new file mode 100644
index 0000000000..b16a98f74b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/page-history/page.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <h1>Hello, World!</h1>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/clickToRequestPermission.html b/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/clickToRequestPermission.html
new file mode 100644
index 0000000000..e6ddcb8c8d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/clickToRequestPermission.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <meta name="viewport" content="initial-scale=1.0" />
+ <script type="text/javascript" src="request-permission.js"></script>
+ </head>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/manifest.json
new file mode 100644
index 0000000000..d2cd405cd1
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/manifest.json
@@ -0,0 +1,13 @@
+{
+ "manifest_version": 2,
+ "name": "permissions",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "permissions@example.com"
+ }
+ },
+ "version": "1.0",
+ "description": "Request optional extension permissions.",
+ "permissions": ["nativeMessaging", "geckoViewAddons"],
+ "optional_permissions": ["geolocation", "*://example.com/*"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/request-permission.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/request-permission.js
new file mode 100644
index 0000000000..d50bff4126
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/permission-request/request-permission.js
@@ -0,0 +1,11 @@
+window.onload = () => {
+ document.body.addEventListener("click", requestPermissions);
+ async function requestPermissions() {
+ const perms = {
+ permissions: ["geolocation"],
+ origins: ["*://example.com/*"],
+ };
+ const response = await browser.permissions.request(perms);
+ browser.runtime.sendNativeMessage("browser", `${response}`);
+ }
+};
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js
new file mode 100644
index 0000000000..fdf088a505
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/background.js
@@ -0,0 +1,39 @@
+"use strict";
+
+function setupRedirect(fromUrl, redirectUrl) {
+ browser.webRequest.onBeforeRequest.addListener(
+ details => {
+ console.log(`Extension redirects from ${fromUrl} to ${redirectUrl}`);
+ return { redirectUrl };
+ },
+ { urls: [fromUrl] },
+ ["blocking"]
+ );
+}
+
+// Intercepts all script requests from androidTest/assets/www/trackers.html.
+// Scripts are executed in order of appearance in the page and block the
+// page's "load" event, so the test runner can just wait for the page to
+// have loaded and then check the page content to verify that the requests
+// were intercepted as expected.
+setupRedirect(
+ "http://trackertest.org/tracker.js",
+ "data:text/javascript,document.body.textContent='start'"
+);
+setupRedirect(
+ "https://tracking.example.com/tracker.js",
+ browser.runtime.getURL("web-accessible-script.js")
+);
+setupRedirect(
+ "https://itisatracker.org/tracker.js",
+ `data:text/javascript,document.body.textContent+=',end'`
+);
+
+// Work around bug 1300234 to ensure that the webRequest listener has been
+// registered before we resume the test. API result doesn't matter, we just
+// want to make a roundtrip.
+var listenerReady = browser.webRequest.getSecurityInfo("").catch(() => {});
+
+listenerReady.then(() => {
+ browser.runtime.sendNativeMessage("browser", "setupReadyStartTest");
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json
new file mode 100644
index 0000000000..71d811faa3
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/manifest.json
@@ -0,0 +1,25 @@
+{
+ "name": "redirect-to-android-resource",
+ "description": "Redirects script requests from trackers.html to moz-extension:-resource packaged in the APK (resource://android/...)",
+ "manifest_version": 2,
+ "version": "1",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "redirect-to-android-resource@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "webRequest",
+ "webRequestBlocking",
+ "http://localhost/",
+ "http://trackertest.org/",
+ "https://tracking.example.com/",
+ "https://itisatracker.org/tracker.js"
+ ],
+ "web_accessible_resources": ["web-accessible-script.js"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js
new file mode 100644
index 0000000000..a26c4cc91c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/redirect-to-android-resource/web-accessible-script.js
@@ -0,0 +1,3 @@
+"use strict";
+
+document.body.textContent += ",extension-was-here";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js
new file mode 100644
index 0000000000..f8ecef0215
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/background.js
@@ -0,0 +1,16 @@
+browser.tabs.onActivated.addListener(async tabChange => {
+ const activeTabs = await browser.tabs.query({ active: true });
+ const currentWindow = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ if (
+ activeTabs.length === 1 &&
+ activeTabs[0].id == tabChange.tabId &&
+ currentWindow.length === 1 &&
+ currentWindow[0].id === tabChange.tabId
+ ) {
+ browser.tabs.remove(tabChange.tabId);
+ }
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json
new file mode 100644
index 0000000000..784215634d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove-2/manifest.json
@@ -0,0 +1,15 @@
+{
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "set-tab-active-2@tests.mozilla.org"
+ }
+ },
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Removes the activated Tab.",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js
new file mode 100644
index 0000000000..f8ecef0215
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/background.js
@@ -0,0 +1,16 @@
+browser.tabs.onActivated.addListener(async tabChange => {
+ const activeTabs = await browser.tabs.query({ active: true });
+ const currentWindow = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ if (
+ activeTabs.length === 1 &&
+ activeTabs[0].id == tabChange.tabId &&
+ currentWindow.length === 1 &&
+ currentWindow[0].id === tabChange.tabId
+ ) {
+ browser.tabs.remove(tabChange.tabId);
+ }
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json
new file mode 100644
index 0000000000..03c3514bb0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-activate-remove/manifest.json
@@ -0,0 +1,15 @@
+{
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "set-tab-active@tests.mozilla.org"
+ }
+ },
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Removes the activated Tab.",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js
new file mode 100644
index 0000000000..8182b6a4f8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/background.js
@@ -0,0 +1,4 @@
+browser.tabs.create({
+ url: "https://www.mozilla.org/en-US/",
+ cookieStoreId: "firefox-container-1",
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json
new file mode 100644
index 0000000000..2746155adf
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-2/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Creates a tab with a contextual identity.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "tabs-create-2@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs", "cookies"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js
new file mode 100644
index 0000000000..a1f55a3a4f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/background.js
@@ -0,0 +1,3 @@
+browser.tabs.create({}).then(tab => {
+ browser.tabs.remove(tab.id);
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json
new file mode 100644
index 0000000000..10b2f454e7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create-remove/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Creates and removes a tab.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "tabs-create-remove@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": []
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js
new file mode 100644
index 0000000000..6fbd381e61
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/background.js
@@ -0,0 +1 @@
+browser.tabs.create({ url: "https://www.mozilla.org/en-US/" });
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json
new file mode 100644
index 0000000000..517ddd0189
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-create/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Creates a tab.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "tabs-create@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js
new file mode 100644
index 0000000000..c6ec7aee33
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/background.js
@@ -0,0 +1,3 @@
+browser.tabs.query({ url: "*://*/*?tabToClose" }).then(([tab]) => {
+ browser.tabs.remove(tab.id);
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json
new file mode 100644
index 0000000000..559512eec5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/tabs-remove/manifest.json
@@ -0,0 +1,15 @@
+{
+ "manifest_version": 2,
+ "name": "messaging",
+ "version": "1.0",
+ "description": "Removes an existing tab.",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "tabs-remove@tests.mozilla.org"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "permissions": ["tabs"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.sys.mjs b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.sys.mjs
new file mode 100644
index 0000000000..6dd3e8eed4
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportChild.sys.mjs
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { GeckoViewActorChild } from "resource://gre/modules/GeckoViewActorChild.sys.mjs";
+
+export class TestSupportChild extends GeckoViewActorChild {
+ receiveMessage(aMsg) {
+ debug`receiveMessage: ${aMsg.name}`;
+
+ switch (aMsg.name) {
+ case "FlushApzRepaints":
+ return new Promise(resolve => {
+ const repaintDone = () => {
+ debug`APZ flush done`;
+ Services.obs.removeObserver(repaintDone, "apz-repaints-flushed");
+ resolve();
+ };
+ Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
+ if (this.contentWindow.windowUtils.flushApzRepaints()) {
+ debug`Flushed APZ repaints, waiting for callback...`;
+ } else {
+ debug`Flushing APZ repaints was a no-op, triggering callback directly...`;
+ repaintDone();
+ }
+ });
+ case "PromiseAllPaintsDone":
+ return new Promise(resolve => {
+ const window = this.contentWindow;
+ const utils = window.windowUtils;
+
+ function waitForPaints() {
+ // Wait until paint suppression has ended
+ if (utils.paintingSuppressed) {
+ dump`waiting for paint suppression to end...`;
+ window.setTimeout(waitForPaints, 0);
+ return;
+ }
+
+ if (utils.isMozAfterPaintPending) {
+ dump`waiting for paint...`;
+ window.addEventListener("MozAfterPaint", waitForPaints, {
+ once: true,
+ });
+ return;
+ }
+ resolve();
+ }
+ waitForPaints();
+ });
+ case "GetLinkColor": {
+ const { selector } = aMsg.data;
+ const element = this.document.querySelector(selector);
+ if (!element) {
+ throw new Error("No element for " + selector);
+ }
+ const color =
+ this.contentWindow.windowUtils.getVisitedDependentComputedStyle(
+ element,
+ "",
+ "color"
+ );
+ return color;
+ }
+ case "SetResolutionAndScaleTo": {
+ return new Promise(resolve => {
+ const window = this.contentWindow;
+ const { resolution } = aMsg.data;
+ window.visualViewport.addEventListener("resize", () => resolve(), {
+ once: true,
+ });
+ window.windowUtils.setResolutionAndScaleTo(resolution);
+ });
+ }
+ case "WaitForContentTransformsReceived": {
+ return this.contentWindow.docShell.browserChild.contentTransformsReceived();
+ }
+ }
+ return null;
+ }
+}
+
+const { debug } = TestSupportChild.initLogging("GeckoViewTestSupport");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportProcessChild.sys.mjs b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportProcessChild.sys.mjs
new file mode 100644
index 0000000000..0684ef0967
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/TestSupportProcessChild.sys.mjs
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { GeckoViewUtils } from "resource://gre/modules/GeckoViewUtils.sys.mjs";
+
+const ProcessTools = Cc["@mozilla.org/processtools-service;1"].getService(
+ Ci.nsIProcessToolsService
+);
+
+export class TestSupportProcessChild extends JSProcessActorChild {
+ receiveMessage(aMsg) {
+ debug`receiveMessage: ${aMsg.name}`;
+
+ switch (aMsg.name) {
+ case "KillContentProcess":
+ ProcessTools.kill(Services.appinfo.processID);
+ }
+ }
+}
+
+const { debug } = GeckoViewUtils.initLogging("TestSupportProcess[C]");
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js
new file mode 100644
index 0000000000..181764859a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/background.js
@@ -0,0 +1,127 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const port = browser.runtime.connectNative("browser");
+
+const APIS = {
+ AddHistogram({ id, value }) {
+ browser.test.addHistogram(id, value);
+ },
+ Eval({ code }) {
+ // eslint-disable-next-line no-eval
+ return eval(`(async () => {
+ ${code}
+ })()`);
+ },
+ SetScalar({ id, value }) {
+ browser.test.setScalar(id, value);
+ },
+ GetRequestedLocales() {
+ return browser.test.getRequestedLocales();
+ },
+ GetLinkColor({ tab, selector }) {
+ return browser.test.getLinkColor(tab.id, selector);
+ },
+ GetPidForTab({ tab }) {
+ return browser.test.getPidForTab(tab.id);
+ },
+ WaitForContentTransformsReceived({ tab }) {
+ return browser.test.waitForContentTransformsReceived(tab.id);
+ },
+ GetProfilePath() {
+ return browser.test.getProfilePath();
+ },
+ GetAllBrowserPids() {
+ return browser.test.getAllBrowserPids();
+ },
+ KillContentProcess({ pid }) {
+ return browser.test.killContentProcess(pid);
+ },
+ GetPrefs({ prefs }) {
+ return browser.test.getPrefs(prefs);
+ },
+ GetActive({ tab }) {
+ return browser.test.getActive(tab.id);
+ },
+ RemoveAllCertOverrides() {
+ browser.test.removeAllCertOverrides();
+ },
+ RestorePrefs({ oldPrefs }) {
+ return browser.test.restorePrefs(oldPrefs);
+ },
+ SetPrefs({ oldPrefs, newPrefs }) {
+ return browser.test.setPrefs(oldPrefs, newPrefs);
+ },
+ SetResolutionAndScaleTo({ tab, resolution }) {
+ return browser.test.setResolutionAndScaleTo(tab.id, resolution);
+ },
+ FlushApzRepaints({ tab }) {
+ return browser.test.flushApzRepaints(tab.id);
+ },
+ PromiseAllPaintsDone({ tab }) {
+ return browser.test.promiseAllPaintsDone(tab.id);
+ },
+ UsingGpuProcess() {
+ return browser.test.usingGpuProcess();
+ },
+ KillGpuProcess() {
+ return browser.test.killGpuProcess();
+ },
+ CrashGpuProcess() {
+ return browser.test.crashGpuProcess();
+ },
+ ClearHSTSState() {
+ return browser.test.clearHSTSState();
+ },
+ TriggerCookieBannerDetected({ tab }) {
+ return browser.test.triggerCookieBannerDetected(tab.id);
+ },
+ TriggerCookieBannerHandled({ tab }) {
+ return browser.test.triggerCookieBannerHandled(tab.id);
+ },
+ TriggerTranslationsOffer({ tab }) {
+ return browser.test.triggerTranslationsOffer(tab.id);
+ },
+ TriggerLanguageStateChange({ tab, languageState }) {
+ return browser.test.triggerLanguageStateChange(tab.id, languageState);
+ },
+};
+
+port.onMessage.addListener(async message => {
+ const impl = APIS[message.type];
+ apiCall(message, impl);
+});
+
+browser.runtime.onConnect.addListener(contentPort => {
+ contentPort.onMessage.addListener(message => {
+ message.args.tab = contentPort.sender.tab;
+
+ const impl = APIS[message.type];
+ apiCall(message, impl);
+ });
+});
+
+function apiCall(message, impl) {
+ const { id, args } = message;
+ try {
+ sendResponse(id, impl(args));
+ } catch (error) {
+ sendResponse(id, Promise.reject(error));
+ }
+}
+
+function sendResponse(id, response) {
+ Promise.resolve(response).then(
+ value => sendSyncResponse(id, value),
+ reason => sendSyncResponse(id, null, reason)
+ );
+}
+
+function sendSyncResponse(id, response, exception) {
+ port.postMessage({
+ id,
+ response: JSON.stringify(response),
+ exception: exception && exception.toString(),
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json
new file mode 100644
index 0000000000..fea5add0de
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/manifest.json
@@ -0,0 +1,42 @@
+{
+ "manifest_version": 2,
+ "name": "Test support",
+ "version": "1.0",
+ "description": "Helper script for GeckoView tests",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "test-support@tests.mozilla.org"
+ }
+ },
+ "content_scripts": [
+ {
+ "matches": ["<all_urls>"],
+ "match_about_blank": true,
+ "js": ["test-support.js"],
+ "run_at": "document_start"
+ }
+ ],
+ "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';",
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "experiment_apis": {
+ "test": {
+ "schema": "test-schema.json",
+ "parent": {
+ "scopes": ["addon_parent"],
+ "script": "test-api.js",
+ "events": ["startup"],
+ "paths": [["test"]]
+ }
+ }
+ },
+ "options_ui": {
+ "page": "dummy.html"
+ },
+ "permissions": [
+ "geckoViewAddons",
+ "nativeMessaging",
+ "nativeMessagingFromContent"
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js
new file mode 100644
index 0000000000..1868d25c84
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-api.js
@@ -0,0 +1,256 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/* globals Services */
+
+const { E10SUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/E10SUtils.sys.mjs"
+);
+const { Preferences } = ChromeUtils.importESModule(
+ "resource://gre/modules/Preferences.sys.mjs"
+);
+
+// eslint-disable-next-line mozilla/reject-importGlobalProperties
+Cu.importGlobalProperties(["PathUtils"]);
+
+this.test = class extends ExtensionAPI {
+ onStartup() {
+ ChromeUtils.registerWindowActor("TestSupport", {
+ child: {
+ esModuleURI:
+ "resource://android/assets/web_extensions/test-support/TestSupportChild.sys.mjs",
+ },
+ allFrames: true,
+ });
+ ChromeUtils.registerProcessActor("TestSupportProcess", {
+ child: {
+ esModuleURI:
+ "resource://android/assets/web_extensions/test-support/TestSupportProcessChild.sys.mjs",
+ },
+ });
+ }
+
+ onShutdown(isAppShutdown) {
+ if (isAppShutdown) {
+ return;
+ }
+ ChromeUtils.unregisterWindowActor("TestSupport");
+ ChromeUtils.unregisterProcessActor("TestSupportProcess");
+ }
+
+ getAPI(context) {
+ /**
+ * Helper function for getting window or process actors.
+ *
+ * @param tabId - id of the tab; required
+ * @param actorName - a string; the name of the actor
+ * Default: "TestSupport" which is our test framework actor
+ * (you can still pass the second parameter when getting the TestSupport actor, for readability)
+ *
+ * @returns actor
+ */
+ function getActorForTab(tabId, actorName = "TestSupport") {
+ const tab = context.extension.tabManager.get(tabId);
+ const { browsingContext } = tab.browser;
+ return browsingContext.currentWindowGlobal.getActor(actorName);
+ }
+
+ return {
+ test: {
+ /* Set prefs and returns set of saved prefs */
+ async setPrefs(oldPrefs, newPrefs) {
+ // Save old prefs
+ Object.assign(
+ oldPrefs,
+ ...Object.keys(newPrefs)
+ .filter(key => !(key in oldPrefs))
+ .map(key => ({ [key]: Preferences.get(key, null) }))
+ );
+
+ // Set new prefs
+ Preferences.set(newPrefs);
+ return oldPrefs;
+ },
+
+ /* Restore prefs to old value. */
+ async restorePrefs(oldPrefs) {
+ for (const [name, value] of Object.entries(oldPrefs)) {
+ if (value === null) {
+ Preferences.reset(name);
+ } else {
+ Preferences.set(name, value);
+ }
+ }
+ },
+
+ /* Get pref values. */
+ async getPrefs(prefs) {
+ return Preferences.get(prefs);
+ },
+
+ /* Gets link color for a given selector. */
+ async getLinkColor(tabId, selector) {
+ return getActorForTab(tabId, "TestSupport").sendQuery(
+ "GetLinkColor",
+ { selector }
+ );
+ },
+
+ async getRequestedLocales() {
+ return Services.locale.requestedLocales;
+ },
+
+ async getPidForTab(tabId) {
+ const tab = context.extension.tabManager.get(tabId);
+ const pids = E10SUtils.getBrowserPids(tab.browser);
+ return pids[0];
+ },
+
+ async waitForContentTransformsReceived(tabId) {
+ return getActorForTab(tabId).sendQuery(
+ "WaitForContentTransformsReceived"
+ );
+ },
+
+ async getAllBrowserPids() {
+ const pids = [];
+ const processes = ChromeUtils.getAllDOMProcesses();
+ for (const process of processes) {
+ if (process.remoteType && process.remoteType.startsWith("web")) {
+ pids.push(process.osPid);
+ }
+ }
+ return pids;
+ },
+
+ async killContentProcess(pid) {
+ const procs = ChromeUtils.getAllDOMProcesses();
+ for (const proc of procs) {
+ if (pid === proc.osPid) {
+ proc
+ .getActor("TestSupportProcess")
+ .sendAsyncMessage("KillContentProcess");
+ }
+ }
+ },
+
+ async addHistogram(id, value) {
+ return Services.telemetry.getHistogramById(id).add(value);
+ },
+
+ removeAllCertOverrides() {
+ const overrideService = Cc[
+ "@mozilla.org/security/certoverride;1"
+ ].getService(Ci.nsICertOverrideService);
+ overrideService.clearAllOverrides();
+ },
+
+ async setScalar(id, value) {
+ return Services.telemetry.scalarSet(id, value);
+ },
+
+ async setResolutionAndScaleTo(tabId, resolution) {
+ return getActorForTab(tabId, "TestSupport").sendQuery(
+ "SetResolutionAndScaleTo",
+ {
+ resolution,
+ }
+ );
+ },
+
+ async getActive(tabId) {
+ const tab = context.extension.tabManager.get(tabId);
+ return tab.browser.docShellIsActive;
+ },
+
+ async getProfilePath() {
+ return PathUtils.profileDir;
+ },
+
+ async flushApzRepaints(tabId) {
+ // TODO: Note that `waitUntilApzStable` in apz_test_utils.js does
+ // flush APZ repaints in the parent process (i.e. calling
+ // nsIDOMWindowUtils.flushApzRepaints for the parent process) before
+ // flushApzRepaints is called for the target content document, if we
+ // still meet intermittent failures, we might want to do it here as
+ // well.
+ await getActorForTab(tabId, "TestSupport").sendQuery(
+ "FlushApzRepaints"
+ );
+ },
+
+ async promiseAllPaintsDone(tabId) {
+ await getActorForTab(tabId, "TestSupport").sendQuery(
+ "PromiseAllPaintsDone"
+ );
+ },
+
+ async usingGpuProcess() {
+ const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
+ Ci.nsIGfxInfo
+ );
+ return gfxInfo.usingGPUProcess;
+ },
+
+ async killGpuProcess() {
+ const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
+ Ci.nsIGfxInfo
+ );
+ return gfxInfo.killGPUProcessForTests();
+ },
+
+ async crashGpuProcess() {
+ const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
+ Ci.nsIGfxInfo
+ );
+ return gfxInfo.crashGPUProcessForTests();
+ },
+
+ async clearHSTSState() {
+ const sss = Cc["@mozilla.org/ssservice;1"].getService(
+ Ci.nsISiteSecurityService
+ );
+ return sss.clearAll();
+ },
+
+ async triggerCookieBannerDetected(tabId) {
+ const actor = getActorForTab(tabId, "CookieBanner");
+ return actor.receiveMessage({
+ name: "CookieBanner::DetectedBanner",
+ });
+ },
+
+ async triggerCookieBannerHandled(tabId) {
+ const actor = getActorForTab(tabId, "CookieBanner");
+ return actor.receiveMessage({
+ name: "CookieBanner::HandledBanner",
+ });
+ },
+
+ async triggerTranslationsOffer(tabId) {
+ const browser = context.extension.tabManager.get(tabId).browser;
+ const { CustomEvent } = browser.ownerGlobal;
+ return browser.dispatchEvent(
+ new CustomEvent("TranslationsParent:OfferTranslation", {
+ bubbles: true,
+ })
+ );
+ },
+
+ async triggerLanguageStateChange(tabId, languageState) {
+ const browser = context.extension.tabManager.get(tabId).browser;
+ const { CustomEvent } = browser.ownerGlobal;
+ return browser.dispatchEvent(
+ new CustomEvent("TranslationsParent:LanguageState", {
+ bubbles: true,
+ detail: languageState,
+ })
+ );
+ },
+ },
+ };
+ }
+};
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json
new file mode 100644
index 0000000000..94e4b3bd9b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-schema.json
@@ -0,0 +1,308 @@
+[
+ {
+ "namespace": "test",
+ "description": "Additional APIs for test support in GeckoView.",
+ "functions": [
+ {
+ "name": "setPrefs",
+ "type": "function",
+ "async": true,
+ "description": "Set prefs and return a set of saved prefs",
+ "parameters": [
+ {
+ "name": "oldPrefs",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": { "type": "any" }
+ },
+ {
+ "name": "newPrefs",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": { "type": "any" }
+ }
+ ]
+ },
+ {
+ "name": "restorePrefs",
+ "type": "function",
+ "async": true,
+ "description": "Restore prefs to old value",
+ "parameters": [
+ {
+ "type": "any",
+ "name": "oldPrefs"
+ }
+ ]
+ },
+ {
+ "name": "getPrefs",
+ "type": "function",
+ "async": true,
+ "description": "Get pref values.",
+ "parameters": [
+ {
+ "name": "prefs",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ {
+ "name": "getLinkColor",
+ "type": "function",
+ "async": true,
+ "description": "Get resolved color for the link resolved by a given selector.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ },
+ {
+ "type": "string",
+ "name": "selector"
+ }
+ ]
+ },
+ {
+ "name": "getRequestedLocales",
+ "type": "function",
+ "async": true,
+ "description": "Gets the requested locales.",
+ "parameters": []
+ },
+ {
+ "name": "addHistogram",
+ "type": "function",
+ "async": true,
+ "description": "Add a sample with the given value to the histogram with the given id.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "id"
+ },
+ {
+ "type": "any",
+ "name": "value"
+ }
+ ]
+ },
+ {
+ "name": "removeAllCertOverrides",
+ "type": "function",
+ "async": true,
+ "description": "Revokes SSL certificate overrides.",
+ "parameters": []
+ },
+ {
+ "name": "setScalar",
+ "type": "function",
+ "async": true,
+ "description": "Set the given value to the scalar with the given id.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "id"
+ },
+ {
+ "type": "any",
+ "name": "value"
+ }
+ ]
+ },
+ {
+ "name": "setResolutionAndScaleTo",
+ "type": "function",
+ "async": true,
+ "description": "Invokes nsIDOMWindowUtils.setResolutionAndScaleTo.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ },
+ {
+ "type": "number",
+ "name": "resolution"
+ }
+ ]
+ },
+ {
+ "name": "getActive",
+ "type": "function",
+ "async": true,
+ "description": "Returns true if the docShell is active for given tab.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "getPidForTab",
+ "type": "function",
+ "async": true,
+ "description": "Gets the top-level pid belonging to tabId.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "waitForContentTransformsReceived",
+ "type": "function",
+ "async": true,
+ "description": "If we want to test screen coordinates, we need to wait for the updated data which is what this function allows us to do",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "getAllBrowserPids",
+ "type": "function",
+ "async": true,
+ "description": "Gets the list of pids of the running browser processes",
+ "parameters": []
+ },
+ {
+ "name": "getProfilePath",
+ "type": "function",
+ "async": true,
+ "description": "Gets the path of the current profile",
+ "parameters": []
+ },
+ {
+ "name": "killContentProcess",
+ "type": "function",
+ "async": true,
+ "description": "Crash all content processes",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "pid"
+ }
+ ]
+ },
+ {
+ "name": "flushApzRepaints",
+ "type": "function",
+ "async": true,
+ "description": "Invokes nsIDOMWindowUtils.flushApzRepaints for the document of the tabId.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "promiseAllPaintsDone",
+ "type": "function",
+ "async": true,
+ "description": "A simplified version of promiseAllPaintsDone in paint_listeners.js.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+ {
+ "name": "usingGpuProcess",
+ "type": "function",
+ "async": true,
+ "description": "Returns true if Gecko is using a GPU process.",
+ "parameters": []
+ },
+
+ {
+ "name": "killGpuProcess",
+ "type": "function",
+ "async": true,
+ "description": "Kills the GPU process cleanly without generating a crash report.",
+ "parameters": []
+ },
+
+ {
+ "name": "crashGpuProcess",
+ "type": "function",
+ "async": true,
+ "description": "Causes the GPU process to crash.",
+ "parameters": []
+ },
+
+ {
+ "name": "clearHSTSState",
+ "type": "function",
+ "async": true,
+ "description": "Clears the sites on the HSTS list.",
+ "parameters": []
+ },
+
+ {
+ "name": "triggerCookieBannerDetected",
+ "type": "function",
+ "async": true,
+ "description": "Simulates a cookie banner detection",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+
+ {
+ "name": "triggerCookieBannerHandled",
+ "type": "function",
+ "async": true,
+ "description": "Simulates a cookie banner handling",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+
+ {
+ "name": "triggerTranslationsOffer",
+ "type": "function",
+ "async": true,
+ "description": "Simulates offering a translation.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ }
+ ]
+ },
+
+ {
+ "name": "triggerLanguageStateChange",
+ "type": "function",
+ "async": true,
+ "description": "Simulates expecting a translation.",
+ "parameters": [
+ {
+ "type": "number",
+ "name": "tabId"
+ },
+ {
+ "name": "languageState",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": { "type": "any" }
+ }
+ ]
+ }
+ ]
+ }
+]
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js
new file mode 100644
index 0000000000..18e047ca1a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/test-support/test-support.js
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+let backgroundPort = null;
+let nativePort = null;
+
+function connectNativePort() {
+ if (nativePort) {
+ return;
+ }
+
+ backgroundPort = browser.runtime.connect();
+ nativePort = browser.runtime.connectNative("browser");
+
+ nativePort.onMessage.addListener(message => {
+ if (message.type) {
+ // This is a session-specific webExtensionApiCall.
+ // Forward to the background script.
+ backgroundPort.postMessage(message);
+ } else if (message.eval) {
+ try {
+ // Using eval here is the whole point of this WebExtension so we can
+ // safely ignore the eslint warning.
+ const response = window.eval(message.eval); // eslint-disable-line no-eval
+ sendResponse(message.id, response);
+ } catch (ex) {
+ sendSyncResponse(message.id, null, ex);
+ }
+ }
+ });
+
+ function sendResponse(id, response, exception) {
+ Promise.resolve(response).then(
+ value => sendSyncResponse(id, value),
+ reason => sendSyncResponse(id, null, reason)
+ );
+ }
+
+ function sendSyncResponse(id, response, exception) {
+ nativePort.postMessage({
+ id,
+ response: JSON.stringify(response),
+ exception: exception && exception.toString(),
+ });
+ }
+}
+
+function disconnectNativePort() {
+ backgroundPort?.disconnect();
+ nativePort?.disconnect();
+ backgroundPort = null;
+ nativePort = null;
+}
+
+window.addEventListener("pageshow", connectNativePort);
+window.addEventListener("pagehide", disconnectNativePort);
+
+// If loading error page, pageshow mightn't fired.
+connectNativePort();
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json
new file mode 100644
index 0000000000..8e54cc4586
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-1/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update@example.com",
+ "update_url": "https://example.org/tests/junit/update_manifest.json"
+ }
+ },
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js
new file mode 100644
index 0000000000..3529928d82
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid blue";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json
new file mode 100644
index 0000000000..19570ea5e5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-2/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update@example.com"
+ }
+ },
+ "version": "2.0",
+ "description": "Adds a blue border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js
new file mode 100644
index 0000000000..a301506ca7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/background.js
@@ -0,0 +1,3 @@
+browser.runtime.onUpdateAvailable.addListener(details => {
+ // Do nothing, this is just here to prevent auto update.
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json
new file mode 100644
index 0000000000..5011e1ea05
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-1/manifest.json
@@ -0,0 +1,21 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-postpone@example.com",
+ "update_url": "https://example.org/tests/junit/update_manifest.json"
+ }
+ },
+ "background": {
+ "scripts": ["background.js"]
+ },
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js
new file mode 100644
index 0000000000..3529928d82
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid blue";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json
new file mode 100644
index 0000000000..720d9ef898
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-postpone-2/manifest.json
@@ -0,0 +1,17 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-postpone@example.com"
+ }
+ },
+ "version": "2.0",
+ "description": "Adds a blue border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js
new file mode 100644
index 0000000000..9c3728b381
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid red";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json
new file mode 100644
index 0000000000..71b6a1eab9
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-1/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-with-perms@example.com",
+ "update_url": "https://example.org/tests/junit/update_manifest.json"
+ }
+ },
+ "version": "1.0",
+ "description": "Adds a red border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js
new file mode 100644
index 0000000000..3529928d82
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/borderify.js
@@ -0,0 +1 @@
+document.body.style.border = "5px solid blue";
diff --git a/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json
new file mode 100644
index 0000000000..9571bdabb2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/web_extensions/update-with-perms-2/manifest.json
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 2,
+ "name": "update",
+ "browser_specific_settings": {
+ "gecko": {
+ "id": "update-with-perms@example.com"
+ }
+ },
+ "version": "2.0",
+ "description": "Adds a blue border to all webpages matching example.com.",
+ "content_scripts": [
+ {
+ "matches": ["*://*.example.com/*"],
+ "js": ["borderify.js"]
+ }
+ ],
+ "permissions": ["tabs"]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-aria-comboboxes.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-aria-comboboxes.html
new file mode 100644
index 0000000000..8816879c1a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-aria-comboboxes.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div contenteditable role="combobox" aria-label="ARIA 1.0 combobox"></div>
+ <div role="combobox">
+ <input type="text" aria-label="ARIA 1.1 combobox" />
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-checkbox.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-checkbox.html
new file mode 100644
index 0000000000..a45cfed92b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-checkbox.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <label>
+ <input type="checkbox" aria-describedby="desc" />many option
+ </label>
+ <div id="desc">description</div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-clipboard.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-clipboard.html
new file mode 100644
index 0000000000..c33b48f4e5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-clipboard.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <input value="hello cruel world" id="input" />
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-collection.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-collection.html
new file mode 100644
index 0000000000..865594ae5b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-collection.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <ul>
+ <li>One</li>
+ <li><a href="#">Two</a></li>
+ </ul>
+ <ul>
+ <li>
+ 1
+ <ul>
+ <li>1.1</li>
+ <li>1.2</li>
+ </ul>
+ </li>
+ </ul>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-expandable.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-expandable.html
new file mode 100644
index 0000000000..8b416cf882
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-expandable.html
@@ -0,0 +1,13 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <button
+ onclick="this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') == 'false')"
+ aria-expanded="false"
+ >
+ button
+ </button>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-headings.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-headings.html
new file mode 100644
index 0000000000..280bbd89d7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-headings.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html><html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <a href=\"%23\">preamble</a>
+ <h1>Fried cheese</h1><p>with club sauce.</p>
+ <a href="#"><h2>Popcorn shrimp</h2></a><button>with club sauce.</button>
+ <h3>Chicken fingers</h3><p>with spicy club sauce.</p>
+</body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-links.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-links.html
new file mode 100644
index 0000000000..a108925dc1
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-links.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <a href="/">a with href</a>
+ <a>a with no attributes</a>
+ <a name="anchor">a with name</a>
+ <a onclick=";">a with onclick</a>
+ <span role="link">span with role link</span>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-atomic.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-atomic.html
new file mode 100644
index 0000000000..85f9f6ccd2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-atomic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div aria-live="polite" aria-atomic="true" id="container">
+ The time is
+ <p>3pm</p>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-descendant.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-descendant.html
new file mode 100644
index 0000000000..82d88613f0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-descendant.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div aria-live="polite"><p id="to_show">I will be shown</p></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image-labeled-by.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image-labeled-by.html
new file mode 100644
index 0000000000..5b91f1f6c2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image-labeled-by.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <img
+ src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
+ aria-live="polite"
+ aria-labelledby="l1"
+ />
+ <span id="l1">Hello</span>
+ <span id="l2">Goodbye</span>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image.html
new file mode 100644
index 0000000000..da05b33c9a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region-image.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div aria-live="polite" aria-atomic="true">
+ This picture is
+ <img
+ src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
+ alt="happy"
+ />
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region.html
new file mode 100644
index 0000000000..c73fb91966
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-live-region.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div id="to_change" aria-live="polite"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-local-iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-local-iframe.html
new file mode 100644
index 0000000000..0aff253395
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-local-iframe.html
@@ -0,0 +1,21 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <style>
+ body {
+ margin: 0;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ }
+ iframe {
+ height: 100%;
+ }
+ </style>
+ </head>
+ <body>
+ Some stuff
+ <iframe src="../hello.html" id="iframe"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-move-caret-accessibility-focus.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-move-caret-accessibility-focus.html
new file mode 100644
index 0000000000..d9d1597991
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-move-caret-accessibility-focus.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <p>Hello <a href="foo">sweet</a>, sweet <span>world</span></p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-mutation.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-mutation.html
new file mode 100644
index 0000000000..5c9c68aca0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-mutation.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div><p id="to_show">I will be shown</p></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-range.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-range.html
new file mode 100644
index 0000000000..70ef76e624
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-range.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <input type="range" aria-label="Rating" min="1" max="10" value="4" /><input
+ type="range"
+ aria-label="Stars"
+ min="1"
+ max="5"
+ step="0.5"
+ value="4.5"
+ /><input
+ type="range"
+ aria-label="Percent"
+ min="0"
+ max="1"
+ step="0.01"
+ value="0.83"
+ />
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-remote-iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-remote-iframe.html
new file mode 100644
index 0000000000..7e3e5da1ca
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-remote-iframe.html
@@ -0,0 +1,24 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <style>
+ body {
+ margin: 0;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ }
+ iframe {
+ height: 100%;
+ }
+ </style>
+ </head>
+ <body>
+ Some stuff
+ <iframe
+ src="https://example.org/tests/junit/hello.html"
+ id="iframe"
+ ></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-scroll.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-scroll.html
new file mode 100644
index 0000000000..912aab9143
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-scroll.html
@@ -0,0 +1,10 @@
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width initial-scale=1" />
+<body style="margin: 0">
+ <div style="height: 100vh"></div>
+ <button>Hello</button>
+ <p style="margin: 0">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua.
+ </p>
+</body>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-selectable.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-selectable.html
new file mode 100644
index 0000000000..f30951ff83
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-selectable.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <ul style="list-style-type: none" role="listbox">
+ <li
+ id="li"
+ role="option"
+ onclick="this.setAttribute('aria-selected',
+ this.getAttribute('aria-selected') == 'true' ? 'false' : 'true')"
+ >
+ 1
+ </li>
+ <li role="option" aria-selected="false">2</li>
+ </ul>
+ <li id="outsideSelectable" role="option" tabindex="0">
+ outside selectable
+ </li>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-text-entry-node.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-text-entry-node.html
new file mode 100644
index 0000000000..002efc9f14
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-text-entry-node.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <input aria-label="Name" aria-describedby="desc" value="Tobias" />
+ <div id="desc">description</div>
+ <input aria-label="Last" value="Funke" required />
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-tree.html b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-tree.html
new file mode 100644
index 0000000000..81ab105c7d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/accessibility/test-tree.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <label for="name">Name:</label
+ ><input id="name" type="text" value="Julie" /><button>Submit</button>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/address_form.html b/mobile/android/geckoview/src/androidTest/assets/www/address_form.html
new file mode 100644
index 0000000000..d247c5ce79
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/address_form.html
@@ -0,0 +1,21 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Address form</title>
+ </head>
+ <body>
+ <form>
+ <input autocomplete="name" id="name" />
+ <input autocomplete="given-name" id="givenName" />
+ <input autocomplete="additional-name" id="additionalName" />
+ <input autocomplete="family-name" id="familyName" />
+ <input autocomplete="street-address" id="streetAddress" />
+ <input autocomplete="country" id="country" />
+ <input autocomplete="postal-code" id="postalCode" />
+ <input autocomplete="organization" id="organization" />
+ <input autocomplete="email" id="email" />
+ <input autocomplete="tel" id="tel" />
+ <input type="submit" value="Submit" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/audio/owl.mp3 b/mobile/android/geckoview/src/androidTest/assets/www/audio/owl.mp3
new file mode 100644
index 0000000000..9fafa32f93
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/audio/owl.mp3
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/autoplay.html b/mobile/android/geckoview/src/androidTest/assets/www/autoplay.html
new file mode 100644
index 0000000000..24cbf474bd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/autoplay.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WEBM Video</title>
+ </head>
+ <body>
+ <video preload autoplay>
+ <source src="videos/gizmo.webm"></source>
+ </video>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/badVideoPath.html b/mobile/android/geckoview/src/androidTest/assets/www/badVideoPath.html
new file mode 100644
index 0000000000..d9b34843fd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/badVideoPath.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Bad Video Path</title>
+ </head>
+ <body>
+ <video controls preload>
+ <source src="videos/fileDoesNotExist.ogg"></source>
+ </video>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/beforeunload.html b/mobile/android/geckoview/src/androidTest/assets/www/beforeunload.html
new file mode 100644
index 0000000000..d521afe532
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/beforeunload.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body onbeforeunload="return beforeUnload()">
+ <a id="navigateAway" href="./hello.html">Click Me</a>
+ <a id="navigateAway2" href="./hello2.html">Click Me</a>
+ <script>
+ function beforeUnload() {
+ return "Please don't leave.";
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/cc_form.html b/mobile/android/geckoview/src/androidTest/assets/www/cc_form.html
new file mode 100644
index 0000000000..7b3ea2a1bb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/cc_form.html
@@ -0,0 +1,22 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Form Autofill Test: Credit Card</title>
+ </head>
+ <body>
+ <form id="form1">
+ <input autocomplete="cc-name" id="name" />
+ <input autocomplete="cc-number" id="number" />
+ <input autocomplete="cc-exp-month" id="expMonth" />
+ <input autocomplete="cc-exp-year" id="expYear" />
+ <input type="submit" value="Submit" />
+ </form>
+ <!-- form2 uses a single expiration date field -->
+ <form id="form2">
+ <input autocomplete="cc-name" id="name" />
+ <input autocomplete="cc-number" id="number" />
+ <input autocomplete="cc-exp" id="exp" />
+ <input type="submit" value="Submit" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/clickToReload.html b/mobile/android/geckoview/src/androidTest/assets/www/clickToReload.html
new file mode 100644
index 0000000000..47bdceccee
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/clickToReload.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <meta name="viewport" content="initial-scale=1.0" />
+ </head>
+ <body style="height: 100%" onclick="window.location.reload()">
+ <p>Hello, world!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/clipboard_read.html b/mobile/android/geckoview/src/androidTest/assets/www/clipboard_read.html
new file mode 100644
index 0000000000..19a034a23d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/clipboard_read.html
@@ -0,0 +1,22 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <meta name="viewport" content="initial-scale=1.0" />
+ </head>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ <script>
+ document.body.addEventListener("click", () => {
+ navigator.clipboard
+ .readText()
+ .then(() => {
+ window.alert("allow");
+ })
+ .catch(() => {
+ window.alert("deny");
+ });
+ });
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/color_grid.html b/mobile/android/geckoview/src/androidTest/assets/www/color_grid.html
new file mode 100644
index 0000000000..ebc989acdb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/color_grid.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Color Grid</title>
+ </head>
+ <style>
+ body {
+ margin: 0;
+ }
+ .container {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ }
+ .box {
+ height: 100vh;
+ width: 33.33vw;
+ }
+ .red {
+ background-color: rgb(255, 0, 0);
+ color-adjust: exact;
+ }
+ .green {
+ background-color: rgb(0, 255, 0);
+ color-adjust: exact;
+ }
+ .blue {
+ background-color: rgb(0, 0, 255);
+ color-adjust: exact;
+ }
+ </style>
+
+ <body>
+ <div class="container">
+ <div class="red box"></div>
+ <div class="green box"></div>
+ <div class="blue box"></div>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/color_orange_background.html b/mobile/android/geckoview/src/androidTest/assets/www/color_orange_background.html
new file mode 100644
index 0000000000..8a682d79a7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/color_orange_background.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Orange Print Background</title>
+ </head>
+ <style>
+ .box {
+ height: 100vh;
+ width: 100vw;
+ }
+ @media screen {
+ .background {
+ background-color: rgb(0, 0, 255);
+ color-adjust: exact;
+ }
+ }
+ @media print {
+ .background {
+ background-color: rgb(255, 113, 57);
+ color-adjust: exact;
+ }
+ }
+ </style>
+
+ <body>
+ <div class="box background"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/colors.html b/mobile/android/geckoview/src/androidTest/assets/www/colors.html
new file mode 100644
index 0000000000..b00da3ed9c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/colors.html
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Colours</title>
+ </head>
+ <!-- background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. !-->
+ <body
+ style="
+ overflow: hidden;
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ background: url('/assets/www/transparent.gif'),
+ linear-gradient(135deg, red, white);
+ "
+ ></body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_audio.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_audio.html
new file mode 100644
index 0000000000..b26323a13e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_audio.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Context Menu Test Audio</title>
+ </head>
+ <style>
+ body {
+ margin: 0;
+ }
+ </style>
+ <body>
+ <div class="center-audio">
+ <audio controls src="audio/owl.mp3">
+ Your browser does not support the
+ <code>audio</code> element.
+ </audio>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html
new file mode 100644
index 0000000000..9849747a41
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_buffered.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Context Menu Test Blob Buffered</title>
+ </head>
+ <body>
+ <video id="video" controls preload></video>
+ </body>
+ <script>
+ window.addEventListener("DOMContentLoaded", function (e) {
+ const video = document.getElementById("video");
+ const mediaSource = new MediaSource();
+ video.src = URL.createObjectURL(mediaSource);
+ mediaSource.addEventListener("sourceopen", createBuffer);
+
+ function createBuffer(event) {
+ const mediaSource = event.target;
+ const assetURL = "/assets/www/videos/gizmo.webm";
+ const codec = 'video/webm; codecs="opus"';
+ const sourceBuffer = mediaSource.addSourceBuffer(codec);
+
+ function addBuffer(response) {
+ sourceBuffer.addEventListener("updateend", function () {
+ mediaSource.endOfStream();
+ });
+ sourceBuffer.appendBuffer(response);
+ }
+
+ fetchVideoData(assetURL, addBuffer);
+ }
+
+ function fetchVideoData(assetURL, videoArrayBuffer) {
+ const request = new XMLHttpRequest();
+ request.open("get", assetURL);
+ request.responseType = "arraybuffer";
+ request.onload = function () {
+ videoArrayBuffer(request.response);
+ };
+ request.send();
+ }
+ });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_full.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_full.html
new file mode 100644
index 0000000000..5ebc2bddba
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_blob_full.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Context Menu Test Blob</title>
+ </head>
+ <body>
+ <div id="image_container"></div>
+ </body>
+ <script>
+ window.addEventListener("DOMContentLoaded", function (e) {
+ const svg = `<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <circle cx="50" cy="50" r="50" stroke="orange" fill="transparent" stroke-width="5"/>
+ </svg>`;
+ const image = document.createElement("img");
+ const blob = new Blob([svg], { type: "image/svg+xml" });
+ image.src = URL.createObjectURL(blob);
+ image.alt = "An orange circle.";
+ document.getElementById("image_container").appendChild(image);
+ });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_image.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_image.html
new file mode 100644
index 0000000000..9564f94628
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_image.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Context Menu Test Image</title>
+ </head>
+ <body>
+ <img id="image" src="images/test.gif" alt="Test Image" />
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_image_nested.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_image_nested.html
new file mode 100644
index 0000000000..99563d66f5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_image_nested.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Context Menu Test Nested Image</title>
+ </head>
+ <body>
+ <div>
+ <div>
+ <img id="image" src="images/test.gif" alt="Test Image" />
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_link.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_link.html
new file mode 100644
index 0000000000..e5b0d0d316
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_link.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Context Menu Test Link</title>
+ </head>
+ <style>
+ #hello {
+ font-size: 20vw;
+ }
+ </style>
+ <body>
+ <a href="hello.html" title="Hello Link Title" id="hello">Hello World</a>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/context_menu_video.html b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_video.html
new file mode 100644
index 0000000000..bca8e46afe
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/context_menu_video.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height">
+ <title>Context Menu Test Video</title>
+ </head>
+ <body>
+ <video controls preload>
+ <source src="videos/short.mp4"></source>
+ </video>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/data_uri.html b/mobile/android/geckoview/src/androidTest/assets/www/data_uri.html
new file mode 100644
index 0000000000..638e4c754c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/data_uri.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Link with a giant data URI</title>
+ </head>
+ <body>
+ <a href="insert uri here" id="smallLink">Open small link</a>
+ <a href="insert uri here" id="largeLink">Open large link</a>
+ <img src="/assets/www/images/test.gif" id="image" />
+ <script language="JavaScript">
+ var imageLoaded = false;
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/dnd.html b/mobile/android/geckoview/src/androidTest/assets/www/dnd.html
new file mode 100644
index 0000000000..0dc36b4f9a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/dnd.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+ <script>
+ document.addEventListener("DOMContentLoaded", () =>
+ document
+ .querySelector("#drop")
+ .addEventListener("dragover", e => e.preventDefault())
+ );
+ </script>
+ </head>
+ <body>
+ <img
+ id="drag"
+ draggable="true"
+ src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2PwmvDoPwAFoAK895OuoAAAAABJRU5ErkJggg=="
+ width="200"
+ height="100"
+ />
+ <br />
+ <div id="drop" style="border: 1px solid red; width: 200px; height: 100px">
+ drop
+ </div>
+ <textarea id="textarea" style="width: 200px; height: 100px"></textarea>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/download.html b/mobile/android/geckoview/src/androidTest/assets/www/download.html
new file mode 100644
index 0000000000..4f06323dc6
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/download.html
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <script>
+ const blob = new Blob(["Downloaded Data"], { type: "text/plain" });
+ const element = document.createElement("a");
+ const uri = URL.createObjectURL(blob);
+ element.href = uri;
+ element.download = "download.txt";
+ element.style.display = "none";
+ document.body.appendChild(element);
+ element.click();
+ URL.revokeObjectURL(uri);
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fedcm_accounts_endpoint.json b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_accounts_endpoint.json
new file mode 100644
index 0000000000..5a8f6eeb30
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_accounts_endpoint.json
@@ -0,0 +1,12 @@
+{
+ "accounts": [
+ {
+ "id": "$RANDOM_ID",
+ "given_name": "",
+ "name": " ",
+ "email": "demo",
+ "picture": "http://localhost:4245/assets/www/images/test.gif",
+ "approved_clients": ["fedcm_rp.html"]
+ }
+ ]
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_manifest.json b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_manifest.json
new file mode 100644
index 0000000000..bc66100e6a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_manifest.json
@@ -0,0 +1,18 @@
+{
+ "accounts_endpoint": "fedcm_accounts_endpoint.json",
+ "client_metadata_endpoint": "fedcm_idp_metadata.json",
+ "id_assertion_endpoint": "fedcm_idtokens_endpoint.json",
+ "id_token_endpoint": "fedcm_idtokens_endpoint.json",
+ "revocation_endpoint": "revocation_endpoint",
+ "branding": {
+ "background_color": "0x6200ee",
+ "color": "0xffffff",
+ "icons": [
+ {
+ "url": "http://localhost:4245/assets/www/images/test.gif",
+ "size": 256
+ }
+ ],
+ "name": "Demo IDP"
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_metadata.json b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_metadata.json
new file mode 100644
index 0000000000..db9b9deaf8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idp_metadata.json
@@ -0,0 +1,4 @@
+{
+ "privacy_policy_url": "privacy_policy",
+ "terms_of_service_url": "terms_of_service"
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idtokens_endpoint.json b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idtokens_endpoint.json
new file mode 100644
index 0000000000..ba6edfe281
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_idtokens_endpoint.json
@@ -0,0 +1,3 @@
+{
+ "token": "token"
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fedcm_rp.html b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_rp.html
new file mode 100644
index 0000000000..4d1fddee7f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fedcm_rp.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <link rel="manifest" href="manifest.webmanifest" />
+ </head>
+ <body></body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fixedbottom.html b/mobile/android/geckoview/src/androidTest/assets/www/fixedbottom.html
new file mode 100644
index 0000000000..b802bb335b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fixedbottom.html
@@ -0,0 +1,36 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>Fixed bottom element</title>
+ </head>
+ <!-- background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. !-->
+ <body
+ style="
+ overflow: hidden;
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ background: url('/assets/www/transparent.gif'),
+ linear-gradient(135deg, blue, blue);
+ "
+ >
+ <div
+ id="bottom-banner"
+ style="
+ width: 100%;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ background-color: lime;
+ height: 10%;
+ "
+ ></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fixedpercent.html b/mobile/android/geckoview/src/androidTest/assets/www/fixedpercent.html
new file mode 100644
index 0000000000..587df00473
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fixedpercent.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, minimum-scale=0.5" />
+<style>
+ html {
+ width: 100%;
+ height: 100%;
+ scrollbar-width: none;
+ }
+ body {
+ width: 200%;
+ height: 2000px;
+ margin: 0;
+ padding: 0;
+ }
+
+ #fixed-element {
+ width: 100%;
+ height: 200%;
+ position: fixed;
+ top: 0px;
+ background-color: green;
+ }
+</style>
+<div id="fixed-element"></div>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fixedvh.html b/mobile/android/geckoview/src/androidTest/assets/www/fixedvh.html
new file mode 100644
index 0000000000..fd6661c2cd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fixedvh.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, minimum-scale=0.5" />
+<style>
+ html {
+ width: 100%;
+ height: 100%;
+ scrollbar-width: none;
+ }
+ body {
+ width: 200%;
+ height: 2000px;
+ margin: 0;
+ padding: 0;
+ }
+
+ #fixed-element {
+ width: 100%;
+ height: 200vh;
+ position: fixed;
+ top: 0px;
+ background-color: green;
+ }
+</style>
+<div id="fixed-element"></div>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/form_blank.html b/mobile/android/geckoview/src/androidTest/assets/www/form_blank.html
new file mode 100644
index 0000000000..918cc4cb7a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/form_blank.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form
+ id="form1"
+ name="form1"
+ action="form_blank.html"
+ method="get"
+ target="_blank"
+ >
+ <input type="text" id="search" value="foo" />
+ <input type="submit" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms.html b/mobile/android/geckoview/src/androidTest/assets/www/forms.html
new file mode 100644
index 0000000000..06c2ed64db
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms.html
@@ -0,0 +1,34 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="text" id="user1" value="foo" />
+ <input type="password" id="pass1" value="foo" />
+ <input type="email" id="email1" value="@" />
+ <input type="number" id="number1" value="0" />
+ <input type="tel" id="tel1" value="0" />
+ <input type="submit" value="submit" />
+ </form>
+ <input type="Text" id="user2" value="foo" />
+ <input type="PassWord" id="pass2" maxlength="8" value="foo" />
+ <input type="button" id="button1" value="foo" />
+ <input type="checkbox" id="checkbox1" />
+ <input type="search" id="search1" />
+ <input type="url" id="url1" />
+ <input type="hidden" id="hidden1" value="foo" />
+
+ <iframe id="iframe"></iframe>
+ </body>
+ <script>
+ addEventListener("load", function (e) {
+ if (window.parent === window) {
+ document.getElementById("iframe").contentWindow.location.href =
+ window.location.href;
+ }
+ });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms2.html b/mobile/android/geckoview/src/androidTest/assets/www/forms2.html
new file mode 100644
index 0000000000..06ab5ec448
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms2.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms2</title>
+ </head>
+ <body>
+ <form>
+ <fieldset>
+ <input type="text" id="firstname" />
+ <input type="text" id="lastname" />
+ <input type="text" id="user1" value="foo" />
+ <input type="password" id="pass1" value="foo" autofocus />
+ </fieldset>
+ </form>
+ <iframe id="iframe" src="forms2_iframe.html"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms2_iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/forms2_iframe.html
new file mode 100644
index 0000000000..849fa43271
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms2_iframe.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms2 iframe</title>
+ </head>
+ <body>
+ <form>
+ <fieldset>
+ <input type="text" id="firstname" />
+ <input type="text" id="lastname" />
+ <input type="text" id="user1" value="foo" />
+ <input type="password" id="pass1" value="foo" autofocus />
+ </fieldset>
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms3.html b/mobile/android/geckoview/src/androidTest/assets/www/forms3.html
new file mode 100644
index 0000000000..91bceb3943
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms3.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="text" id="user1" placeholder="username" />
+ <input type="password" id="pass1" placeholder="password" />
+ <input type="submit" value="submit" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms4.html b/mobile/android/geckoview/src/androidTest/assets/www/forms4.html
new file mode 100644
index 0000000000..3650635396
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms4.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="text" id="user1" />
+ <input type="password" id="pass1" autocomplete="new-password" />
+ <input type="submit" value="submit" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms5.html b/mobile/android/geckoview/src/androidTest/assets/www/forms5.html
new file mode 100644
index 0000000000..b9da67f343
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms5.html
@@ -0,0 +1,24 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="text" id="user1" value="foo" />
+ <input type="password" id="pass1" value="foo" />
+ <input type="email" id="email1" value="@" />
+ <input type="number" id="number1" value="0" />
+ <input type="tel" id="tel1" value="0" />
+ <input type="submit" value="submit" />
+ </form>
+ <input type="Text" id="user2" value="foo" />
+ <input type="PassWord" id="pass2" maxlength="8" value="foo" />
+ <input type="button" id="button1" value="foo" />
+ <input type="checkbox" id="checkbox1" />
+ <input type="search" id="search1" />
+ <input type="url" id="url1" />
+ <input type="hidden" id="hidden1" value="foo" />
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete.html b/mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete.html
new file mode 100644
index 0000000000..81401a1d27
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form>
+ <input type="text" autocomplete="email" autofocus />
+ <input type="text" autocomplete="username" />
+ <input type="password" />
+ <input type="submit" value="submit" />
+ </form>
+ <iframe id="iframe" src="forms_autocomplete_iframe.html"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete_iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete_iframe.html
new file mode 100644
index 0000000000..11137531ba
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms_autocomplete_iframe.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form>
+ <input type="text" autocomplete="email" autofocus />
+ <input type="text" autocomplete="username" />
+ <input type="password" />
+ <input type="submit" value="submit" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms_id_value.html b/mobile/android/geckoview/src/androidTest/assets/www/forms_id_value.html
new file mode 100644
index 0000000000..522dbc1600
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms_id_value.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms ID Value</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="password" id="value" />
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms_iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/forms_iframe.html
new file mode 100644
index 0000000000..2c0ef7dff5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms_iframe.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms iframe</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="text" id="user1" value="foo" />
+ <input type="password" id="pass1" value="foo" />
+ <input type="email" id="email1" value="@" />
+ <input type="number" id="number1" value="0" />
+ <input type="tel" id="tel1" value="0" />
+ <input type="submit" value="submit" />
+ </form>
+ <input type="Text" id="user2" value="foo" />
+ <input type="PassWord" id="pass2" maxlength="8" value="foo" />
+ <input type="button" id="button1" value="foo" />
+ <input type="checkbox" id="checkbox1" />
+ <input type="search" id="search1" />
+ <input type="url" id="url1" />
+ <input type="hidden" id="hidden1" value="foo" />
+ </body>
+ <script>
+ const params = new URL(document.location).searchParams;
+
+ function getEventInterface(event) {
+ if (event instanceof document.defaultView.InputEvent) {
+ return "InputEvent";
+ }
+ if (event instanceof document.defaultView.UIEvent) {
+ return "UIEvent";
+ }
+ if (event instanceof document.defaultView.Event) {
+ return "Event";
+ }
+ return "Unknown";
+ }
+
+ function getData(key, value) {
+ return new Promise(resolve =>
+ document.querySelector(key).addEventListener(
+ "input",
+ event => {
+ resolve([key, event.target.value, value, getEventInterface(event)]);
+ },
+ { once: true }
+ )
+ );
+ }
+
+ window.addEventListener("message", async event => {
+ const { data, source, origin } = event;
+ source.postMessage(await getData(data.key, data.value), origin);
+ });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/forms_xorigin.html b/mobile/android/geckoview/src/androidTest/assets/www/forms_xorigin.html
new file mode 100644
index 0000000000..ebd86c59a1
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/forms_xorigin.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Forms</title>
+ <meta name="viewport" content="minimum-scale=1,width=device-width" />
+ </head>
+ <body>
+ <form id="form1">
+ <input type="text" id="user1" value="foo" />
+ <input type="password" id="pass1" value="foo" />
+ <input type="email" id="email1" value="@" />
+ <input type="number" id="number1" value="0" />
+ <input type="tel" id="tel1" value="0" />
+ <input type="submit" value="submit" />
+ </form>
+ <input type="Text" id="user2" value="foo" />
+ <input type="PassWord" id="pass2" maxlength="8" value="foo" />
+ <input type="button" id="button1" value="foo" />
+ <input type="checkbox" id="checkbox1" />
+ <input type="search" id="search1" />
+ <input type="url" id="url1" />
+ <input type="hidden" id="hidden1" value="foo" />
+
+ <iframe
+ id="iframe"
+ src="http://example.org/tests/junit/forms_iframe.html"
+ ></iframe>
+ </body>
+ <script>
+ const params = new URL(document.location).searchParams;
+ const iframe = document.getElementById("iframe").contentWindow;
+
+ function getEventInterface(event) {
+ if (event instanceof document.defaultView.InputEvent) {
+ return "InputEvent";
+ }
+ if (event instanceof document.defaultView.UIEvent) {
+ return "UIEvent";
+ }
+ if (event instanceof document.defaultView.Event) {
+ return "Event";
+ }
+ return "Unknown";
+ }
+
+ function getData(key, value) {
+ return new Promise(resolve =>
+ document.querySelector(key).addEventListener(
+ "input",
+ event => {
+ resolve([key, event.target.value, value, getEventInterface(event)]);
+ },
+ { once: true }
+ )
+ );
+ }
+
+ window.getDataForAllFrames = function (key, value) {
+ const data = [];
+ data.push(
+ new Promise(resolve =>
+ window.addEventListener(
+ "message",
+ event => {
+ resolve(event.data);
+ },
+ { once: true }
+ )
+ )
+ );
+ iframe.postMessage({ key, value }, "*");
+ data.push(getData(key, value));
+ return Promise.all(data);
+ };
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/fullscreen.html b/mobile/android/geckoview/src/androidTest/assets/www/fullscreen.html
new file mode 100644
index 0000000000..f7d4feb3a4
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/fullscreen.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Fullscreen</title>
+ </head>
+ <body>
+ <div id="fullscreen">Fullscreen Div</div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_container.html b/mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_container.html
new file mode 100644
index 0000000000..2ba4a89b54
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_container.html
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>GetUserMedia from cross-origin iframe: the container document</title>
+ </head>
+ <body>
+ <iframe
+ id="iframe_no_allow"
+ src="http://127.0.0.1:4245/assets/www/getusermedia_xorigin_iframe.html"
+ ></iframe>
+ <iframe
+ id="iframe"
+ allow="camera;microphone"
+ src="http://127.0.0.1:4245/assets/www/getusermedia_xorigin_iframe.html"
+ ></iframe>
+ <script>
+ "use strict";
+
+ let iframeWindow;
+ let generation = 1;
+
+ async function Send(obj) {
+ obj.gen = generation++;
+ iframeWindow.postMessage(obj, "http://127.0.0.1:4245");
+ while (true) {
+ const {
+ data: { gen, result },
+ } = await new Promise(r => (window.onmessage = r));
+ if (gen == obj.gen) {
+ return result;
+ }
+ }
+ }
+
+ function Start(constraints) {
+ if (iframeWindow) {
+ return "iframe mode already decided";
+ }
+ iframeWindow = document.getElementById("iframe").contentWindow;
+ return Send({ name: "start", constraints });
+ }
+
+ function StartNoAllow(constraints) {
+ if (iframeWindow) {
+ return "iframe mode already decided";
+ }
+ iframeWindow = document.getElementById("iframe_no_allow").contentWindow;
+ return Send({ name: "start", constraints });
+ }
+
+ async function Stop() {
+ const result = await Send({ name: "stop" });
+ iframeWindow = undefined;
+ return result;
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_iframe.html
new file mode 100644
index 0000000000..3649167c25
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/getusermedia_xorigin_iframe.html
@@ -0,0 +1,39 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>GetUserMedia from cross-origin iframe: the iframe document</title>
+ </head>
+ <body>
+ <script>
+ "use strict";
+
+ let stream;
+ window.addEventListener(
+ "message",
+ async ({ data: { name, gen, constraints } }) => {
+ if (name == "start") {
+ try {
+ stream = await navigator.mediaDevices.getUserMedia(constraints);
+ Send({ gen, result: "ok" });
+ } catch (e) {
+ Send({ gen, result: `${e}` });
+ }
+ } else if (name == "stop") {
+ const result = !!stream;
+ if (stream) {
+ for (const t of stream.getTracks()) {
+ t.stop();
+ }
+ stream = undefined;
+ }
+ Send({ gen, result });
+ }
+ }
+ );
+
+ function Send(obj) {
+ window.parent.postMessage(obj, "http://localhost:4245");
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/hello.html b/mobile/android/geckoview/src/androidTest/assets/www/hello.html
new file mode 100644
index 0000000000..5ebd20f929
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/hello.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <link rel="manifest" href="manifest.webmanifest" />
+ </head>
+ <body>
+ <p>Hello, world!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/hello2.html b/mobile/android/geckoview/src/androidTest/assets/www/hello2.html
new file mode 100644
index 0000000000..d03c2d5521
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/hello2.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world! Again!</title>
+ </head>
+ <body>
+ <p>Hello, world! Again!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/helloPDFWorld.pdf b/mobile/android/geckoview/src/androidTest/assets/www/helloPDFWorld.pdf
new file mode 100755
index 0000000000..0f429e1a90
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/helloPDFWorld.pdf
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/hsts_header.sjs b/mobile/android/geckoview/src/androidTest/assets/www/hsts_header.sjs
new file mode 100644
index 0000000000..e53ad908fa
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/hsts_header.sjs
@@ -0,0 +1,6 @@
+function handleRequest(request, response) {
+ response.setHeader(
+ "Strict-Transport-Security",
+ "max-age=60; includeSubDomains"
+ );
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/hungScript.html b/mobile/android/geckoview/src/androidTest/assets/www/hungScript.html
new file mode 100644
index 0000000000..6b56f4e2e7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/hungScript.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hung Script</title>
+ </head>
+ <body>
+ <div id="content"></div>
+ </body>
+ <script>
+ var start = new Date().getTime();
+ document.getElementById("content").innerHTML = "Started";
+ // eslint-disable-next-line no-empty
+ while (new Date().getTime() - start < 5000) {}
+ document.getElementById("content").innerHTML = "Finished";
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_no_scrollable.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_no_scrollable.html
new file mode 100644
index 0000000000..3e7bd5cdd0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_no_scrollable.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ iframe {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ display: block;
+ }
+ </style>
+ <iframe
+ frameborder="0"
+ srcdoc="<!DOCTYPE HTML>
+ <html>
+ <style>
+ html, body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style='width: 100%; height: 100%; background-color: green;'></div>
+ <script>
+ if (parent.document.location.search.startsWith('?event')) {
+ document.querySelector('div').addEventListener('touchstart', e => {
+ if (parent.document.location.search == '?event-prevent') {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+ </html>"
+ >
+ </iframe>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_scrollable.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_scrollable.html
new file mode 100644
index 0000000000..e7517c5f12
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_100_percent_height_scrollable.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ iframe {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ border: none;
+ display: block;
+ }
+ </style>
+ <iframe
+ frameborder="0"
+ srcdoc="<!DOCTYPE HTML>
+ <html>
+ <style>
+ html, body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style='width: 100%; height: 500vh; background-color: green;'></div>
+ <script>
+ if (parent.document.location.search.startsWith('?event')) {
+ document.querySelector('div').addEventListener('touchstart', e => {
+ if (parent.document.location.search == '?event-prevent') {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+ </html>"
+ >
+ </iframe>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_no_scrollable.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_no_scrollable.html
new file mode 100644
index 0000000000..9766f41b7f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_no_scrollable.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html,
+ body {
+ margin: 0px;
+ padding: 0px;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ iframe {
+ margin: 0px;
+ padding: 0px;
+ height: 98vh;
+ width: 100%;
+ border: none;
+ display: block;
+ }
+ </style>
+ <iframe
+ frameborder="0"
+ srcdoc="<!DOCTYPE HTML>
+ <html>
+ <style>
+ html, body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style='width: 100%; height: 100%; background-color: green;'></div>
+ <script>
+ if (parent.document.location.search.startsWith('?event')) {
+ document.querySelector('div').addEventListener('touchstart', e => {
+ if (parent.document.location.search == '?event-prevent') {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+ </html>"
+ >
+ </iframe>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_scrollable.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_scrollable.html
new file mode 100644
index 0000000000..ca356958df
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_98vh_scrollable.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html,
+ body {
+ margin: 0px;
+ padding: 0px;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ iframe {
+ margin: 0px;
+ padding: 0px;
+ height: 98vh;
+ width: 100%;
+ border: none;
+ display: block;
+ }
+ </style>
+ <iframe
+ frameborder="0"
+ srcdoc="<!DOCTYPE HTML>
+ <html>
+ <style>
+ html, body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style='width: 100%; height: 500vh; background-color: green;'></div>
+ <script>
+ if (parent.document.location.search.startsWith('?event')) {
+ document.querySelector('div').addEventListener('touchstart', e => {
+ if (parent.document.location.search == '?event-prevent') {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+ </html>"
+ >
+ </iframe>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_hello.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_hello.html
new file mode 100644
index 0000000000..ee4962a2b7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_hello.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ </head>
+ <body>
+ <p>Hello, world! From Top Level.</p>
+ <iframe src="hello.html"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_http_only.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_http_only.html
new file mode 100644
index 0000000000..8f94d6c86d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_http_only.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ </head>
+ <body>
+ Some stuff
+ <iframe
+ src="http://expired.example.com/"
+ width="100%"
+ height="100%"
+ ></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_automation.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_automation.html
new file mode 100644
index 0000000000..c708687a3e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_automation.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ </head>
+ <body>
+ Some stuff
+ <iframe
+ src="https://example.org/tests/junit/simple_redirect.sjs?https://example.org"
+ ></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_local.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_local.html
new file mode 100644
index 0000000000..eb109536f0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_redirect_local.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ </head>
+ <body>
+ Some stuff
+ <iframe src="http://jigsaw.w3.org/HTTP/300/301.html"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/iframe_unknown_protocol.html b/mobile/android/geckoview/src/androidTest/assets/www/iframe_unknown_protocol.html
new file mode 100644
index 0000000000..81fb616b60
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/iframe_unknown_protocol.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ </head>
+ <body>
+ <p>Hello, world! From Top Level.</p>
+ <iframe src="foo://bar"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/images/test.gif b/mobile/android/geckoview/src/androidTest/assets/www/images/test.gif
new file mode 100644
index 0000000000..ba3b541c31
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/images/test.gif
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/inputs.html b/mobile/android/geckoview/src/androidTest/assets/www/inputs.html
new file mode 100644
index 0000000000..554c6c8143
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/inputs.html
@@ -0,0 +1,66 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Inputs</title>
+ <script>
+ class CustomTextBox extends HTMLElement {
+ constructor() {
+ super();
+
+ this.attachShadow({ mode: "open" });
+ const wrapper = document.createElement("span");
+ this.textbox = wrapper.appendChild(document.createElement("input"));
+ this.textbox.value = "adipisci";
+ this.shadowRoot.append(wrapper);
+ }
+
+ focus() {
+ this.textbox.focus();
+ }
+
+ select() {
+ this.textbox.select();
+ }
+
+ setSelectionRange(start, end) {
+ this.textbox.setSelectionRange(start, end);
+ }
+
+ get selectionStart() {
+ return this.textbox.selectionStart;
+ }
+
+ get selectionEnd() {
+ return this.textbox.selectionEnd;
+ }
+
+ get value() {
+ return this.textbox.value;
+ }
+ }
+ customElements.define("x-input", CustomTextBox);
+ </script>
+ </head>
+ <body>
+ <div id="text">lorem</div>
+ <input type="text" id="input" value="ipsum" />
+ <textarea id="textarea">dolor</textarea>
+ <div id="contenteditable" contenteditable="true">sit</div>
+ <iframe id="iframe" src="selectionAction_frame.html"></iframe>
+ <iframe id="designmode" src="selectionAction_frame.html"></iframe>
+ <iframe
+ id="iframe-xorigin"
+ src="http://127.0.0.1:4245/assets/www/selectionAction_frame_xorigin.html"
+ ></iframe>
+ <x-input id="x-input"></x-input>
+ </body>
+ <script>
+ addEventListener("load", function () {
+ document.getElementById("iframe").contentDocument.body.textContent =
+ "amet";
+ var designmode = document.getElementById("designmode");
+ designmode.contentDocument.body.textContent = "consectetur";
+ designmode.contentDocument.designMode = "on";
+ });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/links.html b/mobile/android/geckoview/src/androidTest/assets/www/links.html
new file mode 100644
index 0000000000..186426b0e2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/links.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Links</title>
+ <style>
+ :link {
+ color: rgb(0, 0, 255);
+ }
+
+ :visited {
+ color: rgb(255, 0, 0);
+ }
+ </style>
+ </head>
+ <body>
+ <ul>
+ <li><a id="mozilla" href="https://mozilla.org">Mozilla</a></li>
+ <li><a id="firefox" href="https://getfirefox.com">Get Firefox!</a></li>
+ <li><a id="bugzilla" href="https://bugzilla.mozilla.org">Bugzilla</a></li>
+ <li>
+ <a id="testpilot" href="https://testpilot.firefox.com">Test Pilot</a>
+ </li>
+ <li>
+ <a id="fxa" href="https://accounts.firefox.com">Firefox Accounts</a>
+ </li>
+ </ul>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/loremIpsum.html b/mobile/android/geckoview/src/androidTest/assets/www/loremIpsum.html
new file mode 100644
index 0000000000..e772f605f0
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/loremIpsum.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Lorem ipsum</title>
+ </head>
+ <body>
+ <p style="font-family: monospace; width: 20ch">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+ commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+ velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+ cupidatat non proident, sunt in culpa qui officia deserunt mollit
+ <a href="#">anim id</a> est laborum.
+ </p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest b/mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest
new file mode 100644
index 0000000000..5528465ba2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest
@@ -0,0 +1,17 @@
+{
+ "name": "App",
+ "short_name": "app",
+ "start_url": "./start/index.html",
+ "display": "standalone",
+ "background_color": "#c0ffeeee",
+ "theme_color": "cadetblue",
+ "icons": [{
+ "src": "images/test.gif",
+ "sizes": "192x192",
+ "type": "image/gif"
+ }],
+ "related_applications": [{
+ "platform": "play",
+ "url": "https://play.google.com/store/apps/details?id=my.first.webapp"
+ }]
+} \ No newline at end of file
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/media_session_default1.html b/mobile/android/geckoview/src/androidTest/assets/www/media_session_default1.html
new file mode 100644
index 0000000000..3d6554012b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/media_session_default1.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>MediaSessionDefaultTest1</title>
+ </head>
+ <body>
+ <script>
+ const audio1 = document.createElement("audio");
+ audio1.src = "audio/owl.mp3";
+
+ window.onload = () => {
+ audio1.play();
+ };
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/media_session_dom1.html b/mobile/android/geckoview/src/androidTest/assets/www/media_session_dom1.html
new file mode 100644
index 0000000000..8fa9584428
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/media_session_dom1.html
@@ -0,0 +1,109 @@
+<html>
+ <head>
+ <title>MediaSessionDOMTest1</title>
+ </head>
+ <body>
+ <script>
+ function updatePositionState(event) {
+ if (event.target != active) {
+ return;
+ }
+ navigator.mediaSession.setPositionState({
+ duration: parseFloat(event.target.duration),
+ position: parseFloat(event.target.currentTime),
+ playbackRate: 1,
+ });
+ }
+
+ function updateMetadata() {
+ navigator.mediaSession.metadata = active.metadata;
+ }
+
+ function getTrack(offset) {
+ console.log("" + active.id + " " + offset);
+ const nextId = Math.min(
+ tracks.length - 1,
+ Math.max(0, parseInt(active.id) + offset)
+ );
+ return tracks[nextId];
+ }
+
+ navigator.mediaSession.setActionHandler("play", async () => {
+ updateMetadata();
+ await active.play();
+ });
+
+ navigator.mediaSession.setActionHandler("pause", () => {
+ active.pause();
+ });
+
+ navigator.mediaSession.setActionHandler("previoustrack", () => {
+ active = getTrack(-1);
+ });
+
+ navigator.mediaSession.setActionHandler("nexttrack", () => {
+ active = getTrack(1);
+ });
+
+ const audio1 = document.createElement("audio");
+ audio1.src = "audio/owl.mp3";
+ audio1.addEventListener("timeupdate", updatePositionState);
+ audio1.metadata = new window.MediaMetadata({
+ title: "hoot",
+ artist: "owl",
+ album: "hoots",
+ artwork: [
+ {
+ src: "images/test.gif",
+ type: "image/gif",
+ sizes: "265x199",
+ },
+ ],
+ });
+ audio1.id = 0;
+
+ const audio2 = document.createElement("audio");
+ audio2.src = "audio/owl.mp3";
+ audio2.addEventListener("timeupdate", updatePositionState);
+ audio2.metadata = new window.MediaMetadata({
+ title: "hoot2",
+ artist: "stillowl",
+ album: "dahoots",
+ artwork: [
+ {
+ src: "images/test.gif",
+ type: "image/gif",
+ sizes: "265x199",
+ },
+ ],
+ });
+ audio2.id = 1;
+
+ const audio3 = document.createElement("audio");
+ audio3.src = "audio/owl.mp3";
+ audio3.addEventListener("timeupdate", updatePositionState);
+ audio3.metadata = new window.MediaMetadata({
+ title: "hoot3",
+ artist: "immaowl",
+ album: "mahoots",
+ artwork: [
+ {
+ src: "images/test.gif",
+ type: "image/gif",
+ sizes: "265x199",
+ },
+ ],
+ });
+ audio3.id = 2;
+
+ const tracks = [audio1, audio2, audio3];
+ let active = audio1;
+
+ window.onload = async () => {
+ active = getTrack(0);
+ updateMetadata();
+ await active.play();
+ };
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/metatags.html b/mobile/android/geckoview/src/androidTest/assets/www/metatags.html
new file mode 100644
index 0000000000..946c9faf27
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/metatags.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>MetaTags</title>
+ <meta property="twitter:description" content="twitter:description" />
+ <meta property="og:description" content="og:description" />
+ <meta name="description" content="description" />
+ <meta name="unknown:tag" content="unknown:tag" />
+ <meta property="og:image" content="https://test.com/og-image.jpg" />
+ <meta
+ property="twitter:image"
+ content="https://test.com/twitter-image.jpg"
+ />
+ <meta property="og:image:url" content="https://test.com/og-image-url" />
+ <meta name="thumbnail" content="https://test.com/thumbnail.jpg" />
+ </head>
+ <body></body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/mouseToReload.html b/mobile/android/geckoview/src/androidTest/assets/www/mouseToReload.html
new file mode 100644
index 0000000000..4ef3626119
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/mouseToReload.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <meta name="viewport" content="initial-scale=1.0" />
+ </head>
+ <body style="height: 100%">
+ <p>Hello, world!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/mp4.html b/mobile/android/geckoview/src/androidTest/assets/www/mp4.html
new file mode 100644
index 0000000000..09909fac69
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/mp4.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>MP4 Video</title>
+ </head>
+ <body>
+ <video controls preload>
+ <source src="videos/short.mp4"></source>
+ </video>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/newSession.html b/mobile/android/geckoview/src/androidTest/assets/www/newSession.html
new file mode 100644
index 0000000000..b92657430c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/newSession.html
@@ -0,0 +1,22 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ </head>
+ <body>
+ <a
+ id="targetBlankLink"
+ target="_blank"
+ rel="opener"
+ href="newSession_child.html"
+ >target="_blank"</a
+ >
+ <a
+ id="noOpenerLink"
+ target="_blank"
+ rel="noopener"
+ href="http://example.com"
+ >rel="noopener"</a
+ >
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/newSession_child.html b/mobile/android/geckoview/src/androidTest/assets/www/newSession_child.html
new file mode 100644
index 0000000000..28fd019804
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/newSession_child.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ </head>
+ <body>
+ <p>I'm the child</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/no-meta-viewport.html b/mobile/android/geckoview/src/androidTest/assets/www/no-meta-viewport.html
new file mode 100644
index 0000000000..8f1cb8fa80
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/no-meta-viewport.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <h3>Nothing here</h3>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/ogg.html b/mobile/android/geckoview/src/androidTest/assets/www/ogg.html
new file mode 100644
index 0000000000..dd478d3b3f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/ogg.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>OGG Video</title>
+ </head>
+ <body>
+ <video controls preload>
+ <source src="videos/video.ogg"></source>
+ </video>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/orange.pdf b/mobile/android/geckoview/src/androidTest/assets/www/orange.pdf
new file mode 100755
index 0000000000..684582176a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/orange.pdf
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto-none.html b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto-none.html
new file mode 100644
index 0000000000..ff180f961a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto-none.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ overscroll-behavior: auto none;
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 100vh"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto.html b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto.html
new file mode 100644
index 0000000000..6f2b3ee92a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-auto.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ overscroll-behavior: auto;
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 100vh"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-auto.html b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-auto.html
new file mode 100644
index 0000000000..ff6366ccda
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-auto.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ overscroll-behavior: none auto;
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 100vh"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-on-non-root.html b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-on-non-root.html
new file mode 100644
index 0000000000..fbe2269c19
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/overscroll-behavior-none-on-non-root.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div
+ id="scroll"
+ style="
+ width: 100%;
+ height: 100vh;
+ overscroll-behavior: none;
+ overflow-y: scroll;
+ "
+ >
+ <div style="height: 200vh"></div>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/popup.html b/mobile/android/geckoview/src/androidTest/assets/www/popup.html
new file mode 100644
index 0000000000..7e52870df5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/popup.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ </head>
+ <body>
+ <p>Launching popup...</p>
+ <script>
+ window.open("hello.html");
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/print_content_change.html b/mobile/android/geckoview/src/androidTest/assets/www/print_content_change.html
new file mode 100644
index 0000000000..ae36a6c6b8
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/print_content_change.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Orange Print Background Removal</title>
+ </head>
+ <style>
+ .box {
+ height: 200vh;
+ width: 100vw;
+ }
+ @media screen {
+ .background {
+ background-color: rgb(0, 0, 255);
+ color-adjust: exact;
+ }
+ }
+ @media print {
+ .background {
+ background-color: rgb(255, 113, 57);
+ color-adjust: exact;
+ }
+ }
+ </style>
+
+ <body>
+ <div id="content" class="box background"></div>
+ </body>
+
+ <!-- The window.print should freeze the page before removing the content, so the background should remain present. -->
+ <button
+ id="print-button"
+ onclick="window.print(); document.getElementById('content').remove()"
+ >
+ Print
+ </button>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/print_iframe.html b/mobile/android/geckoview/src/androidTest/assets/www/print_iframe.html
new file mode 100644
index 0000000000..b7dd83f2a5
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/print_iframe.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" content="width=device-width, height=device-height" />
+ <title>Print iframes</title>
+ </head>
+ <style>
+ .box {
+ height: 200vh;
+ width: 100vw;
+ }
+ @media screen {
+ .background {
+ background-color: rgb(255, 0, 0);
+ color-adjust: exact;
+ }
+ }
+ @media print {
+ .background {
+ background-color: rgb(0, 255, 0);
+ color-adjust: exact;
+ }
+ }
+ </style>
+
+ <body>
+ <div id="content" class="box background"></div>
+ </body>
+
+ <!-- The window.print should freeze the page before removing the content, so the background should remain present. -->
+ <button
+ id="print-button-page"
+ onclick="window.print(); document.getElementById('content').remove()"
+ >
+ Print
+ </button>
+
+ <iframe id="iframe" src="print_content_change.html"></iframe>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/prompts.html b/mobile/android/geckoview/src/androidTest/assets/www/prompts.html
new file mode 100644
index 0000000000..53e8f96b04
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/prompts.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <select id="selectexample">
+ <option>1</option>
+ <option>2</option>
+ </select>
+
+ <input type="date" id="dateexample" />
+
+ <input type="month" id="monthexample" />
+
+ <input type="week" id="weekexample" />
+
+ <input type="time" id="timeexample" />
+
+ <input type="datetime-local" id="datetimelocalexample" />
+
+ <input type="color" id="colorexample" value="#ffffff" />
+
+ <input type="file" id="fileexample" accept="image/*,.pdf" capture="user" />
+
+ <datalist id="colorlist">
+ <option>#000000</option>
+ <option>#808080</option>
+ </datalist>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/pull-to-refresh-subframe.html b/mobile/android/geckoview/src/androidTest/assets/www/pull-to-refresh-subframe.html
new file mode 100644
index 0000000000..d1a421c0a3
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/pull-to-refresh-subframe.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta
+ name="viewport"
+ content="height=device-height,width=device-width,initial-scale=1.0"
+ />
+ <style type="text/css">
+ html,
+ body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+
+ .container {
+ width: 100%;
+ height: 25%;
+ overflow: scroll;
+ }
+
+ .subframe {
+ width: 100%;
+ height: 100vh;
+ }
+
+ #one > .subframe {
+ background-color: red;
+ }
+
+ #two > .subframe {
+ background-color: green;
+ }
+
+ #three > .subframe {
+ background-color: blue;
+ }
+
+ #four > .subframe {
+ background-color: yellow;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="one" class="container">
+ <div class="subframe"></div>
+ </div>
+ <div id="two" class="container">
+ <div class="subframe"></div>
+ </div>
+ <div id="three" class="container">
+ <div class="subframe"></div>
+ </div>
+ <div id="four" class="container">
+ <div class="subframe"></div>
+ </div>
+ </body>
+ <script>
+ document
+ .getElementById("three")
+ .scrollTo({ top: 200, behavior: "instant" });
+
+ document.getElementById("four").addEventListener("touchstart", e => {
+ console.log("not preventing default");
+ });
+
+ document.getElementById("two").addEventListener("touchstart", e => {
+ console.log("preventing default");
+ e.preventDefault();
+ });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/push/push.html b/mobile/android/geckoview/src/androidTest/assets/www/push/push.html
new file mode 100644
index 0000000000..ccd091eaea
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/push/push.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Push API test</title>
+ </head>
+ <body>
+ <p>Hello, world!</p>
+ <script src="push.js"></script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/push/push.js b/mobile/android/geckoview/src/androidTest/assets/www/push/push.js
new file mode 100644
index 0000000000..d9322d11cc
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/push/push.js
@@ -0,0 +1,44 @@
+window.doSubscribe = async function (applicationServerKey) {
+ const registration = await navigator.serviceWorker.register("./sw.js");
+ const sub = await registration.pushManager.subscribe({
+ applicationServerKey,
+ });
+ return sub.toJSON();
+};
+
+window.doGetSubscription = async function () {
+ const registration = await navigator.serviceWorker.register("./sw.js");
+ const sub = await registration.pushManager.getSubscription();
+ if (sub) {
+ return sub.toJSON();
+ }
+
+ return null;
+};
+
+window.doUnsubscribe = async function () {
+ const registration = await navigator.serviceWorker.register("./sw.js");
+ const sub = await registration.pushManager.getSubscription();
+ sub.unsubscribe();
+ return {};
+};
+
+window.doWaitForPushEvent = function () {
+ return new Promise(resolve => {
+ navigator.serviceWorker.addEventListener("message", function (e) {
+ if (e.data.type === "push") {
+ resolve(e.data.payload);
+ }
+ });
+ });
+};
+
+window.doWaitForSubscriptionChange = function () {
+ return new Promise(resolve => {
+ navigator.serviceWorker.addEventListener("message", function (e) {
+ if (e.data.type === "pushsubscriptionchange") {
+ resolve(e.data.type);
+ }
+ });
+ });
+};
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/push/sw.js b/mobile/android/geckoview/src/androidTest/assets/www/push/sw.js
new file mode 100644
index 0000000000..2e51383205
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/push/sw.js
@@ -0,0 +1,30 @@
+self.addEventListener("install", function () {
+ self.skipWaiting();
+});
+
+self.addEventListener("activate", function (e) {
+ e.waitUntil(self.clients.claim());
+});
+
+self.addEventListener("push", async function (e) {
+ const clients = await self.clients.matchAll();
+ let text = "";
+ if (e.data) {
+ text = e.data.text();
+ }
+ clients.forEach(function (client) {
+ client.postMessage({ type: "push", payload: text });
+ });
+
+ try {
+ const { title, body } = e.data.json();
+ self.registration.showNotification(title, { body });
+ } catch (e) {}
+});
+
+self.addEventListener("pushsubscriptionchange", async function (e) {
+ const clients = await self.clients.matchAll();
+ clients.forEach(function (client) {
+ client.postMessage({ type: "pushsubscriptionchange" });
+ });
+});
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/red-background-body-fully-covered-by-green-element.html b/mobile/android/geckoview/src/androidTest/assets/www/red-background-body-fully-covered-by-green-element.html
new file mode 100644
index 0000000000..ad6c96599e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/red-background-body-fully-covered-by-green-element.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=windows-1252" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <style>
+ html {
+ scrollbar-width: none;
+ }
+ body {
+ background: red;
+ margin: 0;
+ }
+ .tall {
+ height: 600vh;
+ background: green;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="tall"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/reflect_local_storage_into_title.html b/mobile/android/geckoview/src/androidTest/assets/www/reflect_local_storage_into_title.html
new file mode 100644
index 0000000000..749678c668
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/reflect_local_storage_into_title.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>no title</title>
+ <script>
+ // If we have a query string, save it to the local storage.
+ if (window.location.search.length) {
+ const value = window.location.search.substr(1);
+ localStorage.setItem("ctx", value);
+ }
+
+ // Set the title to reflect the local storage value.
+ document.title = "storage=" + localStorage.getItem("ctx");
+ </script>
+ </head>
+ <body></body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/resubmit.html b/mobile/android/geckoview/src/androidTest/assets/www/resubmit.html
new file mode 100644
index 0000000000..6155270f1b
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/resubmit.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <form action="hello.html" method="post">
+ <input id="text" />
+ <button id="submit">Submit</button>
+ </form>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/root_100_percent_height.html b/mobile/android/geckoview/src/androidTest/assets/www/root_100_percent_height.html
new file mode 100644
index 0000000000..e91c997bbb
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/root_100_percent_height.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ height: 100%;
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 100%; background-color: green"></div>
+ <script>
+ if (document.location.search.startsWith("?event")) {
+ document.querySelector("div").addEventListener("touchstart", e => {
+ if (document.location.search == "?event-prevent") {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/root_100vh.html b/mobile/android/geckoview/src/androidTest/assets/www/root_100vh.html
new file mode 100644
index 0000000000..e6c7fef374
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/root_100vh.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 100vh; background-color: green"></div>
+ <script>
+ if (document.location.search.startsWith("?event")) {
+ document.querySelector("div").addEventListener("touchstart", e => {
+ if (document.location.search == "?event-prevent") {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/root_98vh.html b/mobile/android/geckoview/src/androidTest/assets/www/root_98vh.html
new file mode 100644
index 0000000000..a654353d64
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/root_98vh.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 98vh; background-color: green"></div>
+ <script>
+ if (document.location.search.startsWith("?event")) {
+ document.querySelector("div").addEventListener("touchstart", e => {
+ if (document.location.search == "?event-prevent") {
+ e.preventDefault();
+ }
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/saveState.html b/mobile/android/geckoview/src/androidTest/assets/www/saveState.html
new file mode 100644
index 0000000000..c85b528f01
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/saveState.html
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Hello, world!</title>
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+ <style>
+ p {
+ height: 300vh;
+ }
+ </style>
+ </head>
+ <body>
+ <form id="form">
+ <input type="text" id="name" />
+ </form>
+ <p>Hello, world!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/scroll-handoff.html b/mobile/android/geckoview/src/androidTest/assets/www/scroll-handoff.html
new file mode 100644
index 0000000000..c8f0fe9e95
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/scroll-handoff.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ overscroll-behavior: auto;
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ #scroll {
+ /* set a different overscroll-behavior to make this container different from
+ the root scrollElement. */
+ overscroll-behavior: contain auto;
+ }
+ </style>
+ <body>
+ <div id="scroll" style="width: 100%; height: 100vh; overflow-y: scroll">
+ <div style="height: 300vh"></div>
+ </div>
+ </body>
+ <script>
+ document
+ .getElementById("scroll")
+ .scrollTo({ top: 50, behavior: "instant" });
+ </script>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/scroll.html b/mobile/android/geckoview/src/androidTest/assets/www/scroll.html
new file mode 100644
index 0000000000..e906e45686
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/scroll.html
@@ -0,0 +1,59 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=0.5" />
+ <style type="text/css">
+ body {
+ margin: 0;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+
+ #one {
+ background-color: red;
+ width: 200vw;
+ height: 33vh;
+ }
+
+ #two {
+ background-color: green;
+ width: 200vw;
+ height: 33vh;
+ }
+
+ #three {
+ background-color: blue;
+ width: 200vw;
+ height: 33vh;
+ }
+
+ #four {
+ background-color: purple;
+ width: 200vw;
+ height: 200vh;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="one"></div>
+ <div id="two"></div>
+ <div id="three"></div>
+ <div id="four"></div>
+ <script>
+ document.getElementById("two").addEventListener("touchstart", e => {
+ console.log("preventing default");
+ e.preventDefault();
+ });
+
+ document.getElementById("three").addEventListener("touchstart", e => {
+ console.log("not preventing default");
+ });
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/select-listbox.html b/mobile/android/geckoview/src/androidTest/assets/www/select-listbox.html
new file mode 100644
index 0000000000..5832954d2e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/select-listbox.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<select size="2" id="multiple">
+ <option>ABC</option>
+ <option>DEF</option>
+ <option>GHI</option>
+</select>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/select-multiple.html b/mobile/android/geckoview/src/androidTest/assets/www/select-multiple.html
new file mode 100644
index 0000000000..bb9470fffd
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/select-multiple.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<select multiple id="multiple">
+ <option>ABC</option>
+ <option>DEF</option>
+ <option>GHI</option>
+</select>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/select.html b/mobile/android/geckoview/src/androidTest/assets/www/select.html
new file mode 100644
index 0000000000..e8d28253d2
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/select.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<select id="simple">
+ <option>ABC</option>
+ <option>DEF</option>
+</select>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame.html b/mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame.html
new file mode 100644
index 0000000000..132155c6a1
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame.html
@@ -0,0 +1,6 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body></body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame_xorigin.html b/mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame_xorigin.html
new file mode 100644
index 0000000000..87a4d6039e
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/selectionAction_frame_xorigin.html
@@ -0,0 +1,47 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <script>
+ window.addEventListener("message", e => {
+ switch (e.data.type) {
+ case "focus":
+ window.focus();
+ break;
+
+ case "select": {
+ <!-- On fission, there's no way to wait for parent position change. -->
+ <!-- So we use requestAnimationFrame as a workaround. -->
+ window.requestAnimationFrame(() => {
+ window.requestAnimationFrame(() => {
+ const text = document.body.firstChild;
+ document
+ .getSelection()
+ .setBaseAndExtent(text, 0, text, e.data.length);
+ });
+ });
+ break;
+ }
+
+ case "selectedOffset": {
+ const sel = document.getSelection();
+ const text = document.body.firstChild;
+ if (sel.anchorNode !== text || sel.focusNode !== text) {
+ window.parent.postMessage([-1, -1], "*");
+ } else {
+ window.parent.postMessage(
+ [sel.anchorOffset, sel.focusOffset],
+ "*"
+ );
+ }
+ break;
+ }
+
+ case "content":
+ window.parent.postMessage(document.body.textContent, "*");
+ break;
+ }
+ });
+ </script>
+ </head>
+ <body onload="document.body.textContent = 'elit'"></body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/showDynamicToolbar.html b/mobile/android/geckoview/src/androidTest/assets/www/showDynamicToolbar.html
new file mode 100644
index 0000000000..f6b0dd340c
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/showDynamicToolbar.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>showDynamicToolbar test content</title>
+ <script>
+ document.addEventListener("click", function () {
+ document.body.style.position = "fixed";
+ });
+ </script>
+ </head>
+ <body>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/simple_redirect.sjs b/mobile/android/geckoview/src/androidTest/assets/www/simple_redirect.sjs
new file mode 100644
index 0000000000..43fec90b5a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/simple_redirect.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
+ response.setHeader("Location", request.queryString, false);
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/titleChange.html b/mobile/android/geckoview/src/androidTest/assets/www/titleChange.html
new file mode 100644
index 0000000000..51f8c936b6
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/titleChange.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <header><title>Title1</title></header>
+ <body>
+ <script>
+ addEventListener("load", function () {
+ setTimeout(function () {
+ document.title = "Title2";
+ }, 100);
+ });
+ </script>
+ </body>
+ <iframe src="hello.html"></iframe>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touch-action-wheel-listener.html b/mobile/android/geckoview/src/androidTest/assets/www/touch-action-wheel-listener.html
new file mode 100644
index 0000000000..cfc9489d17
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/touch-action-wheel-listener.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div id="one" style="width: 100%; height: 100vh; touch-action: none"></div>
+ <script>
+ document.getElementById("one").addEventListener("wheel", e => {
+ console.log("preventing default");
+ e.preventDefault();
+ });
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html b/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html
new file mode 100644
index 0000000000..62266b6ef7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/touch-action.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+ <style>
+ html {
+ height: 100%;
+ width: 100%;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+ body {
+ width: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ </style>
+ <body>
+ <div style="width: 100%; height: 50vh; touch-action: auto"></div>
+ <script>
+ const searchParams = new URLSearchParams(location.search);
+ let div = document.querySelector("div");
+ if (searchParams.has("subframe")) {
+ const scrolledContents = document.createElement("div");
+ scrolledContents.style.height = "100%";
+
+ div.appendChild(scrolledContents);
+ div.style.overflow = "auto";
+
+ div = scrolledContents;
+ }
+ if (searchParams.has("scrollable")) {
+ // Scrollable for dynamic toolbar purposes.
+ div.style.height = "100vh";
+ }
+ div.style.touchAction = searchParams.get("touch-action");
+ if (searchParams.has("event")) {
+ div.addEventListener("touchstart", e => {});
+ }
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touch.html b/mobile/android/geckoview/src/androidTest/assets/www/touch.html
new file mode 100644
index 0000000000..ba3bc098a9
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/touch.html
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta
+ name="viewport"
+ content="height=device-height,width=device-width,initial-scale=1.0"
+ />
+ <style type="text/css">
+ body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0px;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+
+ #one {
+ background-color: red;
+ width: 100%;
+ height: 33%;
+ }
+
+ #two {
+ background-color: green;
+ width: 100%;
+ height: 33%;
+ }
+
+ #three {
+ background-color: blue;
+ width: 100%;
+ height: 33%;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="one"></div>
+ <div id="two"></div>
+ <div id="three"></div>
+ <script>
+ document.getElementById("two").addEventListener("touchstart", e => {
+ console.log("preventing default");
+ e.preventDefault();
+ });
+
+ document.getElementById("three").addEventListener("touchstart", e => {
+ console.log("not preventing default");
+ });
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touch_xorigin.html b/mobile/android/geckoview/src/androidTest/assets/www/touch_xorigin.html
new file mode 100644
index 0000000000..89f3762aef
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/touch_xorigin.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <style>
+ body,
+ html {
+ margin: 0;
+ padding: 0;
+ }
+ </style>
+ </head>
+ <body>
+ <iframe src="http://127.0.0.1:4245/assets/www/touch.html"></iframe>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html b/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html
new file mode 100644
index 0000000000..9ee1f461a7
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/touchstart.html
@@ -0,0 +1,37 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=0.5" />
+ <style type="text/css">
+ body {
+ margin: 0;
+ /* background contains one extra transparent.gif because we want trick the
+ contentful paint detection; We want to make sure the background is loaded
+ before the test starts so we always wait for the contentful paint timestamp
+ to exist, however, gradient isn't considered as contentful per spec, so Gecko
+ wouldn't generate a timestamp for it. Hence, we added a transparent gif
+ to the image list to trick the detection. */
+ background: url("/assets/www/transparent.gif"),
+ linear-gradient(135deg, red, white);
+ }
+
+ #one {
+ background-color: red;
+ width: 200%;
+ height: 100vh;
+ }
+ #two {
+ background-color: blue;
+ width: 200%;
+ height: 800vh;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="one"></div>
+ <div id="two"></div>
+ <script>
+ document.getElementById("two").addEventListener("touchstart", e => {});
+ </script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/tracemonkey.pdf b/mobile/android/geckoview/src/androidTest/assets/www/tracemonkey.pdf
new file mode 100644
index 0000000000..4dcf129d65
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/tracemonkey.pdf
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/trackers.html b/mobile/android/geckoview/src/androidTest/assets/www/trackers.html
new file mode 100644
index 0000000000..56ea43979a
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/trackers.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Trackers</title>
+ </head>
+ <body>
+ <p>Trackers</p>
+
+ <!-- test-track-simple -->
+ <script src="http://trackertest.org/tracker.js"></script>
+ <script src="https://tracking.example.com/tracker.js"></script>
+ <script src="https://itisatracker.org/tracker.js"></script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/translations-tester-en.html b/mobile/android/geckoview/src/androidTest/assets/www/translations-tester-en.html
new file mode 100644
index 0000000000..3e5f8e6303
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/translations-tester-en.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+ <!-- See toolkit for original test.-->
+ <head>
+ <meta charset="utf-8" />
+ <title>Translations Test</title>
+ <style>
+ div {
+ margin: 10px auto;
+ width: 300px;
+ }
+ p {
+ margin: 47px 0;
+ font-size: 21px;
+ line-height: 2;
+ }
+ </style>
+ </head>
+ <body>
+ <div>
+ <!-- The following is an excerpt from The Wondeful Wizard of Oz, which is in the public domain -->
+ <h1>"The Wonderful Wizard of Oz" by L. Frank Baum</h1>
+ <p>
+ The little girl, seeing she had lost one of her pretty shoes, grew
+ angry, and said to the Witch, “Give me back my shoe!”
+ </p>
+ <p>
+ “I will not,” retorted the Witch, “for it is now my shoe, and not
+ yours.”
+ </p>
+ <p>
+ “You are a wicked creature!” cried Dorothy. “You have no right to take
+ my shoe from me.”
+ </p>
+ <p>
+ “I shall keep it, just the same,” said the Witch, laughing at her, “and
+ someday I shall get the other one from you, too.”
+ </p>
+ <p>
+ This made Dorothy so very angry that she picked up the bucket of water
+ that stood near and dashed it over the Witch, wetting her from head to
+ foot.
+ </p>
+ <p>
+ Instantly the wicked woman gave a loud cry of fear, and then, as Dorothy
+ looked at her in wonder, the Witch began to shrink and fall away.
+ </p>
+ <p>
+ “See what you have done!” she screamed. “In a minute I shall melt away.”
+ </p>
+ <p>
+ “I’m very sorry, indeed,” said Dorothy, who was truly frightened to see
+ the Witch actually melting away like brown sugar before her very eyes.
+ </p>
+ <p>
+ “Didn’t you know water would be the end of me?” asked the Witch, in a
+ wailing, despairing voice.
+ </p>
+ <p>“Of course not,” answered Dorothy. “How should I?”</p>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/translations-tester-es.html b/mobile/android/geckoview/src/androidTest/assets/www/translations-tester-es.html
new file mode 100644
index 0000000000..e9d39585ee
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/translations-tester-es.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html lang="es">
+ <!-- See toolkit for original test.-->
+ <head>
+ <meta charset="utf-8" />
+ <title>Translations Test</title>
+ <style>
+ div {
+ margin: 10px auto;
+ width: 300px;
+ }
+ p {
+ margin: 47px 0;
+ font-size: 21px;
+ line-height: 2;
+ }
+ </style>
+ </head>
+ <body>
+ <div>
+ <header lang="en">
+ The following is an excerpt from Don Quijote de la Mancha, which is in
+ the public domain
+ </header>
+ <h1>Don Quijote de La Mancha</h1>
+ <h2>Capítulo VIII.</h2>
+ <p>
+ Del buen suceso que el valeroso don Quijote tuvo en la espantable y
+ jamás imaginada aventura de los molinos de viento, con otros sucesos
+ dignos de felice recordación
+ </p>
+ <p>
+ En esto, descubrieron treinta o cuarenta molinos de viento que hay en
+ aquel campo; y, así como don Quijote los vio, dijo a su escudero:
+ </p>
+ <p>
+ — La ventura va guiando nuestras cosas mejor de lo que acertáramos a
+ desear, porque ves allí, amigo Sancho Panza, donde se descubren treinta,
+ o pocos más, desaforados gigantes, con quien pienso hacer batalla y
+ quitarles a todos las vidas, con cuyos despojos comenzaremos a
+ enriquecer; que ésta es buena guerra, y es gran servicio de Dios quitar
+ tan mala simiente de sobre la faz de la tierra.
+ </p>
+ <p>— ¿Qué gigantes? —dijo Sancho Panza.</p>
+ <p>
+ — Aquellos que allí ves —respondió su amo— de los brazos largos, que los
+ suelen tener algunos de casi dos leguas.
+ </p>
+ <p>
+ — Mire vuestra merced —respondió Sancho— que aquellos que allí se
+ parecen no son gigantes, sino molinos de viento, y lo que en ellos
+ parecen brazos son las aspas, que, volteadas del viento, hacen andar la
+ piedra del molino.
+ </p>
+ <p>
+ — Bien parece —respondió don Quijote— que no estás cursado en esto de
+ las aventuras: ellos son gigantes; y si tienes miedo, quítate de ahí, y
+ ponte en oración en el espacio que yo voy a entrar con ellos en fiera y
+ desigual batalla.
+ </p>
+ <p>
+ Y, diciendo esto, dio de espuelas a su caballo Rocinante, sin atender a
+ las voces que su escudero Sancho le daba, advirtiéndole que, sin duda
+ alguna, eran molinos de viento, y no gigantes, aquellos que iba a
+ acometer. Pero él iba tan puesto en que eran gigantes, que ni oía las
+ voces de su escudero Sancho ni echaba de ver, aunque estaba ya bien
+ cerca, lo que eran; antes, iba diciendo en voces altas:
+ </p>
+ <p>
+ — Non fuyades, cobardes y viles criaturas, que un solo caballero es el
+ que os acomete.
+ </p>
+ <p>
+ Levantóse en esto un poco de viento y las grandes aspas comenzaron a
+ moverse, lo cual visto por don Quijote, dijo:
+ </p>
+ <p>
+ — Pues, aunque mováis más brazos que los del gigante Briareo, me lo
+ habéis de pagar.
+ </p>
+ </div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/transparent.gif b/mobile/android/geckoview/src/androidTest/assets/www/transparent.gif
new file mode 100644
index 0000000000..e565824aaf
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/transparent.gif
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/update_manifest.json b/mobile/android/geckoview/src/androidTest/assets/www/update_manifest.json
new file mode 100644
index 0000000000..7b2de1f278
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/update_manifest.json
@@ -0,0 +1,40 @@
+{
+ "addons": {
+ "update@example.com": {
+ "updates": [
+ {
+ "version": "1.0",
+ "update_link": "https://example.org/tests/junit/update-1.xpi"
+ },
+ {
+ "version": "2.0",
+ "update_link": "https://example.org/tests/junit/update-2.xpi"
+ }
+ ]
+ },
+ "update-postpone@example.com": {
+ "updates": [
+ {
+ "version": "1.0",
+ "update_link": "https://example.org/tests/junit/update-postpone-1.xpi"
+ },
+ {
+ "version": "2.0",
+ "update_link": "https://example.org/tests/junit/update-postpone-2.xpi"
+ }
+ ]
+ },
+ "update-with-perms@example.com": {
+ "updates": [
+ {
+ "version": "1.0",
+ "update_link": "https://example.org/tests/junit/update-with-perms-1.xpi"
+ },
+ {
+ "version": "2.0",
+ "update_link": "https://example.org/tests/junit/update-with-perms-2.xpi"
+ }
+ ]
+ }
+ }
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/videos/gizmo.webm b/mobile/android/geckoview/src/androidTest/assets/www/videos/gizmo.webm
new file mode 100644
index 0000000000..518531a93f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/videos/gizmo.webm
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/videos/short.mp4 b/mobile/android/geckoview/src/androidTest/assets/www/videos/short.mp4
new file mode 100644
index 0000000000..a674b7eb68
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/videos/short.mp4
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg b/mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg
new file mode 100644
index 0000000000..ac7ece3519
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/videos/video.ogg
Binary files differ
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/viewport.html b/mobile/android/geckoview/src/androidTest/assets/www/viewport.html
new file mode 100644
index 0000000000..a5dfa0f64f
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/viewport.html
@@ -0,0 +1,19 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta
+ name="viewport"
+ content="width=device-width, initial-scale=1.0, viewport-fit=cover"
+ />
+ <style type="text/css">
+ #wide {
+ background-color: rgb(200, 0, 0);
+ width: 100%;
+ height: 40px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="wide"></div>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/webm.html b/mobile/android/geckoview/src/androidTest/assets/www/webm.html
new file mode 100644
index 0000000000..f329582575
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/webm.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebM Video</title>
+ </head>
+ <body>
+ <video controls preload>
+ <source src="videos/gizmo.webm"></source>
+ </video>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.html b/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.html
new file mode 100644
index 0000000000..d71eb0484d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Open Window test</title>
+ </head>
+ <body>
+ <p>Hello, world!</p>
+ <script type="text/javascript" src="./open_window.js"></script>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.js b/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.js
new file mode 100644
index 0000000000..921cff5b09
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window.js
@@ -0,0 +1,15 @@
+navigator.serviceWorker.register("./service-worker.js", {
+ scope: ".",
+});
+
+function showNotification() {
+ Notification.requestPermission(function (result) {
+ if (result === "granted") {
+ navigator.serviceWorker.ready.then(function (registration) {
+ registration.showNotification("Open Window Notification", {
+ body: "Hello",
+ });
+ });
+ }
+ });
+}
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window_target.html b/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window_target.html
new file mode 100644
index 0000000000..14775aafac
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/worker/open_window_target.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Open Window test target</title>
+ </head>
+ <body>
+ <p>Hello, world!</p>
+ </body>
+</html>
diff --git a/mobile/android/geckoview/src/androidTest/assets/www/worker/service-worker.js b/mobile/android/geckoview/src/androidTest/assets/www/worker/service-worker.js
new file mode 100644
index 0000000000..e3fbbb6388
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/assets/www/worker/service-worker.js
@@ -0,0 +1,15 @@
+self.addEventListener("install", function () {
+ console.log("install");
+ self.skipWaiting();
+});
+
+self.addEventListener("activate", function (e) {
+ console.log("activate");
+ e.waitUntil(self.clients.claim());
+});
+
+self.onnotificationclick = function (event) {
+ console.log("onnotificationclick");
+ self.clients.openWindow("open_window_target.html");
+ event.notification.close();
+};