Skip to content

Commit

Permalink
Migrate all navigation to compose navigation
Browse files Browse the repository at this point in the history
Remove old fragments

Improve animations between destinations

Fix glitch in animation

Temporary fix for pending intent flags

Fix status bar colors

Fix transition for welcome screen

Fix bug caused by triggering navigation too fast

Fix accidentally not starting service

Handle Change log

Fix screen rotation

Make settings use scaffold snackbar instead

Migrate info dialogs to destinations

Fix formatting

Fix some failed tests

Remove unused function

Refactor out MTU dialog

Migrate DnsDialog

Fix Devicelist confirmation dialog

Migrate ReportProblemNoEmail dialog

Migrate custom WG port to dialog

Fix voucher dialog and out of time navigation from connect

Fix tests

Update gradle lockfile

Disable settings button while logging in

Add nav graph

Fix out of time navigation, transitions and multiple navigation calls.

Fix xml formatting

Fix test

Add CVE supression

Clean up build config

Remove duplicate deps

Fix test
  • Loading branch information
Rawa committed Nov 20, 2023
1 parent 89420ba commit 230bbe0
Show file tree
Hide file tree
Showing 136 changed files with 3,190 additions and 3,369 deletions.
7 changes: 5 additions & 2 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ plugins {
id(Dependencies.Plugin.playPublisherId)
id(Dependencies.Plugin.kotlinAndroidId)
id(Dependencies.Plugin.kotlinParcelizeId)
id(Dependencies.Plugin.ksp) version Versions.Plugin.ksp
}

val repoRootPath = rootProject.projectDir.absoluteFile.parentFile.absolutePath
Expand Down Expand Up @@ -181,8 +182,7 @@ android {

val enableInAppVersionNotifications =
gradleLocalProperties(rootProject.projectDir)
.getProperty("ENABLE_IN_APP_VERSION_NOTIFICATIONS")
?: "true"
.getProperty("ENABLE_IN_APP_VERSION_NOTIFICATIONS") ?: "true"

buildConfigField(
"boolean",
Expand Down Expand Up @@ -337,6 +337,9 @@ dependencies {
implementation(Dependencies.Compose.uiController)
implementation(Dependencies.Compose.ui)
implementation(Dependencies.Compose.uiUtil)
implementation(Dependencies.Compose.destinations)
ksp(Dependencies.Compose.destinationsKsp)

implementation(Dependencies.jodaTime)
implementation(Dependencies.Koin.core)
implementation(Dependencies.Koin.android)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package net.mullvad.mullvadvpn.compose.dialog

import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import io.mockk.MockKAnnotations
import net.mullvad.mullvadvpn.compose.dialog.payment.PaymentDialog
import net.mullvad.mullvadvpn.compose.setContentWithTheme
import net.mullvad.mullvadvpn.lib.payment.model.ProductId
import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult
import net.mullvad.mullvadvpn.util.toPaymentDialogData
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class PaymentDialogTest {
@get:Rule val composeTestRule = createComposeRule()

@Before
fun setup() {
MockKAnnotations.init(this)
}

@Test
fun testShowPurchaseCompleteDialog() {
// Arrange
composeTestRule.setContentWithTheme {
PaymentDialog(
paymentDialogData = PurchaseResult.Completed.Success.toPaymentDialogData()!!
)
}

// Assert
composeTestRule.onNodeWithText("Time was successfully added").assertExists()
}

@Test
fun testShowVerificationErrorDialog() {
// Arrange
composeTestRule.setContentWithTheme {
PaymentDialog(
paymentDialogData =
PurchaseResult.Error.VerificationError(null).toPaymentDialogData()!!
)
}

// Assert
composeTestRule.onNodeWithText("Verifying purchase").assertExists()
}

@Test
fun testShowFetchProductsErrorDialog() {
// Arrange
composeTestRule.setContentWithTheme {
PaymentDialog(
paymentDialogData =
PurchaseResult.Error.FetchProductsError(ProductId(""), null)
.toPaymentDialogData()!!
)
}

// Assert
composeTestRule.onNodeWithText("Google Play unavailable").assertExists()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.mullvad.mullvadvpn.compose.screen

import android.app.Activity
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
Expand All @@ -19,8 +18,6 @@ import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct
import net.mullvad.mullvadvpn.lib.payment.model.PaymentStatus
import net.mullvad.mullvadvpn.lib.payment.model.ProductId
import net.mullvad.mullvadvpn.lib.payment.model.ProductPrice
import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult
import net.mullvad.mullvadvpn.util.toPaymentDialogData
import net.mullvad.mullvadvpn.viewmodel.AccountUiState
import net.mullvad.mullvadvpn.viewmodel.AccountViewModel
import org.junit.Before
Expand All @@ -41,15 +38,14 @@ class AccountScreenTest {
// Arrange
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
accountExpiry = null
accountExpiry = null,
showSitePayment = false
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

Expand All @@ -66,15 +62,14 @@ class AccountScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
accountExpiry = null
accountExpiry = null,
showSitePayment = false
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow(),
onManageAccountClick = mockedClickHandler
)
}
Expand All @@ -92,15 +87,14 @@ class AccountScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
accountExpiry = null
accountExpiry = null,
showSitePayment = false
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow(),
onRedeemVoucherClick = mockedClickHandler
)
}
Expand All @@ -118,15 +112,14 @@ class AccountScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
accountExpiry = null
accountExpiry = null,
showSitePayment = false
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow(),
onLogoutClick = mockedClickHandler
)
}
Expand All @@ -138,80 +131,14 @@ class AccountScreenTest {
verify { mockedClickHandler.invoke() }
}

@Test
fun testShowPurchaseCompleteDialog() {
// Arrange
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
paymentDialogData =
PurchaseResult.Completed.Success.toPaymentDialogData()
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

// Assert
composeTestRule.onNodeWithText("Time was successfully added").assertExists()
}

@Test
fun testShowVerificationErrorDialog() {
// Arrange
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
paymentDialogData =
PurchaseResult.Error.VerificationError(null).toPaymentDialogData()
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

// Assert
composeTestRule.onNodeWithText("Verifying purchase").assertExists()
}

@Test
fun testShowFetchProductsErrorDialog() {
// Arrange
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
paymentDialogData =
PurchaseResult.Error.FetchProductsError(ProductId(""), null)
.toPaymentDialogData()
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

// Assert
composeTestRule.onNodeWithText("Google Play unavailable").assertExists()
}

@Test
fun testShowBillingErrorPaymentButton() {
// Arrange
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default().copy(billingPaymentState = PaymentState.Error.Billing),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

Expand All @@ -227,15 +154,13 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns null
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

Expand All @@ -251,15 +176,13 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.PENDING
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

Expand All @@ -275,15 +198,13 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.PENDING
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

Expand All @@ -306,15 +227,13 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.VERIFICATION_IN_PROGRESS
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

Expand All @@ -325,14 +244,13 @@ class AccountScreenTest {
@Test
fun testOnPurchaseBillingProductClick() {
// Arrange
val clickHandler: (ProductId, () -> Activity) -> Unit = mockk(relaxed = true)
val clickHandler: (ProductId) -> Unit = mockk(relaxed = true)
val mockPaymentProduct: PaymentProduct = mockk()
every { mockPaymentProduct.price } returns ProductPrice("$10")
every { mockPaymentProduct.productId } returns ProductId("PRODUCT_ID")
every { mockPaymentProduct.status } returns null
composeTestRule.setContentWithTheme {
AccountScreen(
showSitePayment = true,
uiState =
AccountUiState.default()
.copy(
Expand All @@ -341,15 +259,14 @@ class AccountScreenTest {
),
onPurchaseBillingProductClick = clickHandler,
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
enterTransitionEndAction = MutableSharedFlow<Unit>().asSharedFlow()
)
}

// Act
composeTestRule.onNodeWithText("Add 30 days time ($10)").performClick()

// Assert
verify { clickHandler.invoke(ProductId("PRODUCT_ID"), any()) }
verify { clickHandler.invoke(ProductId("PRODUCT_ID")) }
}

companion object {
Expand Down
Loading

0 comments on commit 230bbe0

Please sign in to comment.