summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorAlbin <albin@mullvad.net>2023-03-22 16:15:30 +0100
committerAlbin <albin@mullvad.net>2023-03-22 17:15:58 +0100
commit128d188883d878dd84d3ace6dbbc6e553702a347 (patch)
treeee30deb2e070db6a555da56a21fed829e77895b9 /android
parentd97365cb916ed05ee07f2defb901db31918fe580 (diff)
downloadmullvadvpn-128d188883d878dd84d3ace6dbbc6e553702a347.tar.xz
mullvadvpn-128d188883d878dd84d3ace6dbbc6e553702a347.zip
Add advanced settings ui tests
Diffstat (limited to 'android')
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt552
1 files changed, 552 insertions, 0 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt
new file mode 100644
index 0000000000..1aaf119773
--- /dev/null
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt
@@ -0,0 +1,552 @@
+package net.mullvad.mullvadvpn.compose.screen
+
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+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 io.mockk.verifyAll
+import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState
+import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem
+import net.mullvad.mullvadvpn.viewmodel.StagedDns
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class AdvancedSettingsScreenTest {
+ @get:Rule val composeTestRule = createComposeRule()
+
+ @Before
+ fun setup() {
+ MockKAnnotations.init(this)
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDefaultState() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(uiState = AdvancedSettingsUiState.DefaultUiState())
+ }
+
+ // Assert
+ composeTestRule.apply {
+ onNodeWithText("WireGuard MTU").assertExists()
+ onNodeWithText("Default").assertExists()
+ onNodeWithText("Split tunneling").assertExists()
+ onNodeWithText("Use custom DNS server").assertExists()
+ onNodeWithText("Add a server").assertDoesNotExist()
+ }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuCustomValue() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.DefaultUiState(mtu = VALID_DUMMY_MTU_VALUE)
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(VALID_DUMMY_MTU_VALUE).assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuClick() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.DefaultUiState(),
+ onMtuCellClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("WireGuard MTU").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogWithDefaultValue() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING)
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(EMPTY_STRING).assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogWithEditValue() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = VALID_DUMMY_MTU_VALUE)
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(VALID_DUMMY_MTU_VALUE).assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogTextInput() {
+ // Arrange
+ val mockedInputHandler: (String) -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
+ onMtuInputChange = mockedInputHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText(EMPTY_STRING).performTextInput(VALID_DUMMY_MTU_VALUE)
+
+ // Assert
+ verifyAll { mockedInputHandler.invoke(VALID_DUMMY_MTU_VALUE) }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogSubmitOfValidValue() {
+ // Arrange
+ val mockedSubmitHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = VALID_DUMMY_MTU_VALUE),
+ onSaveMtuClick = mockedSubmitHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Submit").assertIsEnabled().performClick()
+
+ // Assert
+ verify { mockedSubmitHandler.invoke() }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogSubmitButtonDisabledWhenInvalidInput() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = INVALID_DUMMY_MTU_VALUE)
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText("Submit").assertIsNotEnabled()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogResetClick() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
+ onRestoreMtuClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Reset to default").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testMtuDialogCancelClick() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
+ onCancelMtuDialogClicked = mockedClickHandler
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText("Cancel").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testClickSplitTunneling() {
+ // Arrange
+ val mockedClickHandler: () -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.DefaultUiState(),
+ onSplitTunnelingNavigationClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Split tunneling").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke() }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testCustomDnsAddressesAndAddButtonVisibleWhenCustomDnsEnabled() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DefaultUiState(
+ isCustomDnsEnabled = true,
+ isAllowLanEnabled = false,
+ customDnsItems =
+ listOf(
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS, false),
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS_2, false),
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS_3, false)
+ )
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.apply {
+ onNodeWithText(DUMMY_DNS_ADDRESS).assertExists()
+ onNodeWithText(DUMMY_DNS_ADDRESS_2).assertExists()
+ onNodeWithText(DUMMY_DNS_ADDRESS_3).assertExists()
+ onNodeWithText("Add a server").assertExists()
+ }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testCustomDnsAddressesAndAddButtonNotVisibleWhenCustomDnsDisabled() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DefaultUiState(
+ isCustomDnsEnabled = false,
+ customDnsItems = listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, false))
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(DUMMY_DNS_ADDRESS).assertDoesNotExist()
+ composeTestRule.onNodeWithText("Add a server").assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testLanWarningNotShownWhenLanTrafficEnabledAndLocalAddressIsUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DefaultUiState(
+ isCustomDnsEnabled = true,
+ isAllowLanEnabled = true,
+ customDnsItems =
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true))
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithContentDescription(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testLanWarningNotShowedWhenLanTrafficDisabledAndLocalAddressIsNotUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DefaultUiState(
+ isCustomDnsEnabled = true,
+ isAllowLanEnabled = false,
+ customDnsItems =
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false))
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithContentDescription(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testLanWarningNotShowedWhenLanTrafficEnabledAndLocalAddressIsNotUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DefaultUiState(
+ isCustomDnsEnabled = true,
+ isAllowLanEnabled = true,
+ customDnsItems =
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false))
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithContentDescription(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testLanWarningShowedWhenAllowLanEnabledAndLocalDnsAddressIsUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DefaultUiState(
+ isCustomDnsEnabled = true,
+ isAllowLanEnabled = false,
+ customDnsItems =
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true))
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.apply {
+ onNodeWithContentDescription(LOCAL_DNS_SERVER_WARNING).assertExists()
+ }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testClickAddDns() {
+ // Arrange
+ val mockedClickHandler: (Int?) -> Unit = mockk(relaxed = true)
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.DefaultUiState(isCustomDnsEnabled = true),
+ onDnsClick = mockedClickHandler
+ )
+ }
+
+ // Act
+ composeTestRule.onNodeWithText("Add a server").performClick()
+
+ // Assert
+ verify { mockedClickHandler.invoke(null) }
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testShowDnsDialogForNewDnsServer() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false)
+ )
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText("Add DNS server").assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testShowDnsDialogForUpdatingDnsServer() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.EditDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
+ index = 0
+ )
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText("Update DNS server").assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDnsDialogLanWarningShownWhenLanTrafficDisabledAndLocalAddressUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = true),
+ validationResult = StagedDns.ValidationResult.Success
+ ),
+ isAllowLanEnabled = false
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertExists()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDnsDialogLanWarningNotShownWhenLanTrafficEnabledAndLocalAddressUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = true),
+ validationResult = StagedDns.ValidationResult.Success
+ ),
+ isAllowLanEnabled = true
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDnsDialogLanWarningNotShownWhenLanTrafficEnabledAndNonLocalAddressUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
+ validationResult = StagedDns.ValidationResult.Success
+ ),
+ isAllowLanEnabled = true
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDnsDialogLanWarningNotShownWhenLanTrafficDisabledAndNonLocalAddressUsed() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
+ validationResult = StagedDns.ValidationResult.Success
+ ),
+ isAllowLanEnabled = false
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDnsDialogSubmitButtonDisabledOnInvalidDnsAddress() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
+ validationResult = StagedDns.ValidationResult.InvalidAddress
+ )
+ )
+ )
+ }
+
+ // Assert
+ composeTestRule.onNodeWithText("Submit").assertIsNotEnabled()
+ }
+
+ @Test
+ @OptIn(ExperimentalMaterialApi::class)
+ fun testDnsDialogSubmitButtonDisabledOnDuplicateDnsAddress() {
+ // Arrange
+ composeTestRule.setContent {
+ AdvancedSettingScreen(
+ uiState =
+ AdvancedSettingsUiState.DnsDialogUiState(
+ stagedDns =
+ StagedDns.NewDns(
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
+ validationResult = StagedDns.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."
+ private const val EMPTY_STRING = ""
+ private const val VALID_DUMMY_MTU_VALUE = "1337"
+ private const val INVALID_DUMMY_MTU_VALUE = "1111"
+ private const val DUMMY_DNS_ADDRESS = "0.0.0.1"
+ private const val DUMMY_DNS_ADDRESS_2 = "0.0.0.2"
+ private const val DUMMY_DNS_ADDRESS_3 = "0.0.0.3"
+ }
+}