Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* Any copyright is dedicated to the Public Domain.
package org.mozilla.geckoview.test
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.view.MotionEvent
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 {
@Suppress("OVERRIDE_DEPRECATION")
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 synthesizeMouse() {
mainSession.loadTestPath(MOUSE_TO_RELOAD_HTML_PATH)
mainSession.waitForPageStop()
val time = SystemClock.uptimeMillis()
mainSession.evaluateJS("document.body.addEventListener('mousedown', () => { window.location.reload() })")
mainSession.synthesizeMouse(time, MotionEvent.ACTION_DOWN, 50, 50, MotionEvent.BUTTON_PRIMARY)
mainSession.waitForPageStop()
mainSession.evaluateJS("document.body.addEventListener('mouseup', () => { window.location.reload() })")
mainSession.synthesizeMouse(time, MotionEvent.ACTION_UP, 50, 50, 0)
mainSession.waitForPageStop()
}
@WithDisplay(width = 100, height = 100)
@Test
fun synthesizeMouseMove() {
mainSession.loadTestPath(MOUSE_TO_RELOAD_HTML_PATH)
mainSession.waitForPageStop()
mainSession.evaluateJS("document.body.addEventListener('mousemove', () => { window.location.reload() })")
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 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))
}
}
}