summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt')
-rw-r--r--mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt2114
1 files changed, 2114 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt
new file mode 100644
index 0000000000..d7169c0266
--- /dev/null
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/GeckoSessionTestRuleTest.kt
@@ -0,0 +1,2114 @@
+/* -*- 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.os.Handler
+import android.os.Looper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.hamcrest.Matchers.* // ktlint-disable no-wildcard-imports
+import org.json.JSONArray
+import org.json.JSONObject
+import org.junit.Assume.assumeThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mozilla.geckoview.ContentBlocking.CookieBannerMode
+import org.mozilla.geckoview.GeckoResult
+import org.mozilla.geckoview.GeckoSession
+import org.mozilla.geckoview.GeckoSession.ContentDelegate
+import org.mozilla.geckoview.GeckoSession.HistoryDelegate
+import org.mozilla.geckoview.GeckoSession.NavigationDelegate
+import org.mozilla.geckoview.GeckoSession.PermissionDelegate
+import org.mozilla.geckoview.GeckoSession.ProgressDelegate
+import org.mozilla.geckoview.GeckoSession.PromptDelegate
+import org.mozilla.geckoview.GeckoSession.ScrollDelegate
+import org.mozilla.geckoview.GeckoSession.SessionState
+import org.mozilla.geckoview.GeckoSessionSettings
+import org.mozilla.geckoview.WebRequestError
+import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.* // ktlint-disable no-wildcard-imports
+import org.mozilla.geckoview.test.util.UiThreadUtils
+
+/**
+ * Test for the GeckoSessionTestRule class, to ensure it properly sets up a session for
+ * each test, and to ensure it can properly wait for and assert delegate
+ * callbacks.
+ */
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+class GeckoSessionTestRuleTest : BaseSessionTest(noErrorCollector = true) {
+
+ @Test fun getSession() {
+ assertThat("Can get session", mainSession, notNullValue())
+ assertThat(
+ "Session is open",
+ mainSession.isOpen,
+ equalTo(true),
+ )
+ }
+
+ @ClosedSessionAtStart
+ @Test
+ fun getSession_closedSession() {
+ assertThat("Session is closed", mainSession.isOpen, equalTo(false))
+ }
+
+ @Setting.List(
+ Setting(key = Setting.Key.USE_PRIVATE_MODE, value = "true"),
+ Setting(key = Setting.Key.DISPLAY_MODE, value = "DISPLAY_MODE_MINIMAL_UI"),
+ Setting(key = Setting.Key.ALLOW_JAVASCRIPT, value = "false"),
+ )
+ @Setting(key = Setting.Key.USE_TRACKING_PROTECTION, value = "true")
+ @Test
+ fun settingsApplied() {
+ assertThat(
+ "USE_PRIVATE_MODE should be set",
+ mainSession.settings.usePrivateMode,
+ equalTo(true),
+ )
+ assertThat(
+ "DISPLAY_MODE should be set",
+ mainSession.settings.displayMode,
+ equalTo(GeckoSessionSettings.DISPLAY_MODE_MINIMAL_UI),
+ )
+ assertThat(
+ "USE_TRACKING_PROTECTION should be set",
+ mainSession.settings.useTrackingProtection,
+ equalTo(true),
+ )
+ assertThat(
+ "ALLOW_JAVASCRIPT should be set",
+ mainSession.settings.allowJavascript,
+ equalTo(false),
+ )
+ }
+
+ @Test(expected = UiThreadUtils.TimeoutException::class)
+ @TimeoutMillis(2000)
+ fun noPendingCallbacks() {
+ // Make sure we don't have unexpected pending callbacks at the start of a test.
+ sessionRule.waitUntilCalled(object : ProgressDelegate, HistoryDelegate {
+ // There may be extraneous onSessionStateChange and onHistoryStateChange calls
+ // after a test, so ignore the first received.
+ @AssertCalled(count = 2)
+ override fun onSessionStateChange(session: GeckoSession, state: SessionState) {
+ }
+
+ @AssertCalled(count = 2)
+ override fun onHistoryStateChange(session: GeckoSession, historyList: HistoryDelegate.HistoryList) {
+ }
+ })
+ }
+
+ @NullDelegate.List(
+ NullDelegate(ContentDelegate::class),
+ NullDelegate(NavigationDelegate::class),
+ )
+ @NullDelegate(ScrollDelegate::class)
+ @Test
+ fun nullDelegate() {
+ assertThat(
+ "Content delegate should be null",
+ mainSession.contentDelegate,
+ nullValue(),
+ )
+ assertThat(
+ "Navigation delegate should be null",
+ mainSession.navigationDelegate,
+ nullValue(),
+ )
+ assertThat(
+ "Scroll delegate should be null",
+ mainSession.scrollDelegate,
+ nullValue(),
+ )
+
+ assertThat(
+ "Progress delegate should not be null",
+ mainSession.progressDelegate,
+ notNullValue(),
+ )
+ }
+
+ @NullDelegate(ProgressDelegate::class)
+ @ClosedSessionAtStart
+ @Test
+ fun nullDelegate_closed() {
+ assertThat(
+ "Progress delegate should be null",
+ mainSession.progressDelegate,
+ nullValue(),
+ )
+ }
+
+ @Test(expected = AssertionError::class)
+ @NullDelegate(ProgressDelegate::class)
+ @ClosedSessionAtStart
+ fun nullDelegate_requireProgressOnOpen() {
+ assertThat(
+ "Progress delegate should be null",
+ mainSession.progressDelegate,
+ nullValue(),
+ )
+
+ mainSession.open()
+ }
+
+ @Test fun waitForPageStop() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun waitForPageStops() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitForPageStops(2)
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test(expected = AssertionError::class)
+ @NullDelegate(ProgressDelegate::class)
+ @ClosedSessionAtStart
+ fun waitForPageStops_throwOnNullDelegate() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ mainSession.open(sessionRule.runtime) // Avoid waiting for initial load
+ mainSession.reload()
+ mainSession.waitForPageStops(2)
+ }
+
+ @Test fun waitUntilCalled_anyInterfaceMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(ProgressDelegate::class)
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+
+ override fun onSecurityChange(
+ session: GeckoSession,
+ securityInfo: ProgressDelegate.SecurityInformation,
+ ) {
+ counter++
+ }
+
+ override fun onProgressChange(session: GeckoSession, progress: Int) {
+ counter++
+ }
+
+ override fun onSessionStateChange(session: GeckoSession, state: SessionState) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun waitUntilCalled_specificInterfaceMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(
+ ProgressDelegate::class,
+ "onPageStart",
+ "onPageStop",
+ )
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test fun waitUntilCalled_shouldContinue() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ProgressDelegate, ShouldContinue {
+ var pageStart = false
+
+ override fun shouldContinue(): Boolean = pageStart
+
+ override fun onPageStart(session: GeckoSession, url: String) {
+ pageStart = true
+ }
+
+ // This is here to verify that we don't wait on all methods of this object
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+
+ // This is to verify that the above only waits until pageStart, but not pageStop.
+ // If the above block waits until pageStop, this will time out, indicating a problem.
+ sessionRule.waitForPageStop()
+ }
+
+ @Test(expected = AssertionError::class)
+ fun waitUntilCalled_throwOnNotGeckoSessionInterface() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(CharSequence::class)
+ }
+
+ fun waitUntilCalled_notThrowOnCallbackInterface() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(ProgressDelegate::class)
+ }
+
+ @NullDelegate(ScrollDelegate::class)
+ @Test
+ fun waitUntilCalled_notThrowOnNonNullDelegateMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ mainSession.reload()
+ mainSession.waitUntilCalled(ProgressDelegate::class, "onPageStop")
+ }
+
+ @Test fun waitUntilCalled_anyObjectMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+
+ var counter = 0
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+
+ override fun onSecurityChange(
+ session: GeckoSession,
+ securityInfo: ProgressDelegate.SecurityInformation,
+ ) {
+ counter++
+ }
+
+ override fun onProgressChange(session: GeckoSession, progress: Int) {
+ counter++
+ }
+
+ override fun onSessionStateChange(session: GeckoSession, state: SessionState) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun waitUntilCalled_specificObjectMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+
+ var counter = 0
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test(expected = AssertionError::class)
+ @NullDelegate(ScrollDelegate::class)
+ fun waitUntilCalled_throwOnNullDelegateObject() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ mainSession.reload()
+ mainSession.waitUntilCalled(object : ScrollDelegate {
+ @AssertCalled
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @NullDelegate(ScrollDelegate::class)
+ @Test
+ fun waitUntilCalled_notThrowOnNonNullDelegateObject() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ mainSession.reload()
+ mainSession.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun waitUntilCalled_multipleCount() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+
+ var counter = 0
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 2)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(4))
+ }
+
+ @Test fun waitUntilCalled_currentCall() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+
+ var counter = 0
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 2, order = [1, 2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ val info = sessionRule.currentCall
+ assertThat("Method info should be valid", info, notNullValue())
+ assertThat(
+ "Counter should be correct",
+ info.counter,
+ equalTo(forEachCall(1, 2)),
+ )
+ assertThat(
+ "Order should equal counter",
+ info.order,
+ equalTo(info.counter),
+ )
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun waitUntilCalled_passThroughExceptions() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ throw IllegalStateException()
+ }
+ })
+ }
+
+ @Test fun waitUntilCalled_zeroCount() {
+ // Support having @AssertCalled(count = 0) annotations for waitUntilCalled calls.
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ProgressDelegate, ScrollDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+
+ @AssertCalled(count = 0)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_anyMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnAnyMethodNotCalled() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ScrollDelegate {})
+ }
+
+ @Test fun forCallbacksDuringWait_specificMethod() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test fun forCallbacksDuringWait_specificMethodMultipleTimes() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitForPageStops(2)
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(4))
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnSpecificMethodNotCalled() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ScrollDelegate {
+ @AssertCalled
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @Test fun waitUntilCalled_specificCount() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+
+ var counter = 0
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 2)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(4))
+ }
+
+ @Test fun forCallbacksDuringWait_specificCount() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitForPageStops(2)
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 2)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(4))
+ }
+
+ @Test(expected = AssertionError::class)
+ fun waitUntilCalled_throwOnWrongCount() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnWrongCount() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitForPageStops(2)
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun waitUntilCalled_specificOrder() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(order = [1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_specificOrder() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(order = [1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun waitUntilCalled_throwOnWrongOrder() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(order = [2])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(order = [1])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnWrongOrder() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(order = [2])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(order = [1])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_multipleOrder() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitForPageStops(2)
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(order = [1, 3, 1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(order = [2, 4, 1])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnWrongMultipleOrder() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ sessionRule.waitForPageStops(2)
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(order = [1, 2, 1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(order = [3, 4, 1])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_notCalled() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ScrollDelegate {
+ @AssertCalled(false)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun waitUntilCalled_throwOnCallingZeroCall() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 0)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ fun waitUntilCalled_assertCalledFalseNoTimeout() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate, NavigationDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {}
+
+ @AssertCalled(false)
+ override fun onLoadError(
+ session: GeckoSession,
+ uri: String?,
+ error: WebRequestError,
+ ): GeckoResult<String>? {
+ return null
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun waitUntilCalled_throwOnCallingNoCall() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {}
+
+ @AssertCalled(false)
+ override fun onPageStart(session: GeckoSession, url: String) {}
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnCallingNoCall() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_zeroCountEqualsNotCalled() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ScrollDelegate {
+ @AssertCalled(count = 0)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun forCallbacksDuringWait_throwOnCallingZeroCount() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 0)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_limitedToLastWait() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.reload()
+ mainSession.reload()
+ mainSession.reload()
+
+ // Wait for Gecko to finish all loads.
+ Thread.sleep(100)
+
+ sessionRule.waitForPageStop() // Wait for loadUri.
+ sessionRule.waitForPageStop() // Wait for first reload.
+
+ var counter = 0
+
+ // assert should only apply to callbacks within range (loadUri, first reload].
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test fun forCallbacksDuringWait_currentCall() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ val info = sessionRule.currentCall
+ assertThat("Method info should be valid", info, notNullValue())
+ assertThat(
+ "Counter should be correct",
+ info.counter,
+ equalTo(1),
+ )
+ assertThat(
+ "Order should equal counter",
+ info.order,
+ equalTo(0),
+ )
+ }
+ })
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun forCallbacksDuringWait_passThroughExceptions() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ throw IllegalStateException()
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ @NullDelegate(ScrollDelegate::class)
+ fun forCallbacksDuringWait_throwOnAnyNullDelegate() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ mainSession.reload()
+ mainSession.waitForPageStop()
+
+ mainSession.forCallbacksDuringWait(object : NavigationDelegate, ScrollDelegate {})
+ }
+
+ @Test(expected = AssertionError::class)
+ @NullDelegate(ScrollDelegate::class)
+ fun forCallbacksDuringWait_throwOnSpecificNullDelegate() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ mainSession.reload()
+ mainSession.waitForPageStop()
+
+ mainSession.forCallbacksDuringWait(object : ScrollDelegate {
+ @AssertCalled
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @NullDelegate(ScrollDelegate::class)
+ @Test
+ fun forCallbacksDuringWait_notThrowOnNonNullDelegate() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ mainSession.reload()
+ mainSession.waitForPageStop()
+
+ mainSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun getCurrentCall_throwOnNoCurrentCall() {
+ sessionRule.currentCall
+ }
+
+ @Test fun delegateUntilTestEnd() {
+ var counter = 0
+
+ sessionRule.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(count = 1, order = [1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test fun delegateUntilTestEnd_notCalled() {
+ sessionRule.delegateUntilTestEnd(object : ScrollDelegate {
+ @AssertCalled(false)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ }
+
+ @Test(expected = AssertionError::class)
+ fun delegateUntilTestEnd_throwOnNotCalled() {
+ sessionRule.delegateUntilTestEnd(object : ScrollDelegate {
+ @AssertCalled(count = 1)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ sessionRule.performTestEndCheck()
+ }
+
+ @Test(expected = AssertionError::class)
+ fun delegateUntilTestEnd_throwOnCallingNoCall() {
+ sessionRule.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test(expected = AssertionError::class)
+ fun delegateUntilTestEnd_throwOnWrongOrder() {
+ sessionRule.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ }
+
+ @AssertCalled(count = 1, order = [1])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test fun delegateUntilTestEnd_currentCall() {
+ sessionRule.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ val info = sessionRule.currentCall
+ assertThat("Method info should be valid", info, notNullValue())
+ assertThat(
+ "Counter should be correct",
+ info.counter,
+ equalTo(1),
+ )
+ assertThat(
+ "Order should equal counter",
+ info.order,
+ equalTo(0),
+ )
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test fun delegateDuringNextWait() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ var counter = 0
+
+ sessionRule.delegateDuringNextWait(object : ProgressDelegate {
+ @AssertCalled(count = 1, order = [1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ counter++
+ }
+
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ assertThat("Should have delegated", counter, equalTo(2))
+
+ mainSession.reload()
+ sessionRule.waitForPageStop()
+
+ assertThat("Delegate should be cleared", counter, equalTo(2))
+ }
+
+ @Test(expected = AssertionError::class)
+ fun delegateDuringNextWait_throwOnNotCalled() {
+ sessionRule.delegateDuringNextWait(object : ScrollDelegate {
+ @AssertCalled(count = 1)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test(expected = AssertionError::class)
+ fun delegateDuringNextWait_throwOnNotCalledAtTestEnd() {
+ sessionRule.delegateDuringNextWait(object : ScrollDelegate {
+ @AssertCalled(count = 1)
+ override fun onScrollChanged(session: GeckoSession, scrollX: Int, scrollY: Int) {
+ }
+ })
+ sessionRule.performTestEndCheck()
+ }
+
+ @Test fun delegateDuringNextWait_hasPrecedence() {
+ var testCounter = 0
+ var waitCounter = 0
+
+ sessionRule.delegateUntilTestEnd(object :
+ ProgressDelegate,
+ NavigationDelegate {
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ testCounter++
+ }
+
+ @AssertCalled(count = 1, order = [4])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ testCounter++
+ }
+
+ @AssertCalled(count = 2, order = [1, 3])
+ override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) {
+ testCounter++
+ }
+
+ @AssertCalled(count = 2, order = [1, 3])
+ override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) {
+ testCounter++
+ }
+ })
+
+ sessionRule.delegateDuringNextWait(object : ProgressDelegate {
+ @AssertCalled(count = 1, order = [1])
+ override fun onPageStart(session: GeckoSession, url: String) {
+ waitCounter++
+ }
+
+ @AssertCalled(count = 1, order = [2])
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ waitCounter++
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ assertThat(
+ "Text delegate should be overridden",
+ testCounter,
+ equalTo(2),
+ )
+ assertThat("Wait delegate should be used", waitCounter, equalTo(2))
+
+ mainSession.reload()
+ sessionRule.waitForPageStop()
+
+ assertThat("Test delegate should be used", testCounter, equalTo(6))
+ assertThat("Wait delegate should be cleared", waitCounter, equalTo(2))
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun delegateDuringNextWait_passThroughExceptions() {
+ sessionRule.delegateDuringNextWait(object : ProgressDelegate {
+ @AssertCalled
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ throw IllegalStateException()
+ }
+ })
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test(expected = AssertionError::class)
+ @NullDelegate(NavigationDelegate::class)
+ fun delegateDuringNextWait_throwOnNullDelegate() {
+ mainSession.delegateDuringNextWait(object : NavigationDelegate {
+ override fun onLocationChange(session: GeckoSession, url: String?, perms: MutableList<PermissionDelegate.ContentPermission>) {
+ }
+ })
+ }
+
+ @Test fun wrapSession() {
+ val session = sessionRule.wrapSession(
+ GeckoSession(mainSession.settings),
+ )
+ sessionRule.openSession(session)
+ session.reload()
+ session.waitForPageStop()
+ }
+
+ @Test fun createOpenSession() {
+ val newSession = sessionRule.createOpenSession()
+ assertThat("Can create session", newSession, notNullValue())
+ assertThat("New session is open", newSession.isOpen, equalTo(true))
+ assertThat(
+ "New session has same settings",
+ newSession.settings,
+ equalTo(mainSession.settings),
+ )
+ }
+
+ @Test fun createOpenSession_withSettings() {
+ val settings = GeckoSessionSettings.Builder(mainSession.settings)
+ .usePrivateMode(true)
+ .build()
+
+ val newSession = sessionRule.createOpenSession(settings)
+ assertThat("New session has same settings", newSession.settings, equalTo(settings))
+ }
+
+ @Test fun createOpenSession_canInterleaveOtherCalls() {
+ // TODO: Bug 1673953
+ assumeThat(sessionRule.env.isFission, equalTo(false))
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+
+ val newSession = sessionRule.createOpenSession()
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStops(2)
+
+ newSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+
+ mainSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun createClosedSession() {
+ val newSession = sessionRule.createClosedSession()
+ assertThat("Can create session", newSession, notNullValue())
+ assertThat("New session is open", newSession.isOpen, equalTo(false))
+ assertThat(
+ "New session has same settings",
+ newSession.settings,
+ equalTo(mainSession.settings),
+ )
+ }
+
+ @Test fun createClosedSession_withSettings() {
+ val settings = GeckoSessionSettings.Builder(mainSession.settings).usePrivateMode(true).build()
+
+ val newSession = sessionRule.createClosedSession(settings)
+ assertThat("New session has same settings", newSession.settings, equalTo(settings))
+ }
+
+ @Test(expected = UiThreadUtils.TimeoutException::class)
+ @TimeoutMillis(2000)
+ @ClosedSessionAtStart
+ fun noPendingCallbacks_withSpecificSession() {
+ sessionRule.createOpenSession()
+ // Make sure we don't have unexpected pending callbacks after opening a session.
+ sessionRule.waitUntilCalled(object : HistoryDelegate, ProgressDelegate {
+ // There may be extraneous onSessionStateChange and onHistoryStateChange calls
+ // after a test, so ignore the first received.
+ @AssertCalled(count = 2)
+ override fun onSessionStateChange(session: GeckoSession, state: SessionState) {
+ }
+
+ @AssertCalled(count = 2)
+ override fun onHistoryStateChange(session: GeckoSession, historyList: HistoryDelegate.HistoryList) {
+ }
+ })
+ }
+
+ @Test fun waitForPageStop_withSpecificSession() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitForPageStop()
+ }
+
+ @Test fun waitForPageStop_withAllSessions() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test(expected = AssertionError::class)
+ fun waitForPageStop_throwOnNotWrapped() {
+ GeckoSession(mainSession.settings).waitForPageStop()
+ }
+
+ @Test fun waitForPageStops_withSpecificSessions() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.reload()
+ newSession.waitForPageStops(2)
+ }
+
+ @Test fun waitForPageStops_withAllSessions() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStops(2)
+ }
+
+ @Test fun waitForPageStops_acrossSessionCreation() {
+ // TODO: Bug 1673953
+ assumeThat(sessionRule.env.isFission, equalTo(false))
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ val session = sessionRule.createOpenSession()
+ mainSession.reload()
+ session.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStops(3)
+ }
+
+ @Test fun waitUntilCalled_interfaceWithSpecificSession() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitUntilCalled(ProgressDelegate::class, "onPageStop")
+ }
+
+ @Test fun waitUntilCalled_interfaceWithAllSessions() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(ProgressDelegate::class, "onPageStop")
+ }
+
+ @Test fun waitUntilCalled_callbackWithSpecificSession() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun waitUntilCalled_callbackWithAllSessions() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitUntilCalled(object : ProgressDelegate {
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ }
+ })
+ }
+
+ @Test fun forCallbacksDuringWait_withSpecificSession() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitForPageStop()
+
+ var counter = 0
+
+ newSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ mainSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun forCallbacksDuringWait_withAllSessions() {
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStops(2)
+
+ var counter = 0
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 2)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test fun forCallbacksDuringWait_limitedToLastSessionWait() {
+ val newSession = sessionRule.createOpenSession()
+
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitForPageStop()
+
+ // forCallbacksDuringWait calls strictly apply to the last wait, session-specific or not.
+ var counter = 0
+
+ mainSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ newSession.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ sessionRule.forCallbacksDuringWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @Test fun delegateUntilTestEnd_withSpecificSession() {
+ val newSession = sessionRule.createOpenSession()
+
+ var counter = 0
+
+ newSession.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ mainSession.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitForPageStop()
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun delegateUntilTestEnd_withAllSessions() {
+ var counter = 0
+
+ sessionRule.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitForPageStop()
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun delegateDuringNextWait_hasPrecedenceWithSpecificSession() {
+ val newSession = sessionRule.createOpenSession()
+ var counter = 0
+
+ newSession.delegateDuringNextWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ newSession.delegateUntilTestEnd(object : ProgressDelegate {
+ @AssertCalled(false)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStops(2)
+
+ assertThat("Callback count should be correct", counter, equalTo(1))
+ }
+
+ @Test fun delegateDuringNextWait_specificSessionOverridesAll() {
+ val newSession = sessionRule.createOpenSession()
+ var counter = 0
+
+ newSession.delegateDuringNextWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ sessionRule.delegateDuringNextWait(object : ProgressDelegate {
+ @AssertCalled(count = 1)
+ override fun onPageStop(session: GeckoSession, success: Boolean) {
+ counter++
+ }
+ })
+
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStops(2)
+
+ assertThat("Callback count should be correct", counter, equalTo(2))
+ }
+
+ @WithDisplay(width = 100, height = 100)
+ @Test
+ fun synthesizeTap() {
+ mainSession.loadTestPath(CLICK_TO_RELOAD_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ mainSession.synthesizeTap(50, 50)
+ mainSession.waitForPageStop()
+ }
+
+ @WithDisplay(width = 100, height = 100)
+ @Test
+ fun synthesizeMouseMove() {
+ mainSession.loadTestPath(MOUSE_TO_RELOAD_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ mainSession.synthesizeMouseMove(50, 50)
+ mainSession.waitForPageStop()
+ }
+
+ @Test fun evaluateExtensionJS() {
+ assertThat(
+ "JS string result should be correct",
+ sessionRule.evaluateExtensionJS("return 'foo';") as String,
+ equalTo("foo"),
+ )
+
+ assertThat(
+ "JS number result should be correct",
+ sessionRule.evaluateExtensionJS("return 1+1;") as Double,
+ equalTo(2.0),
+ )
+
+ assertThat(
+ "JS boolean result should be correct",
+ sessionRule.evaluateExtensionJS("return !0;") as Boolean,
+ equalTo(true),
+ )
+
+ val expected = JSONObject("{bar:42,baz:true,foo:'bar'}")
+ val actual = sessionRule.evaluateExtensionJS("return {foo:'bar',bar:42,baz:true};") as JSONObject
+ for (key in expected.keys()) {
+ assertThat(
+ "JS object result should be correct",
+ actual.get(key),
+ equalTo(expected.get(key)),
+ )
+ }
+
+ assertThat(
+ "JS array result should be correct",
+ sessionRule.evaluateExtensionJS("return [1,2,3];") as JSONArray,
+ equalTo(JSONArray("[1,2,3]")),
+ )
+
+ assertThat(
+ "Can access extension APIS",
+ sessionRule.evaluateExtensionJS("return !!browser.runtime;") as Boolean,
+ equalTo(true),
+ )
+
+ assertThat(
+ "Can access extension APIS",
+ sessionRule.evaluateExtensionJS(
+ """
+ return true;
+ // Comments at the end are allowed
+ """.trimIndent(),
+ ) as Boolean,
+ equalTo(true),
+ )
+
+ try {
+ sessionRule.evaluateExtensionJS("test({ what")
+ assertThat("Should fail", true, equalTo(false))
+ } catch (e: RejectedPromiseException) {
+ assertThat(
+ "Syntax errors are reported",
+ e.message,
+ containsString("SyntaxError"),
+ )
+ }
+ }
+
+ @Test fun evaluateJS() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ assertThat(
+ "JS string result should be correct",
+ mainSession.evaluateJS("'foo'") as String,
+ equalTo("foo"),
+ )
+
+ assertThat(
+ "JS number result should be correct",
+ mainSession.evaluateJS("1+1") as Double,
+ equalTo(2.0),
+ )
+
+ assertThat(
+ "JS boolean result should be correct",
+ mainSession.evaluateJS("!0") as Boolean,
+ equalTo(true),
+ )
+
+ val expected = JSONObject("{bar:42,baz:true,foo:'bar'}")
+ val actual = mainSession.evaluateJS("({foo:'bar',bar:42,baz:true})") as JSONObject
+ for (key in expected.keys()) {
+ assertThat(
+ "JS object result should be correct",
+ actual.get(key),
+ equalTo(expected.get(key)),
+ )
+ }
+
+ assertThat(
+ "JS array result should be correct",
+ mainSession.evaluateJS("[1,2,3]") as JSONArray,
+ equalTo(JSONArray("[1,2,3]")),
+ )
+
+ assertThat(
+ "JS DOM object result should be correct",
+ mainSession.evaluateJS("document.body.tagName") as String,
+ equalTo("BODY"),
+ )
+ }
+
+ @Test fun evaluateJS_windowObject() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ assertThat(
+ "JS DOM window result should be correct",
+ (mainSession.evaluateJS("window.location.pathname")) as String,
+ equalTo(HELLO_HTML_PATH),
+ )
+ }
+
+ @Test fun evaluateJS_multipleSessions() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ mainSession.evaluateJS("this.foo = 42")
+ assertThat(
+ "Variable should be set",
+ mainSession.evaluateJS("this.foo") as Double,
+ equalTo(42.0),
+ )
+
+ val newSession = sessionRule.createOpenSession()
+ newSession.loadTestPath(HELLO_HTML_PATH)
+ newSession.waitForPageStop()
+
+ val result = newSession.evaluateJS("this.foo")
+ assertThat(
+ "New session should have separate JS context",
+ result,
+ nullValue(),
+ )
+ }
+
+ @Test fun evaluateJS_supportPromises() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ assertThat(
+ "Can get resolved promise",
+ mainSession.evaluatePromiseJS(
+ "new Promise(resolve => resolve('foo'))",
+ ).value as String,
+ equalTo("foo"),
+ )
+
+ val promise = mainSession.evaluatePromiseJS(
+ "new Promise(r => window.resolve = r)",
+ )
+
+ mainSession.evaluateJS("window.resolve('bar')")
+
+ assertThat(
+ "Can wait for promise to resolve",
+ promise.value as String,
+ equalTo("bar"),
+ )
+ }
+
+ @Test(expected = RejectedPromiseException::class)
+ fun evaluateJS_throwOnRejectedPromise() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.evaluatePromiseJS("Promise.reject('foo')").value
+ }
+
+ @Test fun evaluateJS_notBlockMainThread() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ // Test that we can still receive delegate callbacks during evaluateJS,
+ // by calling alert(), which blocks until prompt delegate is called.
+ assertThat(
+ "JS blocking result should be correct",
+ mainSession.evaluateJS("alert(); 'foo'") as String,
+ equalTo("foo"),
+ )
+ }
+
+ @TimeoutMillis(1000)
+ @Test(expected = UiThreadUtils.TimeoutException::class)
+ fun evaluateJS_canTimeout() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.delegateUntilTestEnd(object : PromptDelegate {
+ override fun onAlertPrompt(session: GeckoSession, prompt: PromptDelegate.AlertPrompt): GeckoResult<PromptDelegate.PromptResponse> {
+ // Return a GeckoResult that we will never complete, so it hangs.
+ val res = GeckoResult<PromptDelegate.PromptResponse>()
+ return res
+ }
+ })
+ mainSession.evaluateJS("new Promise(resolve => window.setTimeout(resolve, 2000))")
+ }
+
+ @Test(expected = RuntimeException::class)
+ fun evaluateJS_throwOnJSException() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.evaluateJS("throw Error()")
+ }
+
+ @Test(expected = RuntimeException::class)
+ fun evaluateJS_throwOnSyntaxError() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.evaluateJS("<{[")
+ }
+
+ @Test(expected = RuntimeException::class)
+ fun evaluateJS_throwOnChromeAccess() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+ mainSession.evaluateJS("ChromeUtils")
+ }
+
+ @Test fun getPrefs_undefinedPrefReturnsNull() {
+ assertThat(
+ "Undefined pref should have null value",
+ sessionRule.getPrefs("invalid.pref")[0],
+ equalTo(JSONObject.NULL),
+ )
+ }
+
+ @Test fun setPrefsUntilTestEnd() {
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "test.pref.bool" to true,
+ "test.pref.int" to 1,
+ "test.pref.foo" to "foo",
+ ),
+ )
+
+ var prefs = sessionRule.getPrefs(
+ "test.pref.bool",
+ "test.pref.int",
+ "test.pref.foo",
+ "test.pref.bar",
+ )
+
+ assertThat("Prefs should be set", prefs[0] as Boolean, equalTo(true))
+ assertThat("Prefs should be set", prefs[1] as Int, equalTo(1))
+ assertThat("Prefs should be set", prefs[2] as String, equalTo("foo"))
+ assertThat("Prefs should be set", prefs[3], equalTo(JSONObject.NULL))
+
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "test.pref.foo" to "bar",
+ "test.pref.bar" to "baz",
+ ),
+ )
+
+ prefs = sessionRule.getPrefs(
+ "test.pref.bool",
+ "test.pref.int",
+ "test.pref.foo",
+ "test.pref.bar",
+ )
+
+ assertThat("New prefs should be set", prefs[0] as Boolean, equalTo(true))
+ assertThat("New prefs should be set", prefs[1] as Int, equalTo(1))
+ assertThat("New prefs should be set", prefs[2] as String, equalTo("bar"))
+ assertThat("New prefs should be set", prefs[3] as String, equalTo("baz"))
+ }
+
+ @Test fun setPrefsDuringNextWait() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.setPrefsDuringNextWait(
+ mapOf(
+ "test.pref.bool" to true,
+ "test.pref.int" to 1,
+ "test.pref.foo" to "foo",
+ ),
+ )
+
+ var prefs = sessionRule.getPrefs(
+ "test.pref.bool",
+ "test.pref.int",
+ "test.pref.foo",
+ )
+
+ assertThat("Prefs should be set before wait", prefs[0] as Boolean, equalTo(true))
+ assertThat("Prefs should be set before wait", prefs[1] as Int, equalTo(1))
+ assertThat("Prefs should be set before wait", prefs[2] as String, equalTo("foo"))
+
+ mainSession.reload()
+ mainSession.waitForPageStop()
+
+ prefs = sessionRule.getPrefs(
+ "test.pref.bool",
+ "test.pref.int",
+ "test.pref.foo",
+ )
+
+ assertThat("Prefs should be cleared after wait", prefs[0], equalTo(JSONObject.NULL))
+ assertThat("Prefs should be cleared after wait", prefs[1], equalTo(JSONObject.NULL))
+ assertThat("Prefs should be cleared after wait", prefs[2], equalTo(JSONObject.NULL))
+ }
+
+ @Test fun setPrefsDuringNextWait_hasPrecedence() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "test.pref.int" to 1,
+ "test.pref.foo" to "foo",
+ ),
+ )
+
+ sessionRule.setPrefsDuringNextWait(
+ mapOf(
+ "test.pref.foo" to "bar",
+ "test.pref.bar" to "baz",
+ ),
+ )
+
+ var prefs = sessionRule.getPrefs(
+ "test.pref.int",
+ "test.pref.foo",
+ "test.pref.bar",
+ )
+
+ assertThat("Prefs should be overridden", prefs[0] as Int, equalTo(1))
+ assertThat("Prefs should be overridden", prefs[1] as String, equalTo("bar"))
+ assertThat("Prefs should be overridden", prefs[2] as String, equalTo("baz"))
+
+ mainSession.reload()
+ mainSession.waitForPageStop()
+
+ prefs = sessionRule.getPrefs(
+ "test.pref.int",
+ "test.pref.foo",
+ "test.pref.bar",
+ )
+
+ assertThat("Overriden prefs should be restored", prefs[0] as Int, equalTo(1))
+ assertThat("Overriden prefs should be restored", prefs[1] as String, equalTo("foo"))
+ assertThat("Overriden prefs should be restored", prefs[2], equalTo(JSONObject.NULL))
+ }
+
+ @Test fun waitForJS() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ assertThat(
+ "waitForJS should return correct result",
+ mainSession.waitForJS("alert(), 'foo'") as String,
+ equalTo("foo"),
+ )
+
+ mainSession.forCallbacksDuringWait(object : PromptDelegate {
+ @AssertCalled(count = 1)
+ override fun onAlertPrompt(session: GeckoSession, prompt: PromptDelegate.AlertPrompt): GeckoResult<PromptDelegate.PromptResponse>? {
+ return null
+ }
+ })
+ }
+
+ @Test fun waitForJS_resolvePromise() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ assertThat(
+ "waitForJS should wait for promises",
+ mainSession.waitForJS("Promise.resolve('foo')") as String,
+ equalTo("foo"),
+ )
+ }
+
+ @Test fun waitForJS_delegateDuringWait() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ var count = 0
+ mainSession.delegateDuringNextWait(object : PromptDelegate {
+ override fun onAlertPrompt(session: GeckoSession, prompt: PromptDelegate.AlertPrompt): GeckoResult<PromptDelegate.PromptResponse> {
+ count++
+ return GeckoResult.fromValue(prompt.dismiss())
+ }
+ })
+
+ mainSession.waitForJS("alert()")
+ mainSession.waitForJS("alert()")
+
+ // The delegate set through delegateDuringNextWait
+ // should have been cleared after the first wait.
+ assertThat("Delegate should only run once", count, equalTo(1))
+ }
+
+ @Test(expected = RejectedPromiseException::class)
+ fun waitForJS_whileNavigating() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ // Trigger navigation and try again
+ mainSession.loadTestPath(HELLO2_HTML_PATH)
+ mainSession.waitForPageStop()
+
+ // Navigate away and trigger a waitForJS that never completes, this will
+ // fail because the page navigates away (disconnecting the port) before
+ // the page can respond.
+ mainSession.goBack()
+ mainSession.waitForJS("new Promise(resolve => {})")
+ }
+
+ private interface TestDelegate {
+ fun onDelegate(foo: String, bar: String): Int
+ }
+
+ @Test fun addExternalDelegateUntilTestEnd() {
+ lateinit var delegate: TestDelegate
+
+ sessionRule.addExternalDelegateUntilTestEnd(
+ TestDelegate::class,
+ { newDelegate -> delegate = newDelegate },
+ { },
+ object : TestDelegate {
+ @AssertCalled(count = 1)
+ override fun onDelegate(foo: String, bar: String): Int {
+ assertThat("First argument should be correct", foo, equalTo("foo"))
+ assertThat("Second argument should be correct", bar, equalTo("bar"))
+ return 42
+ }
+ },
+ )
+
+ assertThat("Delegate should be registered", delegate, notNullValue())
+ assertThat(
+ "Delegate return value should be correct",
+ delegate.onDelegate("foo", "bar"),
+ equalTo(42),
+ )
+ sessionRule.performTestEndCheck()
+ }
+
+ @Test(expected = AssertionError::class)
+ fun addExternalDelegateUntilTestEnd_throwOnNotCalled() {
+ sessionRule.addExternalDelegateUntilTestEnd(
+ TestDelegate::class,
+ { },
+ { },
+ object : TestDelegate {
+ @AssertCalled(count = 1)
+ override fun onDelegate(foo: String, bar: String): Int {
+ return 42
+ }
+ },
+ )
+ sessionRule.performTestEndCheck()
+ }
+
+ @Test fun addExternalDelegateDuringNextWait() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ var delegate: Runnable? = null
+
+ sessionRule.addExternalDelegateDuringNextWait(
+ Runnable::class,
+ { newDelegate -> delegate = newDelegate },
+ { delegate = null },
+ Runnable { },
+ )
+
+ assertThat("Delegate should be registered", delegate, notNullValue())
+ delegate?.run()
+
+ mainSession.reload()
+ mainSession.waitForPageStop()
+ mainSession.forCallbacksDuringWait(Runnable @AssertCalled(count = 1) {}) // ktlint-disable annotation
+
+ assertThat("Delegate should be unregistered after wait", delegate, nullValue())
+ }
+
+ @Test fun addExternalDelegateDuringNextWait_hasPrecedence() {
+ mainSession.loadTestPath(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+
+ var delegate: TestDelegate? = null
+ val register = { newDelegate: TestDelegate -> delegate = newDelegate }
+ val unregister = { _: TestDelegate -> delegate = null }
+
+ sessionRule.addExternalDelegateDuringNextWait(
+ TestDelegate::class,
+ register,
+ unregister,
+ object : TestDelegate {
+ @AssertCalled(count = 1)
+ override fun onDelegate(foo: String, bar: String): Int {
+ return 24
+ }
+ },
+ )
+
+ sessionRule.addExternalDelegateUntilTestEnd(
+ TestDelegate::class,
+ register,
+ unregister,
+ object : TestDelegate {
+ @AssertCalled(count = 1)
+ override fun onDelegate(foo: String, bar: String): Int {
+ return 42
+ }
+ },
+ )
+
+ assertThat("Wait delegate should be registered", delegate, notNullValue())
+ assertThat(
+ "Wait delegate return value should be correct",
+ delegate?.onDelegate("", ""),
+ equalTo(24),
+ )
+
+ mainSession.reload()
+ mainSession.waitForPageStop()
+
+ assertThat("Test delegate should still be registered", delegate, notNullValue())
+ assertThat(
+ "Test delegate return value should be correct",
+ delegate?.onDelegate("", ""),
+ equalTo(42),
+ )
+ sessionRule.performTestEndCheck()
+ }
+
+ @IgnoreCrash
+ @Test
+ fun contentCrashIgnored() {
+ // TODO: Bug 1673953
+ assumeThat(sessionRule.env.isFission, equalTo(false))
+
+ // 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) = Unit
+ })
+ }
+
+ @Test(expected = ChildCrashedException::class)
+ fun contentCrashFails() {
+ assumeThat(sessionRule.env.shouldShutdownOnCrash(), equalTo(false))
+
+ mainSession.loadUri(CONTENT_CRASH_URL)
+ sessionRule.waitForPageStop()
+ }
+
+ @Test fun waitForResult() {
+ val handler = Handler(Looper.getMainLooper())
+ val result = object : GeckoResult<Int>() {
+ init {
+ handler.postDelayed({
+ complete(42)
+ }, 100)
+ }
+ }
+
+ val value = sessionRule.waitForResult(result)
+ assertThat("Value should match", value, equalTo(42))
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun waitForResultExceptionally() {
+ val handler = Handler(Looper.getMainLooper())
+ val result = object : GeckoResult<Int>() {
+ init {
+ handler.postDelayed({
+ completeExceptionally(IllegalStateException("boom"))
+ }, 100)
+ }
+ }
+
+ sessionRule.waitForResult(result)
+ }
+
+ @Test fun checkCookieBannerRuleForSession() {
+ // set preferences. We have a cookie rule for example.com
+ val testRules = "[{\"id\":\"87815b2d-a840-4155-8713-f8a26d1f483a\",\"click\":{\"optOut\":\"#optOutBtn\",\"presence\": \"#cookieBanner\"},\"cookies\":{\"optOut\":[{\"name\":\"foo\", \"value\":\"bar\"}]}, \"domains\":[\"example.org\"]}]"
+ sessionRule.setPrefsUntilTestEnd(
+ mapOf(
+ "cookiebanners.service.mode" to CookieBannerMode.COOKIE_BANNER_MODE_REJECT,
+ "cookiebanners.listService.testSkipRemoteSettings" to true,
+ "cookiebanners.listService.testRules" to testRules,
+ "cookiebanners.service.detectOnly" to false,
+ ),
+ )
+ var prefs = sessionRule.getPrefs(
+ "cookiebanners.service.mode",
+ "cookiebanners.listService.testSkipRemoteSettings",
+ "cookiebanners.listService.testRules",
+ "cookiebanners.service.detectOnly",
+ )
+ assertThat("Cookie banner service mode should be correct", prefs[0] as Int, equalTo(1))
+ assertThat("Cookie banner remote settings should be skipped", prefs[1] as Boolean, equalTo(true))
+ assertThat("Cookie banner rule should be set", prefs[2] as String, equalTo(testRules))
+ assertThat("Cookie banner service should not be in detect only mode", prefs[3] as Boolean, equalTo(false))
+
+ // session 1 - load url for which there is no rule
+ mainSession.loadUri(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ val response1 = mainSession.hasCookieBannerRuleForBrowsingContextTree()
+ sessionRule.waitForResult(response1).let {
+ assertThat("There should be no rule", it, equalTo(false))
+ }
+
+ // session 1 - load url for which there is a rule
+ mainSession.loadUri("http://example.org/")
+ sessionRule.waitForPageStop()
+ val response2 = mainSession.hasCookieBannerRuleForBrowsingContextTree()
+ sessionRule.waitForResult(response2).let {
+ assertThat("There should be a rule", it, equalTo(true))
+ }
+
+ // session 2 load url for which there is no rule
+ val session2 = sessionRule.createOpenSession()
+ session2.loadUri(HELLO_HTML_PATH)
+ sessionRule.waitForPageStop()
+ val response3 = session2.hasCookieBannerRuleForBrowsingContextTree()
+ sessionRule.waitForResult(response3).let {
+ assertThat("There should be no rule", it, equalTo(false))
+ }
+
+ // API shoul return the correct result for the page we have loaded in session 1
+ val response4 = mainSession.hasCookieBannerRuleForBrowsingContextTree()
+ sessionRule.waitForResult(response4).let {
+ assertThat("There should be a rule the second time", it, equalTo(true))
+ }
+ }
+}