summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt')
-rw-r--r--mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt660
1 files changed, 660 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
new file mode 100644
index 0000000000..65a07d384d
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
@@ -0,0 +1,660 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.geckoview.test
+
+import android.graphics.SurfaceTexture
+import android.net.Uri
+import android.view.PointerIcon
+import android.view.Surface
+import androidx.annotation.AnyThread
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.hamcrest.Matchers.* // ktlint-disable no-wildcard-imports
+import org.json.JSONObject
+import org.junit.Assume.assumeThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mozilla.geckoview.* // ktlint-disable no-wildcard-imports
+import org.mozilla.geckoview.ContentBlocking.CookieBannerMode
+import org.mozilla.geckoview.GeckoDisplay.SurfaceInfo
+import org.mozilla.geckoview.GeckoSession.ContentDelegate
+import org.mozilla.geckoview.GeckoSession.NavigationDelegate
+import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
+import org.mozilla.geckoview.GeckoSession.ProgressDelegate
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.IgnoreCrash
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.NullDelegate
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
+import java.io.ByteArrayInputStream
+
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+class ContentDelegateTest : BaseSessionTest() {
+ @Test fun titleChange() {
+ mainSession.loadTestPath(TITLE_CHANGE_HTML_PATH)
+
+ sessionRule.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 2)
+ override fun onTitleChange(session: GeckoSession, title: String?) {
+ assertThat(
+ "Title should match",
+ title,
+ equalTo(forEachCall("Title1", "Title2")),
+ )
+ }
+ })
+ }
+
+ @Test fun openInAppRequest() {
+ // Testing WebResponse behavior
+ val data = "Hello, World.".toByteArray()
+ val fileHeader = "attachment; filename=\"hello-world.txt\""
+ val requestExternal = true
+ val skipConfirmation = true
+ var response = WebResponse.Builder(HELLO_HTML_PATH)
+ .statusCode(200)
+ .body(ByteArrayInputStream(data))
+ .addHeader("Content-Type", "application/txt")
+ .addHeader("Content-Length", data.size.toString())
+ .addHeader("Content-Disposition", fileHeader)
+ .requestExternalApp(requestExternal)
+ .skipConfirmation(skipConfirmation)
+ .build()
+ assertThat(
+ "Filename matches as expected",
+ response.headers["Content-Disposition"],
+ equalTo(fileHeader),
+ )
+ assertThat(
+ "Request external response matches as expected.",
+ requestExternal,
+ equalTo(response.requestExternalApp),
+ )
+ assertThat(
+ "Skipping the confirmation matches as expected.",
+ skipConfirmation,
+ equalTo(response.skipConfirmation),
+ )
+ }
+
+ @Test fun downloadOneRequest() {
+ // disable test on pgo for frequently failing Bug 1543355
+ assumeThat(sessionRule.env.isDebugBuild, equalTo(true))
+
+ mainSession.loadTestPath(DOWNLOAD_HTML_PATH)
+
+ sessionRule.waitUntilCalled(object : NavigationDelegate, ContentDelegate {
+
+ @AssertCalled(count = 2)
+ override fun onLoadRequest(session: GeckoSession, request: LoadRequest): GeckoResult<AllowOrDeny>? {
+ return null
+ }
+
+ @AssertCalled(false)
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
+ }
+
+ @AssertCalled(count = 1)
+ override fun onExternalResponse(session: GeckoSession, response: WebResponse) {
+ assertThat("Uri should start with data:", response.uri, startsWith("blob:"))
+ assertThat("We should download the thing", String(response.body?.readBytes()!!), equalTo("Downloaded Data"))
+ // The headers below are special headers that we try to get for responses of any kind (http, blob, etc.)
+ // Note the case of the header keys. In the WebResponse object, all of them are lower case.
+ assertThat("Content type should match", response.headers.get("content-type"), equalTo("text/plain"))
+ assertThat("Content length should be non-zero", response.headers.get("Content-Length")!!.toLong(), greaterThan(0L))
+ assertThat("Filename should match", response.headers.get("cONTent-diSPOsiTion"), equalTo("attachment; filename=\"download.txt\""))
+ assertThat("Request external response should not be set.", response.requestExternalApp, equalTo(false))
+ assertThat("Should not skip the confirmation on a regular download.", response.skipConfirmation, equalTo(false))
+ }
+ })
+ }
+
+ @IgnoreCrash
+ @Test
+ fun crashContent() {
+ // TODO: bug 1710940
+ assumeThat(sessionRule.env.isIsolatedProcess, equalTo(false))
+
+ mainSession.loadUri(CONTENT_CRASH_URL)
+ mainSession.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onCrash(session: GeckoSession) {
+ assertThat(
+ "Session should be closed after a crash",
+ session.isOpen,
+ equalTo(false),
+ )
+ }
+ })
+
+ // Recover immediately
+ mainSession.open()
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat("Page should load successfully", success, equalTo(true))
+ }
+ })
+ }
+
+ @IgnoreCrash
+ @WithDisplay(width = 10, height = 10)
+ @Test
+ fun crashContent_tapAfterCrash() {
+ // TODO: bug 1710940
+ assumeThat(sessionRule.env.isIsolatedProcess, equalTo(false))
+
+ mainSession.delegateUntilTestEnd(object : ContentDelegate {
+ override fun onCrash(session: GeckoSession) {
+ mainSession.open()
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ }
+ })
+
+ mainSession.synthesizeTap(5, 5)
+ mainSession.loadUri(CONTENT_CRASH_URL)
+ mainSession.waitForPageStop()
+
+ mainSession.synthesizeTap(5, 5)
+ mainSession.reload()
+ mainSession.waitForPageStop()
+ }
+
+ @AnyThread
+ fun killAllContentProcesses() {
+ val contentProcessPids = sessionRule.getAllSessionPids()
+ for (pid in contentProcessPids) {
+ sessionRule.killContentProcess(pid)
+ }
+ }
+
+ @IgnoreCrash
+ @Test
+ fun killContent() {
+ killAllContentProcesses()
+ mainSession.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onKill(session: GeckoSession) {
+ assertThat(
+ "Session should be closed after being killed",
+ session.isOpen,
+ equalTo(false),
+ )
+ }
+ })
+
+ mainSession.open()
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat("Page should load successfully", success, equalTo(true))
+ }
+ })
+ }
+
+ private fun goFullscreen() {
+ sessionRule.setPrefsUntilTestEnd(mapOf("full-screen-api.allow-trusted-requests-only" to false))
+ mainSession.loadTestPath(FULLSCREEN_PATH)
+ mainSession.waitForPageStop()
+ val promise = mainSession.evaluatePromiseJS("document.querySelector('#fullscreen').requestFullscreen()")
+ sessionRule.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onFullScreen(session: GeckoSession, fullScreen: Boolean) {
+ assertThat("Div went fullscreen", fullScreen, equalTo(true))
+ }
+ })
+ promise.value
+ }
+
+ private fun waitForFullscreenExit() {
+ sessionRule.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onFullScreen(session: GeckoSession, fullScreen: Boolean) {
+ assertThat("Div left fullscreen", fullScreen, equalTo(false))
+ }
+ })
+ }
+
+ @Test fun fullscreen() {
+ goFullscreen()
+ val promise = mainSession.evaluatePromiseJS("document.exitFullscreen()")
+ waitForFullscreenExit()
+ promise.value
+ }
+
+ @Test fun sessionExitFullscreen() {
+ goFullscreen()
+ mainSession.exitFullScreen()
+ waitForFullscreenExit()
+ }
+
+ @Test fun firstComposite() {
+ val display = mainSession.acquireDisplay()
+ val texture = SurfaceTexture(0)
+ texture.setDefaultBufferSize(100, 100)
+ val surface = Surface(texture)
+ display.surfaceChanged(SurfaceInfo.Builder(surface).size(100, 100).build())
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onFirstComposite(session: GeckoSession) {
+ }
+ })
+ display.surfaceDestroyed()
+ display.surfaceChanged(SurfaceInfo.Builder(surface).size(100, 100).build())
+ sessionRule.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onFirstComposite(session: GeckoSession) {
+ }
+ })
+ display.surfaceDestroyed()
+ mainSession.releaseDisplay(display)
+ }
+
+ @WithDisplay(width = 10, height = 10)
+ @Test
+ fun firstContentfulPaint() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onFirstContentfulPaint(session: GeckoSession) {
+ }
+ })
+ }
+
+ @Test fun webAppManifestPref() {
+ val initialState = sessionRule.runtime.settings.getWebManifestEnabled()
+ val jsToRun = "document.querySelector('link[rel=manifest]').relList.supports('manifest');"
+
+ // Check pref'ed off
+ sessionRule.runtime.settings.setWebManifestEnabled(false)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop(mainSession)
+
+ var result = equalTo(mainSession.evaluateJS(jsToRun) as Boolean)
+
+ assertThat("Disabling pref makes relList.supports('manifest') return false", false, result)
+
+ // Check pref'ed on
+ sessionRule.runtime.settings.setWebManifestEnabled(true)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop(mainSession)
+
+ result = equalTo(mainSession.evaluateJS(jsToRun) as Boolean)
+ assertThat("Enabling pref makes relList.supports('manifest') return true", true, result)
+
+ sessionRule.runtime.settings.setWebManifestEnabled(initialState)
+ }
+
+ @Test fun webAppManifest() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitUntilCalled(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat("Page load should succeed", success, equalTo(true))
+ }
+
+ @AssertCalled(count = 1)
+ override fun onWebAppManifest(session: GeckoSession, manifest: JSONObject) {
+ // These values come from the manifest at assets/www/manifest.webmanifest
+ assertThat("name should match", manifest.getString("name"), equalTo("App"))
+ assertThat("short_name should match", manifest.getString("short_name"), equalTo("app"))
+ assertThat("display should match", manifest.getString("display"), equalTo("standalone"))
+
+ // The color here is "cadetblue" converted to #aarrggbb.
+ assertThat("theme_color should match", manifest.getString("theme_color"), equalTo("#ff5f9ea0"))
+ assertThat("background_color should match", manifest.getString("background_color"), equalTo("#eec0ffee"))
+ assertThat("start_url should match", manifest.getString("start_url"), endsWith("/assets/www/start/index.html"))
+
+ val icon = manifest.getJSONArray("icons").getJSONObject(0)
+
+ val iconSrc = Uri.parse(icon.getString("src"))
+ assertThat("icon should have a valid src", iconSrc, notNullValue())
+ assertThat("icon src should be absolute", iconSrc.isAbsolute, equalTo(true))
+ assertThat("icon should have sizes", icon.getString("sizes"), not(isEmptyOrNullString()))
+ assertThat("icon type should match", icon.getString("type"), equalTo("image/gif"))
+ }
+ })
+ }
+
+ @Test fun previewImage() {
+ mainSession.loadTestPath(METATAGS_PATH)
+ mainSession.waitUntilCalled(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPreviewImage(session: GeckoSession, previewImageUrl: String) {
+ assertThat("Preview image should match", previewImageUrl, equalTo("https://test.com/og-image-url"))
+ }
+ })
+ }
+
+ @Test fun viewportFit() {
+ mainSession.loadTestPath(VIEWPORT_PATH)
+ mainSession.waitUntilCalled(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat("Page load should succeed", success, equalTo(true))
+ }
+
+ @AssertCalled(count = 1)
+ override fun onMetaViewportFitChange(session: GeckoSession, viewportFit: String) {
+ assertThat("viewport-fit should match", viewportFit, equalTo("cover"))
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitUntilCalled(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat("Page load should succeed", success, equalTo(true))
+ }
+
+ @AssertCalled(count = 1)
+ override fun onMetaViewportFitChange(session: GeckoSession, viewportFit: String) {
+ assertThat("viewport-fit should match", viewportFit, equalTo("auto"))
+ }
+ })
+ }
+
+ @Test fun closeRequest() {
+ if (!sessionRule.env.isAutomation) {
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.allow_scripts_to_close_windows" to true))
+ }
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ mainSession.evaluateJS("window.close()")
+ mainSession.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onCloseRequest(session: GeckoSession) {
+ }
+ })
+ }
+
+ @Test fun windowOpenClose() {
+ sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ val newSession = sessionRule.createClosedSession()
+ mainSession.delegateDuringNextWait(object : NavigationDelegate {
+ @AssertCalled(count = 1)
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return GeckoResult.fromValue(newSession)
+ }
+ })
+
+ mainSession.evaluateJS("const w = window.open('about:blank'); w.close()")
+
+ newSession.waitUntilCalled(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onCloseRequest(session: GeckoSession) {
+ }
+
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun cookieBannerDetectedEvent() {
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "cookiebanners.service.mode" to CookieBannerMode.COOKIE_BANNER_MODE_REJECT,
+ ),
+ )
+
+ val detectHandled = GeckoResult<Void>()
+ mainSession.delegateUntilTestEnd(object : GeckoSession.ContentDelegate {
+ override fun onCookieBannerDetected(
+ session: GeckoSession,
+ ) {
+ detectHandled.complete(null)
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.triggerCookieBannerDetected()
+
+ sessionRule.waitForResult(detectHandled)
+ }
+
+ @Test fun cookieBannerHandledEvent() {
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "cookiebanners.service.mode" to CookieBannerMode.COOKIE_BANNER_MODE_REJECT,
+ ),
+ )
+
+ val handleHandled = GeckoResult<Void>()
+ mainSession.delegateUntilTestEnd(object : GeckoSession.ContentDelegate {
+ override fun onCookieBannerHandled(
+ session: GeckoSession,
+ ) {
+ handleHandled.complete(null)
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.triggerCookieBannerHandled()
+
+ sessionRule.waitForResult(handleHandled)
+ }
+
+ @WithDisplay(width = 100, height = 100)
+ @Test
+ fun setCursor() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ mainSession.evaluateJS("document.body.style.cursor = 'wait'")
+ mainSession.synthesizeMouseMove(50, 50)
+
+ mainSession.waitUntilCalled(object : ContentDelegate {
+ @AssertCalled(count = 1)
+ override fun onPointerIconChange(session: GeckoSession, icon: PointerIcon) {
+ // PointerIcon has no compare method.
+ }
+ })
+
+ val delegate = mainSession.contentDelegate
+ mainSession.contentDelegate = null
+ mainSession.evaluateJS("document.body.style.cursor = 'text'")
+ for (i in 51..70) {
+ mainSession.synthesizeMouseMove(i, 50)
+ // No wait function since we remove content delegate.
+ mainSession.waitForJS("new Promise(resolve => window.setTimeout(resolve, 100))")
+ }
+ mainSession.contentDelegate = delegate
+ }
+
+ /**
+ * Preferences to induce wanted behaviour.
+ */
+ private fun setHangReportTestPrefs(timeout: Int = 20000) {
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "dom.max_script_run_time" to 1,
+ "dom.max_chrome_script_run_time" to 1,
+ "dom.max_ext_content_script_run_time" to 1,
+ "dom.ipc.cpow.timeout" to 100,
+ "browser.hangNotification.waitPeriod" to timeout,
+ ),
+ )
+ }
+
+ /**
+ * With no delegate set, the default behaviour is to stop hung scripts.
+ */
+ @NullDelegate(ContentDelegate::class)
+ @Test
+ fun stopHungProcessDefault() {
+ setHangReportTestPrefs()
+ mainSession.loadTestPath(HUNG_SCRIPT)
+ sessionRule.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat(
+ "The script did not complete.",
+ mainSession.evaluateJS("document.getElementById(\"content\").innerHTML") as String,
+ equalTo("Started"),
+ )
+ }
+ })
+ sessionRule.waitForPageStop(mainSession)
+ }
+
+ /**
+ * With no overriding implementation for onSlowScript, the default behaviour is to stop hung
+ * scripts.
+ */
+ @Test fun stopHungProcessNull() {
+ setHangReportTestPrefs()
+ sessionRule.delegateUntilTestEnd(object : ContentDelegate, ProgressDelegate {
+ // default onSlowScript returns null
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat(
+ "The script did not complete.",
+ mainSession.evaluateJS("document.getElementById(\"content\").innerHTML") as String,
+ equalTo("Started"),
+ )
+ }
+ })
+ mainSession.loadTestPath(HUNG_SCRIPT)
+ sessionRule.waitForPageStop(mainSession)
+ }
+
+ /**
+ * Test that, with a 'do nothing' delegate, the hung process completes after its delay
+ */
+ @Test fun stopHungProcessDoNothing() {
+ setHangReportTestPrefs()
+ var scriptHungReportCount = 0
+ sessionRule.delegateUntilTestEnd(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled()
+ override fun onSlowScript(geckoSession: GeckoSession, scriptFileName: String): GeckoResult<SlowScriptResponse> {
+ scriptHungReportCount += 1
+ return GeckoResult.fromValue(null)
+ }
+
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat("The delegate was informed of the hang repeatedly", scriptHungReportCount, greaterThan(1))
+ assertThat(
+ "The script did complete.",
+ mainSession.evaluateJS("document.getElementById(\"content\").innerHTML") as String,
+ equalTo("Finished"),
+ )
+ }
+ })
+ mainSession.loadTestPath(HUNG_SCRIPT)
+ sessionRule.waitForPageStop(mainSession)
+ }
+
+ /**
+ * Test that the delegate is called and can stop a hung script
+ */
+ @Test fun stopHungProcess() {
+ setHangReportTestPrefs()
+ sessionRule.delegateUntilTestEnd(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1, order = [1])
+ override fun onSlowScript(geckoSession: GeckoSession, scriptFileName: String): GeckoResult<SlowScriptResponse> {
+ return GeckoResult.fromValue(SlowScriptResponse.STOP)
+ }
+
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat(
+ "The script did not complete.",
+ mainSession.evaluateJS("document.getElementById(\"content\").innerHTML") as String,
+ equalTo("Started"),
+ )
+ }
+ })
+ mainSession.loadTestPath(HUNG_SCRIPT)
+ sessionRule.waitForPageStop(mainSession)
+ }
+
+ /**
+ * Test that the delegate is called and can continue executing hung scripts
+ */
+ @Test fun stopHungProcessWait() {
+ setHangReportTestPrefs()
+ sessionRule.delegateUntilTestEnd(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 1, order = [1])
+ override fun onSlowScript(geckoSession: GeckoSession, scriptFileName: String): GeckoResult<SlowScriptResponse> {
+ return GeckoResult.fromValue(SlowScriptResponse.CONTINUE)
+ }
+
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat(
+ "The script did complete.",
+ mainSession.evaluateJS("document.getElementById(\"content\").innerHTML") as String,
+ equalTo("Finished"),
+ )
+ }
+ })
+ mainSession.loadTestPath(HUNG_SCRIPT)
+ sessionRule.waitForPageStop(mainSession)
+ }
+
+ /**
+ * Test that the delegate is called and paused scripts re-notify after the wait period
+ */
+ @Test fun stopHungProcessWaitThenStop() {
+ setHangReportTestPrefs(500)
+ var scriptWaited = false
+ sessionRule.delegateUntilTestEnd(object : ContentDelegate, ProgressDelegate {
+ @AssertCalled(count = 2, order = [1, 2])
+ override fun onSlowScript(geckoSession: GeckoSession, scriptFileName: String): GeckoResult<SlowScriptResponse> {
+ return if (!scriptWaited) {
+ scriptWaited = true
+ GeckoResult.fromValue(SlowScriptResponse.CONTINUE)
+ } else {
+ GeckoResult.fromValue(SlowScriptResponse.STOP)
+ }
+ }
+
+ @AssertCalled(count = 1, order = [3])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ assertThat(
+ "The script did not complete.",
+ mainSession.evaluateJS("document.getElementById(\"content\").innerHTML") as String,
+ equalTo("Started"),
+ )
+ }
+ })
+ mainSession.loadTestPath(HUNG_SCRIPT)
+ sessionRule.waitForPageStop(mainSession)
+ }
+
+ /**
+ * Test that the display mode is applied to CSS media query
+ */
+ @Test fun displayMode() {
+ val pwaSession = sessionRule.createOpenSession(
+ GeckoSessionSettings.Builder(mainSession.settings)
+ .displayMode(GeckoSessionSettings.DISPLAY_MODE_FULLSCREEN)
+ .build(),
+ )
+ pwaSession.loadTestPath(HELLO_HTML_PATH)
+ pwaSession.waitForPageStop()
+
+ val matches = pwaSession.evaluateJS("window.matchMedia('(display-mode: fullscreen)').matches") as Boolean
+ assertThat(
+ "display-mode should be fullscreen",
+ matches,
+ equalTo(true),
+ )
+ }
+}