test(coreexample): Add MockTestRule which adds common configuration for tests with server mocks and hilt-testing.

This commit is contained in:
Mateusz Armatys
2022-10-21 14:34:04 +02:00
parent 091b75f783
commit fb4a004df0
6 changed files with 154 additions and 69 deletions
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonCore is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.test.android.uitests
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidTest
import me.proton.core.network.data.di.BaseProtonApiUrl
import okhttp3.HttpUrl
import org.junit.Rule
interface BaseMockTest {
@BaseProtonApiUrl
var baseProtonApiUrl: HttpUrl
val testUsername get() = "test-mock-936"
val testPassword get() = "password"
}
/** A minimal example for writing a test with hilt-testing and mocked server. */
@HiltAndroidTest
class SampleMockTest : BaseMockTest {
@get:Rule
val mockTestRule = MockTestRule(this)
@BindValue
@BaseProtonApiUrl
override lateinit var baseProtonApiUrl: HttpUrl
}
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonCore is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.test.android.uitests
import dagger.hilt.android.testing.HiltAndroidRule
import me.proton.android.core.coreexample.CoreExampleLogger
import me.proton.core.test.android.TestWebServerDispatcher
import me.proton.core.test.android.instrumented.utils.Shell
import me.proton.core.util.kotlin.CoreLogger
import okhttp3.mockwebserver.MockWebServer
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import timber.log.Timber
/** A test rule that applies [HiltAndroidRule] and prepares a mock [MockWebServer].
* @see SampleMockTest
*/
class MockTestRule constructor(private val testInstance: BaseMockTest) : TestRule {
lateinit var dispatcher: TestWebServerDispatcher
override fun apply(base: Statement, description: Description): Statement {
initLogging()
dispatcher = TestWebServerDispatcher()
val webServer = MockWebServer()
webServer.dispatcher = dispatcher
val hiltRule = HiltAndroidRule(testInstance)
val result = hiltRule.apply(object : Statement() {
override fun evaluate() {
testInstance.baseProtonApiUrl = webServer.url("/")
hiltRule.inject()
base.evaluate()
}
}, description)
return object : Statement() {
override fun evaluate() {
try {
result.evaluate()
} catch (t: Throwable) {
Shell.saveToFile(description)
throw t
} finally {
webServer.shutdown()
}
}
}
}
private fun initLogging() {
Timber.plant(Timber.DebugTree())
CoreLogger.set(CoreExampleLogger())
}
}
@@ -21,9 +21,7 @@ package me.proton.core.test.android.uitests.giap
import androidx.test.core.app.ActivityScenario
import com.android.billingclient.api.BillingClient
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import me.proton.android.core.coreexample.CoreExampleLogger
import me.proton.android.core.coreexample.MainActivity
import me.proton.core.network.data.di.BaseProtonApiUrl
import me.proton.core.test.android.TestWebServerDispatcher
@@ -31,55 +29,30 @@ import me.proton.core.test.android.mocks.FakeBillingClientFactory
import me.proton.core.test.android.mocks.mockBillingClientSuccess
import me.proton.core.test.android.robots.auth.AddAccountRobot
import me.proton.core.test.android.robots.payments.GoogleIAPRobot
import me.proton.core.test.android.uitests.BaseMockTest
import me.proton.core.test.android.uitests.CoreexampleRobot
import me.proton.core.util.kotlin.CoreLogger
import me.proton.core.test.android.uitests.MockTestRule
import okhttp3.HttpUrl
import okhttp3.mockwebserver.MockWebServer
import org.junit.Rule
import timber.log.Timber
import javax.inject.Inject
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import me.proton.core.test.android.plugins.data.Plan as TestPlan
@HiltAndroidTest
class GiapUpgradeTests {
private val testUsername = "test-mock-936"
private val testPassword = "password"
@get:Rule(order = Rule.DEFAULT_ORDER - 1)
val hiltAndroidRule = HiltAndroidRule(this)
class GiapUpgradeTests: BaseMockTest {
@get:Rule
val mockTestRule = MockTestRule(this)
@BindValue
@BaseProtonApiUrl
lateinit var baseProtonApiUrl: HttpUrl
override lateinit var baseProtonApiUrl: HttpUrl
@Inject
lateinit var billingClientFactory: FakeBillingClientFactory
private val billingClient: BillingClient get() = billingClientFactory.billingClient
private lateinit var dispatcher: TestWebServerDispatcher
private lateinit var webServer: MockWebServer
@BeforeTest
fun setUp() {
Timber.plant(Timber.DebugTree())
CoreLogger.set(CoreExampleLogger())
dispatcher = TestWebServerDispatcher()
webServer = MockWebServer().apply {
dispatcher = this@GiapUpgradeTests.dispatcher
}
baseProtonApiUrl = webServer.url("/")
hiltAndroidRule.inject()
}
@AfterTest
fun tearDown() {
webServer.shutdown()
}
private val dispatcher: TestWebServerDispatcher get() = mockTestRule.dispatcher
@Test
fun freeUserUpgradeAllProvidersAvailable() {
@@ -24,9 +24,7 @@ import androidx.test.core.app.ApplicationProvider
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingClient.BillingResponseCode
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import me.proton.android.core.coreexample.CoreExampleLogger
import me.proton.core.auth.presentation.ui.AddAccountActivity
import me.proton.core.network.data.di.BaseProtonApiUrl
import me.proton.core.plan.presentation.entity.PlanInput
@@ -41,56 +39,30 @@ import me.proton.core.test.android.robots.auth.signup.RecoveryMethodsRobot
import me.proton.core.test.android.robots.auth.signup.SignupFinishedRobot
import me.proton.core.test.android.robots.payments.GoogleIAPRobot
import me.proton.core.test.android.robots.plans.SelectPlanRobot
import me.proton.core.util.kotlin.CoreLogger
import me.proton.core.test.android.uitests.BaseMockTest
import me.proton.core.test.android.uitests.MockTestRule
import okhttp3.HttpUrl
import okhttp3.mockwebserver.MockWebServer
import org.junit.Rule
import timber.log.Timber
import javax.inject.Inject
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import me.proton.core.paymentiap.presentation.R as PaymentIapR
import me.proton.core.test.android.plugins.data.Plan as TestPlan
@HiltAndroidTest
class SignupWithGoogleIapTests {
private val testUsername = "test-mock-936"
private val testPassword = "password"
@get:Rule(order = Rule.DEFAULT_ORDER - 1)
val hiltAndroidRule = HiltAndroidRule(this)
class SignupWithGoogleIapTests : BaseMockTest {
@get:Rule
val mockTestRule = MockTestRule(this)
@BindValue
@BaseProtonApiUrl
lateinit var baseProtonApiUrl: HttpUrl
override lateinit var baseProtonApiUrl: HttpUrl
@Inject
lateinit var billingClientFactory: FakeBillingClientFactory
private val appContext: Context get() = ApplicationProvider.getApplicationContext()
private val billingClient: BillingClient get() = billingClientFactory.billingClient
private lateinit var dispatcher: TestWebServerDispatcher
private lateinit var webServer: MockWebServer
@BeforeTest
fun setUp() {
Timber.plant(Timber.DebugTree())
CoreLogger.set(CoreExampleLogger())
dispatcher = TestWebServerDispatcher()
webServer = MockWebServer().apply {
dispatcher = this@SignupWithGoogleIapTests.dispatcher
}
baseProtonApiUrl = webServer.url("/")
hiltAndroidRule.inject()
}
@AfterTest
fun tearDown() {
webServer.shutdown()
}
private val dispatcher: TestWebServerDispatcher get() = mockTestRule.dispatcher
@Test
fun googleBillingNotAvailable() {
@@ -137,6 +109,13 @@ class SignupWithGoogleIapTests {
.skipConfirm<SelectPlanRobot>()
.toggleExpandPlan(TestPlan.Plus)
.selectPlan<GoogleIAPRobot>(TestPlan.Plus)
.apply {
verify<GoogleIAPRobot.Verify> {
payWithGoogleButtonIsClickable()
payWithCardButtonIsNotVisible()
switchPaymentProviderButtonIsNotVisible()
}
}
.payWithGPay<SignupFinishedRobot>()
.verify {
signupFinishedDisplayed()
@@ -169,6 +148,13 @@ class SignupWithGoogleIapTests {
.skipConfirm<SelectPlanRobot>()
.toggleExpandPlan(TestPlan.Plus)
.selectPlan<GoogleIAPRobot>(TestPlan.Plus)
.apply {
verify<GoogleIAPRobot.Verify> {
payWithGoogleButtonIsClickable()
payWithCardButtonIsNotVisible()
switchPaymentProviderButtonIsVisible()
}
}
.payWithGPay<SignupFinishedRobot>()
.verify {
signupFinishedDisplayed()
@@ -1063,6 +1063,8 @@ public final class me/proton/core/test/android/robots/payments/GoogleIAPRobot$Ve
public fun <init> ()V
public final fun payWithCardButtonIsNotVisible ()V
public final fun payWithGoogleButtonIsClickable ()V
public final fun switchPaymentProviderButtonIsNotVisible ()V
public final fun switchPaymentProviderButtonIsVisible ()V
}
public class me/proton/core/test/android/robots/payments/PaymentRobot : me/proton/core/test/android/robots/CoreRobot {
@@ -37,6 +37,14 @@ class GoogleIAPRobot : PaymentRobot() {
view.withId(R.id.payButton).checkNotDisplayed()
}
fun switchPaymentProviderButtonIsNotVisible() {
view.withId(R.id.nextPaymentProviderButton).checkNotDisplayed()
}
fun switchPaymentProviderButtonIsVisible() {
view.withId(R.id.nextPaymentProviderButton).checkDisplayed()
}
fun payWithGoogleButtonIsClickable() {
view.withId(R.id.gPayButton)
.checkDisplayed()