Skip to content

Commit

Permalink
Fix VPNSettings UI tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawa committed Nov 21, 2023
1 parent 64ded64 commit 595720d
Show file tree
Hide file tree
Showing 17 changed files with 548 additions and 459 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package net.mullvad.mullvadvpn.compose.dialog

import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTextInput
import io.mockk.MockKAnnotations
import net.mullvad.mullvadvpn.compose.setContentWithTheme
import net.mullvad.mullvadvpn.compose.test.CUSTOM_PORT_DIALOG_INPUT_TEST_TAG
import net.mullvad.mullvadvpn.model.PortRange
import net.mullvad.mullvadvpn.onNodeWithTagAndText
import org.junit.Before
import org.junit.Rule
import org.junit.Test

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

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

@SuppressLint("ComposableNaming")
@Composable
private fun testWireguardCustomPortDialog(
initialPort: Int? = null,
allowedPortRanges: List<PortRange> = emptyList(),
onSave: (Int?) -> Unit = { _ -> },
onDismiss: () -> Unit = {},
) {

WireguardCustomPortDialog(
initialPort = initialPort,
allowedPortRanges = allowedPortRanges,
onSave = onSave,
onDismiss = onDismiss
)
}

@Test
fun testShowWireguardCustomPortDialogInvalidInt() {
// Input a number to make sure that a too long number does not show and it does not crash
// the app

// Arrange
composeTestRule.setContentWithTheme { testWireguardCustomPortDialog() }

// Act
composeTestRule
.onNodeWithTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG)
.performTextInput("21474836471")

// Assert
composeTestRule
.onNodeWithTagAndText(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG, "21474836471")
.assertDoesNotExist()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package net.mullvad.mullvadvpn.compose.dialog

import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import io.mockk.MockKAnnotations
import net.mullvad.mullvadvpn.compose.setContentWithTheme
import net.mullvad.mullvadvpn.viewmodel.DnsDialogViewState
import org.junit.Before
import org.junit.Rule
import org.junit.Test

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

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

val defaultState =
DnsDialogViewState(
ipAddress = "",
validationResult = DnsDialogViewState.ValidationResult.Success,
isLocal = false,
isAllowLanEnabled = false,
isNewEntry = true
)

@SuppressLint("ComposableNaming")
@Composable
private fun testDnsDialog(
state: DnsDialogViewState = defaultState,
onDnsInputChange: (String) -> Unit = { _ -> },
onSaveDnsClick: () -> Unit = {},
onRemoveDnsClick: () -> Unit = {},
onDismiss: () -> Unit = {}
) {
DnsDialog(state, onDnsInputChange, onSaveDnsClick, onRemoveDnsClick, onDismiss)
}

@Test
fun testDnsDialogLanWarningShownWhenLanTrafficDisabledAndLocalAddressUsed() {
// Arrange
composeTestRule.setContentWithTheme {
testDnsDialog(defaultState.copy(isAllowLanEnabled = false, isLocal = true))
}

// Assert
composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertExists()
}

@Test
fun testDnsDialogLanWarningNotShownWhenLanTrafficEnabledAndLocalAddressUsed() {
// Arrange
composeTestRule.setContentWithTheme {
testDnsDialog(defaultState.copy(isAllowLanEnabled = true, isLocal = true))
}

// Assert
composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
}

@Test
fun testDnsDialogLanWarningNotShownWhenLanTrafficEnabledAndNonLocalAddressUsed() {
// Arrange
composeTestRule.setContentWithTheme {
testDnsDialog(defaultState.copy(isAllowLanEnabled = true, isLocal = false))
}

// Assert
composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
}

@Test
fun testDnsDialogLanWarningNotShownWhenLanTrafficDisabledAndNonLocalAddressUsed() {
// Arrange
composeTestRule.setContentWithTheme {
testDnsDialog(defaultState.copy(isAllowLanEnabled = false, isLocal = false))
}

// Assert
composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
}

@Test
fun testDnsDialogSubmitButtonDisabledOnInvalidDnsAddress() {
// Arrange
composeTestRule.setContentWithTheme {
testDnsDialog(
defaultState.copy(
ipAddress = "300.300.300.300",
validationResult = DnsDialogViewState.ValidationResult.InvalidAddress,
)
)
}

// Assert
composeTestRule.onNodeWithText("Submit").assertIsNotEnabled()
}

@Test
fun testDnsDialogSubmitButtonDisabledOnDuplicateDnsAddress() {
// Arrange
composeTestRule.setContentWithTheme {
testDnsDialog(
defaultState.copy(
ipAddress = "192.168.0.1",
validationResult = DnsDialogViewState.ValidationResult.DuplicateAddress,
)
)
}

// Assert
composeTestRule.onNodeWithText("Submit").assertIsNotEnabled()
}

companion object {
private const val LOCAL_DNS_SERVER_WARNING =
"The local DNS server will not work unless you enable " +
"\"Local Network Sharing\" under Preferences."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package net.mullvad.mullvadvpn.compose.dialog

import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import io.mockk.MockKAnnotations
import io.mockk.mockk
import io.mockk.verify
import net.mullvad.mullvadvpn.compose.setContentWithTheme
import org.junit.Before
import org.junit.Rule
import org.junit.Test

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

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

@SuppressLint("ComposableNaming")
@Composable
private fun testMtuDialog(
mtuInitial: Int? = null,
onSaveMtu: (Int) -> Unit = { _ -> },
onResetMtu: () -> Unit = {},
onDismiss: () -> Unit = {},
) {
MtuDialog(
mtuInitial = mtuInitial,
onSaveMtu = onSaveMtu,
onResetMtu = onResetMtu,
onDismiss = onDismiss
)
}

@Test
fun testMtuDialogWithDefaultValue() {
// Arrange
composeTestRule.setContentWithTheme { testMtuDialog() }

// Assert
composeTestRule.onNodeWithText(EMPTY_STRING).assertExists()
}

@Test
fun testMtuDialogWithEditValue() {
// Arrange
composeTestRule.setContentWithTheme {
testMtuDialog(
mtuInitial = VALID_DUMMY_MTU_VALUE,
)
}

// Assert
composeTestRule.onNodeWithText(VALID_DUMMY_MTU_VALUE.toString()).assertExists()
}

@Test
fun testMtuDialogTextInput() {
// Arrange
composeTestRule.setContentWithTheme {
testMtuDialog(
null,
)
}

// Act
composeTestRule
.onNodeWithText(EMPTY_STRING)
.performTextInput(VALID_DUMMY_MTU_VALUE.toString())

// Assert
composeTestRule.onNodeWithText(VALID_DUMMY_MTU_VALUE.toString()).assertExists()
}

@Test
fun testMtuDialogSubmitOfValidValue() {
// Arrange
val mockedSubmitHandler: (Int) -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
testMtuDialog(
VALID_DUMMY_MTU_VALUE,
onSaveMtu = mockedSubmitHandler,
)
}

// Act
composeTestRule.onNodeWithText("Submit").assertIsEnabled().performClick()

// Assert
verify { mockedSubmitHandler.invoke(VALID_DUMMY_MTU_VALUE) }
}

@Test
fun testMtuDialogSubmitButtonDisabledWhenInvalidInput() {
// Arrange
composeTestRule.setContentWithTheme {
testMtuDialog(
INVALID_DUMMY_MTU_VALUE,
)
}

// Assert
composeTestRule.onNodeWithText("Submit").assertIsNotEnabled()
}

@Test
fun testMtuDialogResetClick() {
// Arrange
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
testMtuDialog(
onResetMtu = mockedClickHandler,
)
}

// Act
composeTestRule.onNodeWithText("Reset to default").performClick()

// Assert
verify { mockedClickHandler.invoke() }
}

@Test
fun testMtuDialogCancelClick() {
// Arrange
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
testMtuDialog(
onDismiss = mockedClickHandler,
)
}

// Assert
composeTestRule.onNodeWithText("Cancel").performClick()

// Assert
verify { mockedClickHandler.invoke() }
}

companion object {
private const val EMPTY_STRING = ""
private const val VALID_DUMMY_MTU_VALUE = 1337
private const val INVALID_DUMMY_MTU_VALUE = 1111
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ class AccountScreenTest {
AccountScreen(
uiState =
AccountUiState(
showSitePayment = true,
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
accountExpiry = null,
showSitePayment = false
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
onManageAccountClick = mockedClickHandler
Expand Down Expand Up @@ -196,6 +196,7 @@ class AccountScreenTest {
val mockPaymentProduct: PaymentProduct = mockk()
every { mockPaymentProduct.price } returns ProductPrice("$10")
every { mockPaymentProduct.status } returns PaymentStatus.PENDING
val mockNavigateToVerificationPending: () -> Unit = mockk(relaxed = true)
composeTestRule.setContentWithTheme {
AccountScreen(
uiState =
Expand All @@ -205,18 +206,15 @@ class AccountScreenTest {
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
),
uiSideEffect = MutableSharedFlow<AccountViewModel.UiSideEffect>().asSharedFlow(),
navigateToVerificationPendingDialog = mockNavigateToVerificationPending
)
}

// Act
composeTestRule.onNodeWithTag(PLAY_PAYMENT_INFO_ICON_TEST_TAG).performClick()

// Assert
composeTestRule
.onNodeWithText(
"We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful."
)
.assertExists()
verify(exactly = 1) { mockNavigateToVerificationPending.invoke() }
}

@Test
Expand Down
Loading

0 comments on commit 595720d

Please sign in to comment.