Skip to content

Commit

Permalink
Migrate ConnectionTest e2e tests to use POP
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasberglund committed Dec 6, 2024
1 parent 4baba02 commit 3fe2615
Show file tree
Hide file tree
Showing 13 changed files with 372 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import androidx.compose.ui.unit.dp
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.test.TOP_BAR_ACCOUNT_BUTTON
import net.mullvad.mullvadvpn.compose.test.TOP_BAR_SETTINGS_BUTTON
import net.mullvad.mullvadvpn.compose.test.TOP_BAR_TEST_TAG
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens

Expand Down Expand Up @@ -117,7 +118,7 @@ fun MullvadTopBar(
isIconAndLogoVisible: Boolean = true,
) {
TopAppBar(
modifier = modifier,
modifier = modifier.testTag(TOP_BAR_TEST_TAG),
title = {
if (isIconAndLogoVisible) {
Row(verticalAlignment = Alignment.CenterVertically) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider
import net.mullvad.mullvadvpn.compose.preview.SettingsUiStatePreviewParameterProvider
import net.mullvad.mullvadvpn.compose.state.SettingsUiState
import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG
import net.mullvad.mullvadvpn.compose.test.VPN_SETTINGS_CELL_TEST_TAG
import net.mullvad.mullvadvpn.compose.transitions.TopLevelTransition
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
Expand Down Expand Up @@ -115,6 +116,7 @@ fun SettingsScreen(
NavigationComposeCell(
title = stringResource(id = R.string.settings_vpn),
onClick = onVpnSettingCellClick,
testTag = VPN_SETTINGS_CELL_TEST_TAG,
)
}
item { Spacer(modifier = Modifier.height(Dimens.cellVerticalSpacing)) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
Expand Down Expand Up @@ -63,6 +64,7 @@ import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed
import net.mullvad.mullvadvpn.compose.preview.SelectLocationsUiStatePreviewParameterProvider
import net.mullvad.mullvadvpn.compose.state.RelayListType
import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState
import net.mullvad.mullvadvpn.compose.test.SELECT_LOCATION_SCREEN_TEST_TAG
import net.mullvad.mullvadvpn.compose.transitions.TopLevelTransition
import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle
import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately
Expand Down Expand Up @@ -237,6 +239,7 @@ fun SelectLocationScreen(
)
}
},
modifier = Modifier.testTag(SELECT_LOCATION_SCREEN_TEST_TAG),
snackbarHostState = snackbarHostState,
actions = {
IconButton(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package net.mullvad.mullvadvpn.compose.test
// Top Bar
const val TOP_BAR_ACCOUNT_BUTTON = "top_bar_account_button"
const val TOP_BAR_SETTINGS_BUTTON = "top_bar_settings_button"
const val TOP_BAR_TEST_TAG = "top_bar_test_tag"

// Settings screen
const val VPN_SETTINGS_CELL_TEST_TAG = "vpn_settings_cell_test_tag"

// VpnSettingsScreen
const val LAZY_LIST_VPN_SETTINGS_TEST_TAG = "lazy_list_vpn_settings_test_tag"
Expand All @@ -24,6 +28,7 @@ const val WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL =
"wireguard_obfuscation_udp_over_tcp_cell_test_tag"

// SelectLocationScreen, ConnectScreen, CustomListLocationsScreen
const val SELECT_LOCATION_SCREEN_TEST_TAG = "select_location_screen_test_tag"
const val CIRCULAR_PROGRESS_INDICATOR = "circular_progress_indicator"
const val EXPAND_BUTTON_TEST_TAG = "expand_button_test_tag"
const val LOCATION_CELL_TEST_TAG = "location_cell_test_tag"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,79 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.constant.VERY_LONG_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class ConnectPage internal constructor() : Page() {
private val disconnectSelector = By.text("Disconnect")
private val cancelSelector = By.text("Cancel")
private val connectedSelector = By.text("CONNECTED")
private val connectingSelector = By.text("CONNECTING...")

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.res("connect_card_header_test_tag"))
uiDevice.findObjectWithTimeout(By.res(CONNECT_CARD_HEADER_TEST_TAG))
}

fun clickSelectLocation() {
uiDevice.findObjectWithTimeout(By.res(SELECT_LOCATION_BUTTON_TEST_TAG)).click()
}

fun clickConnect() {
uiDevice.findObjectWithTimeout(By.res(CONNECT_BUTTON_TEST_TAG)).click()
}

fun clickDisconnect() {
uiDevice.findObjectWithTimeout(disconnectSelector).click()
}

fun clickCancel() {
uiDevice.findObjectWithTimeout(cancelSelector).click()
}

fun waitForConnectedLabel(timeout: Long = VERY_LONG_TIMEOUT) {
uiDevice.findObjectWithTimeout(connectedSelector, timeout)
}

fun waitForConnectingLabel() {
uiDevice.findObjectWithTimeout(connectingSelector)
}

/**
* Extracts the in IPv4 address from the connection card. It is a prerequisite that the
* connection card is in collapsed state.
*/
fun extractInIpv4Address(): String {
uiDevice.findObjectWithTimeout(By.res("connect_card_header_test_tag")).click()
val inString =
uiDevice
.findObjectWithTimeout(
By.res("location_info_connection_in_test_tag"),
VERY_LONG_TIMEOUT,
)
.text

val extractedIpAddress = inString.split(" ")[0].split(":")[0]
return extractedIpAddress
}

/**
* Extracts the out IPv4 address from the connection card. It is a prerequisite that the
* connection card is in collapsed state.
*/
fun extractOutIpv4Address(): String {
uiDevice.findObjectWithTimeout(By.res("connect_card_header_test_tag")).click()
return uiDevice
.findObjectWithTimeout(
// Text exist and contains IP address
By.res("location_info_connection_out_test_tag").textContains("."),
VERY_LONG_TIMEOUT,
)
.text
}

companion object {
const val CONNECT_CARD_HEADER_TEST_TAG = "connect_card_header_test_tag"
const val SELECT_LOCATION_BUTTON_TEST_TAG = "select_location_button_test_tag"
const val CONNECT_BUTTON_TEST_TAG = "connect_button_test_tag"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import net.mullvad.mullvadvpn.test.common.constant.EXTREMELY_LONG_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class LoginPage internal constructor() : Page() {
private val invalidAccountNumberSelector = By.text("Invalid account number")
private val loginSelector = By.text("Login")

fun enterAccountNumber(accountNumber: String) {
uiDevice.findObjectWithTimeout(By.clazz("android.widget.EditText")).text = accountNumber
}
Expand All @@ -20,10 +23,10 @@ class LoginPage internal constructor() : Page() {
}

fun verifyShowingInvalidAccount() {
uiDevice.findObjectWithTimeout(By.text("Invalid account number"), EXTREMELY_LONG_TIMEOUT)
uiDevice.findObjectWithTimeout(invalidAccountNumberSelector, EXTREMELY_LONG_TIMEOUT)
}

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.text("Login"))
uiDevice.findObjectWithTimeout(loginSelector)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import net.mullvad.mullvadvpn.test.common.constant.DEFAULT_TIMEOUT
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class PrivacyPage internal constructor() : Page() {
private val privacySelector = By.text("Privacy")
private val agreeSelector = By.text("Agree and continue")
private val allowSelector = By.text("Allow")

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.text("Privacy"))
uiDevice.findObjectWithTimeout(privacySelector)
}

fun clickAgreeOnPrivacyDisclaimer() {
uiDevice.findObjectWithTimeout(By.text("Agree and continue")).click()
uiDevice.findObjectWithTimeout(agreeSelector).click()
}

fun clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove(
Expand All @@ -23,12 +27,10 @@ class PrivacyPage internal constructor() : Page() {
return
}

val selector = By.text("Allow")

uiDevice.wait(Until.hasObject(selector), timeout)
uiDevice.wait(Until.hasObject(allowSelector), timeout)

try {
uiDevice.findObjectWithTimeout(selector).click()
uiDevice.findObjectWithTimeout(allowSelector).click()
} catch (e: IllegalArgumentException) {
throw IllegalArgumentException(
"Failed to allow notification permission within timeout ($timeout)"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class SelectLocationPage internal constructor() : Page() {
override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.res(SELECT_LOCATION_SCREEN_TEST_TAG))
}

fun clickLocationExpandButton(locationName: String) {
val locationCell = uiDevice.findObjectWithTimeout(By.text(locationName)).parent.parent
val expandButton = locationCell.findObjectWithTimeout(By.res(EXPAND_BUTTON_TEST_TAG))
expandButton.click()
}

fun clickLocationCell(locationName: String) {
uiDevice.findObjectWithTimeout(By.text(locationName)).click()
}

companion object {
const val SELECT_LOCATION_SCREEN_TEST_TAG = "select_location_screen_test_tag"
const val EXPAND_BUTTON_TEST_TAG = "expand_button_test_tag"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class SettingsPage internal constructor() : Page() {
private val settingsSelector = By.text("Settings")

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(settingsSelector)
}

fun clickVpnSettings() {
uiDevice.findObjectWithTimeout(By.res(VPN_SETTINGS_CELL_TEST_TAG)).click()
}

companion object {
const val VPN_SETTINGS_CELL_TEST_TAG = "vpn_settings_cell_test_tag"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class SystemVpnConfigurationAlert internal constructor() : Page() {
private val okSelector = By.text("OK")

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(okSelector)
}

fun clickOk() {
uiDevice.findObjectWithTimeout(okSelector).click()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class TopBar internal constructor() : Page() {
override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(By.res(TOP_BAR_TEST_TAG))
}

fun clickSettings() {
uiDevice.findObjectWithTimeout(By.res(TOP_BAR_SETTINGS_BUTTON)).click()
}

fun clickAccount() {
uiDevice.findObjectWithTimeout(By.res(TOP_BAR_ACCOUNT_BUTTON)).click()
}

companion object {
const val TOP_BAR_TEST_TAG = "top_bar_test_tag"
const val TOP_BAR_ACCOUNT_BUTTON = "top_bar_account_button"
const val TOP_BAR_SETTINGS_BUTTON = "top_bar_settings_button"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package net.mullvad.mullvadvpn.test.common.page

import androidx.test.uiautomator.By
import androidx.test.uiautomator.Direction
import androidx.test.uiautomator.Until
import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout

class VpnSettingsPage internal constructor() : Page() {
private val vpnSettingsSelector = By.text("VPN settings")
private val localNetworkSharingSelector = By.text("Local network sharing")

override fun assertIsDisplayed() {
uiDevice.findObjectWithTimeout(vpnSettingsSelector)
}

fun clickLocalNetworkSharingSwitch() {
val localNetworkSharingCell =
uiDevice.findObjectWithTimeout(localNetworkSharingSelector).parent
val localNetworkSharingSwitch =
localNetworkSharingCell.findObjectWithTimeout(By.res(SWITCH_TEST_TAG))

localNetworkSharingSwitch.click()
}

fun scrollUntilWireguardObfuscationUdpOverTcpCell() {
scrollUntilCell(WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL_TEST_TAG)
}

fun scrollUntilWireguardObfuscationOffCell() {
scrollUntilCell(WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG)
}

fun clickWireguardObfuscationUdpOverTcpCell() {
uiDevice
.findObjectWithTimeout(By.res(WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL_TEST_TAG))
.click()
}

fun clickWireguardObfuscationOffCell() {
uiDevice.findObjectWithTimeout(By.res(WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG)).click()
}

private fun scrollUntilCell(testTag: String) {
val scrollView2 = uiDevice.findObjectWithTimeout(By.res(SETTINGS_SCROLL_VIEW_TEST_TAG))
scrollView2.scrollUntil(Direction.DOWN, Until.hasObject(By.res(testTag)))
}

companion object {
const val SETTINGS_SCROLL_VIEW_TEST_TAG = "lazy_list_vpn_settings_test_tag"
const val WIREGUARD_OBFUSCATION_UDP_OVER_TCP_CELL_TEST_TAG =
"wireguard_obfuscation_udp_over_tcp_cell_test_tag"
const val WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG =
"wireguard_obfuscation_off_cell_test_tag"
const val SWITCH_TEST_TAG = "switch_test_tag"
}
}
Loading

0 comments on commit 3fe2615

Please sign in to comment.