diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2024-06-13 16:39:26 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2024-06-14 15:01:20 +0200 |
| commit | c0361dbef8c76fdea544d7733f29efe653d75b9e (patch) | |
| tree | 8a70465bae5671a9ee76ea188e664eba580b46a2 | |
| parent | 4e2c10994a7bd7916e74aedbe8f90e0da67d1a42 (diff) | |
| download | mullvadvpn-c0361dbef8c76fdea544d7733f29efe653d75b9e.tar.xz mullvadvpn-c0361dbef8c76fdea544d7733f29efe653d75b9e.zip | |
Add ui tests for api access method
6 files changed, 754 insertions, 0 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyApiAccessMethods.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyApiAccessMethods.kt new file mode 100644 index 0000000000..a644449a91 --- /dev/null +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyApiAccessMethods.kt @@ -0,0 +1,33 @@ +package net.mullvad.mullvadvpn.compose.data + +import net.mullvad.mullvadvpn.lib.model.ApiAccessMethod +import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId +import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodName +import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodSetting +import net.mullvad.mullvadvpn.lib.model.Cipher +import net.mullvad.mullvadvpn.lib.model.Port + +private const val UUID1 = "12345678-1234-5678-1234-567812345678" +private const val UUID2 = "12345678-1234-5678-1234-567812345679" + +val DIRECT_ACCESS_METHOD = + ApiAccessMethodSetting( + id = ApiAccessMethodId.fromString(UUID1), + name = ApiAccessMethodName.fromString("Direct"), + enabled = true, + apiAccessMethod = ApiAccessMethod.Direct + ) + +val CUSTOM_ACCESS_METHOD = + ApiAccessMethodSetting( + id = ApiAccessMethodId.fromString(UUID2), + name = ApiAccessMethodName.fromString("ShadowSocks"), + enabled = true, + apiAccessMethod = + ApiAccessMethod.CustomProxy.Shadowsocks( + ip = "1.1.1.1", + port = Port(123), + password = "Password", + cipher = Cipher.RC4 + ) + ) diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialogTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialogTest.kt new file mode 100644 index 0000000000..07f8b039eb --- /dev/null +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialogTest.kt @@ -0,0 +1,125 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import io.mockk.mockk +import io.mockk.verify +import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension +import net.mullvad.mullvadvpn.compose.setContentWithTheme +import net.mullvad.mullvadvpn.compose.state.SaveApiAccessMethodUiState +import net.mullvad.mullvadvpn.compose.state.TestApiAccessMethodState +import net.mullvad.mullvadvpn.compose.test.SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.SAVE_API_ACCESS_METHOD_LOADING_SPINNER_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.SAVE_API_ACCESS_METHOD_SAVE_BUTTON_TEST_TAG +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension + +@OptIn(ExperimentalTestApi::class) +class SaveApiAccessMethodDialogTest { + @JvmField @RegisterExtension val composeExtension = createEdgeToEdgeComposeExtension() + + @Test + fun whenTestingInProgressShouldShowSpinnerWithCancelButton() = + composeExtension.use { + // Arrange + setContentWithTheme { + SaveApiAccessMethodDialog( + state = + SaveApiAccessMethodUiState( + testingState = TestApiAccessMethodState.Testing, + isSaving = false + ) + ) + } + + // Assert + onNodeWithTag(SAVE_API_ACCESS_METHOD_LOADING_SPINNER_TEST_TAG).assertExists() + onNodeWithTag(SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG).assertExists() + } + + @Test + fun whenTestingFailedShouldShowSaveAndCancelButton() = + composeExtension.use { + // Arrange + setContentWithTheme { + SaveApiAccessMethodDialog( + state = + SaveApiAccessMethodUiState( + testingState = TestApiAccessMethodState.Result.Failure, + isSaving = false + ) + ) + } + + // Assert + onNodeWithTag(SAVE_API_ACCESS_METHOD_SAVE_BUTTON_TEST_TAG).assertExists() + onNodeWithTag(SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG).assertExists() + } + + @Test + fun whenTestingSuccessfulAndSavingShouldShowDisabledCancelButton() = + composeExtension.use { + // Arrange + setContentWithTheme { + SaveApiAccessMethodDialog( + state = + SaveApiAccessMethodUiState( + testingState = TestApiAccessMethodState.Result.Successful, + isSaving = true + ) + ) + } + + // Assert + onNodeWithTag(SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG).assertExists() + onNodeWithTag(SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG).assertIsNotEnabled() + } + + @Test + fun whenTestingInProgressAndClickingCancelShouldCallOnCancel() = + composeExtension.use { + // Arrange + val onCancelClick: () -> Unit = mockk(relaxed = true) + setContentWithTheme { + SaveApiAccessMethodDialog( + state = + SaveApiAccessMethodUiState( + testingState = TestApiAccessMethodState.Testing, + isSaving = false + ), + onCancel = onCancelClick + ) + } + + // Act + onNodeWithTag(SAVE_API_ACCESS_METHOD_CANCEL_BUTTON_TEST_TAG).performClick() + + // Assert + verify { onCancelClick() } + } + + @Test + fun whenTestingFailedAndClickingSaveShouldCallOnSave() = + composeExtension.use { + // Arrange + val onSaveClick: () -> Unit = mockk(relaxed = true) + setContentWithTheme { + SaveApiAccessMethodDialog( + state = + SaveApiAccessMethodUiState( + testingState = TestApiAccessMethodState.Result.Failure, + isSaving = false + ), + onSave = onSaveClick + ) + } + + // Act + onNodeWithTag(SAVE_API_ACCESS_METHOD_SAVE_BUTTON_TEST_TAG).performClick() + + // Assert + verify { onSaveClick() } + } +} diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreenTest.kt new file mode 100644 index 0000000000..97eed92d91 --- /dev/null +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreenTest.kt @@ -0,0 +1,111 @@ +package net.mullvad.mullvadvpn.compose.screen + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import io.mockk.mockk +import io.mockk.verify +import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension +import net.mullvad.mullvadvpn.compose.data.DIRECT_ACCESS_METHOD +import net.mullvad.mullvadvpn.compose.setContentWithTheme +import net.mullvad.mullvadvpn.compose.state.ApiAccessListUiState +import net.mullvad.mullvadvpn.compose.test.API_ACCESS_LIST_INFO_TEST_TAG +import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodSetting +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension + +@OptIn(ExperimentalTestApi::class) +class ApiAccessListScreenTest { + @JvmField @RegisterExtension val composeExtension = createEdgeToEdgeComposeExtension() + + @Test + fun shouldShowCurrentApiAccessName() = + composeExtension.use { + // Arrange + val currentApiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessListScreen( + state = + ApiAccessListUiState(currentApiAccessMethodSetting = currentApiAccessMethod) + ) + } + + // Assert + onNodeWithText("Current: ${currentApiAccessMethod.name}") + } + + @Test + fun shouldShowApiAccessNameAndStatusInList() = + composeExtension.use { + // Arrange + val apiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessListScreen( + state = ApiAccessListUiState(apiAccessMethodSettings = listOf(apiAccessMethod)) + ) + } + + // Assert + onNodeWithText(apiAccessMethod.name.value) + onNodeWithText("On") + } + + @Test + fun whenClickingOnAddMethodShouldCallOnAddMethodClicked() = + composeExtension.use { + // Arrange + val onAddMethodClick: () -> Unit = mockk(relaxed = true) + setContentWithTheme { + ApiAccessListScreen( + state = ApiAccessListUiState(), + onAddMethodClick = onAddMethodClick + ) + } + + // Act + onNodeWithText("Add").performClick() + + // Assert + verify { onAddMethodClick() } + } + + @Test + fun whenClickingOnInfoButtonShouldCallOnApiAccessInfoClick() = + composeExtension.use { + // Arrange + val onApiAccessInfoClick: () -> Unit = mockk(relaxed = true) + setContentWithTheme { + ApiAccessListScreen( + state = ApiAccessListUiState(), + onApiAccessInfoClick = onApiAccessInfoClick + ) + } + + // Act + onNodeWithTag(API_ACCESS_LIST_INFO_TEST_TAG).performClick() + + // Assert + verify { onApiAccessInfoClick() } + } + + @Test + fun whenClickingOnApiAccessMethodShouldCallOnApiAccessMethodClickWithCorrectAccessMethod() = + composeExtension.use { + // Arrange + val apiAccessMethod = DIRECT_ACCESS_METHOD + val onApiAccessMethodClick: (ApiAccessMethodSetting) -> Unit = mockk(relaxed = true) + setContentWithTheme { + ApiAccessListScreen( + state = ApiAccessListUiState(apiAccessMethodSettings = listOf(apiAccessMethod)), + onApiAccessMethodClick = onApiAccessMethodClick + ) + } + + // Act + onNodeWithText(apiAccessMethod.name.value).performClick() + + // Assert + verify { onApiAccessMethodClick(apiAccessMethod) } + } +} diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreenTest.kt new file mode 100644 index 0000000000..8dbd8f9832 --- /dev/null +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreenTest.kt @@ -0,0 +1,226 @@ +package net.mullvad.mullvadvpn.compose.screen + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import io.mockk.mockk +import io.mockk.verify +import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension +import net.mullvad.mullvadvpn.compose.data.CUSTOM_ACCESS_METHOD +import net.mullvad.mullvadvpn.compose.data.DIRECT_ACCESS_METHOD +import net.mullvad.mullvadvpn.compose.setContentWithTheme +import net.mullvad.mullvadvpn.compose.state.ApiAccessMethodDetailsUiState +import net.mullvad.mullvadvpn.compose.test.API_ACCESS_DETAILS_EDIT_BUTTON +import net.mullvad.mullvadvpn.compose.test.API_ACCESS_DETAILS_TOP_BAR_DROPDOWN_BUTTON_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.API_ACCESS_TEST_METHOD_BUTTON +import net.mullvad.mullvadvpn.compose.test.API_ACCESS_USE_METHOD_BUTTON +import net.mullvad.mullvadvpn.lib.model.ApiAccessMethodId +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension + +@OptIn(ExperimentalTestApi::class) +class ApiAccessMethodDetailsScreenTest { + @JvmField @RegisterExtension val composeExtension = createEdgeToEdgeComposeExtension() + + @Test + fun whenApiAccessMethodIsNotEditableShouldNotShowDeleteAndEdit() = + composeExtension.use { + // Arrange + val apiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = false, + isDisableable = true, + isCurrentMethod = true, + isTestingAccessMethod = false + ) + ) + } + + // Assert + onNodeWithTag(API_ACCESS_DETAILS_TOP_BAR_DROPDOWN_BUTTON_TEST_TAG).assertDoesNotExist() + onNodeWithTag(API_ACCESS_DETAILS_EDIT_BUTTON).assertDoesNotExist() + } + + @Test + fun whenApiAccessMethodIsNotDisableableShouldNotBeAbleDisable() = + composeExtension.use { + // Arrange + val onEnableClicked: (Boolean) -> Unit = mockk(relaxed = true) + val apiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = false, + isDisableable = false, + isCurrentMethod = true, + isTestingAccessMethod = false + ), + onEnableClicked = onEnableClicked + ) + } + + // Act + onNodeWithText("Enable method").performClick() + + // Assert + onNodeWithText("At least one method needs to be enabled") + verify(exactly = 0) { onEnableClicked(any()) } + } + + @Test + fun whenClickingOnDeleteMethodShouldCallOnDeleteApiAccessMethodClicked() = + composeExtension.use { + // Arrange + val onDeleteApiAccessMethodClicked: (ApiAccessMethodId) -> Unit = mockk(relaxed = true) + val apiAccessMethod = CUSTOM_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = true, + isDisableable = false, + isCurrentMethod = true, + isTestingAccessMethod = false + ), + onDeleteApiAccessMethodClicked = onDeleteApiAccessMethodClicked + ) + } + + // Act + onNodeWithTag(API_ACCESS_DETAILS_TOP_BAR_DROPDOWN_BUTTON_TEST_TAG).performClick() + onNodeWithText("Delete method").performClick() + + // Assert + verify(exactly = 1) { onDeleteApiAccessMethodClicked(apiAccessMethod.id) } + } + + @Test + fun whenClickingOnEditMethodShouldCallOnEditMethodClicked() = + composeExtension.use { + // Arrange + val onEditMethodClicked: () -> Unit = mockk(relaxed = true) + val apiAccessMethod = CUSTOM_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = true, + isDisableable = false, + isCurrentMethod = true, + isTestingAccessMethod = false + ), + onEditMethodClicked = onEditMethodClicked + ) + } + + // Act + onNodeWithTag(API_ACCESS_DETAILS_EDIT_BUTTON).performClick() + + // Assert + verify(exactly = 1) { onEditMethodClicked() } + } + + @Test + fun whenClickingOnEnableMethodShouldCallOnEnableClicked() = + composeExtension.use { + // Arrange + val onEnableClicked: (Boolean) -> Unit = mockk(relaxed = true) + val apiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = false, + isDisableable = true, + isCurrentMethod = true, + isTestingAccessMethod = false + ), + onEnableClicked = onEnableClicked + ) + } + + // Act + onNodeWithText("Enable method").performClick() + + // Assert + verify(exactly = 1) { onEnableClicked(false) } + } + + @Test + fun whenClickingOnTestMethodShouldCallOnTestMethodClicked() = + composeExtension.use { + // Arrange + val onTestMethodClicked: () -> Unit = mockk(relaxed = true) + val apiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = false, + isDisableable = true, + isCurrentMethod = true, + isTestingAccessMethod = false + ), + onTestMethodClicked = onTestMethodClicked + ) + } + + // Act + onNodeWithTag(API_ACCESS_TEST_METHOD_BUTTON).performClick() + + // Assert + verify(exactly = 1) { onTestMethodClicked() } + } + + @Test + fun whenClickingOnUseMethodShouldCallOnUseMethodClicked() = + composeExtension.use { + // Arrange + val onUseMethodClicked: () -> Unit = mockk(relaxed = true) + val apiAccessMethod = DIRECT_ACCESS_METHOD + setContentWithTheme { + ApiAccessMethodDetailsScreen( + state = + ApiAccessMethodDetailsUiState.Content( + apiAccessMethodId = apiAccessMethod.id, + name = apiAccessMethod.name, + enabled = apiAccessMethod.enabled, + isEditable = false, + isDisableable = true, + isCurrentMethod = false, + isTestingAccessMethod = false + ), + onUseMethodClicked = onUseMethodClicked + ) + } + + // Act + onNodeWithTag(API_ACCESS_USE_METHOD_BUTTON).performClick() + + // Assert + verify(exactly = 1) { onUseMethodClicked() } + } +} diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreenTest.kt new file mode 100644 index 0000000000..584be7e074 --- /dev/null +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreenTest.kt @@ -0,0 +1,257 @@ +package net.mullvad.mullvadvpn.compose.screen + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performTextInput +import io.mockk.mockk +import io.mockk.verify +import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension +import net.mullvad.mullvadvpn.compose.setContentWithTheme +import net.mullvad.mullvadvpn.compose.state.ApiAccessMethodTypes +import net.mullvad.mullvadvpn.compose.state.EditApiAccessFormData +import net.mullvad.mullvadvpn.compose.state.EditApiAccessMethodUiState +import net.mullvad.mullvadvpn.compose.test.EDIT_API_ACCESS_NAME_INPUT +import net.mullvad.mullvadvpn.lib.model.InvalidDataError +import net.mullvad.mullvadvpn.lib.model.ParsePortError +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension + +@OptIn(ExperimentalTestApi::class) +class EditApiAccessMethodScreenTest { + @JvmField @RegisterExtension val composeExtension = createEdgeToEdgeComposeExtension() + + @Test + fun whenInEditModeAddButtonShouldSaySave() = + composeExtension.use { + // Arrange + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = true, + formData = EditApiAccessFormData.empty(), + hasChanges = false, + isTestingApiAccessMethod = false + ) + ) + } + + // Assert + onNodeWithText("Save").assertExists() + } + + @Test + fun whenNotInEditModeAddButtonShouldSayAdd() = + composeExtension.use { + // Arrange + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = EditApiAccessFormData.empty(), + hasChanges = false, + isTestingApiAccessMethod = false + ) + ) + } + + // Assert + onNodeWithText("Add").assertExists() + } + + @Test + fun whenNameInputHasErrorShouldShowError() = + composeExtension.use { + // Arrange + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = + EditApiAccessFormData( + name = "", + nameError = InvalidDataError.NameError.Required, + serverIp = "", + username = "", + password = "", + port = "" + ), + hasChanges = false, + isTestingApiAccessMethod = false + ) + ) + } + + // Assert + onNodeWithText("This field is required").assertExists() + } + + @Test + fun whenServerInputIsNotIpAddressShouldShowError() = + composeExtension.use { + // Arrange + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = + EditApiAccessFormData( + name = "", + serverIp = "123", + serverIpError = InvalidDataError.ServerIpError.Invalid, + username = "", + password = "", + port = "" + ), + hasChanges = false, + isTestingApiAccessMethod = false + ) + ) + } + + // Assert + onNodeWithText("Please enter a valid IPv4 or IPv6 address").assertExists() + } + + @Test + fun whenPortInputIsNotWithinRangeShouldShowError() = + composeExtension.use { + // Arrange + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = + EditApiAccessFormData( + name = "", + serverIp = "", + username = "", + password = "", + port = "1111111111", + portError = + InvalidDataError.PortError.Invalid( + ParsePortError.OutOfRange(1111111111) + ) + ), + hasChanges = false, + isTestingApiAccessMethod = false + ) + ) + } + + // Assert + onNodeWithText("Please enter a valid remote server port").assertExists() + } + + @Test + fun whenNameInputChangesShouldCallOnNameChanged() = + composeExtension.use { + // Arrange + val onNameChanged: (String) -> Unit = mockk(relaxed = true) + val mockInput = "Name" + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = EditApiAccessFormData.empty(), + hasChanges = false, + isTestingApiAccessMethod = false + ), + onNameChanged = onNameChanged + ) + } + + // Act + onNodeWithTag(EDIT_API_ACCESS_NAME_INPUT).performTextInput(mockInput) + + // Assert + verify(exactly = 1) { onNameChanged(mockInput) } + } + + @Test + fun whenSocks5IsSelectedAndAuthenticationIsEnabledShouldShowUsernameAndPassword() = + composeExtension.use { + // Arrange + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = + EditApiAccessFormData( + name = "", + serverIp = "", + username = "", + password = "", + port = "", + enableAuthentication = true, + apiAccessMethodTypes = ApiAccessMethodTypes.SOCKS5_REMOTE + ), + hasChanges = false, + isTestingApiAccessMethod = false + ) + ) + } + + // Assert + onNodeWithText("Username").assertExists() + onNodeWithText("Password").assertExists() + } + + @Test + fun whenClickingOnTestMethodButtonShouldCallOnTestMethod() = + composeExtension.use { + // Arrange + val onTestMethod: () -> Unit = mockk(relaxed = true) + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = EditApiAccessFormData.empty(), + hasChanges = false, + isTestingApiAccessMethod = false + ), + onTestMethod = onTestMethod + ) + } + + // Act + onNodeWithText("Test method").performClick() + + // Assert + verify(exactly = 1) { onTestMethod() } + } + + @Test + fun whenClickingOnAddMethodButtonShouldCallOnAddMethod() = + composeExtension.use { + // Arrange + val onAddMethod: () -> Unit = mockk(relaxed = true) + setContentWithTheme { + EditApiAccessMethodScreen( + state = + EditApiAccessMethodUiState.Content( + editMode = false, + formData = EditApiAccessFormData.empty(), + hasChanges = false, + isTestingApiAccessMethod = false + ), + onAddMethod = onAddMethod + ) + } + + // Act + onNodeWithText("Add").performClick() + + // Assert + verify(exactly = 1) { onAddMethod() } + } +} diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt index b8b6a4e4b8..afa144f405 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt @@ -40,6 +40,7 @@ class SettingsScreenTest { onNodeWithText("VPN settings").assertExists() onNodeWithText("Split tunneling").assertExists() onNodeWithText("App version").assertExists() + onNodeWithText("API access").assertExists() } @Test @@ -62,5 +63,6 @@ class SettingsScreenTest { onNodeWithText("VPN settings").assertDoesNotExist() onNodeWithText("Split tunneling").assertDoesNotExist() onNodeWithText("App version").assertExists() + onNodeWithText("API access").assertExists() } } |
