summaryrefslogtreecommitdiffhomepage
path: root/ios
diff options
context:
space:
mode:
authorNiklas Berglund <niklas.berglund@gmail.com>2024-04-04 18:03:11 +0200
committerNiklas Berglund <niklas.berglund@gmail.com>2024-05-13 11:00:00 +0200
commitabed8379bc59aff40aa70439d10d6528dad758e2 (patch)
tree4a1358aecc82f29d6719247a09bee426063b5554 /ios
parent4380b7a738b777e494d164f920a19ad08338c4ff (diff)
downloadmullvadvpn-abed8379bc59aff40aa70439d10d6528dad758e2.tar.xz
mullvadvpn-abed8379bc59aff40aa70439d10d6528dad758e2.zip
Add iOS test making sure app functioning when API is down
Diffstat (limited to 'ios')
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj24
-rw-r--r--ios/MullvadVPN/Classes/AccessbilityIdentifier.swift25
-rw-r--r--ios/MullvadVPN/Coordinators/AccountCoordinator.swift1
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift2
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift1
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift3
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift2
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift2
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift8
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentView.swift10
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodViewController.swift3
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift1
-rw-r--r--ios/MullvadVPN/View controllers/Login/LoginViewController.swift11
-rw-r--r--ios/MullvadVPN/Views/CustomSwitchContainer.swift6
-rw-r--r--ios/MullvadVPNUITests/ConnectivityTests.swift121
-rw-r--r--ios/MullvadVPNUITests/Pages/APIAccessPage.swift28
-rw-r--r--ios/MullvadVPNUITests/Pages/AccountPage.swift5
-rw-r--r--ios/MullvadVPNUITests/Pages/AddAccessMethodPage.swift92
-rw-r--r--ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift41
-rw-r--r--ios/MullvadVPNUITests/Pages/LoginPage.swift4
-rw-r--r--ios/MullvadVPNUITests/Pages/Page.swift3
-rw-r--r--ios/MullvadVPNUITests/Pages/SettingsPage.swift8
-rw-r--r--ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift31
-rw-r--r--ios/MullvadVPNUITests/XCUIElement+Extensions.swift3
24 files changed, 401 insertions, 34 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index b01bed21d7..fc84c277da 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -631,6 +631,8 @@
852BC6702BAB44F500A47558 /* MullvadVPNUITestsChangeSettings.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 852BC66D2BAB44F500A47558 /* MullvadVPNUITestsChangeSettings.xctestplan */; };
852BC6712BAB44F500A47558 /* MullvadVPNUITestsVerifyDNSSettingsChanged.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 852BC66E2BAB44F500A47558 /* MullvadVPNUITestsVerifyDNSSettingsChanged.xctestplan */; };
852BC6732BAB450B00A47558 /* MullvadVPNUITestsChangeDNSSettings.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 852BC6722BAB450B00A47558 /* MullvadVPNUITestsChangeDNSSettings.xctestplan */; };
+ 852D054D2BC3DE3A008578D2 /* APIAccessPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852D054C2BC3DE3A008578D2 /* APIAccessPage.swift */; };
+ 852D054F2BC43DF7008578D2 /* AddAccessMethodPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852D054E2BC43DF7008578D2 /* AddAccessMethodPage.swift */; };
8532E6872B8CCED600ACECD1 /* ProblemReportSubmittedPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8532E6862B8CCED600ACECD1 /* ProblemReportSubmittedPage.swift */; };
8542CE242B95F7B9006FCA14 /* VPNSettingsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8542CE232B95F7B9006FCA14 /* VPNSettingsPage.swift */; };
8542F7532BCFBD050035C042 /* SelectLocationFilterPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8542F7522BCFBD050035C042 /* SelectLocationFilterPage.swift */; };
@@ -644,9 +646,10 @@
8556EB542B9A1D7100D26DD4 /* BridgingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 8556EB532B9A1D7100D26DD4 /* BridgingHeader.h */; };
8556EB562B9B0AC500D26DD4 /* RevokedDevicePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8556EB552B9B0AC500D26DD4 /* RevokedDevicePage.swift */; };
855D9F5B2B63E56B00D7C64D /* ProblemReportPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */; };
+ 856952E22BD6B04C008C1F84 /* XCUIElement+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856952E12BD6B04C008C1F84 /* XCUIElement+Extensions.swift */; };
+ 8585CBE32BC684180015B6A4 /* EditAccessMethodPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8585CBE22BC684180015B6A4 /* EditAccessMethodPage.swift */; };
8587A05D2B84D43100152938 /* ChangeLogAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8587A05C2B84D43100152938 /* ChangeLogAlert.swift */; };
8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */; };
- 85A42B862BB1D627007BABF7 /* XCUIElement+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A42B852BB1D627007BABF7 /* XCUIElement+Extensions.swift */; };
85A42B882BB44D31007BABF7 /* DeviceManagementPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A42B872BB44D31007BABF7 /* DeviceManagementPage.swift */; };
85B267612B849ADB0098E3CD /* mullvad-api.h in Headers */ = {isa = PBXBuildFile; fileRef = 85B267602B849ADB0098E3CD /* mullvad-api.h */; };
85C7A2E92B89024B00035D5A /* SettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C7A2E82B89024B00035D5A /* SettingsTests.swift */; };
@@ -1883,7 +1886,6 @@
850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControlPage.swift; sourceTree = "<group>"; };
850201E22B51A93C00EF8C96 /* SettingsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPage.swift; sourceTree = "<group>"; };
85139B2C2B84B4A700734217 /* OutOfTimePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutOfTimePage.swift; sourceTree = "<group>"; };
- 8518F6372B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedInWithoutTimeUITestCase.swift; sourceTree = "<group>"; };
852969252B4D9C1F007EAD4C /* MullvadVPNUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MullvadVPNUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
852969272B4D9C1F007EAD4C /* AccountTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTests.swift; sourceTree = "<group>"; };
852969302B4D9E70007EAD4C /* MullvadVPNUITestsAll.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MullvadVPNUITestsAll.xctestplan; sourceTree = "<group>"; };
@@ -1898,6 +1900,8 @@
852BC66D2BAB44F500A47558 /* MullvadVPNUITestsChangeSettings.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MullvadVPNUITestsChangeSettings.xctestplan; sourceTree = "<group>"; };
852BC66E2BAB44F500A47558 /* MullvadVPNUITestsVerifyDNSSettingsChanged.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MullvadVPNUITestsVerifyDNSSettingsChanged.xctestplan; sourceTree = "<group>"; };
852BC6722BAB450B00A47558 /* MullvadVPNUITestsChangeDNSSettings.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MullvadVPNUITestsChangeDNSSettings.xctestplan; sourceTree = "<group>"; };
+ 852D054C2BC3DE3A008578D2 /* APIAccessPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIAccessPage.swift; sourceTree = "<group>"; };
+ 852D054E2BC43DF7008578D2 /* AddAccessMethodPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccessMethodPage.swift; sourceTree = "<group>"; };
8532E6862B8CCED600ACECD1 /* ProblemReportSubmittedPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportSubmittedPage.swift; sourceTree = "<group>"; };
8542CE232B95F7B9006FCA14 /* VPNSettingsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNSettingsPage.swift; sourceTree = "<group>"; };
8542F7522BCFBD050035C042 /* SelectLocationFilterPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationFilterPage.swift; sourceTree = "<group>"; };
@@ -1912,11 +1916,12 @@
8556EB532B9A1D7100D26DD4 /* BridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = "<group>"; };
8556EB552B9B0AC500D26DD4 /* RevokedDevicePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RevokedDevicePage.swift; sourceTree = "<group>"; };
855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportPage.swift; sourceTree = "<group>"; };
+ 856952E12BD6B04C008C1F84 /* XCUIElement+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCUIElement+Extensions.swift"; sourceTree = "<group>"; };
+ 8585CBE22BC684180015B6A4 /* EditAccessMethodPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditAccessMethodPage.swift; sourceTree = "<group>"; };
8587A05C2B84D43100152938 /* ChangeLogAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeLogAlert.swift; sourceTree = "<group>"; };
859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedInWithTimeUITestCase.swift; sourceTree = "<group>"; };
8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; };
8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutUITestCase.swift; sourceTree = "<group>"; };
- 85A42B852BB1D627007BABF7 /* XCUIElement+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIElement+Extensions.swift"; sourceTree = "<group>"; };
85A42B872BB44D31007BABF7 /* DeviceManagementPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceManagementPage.swift; sourceTree = "<group>"; };
85B267602B849ADB0098E3CD /* mullvad-api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mullvad-api.h"; path = "../../mullvad-api/include/mullvad-api.h"; sourceTree = "<group>"; };
85C7A2E82B89024B00035D5A /* SettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTests.swift; sourceTree = "<group>"; };
@@ -3766,7 +3771,6 @@
8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */,
859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */,
8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */,
- 8518F6372B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift */,
);
path = "Test base classes";
sourceTree = "<group>";
@@ -3783,6 +3787,10 @@
85557B0C2B591B0F00795FE1 /* Networking */,
852969312B4E9220007EAD4C /* Pages */,
850201DA2B503D7700EF8C96 /* RelayTests.swift */,
+ 8518F6392B601910009EB113 /* Test base classes */,
+ 856952E12BD6B04C008C1F84 /* XCUIElement+Extensions.swift */,
+ 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */,
+ 85C7A2E82B89024B00035D5A /* SettingsTests.swift */,
85D039972BA4711800940E7F /* SettingsMigrationTests.swift */,
85C7A2E82B89024B00035D5A /* SettingsTests.swift */,
8518F6392B601910009EB113 /* Test base classes */,
@@ -3818,6 +3826,9 @@
8542CE232B95F7B9006FCA14 /* VPNSettingsPage.swift */,
85FB5A0B2B6903990015DCED /* WelcomePage.swift */,
8542F7522BCFBD050035C042 /* SelectLocationFilterPage.swift */,
+ 852D054C2BC3DE3A008578D2 /* APIAccessPage.swift */,
+ 852D054E2BC43DF7008578D2 /* AddAccessMethodPage.swift */,
+ 8585CBE22BC684180015B6A4 /* EditAccessMethodPage.swift */,
);
path = Pages;
sourceTree = "<group>";
@@ -5799,6 +5810,7 @@
buildActionMask = 2147483647;
files = (
A9BFB0012BD00B7F00F2BCA1 /* CustomListPage.swift in Sources */,
+ 8585CBE32BC684180015B6A4 /* EditAccessMethodPage.swift in Sources */,
8556EB522B9A1C6900D26DD4 /* MullvadApi.swift in Sources */,
85EC620C2B838D10005AFFB5 /* MullvadAPIWrapper.swift in Sources */,
A9DF789D2B7D1E8B0094E4AD /* LoggedInWithTimeUITestCase.swift in Sources */,
@@ -5808,10 +5820,11 @@
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */,
85D039982BA4711800940E7F /* SettingsMigrationTests.swift in Sources */,
850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */,
+ 852D054D2BC3DE3A008578D2 /* APIAccessPage.swift in Sources */,
85139B2D2B84B4A700734217 /* OutOfTimePage.swift in Sources */,
- 85A42B862BB1D627007BABF7 /* XCUIElement+Extensions.swift in Sources */,
852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */,
85E3BDE52B70E18C00FA71FD /* Networking.swift in Sources */,
+ 856952E22BD6B04C008C1F84 /* XCUIElement+Extensions.swift in Sources */,
85C7A2E92B89024B00035D5A /* SettingsTests.swift in Sources */,
8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */,
85557B202B5FBBD700795FE1 /* AccountPage.swift in Sources */,
@@ -5838,6 +5851,7 @@
85557B122B594FC900795FE1 /* ConnectivityTests.swift in Sources */,
852969332B4E9232007EAD4C /* Page.swift in Sources */,
A9A557F32B7E19B10017ADA8 /* SettingsPage.swift in Sources */,
+ 852D054F2BC43DF7008578D2 /* AddAccessMethodPage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
index 9fab241c13..f0d8c26ec0 100644
--- a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
+++ b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
@@ -10,7 +10,11 @@ import UIKit
public enum AccessibilityIdentifier: String {
// Buttons
+ case addAccessMethodButton
+ case accessMethodAddButton
case accountButton
+ case accessMethodUnreachableBackButton
+ case accessMethodUnreachableSaveButton
case agreeButton
case alertOkButton
case applyButton
@@ -56,6 +60,7 @@ public enum AccessibilityIdentifier: String {
// Cells
case deviceCell
+ case accessMethodProtocolSelectionCell
case vpnSettingsCell
case dnsSettingsAddServerCell
case dnsSettingsUseCustomDNSCell
@@ -83,8 +88,13 @@ public enum AccessibilityIdentifier: String {
case customListLocationCell
// Labels
- case accountPagePaidUntilLabel
case accountPageDeviceNameLabel
+ case socks5ServerCell
+ case socks5PortCell
+ case accountPagePaidUntilLabel
+ case addAccessMethodTestStatusReachableLabel
+ case addAccessMethodTestStatusTestingLabel
+ case addAccessMethodTestStatusUnreachableLabel
case headerDeviceNameLabel
case connectionStatusConnectedLabel
case connectionStatusNotConnectedLabel
@@ -92,11 +102,17 @@ public enum AccessibilityIdentifier: String {
case connectionPanelDetailLabel
// Views
+ case accessMethodProtocolPickerView
+ case accessMethodUnreachableAlert
case accountView
+ case addLocationsView
+ case addAccessMethodTableView
+ case apiAccessView
case alertContainerView
case alertTitle
case changeLogAlert
case deviceManagementView
+ case editAccessMethodView
case headerBarView
case loginView
case outOfTimeView
@@ -121,17 +137,24 @@ public enum AccessibilityIdentifier: String {
case editCustomListEditLocationsTableView
// Other UI elements
+ case accessMethodEnableSwitch
+ case accessMethodNameTextField
+ case logOutSpinnerAlertView
case connectionPanelInAddressRow
case connectionPanelOutAddressRow
case customSwitch
case customWireGuardPortTextField
case dnsContentBlockersHeaderView
case dnsSettingsEnterIPAddressTextField
+ case loginStatusIconAuthenticating
+ case loginStatusIconFailure
+ case loginStatusIconSuccess
case loginTextField
case selectLocationSearchTextField
case problemReportEmailTextField
case problemReportMessageTextView
case deleteAccountTextField
+ case socks5AuthenticationSwitch
// DNS settings
case dnsSettings
diff --git a/ios/MullvadVPN/Coordinators/AccountCoordinator.swift b/ios/MullvadVPN/Coordinators/AccountCoordinator.swift
index 51da8b43b9..839126f4fc 100644
--- a/ios/MullvadVPN/Coordinators/AccountCoordinator.swift
+++ b/ios/MullvadVPN/Coordinators/AccountCoordinator.swift
@@ -135,6 +135,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting {
private func logOut() {
let presentation = AlertPresentation(
id: "account-logout-alert",
+ accessibilityIdentifier: .logOutSpinnerAlertView,
icon: .spinner,
message: nil,
buttons: []
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift
index 55d9c01533..a4dc973eb3 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift
@@ -15,6 +15,8 @@ struct SwitchCellContentConfiguration: UIContentConfiguration, Equatable {
var color = UIColor.Cell.titleTextColor
}
+ var accessibilityIdentifier: AccessibilityIdentifier?
+
/// Text label.
var text: String?
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift
index a0a0d66eec..fe8817f523 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift
@@ -76,6 +76,7 @@ class SwitchCellContentView: UIView, UIContentView, UITextFieldDelegate {
private func configureSwitch() {
switchContainer.control.isOn = actualConfiguration.isOn
switchContainer.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
+ switchContainer.accessibilityIdentifier = accessibilityIdentifier
}
private func addSubviews() {
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift
index 201ec4e04c..e2dd45f9d6 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Common/SocksSectionHandler.swift
@@ -38,6 +38,7 @@ struct SocksSectionHandler {
contentConfiguration.inputText = subject.value.socks.server
contentConfiguration.textFieldProperties = .withSmartFeaturesDisabled()
contentConfiguration.editingEvents.onChange = subject.bindTextAction(to: \.socks.server)
+ cell.accessibilityIdentifier = .socks5ServerCell
cell.contentConfiguration = contentConfiguration
}
@@ -52,6 +53,7 @@ struct SocksSectionHandler {
if case .phone = cell.traitCollection.userInterfaceIdiom {
contentConfiguration.textFieldProperties.keyboardType = .numberPad
}
+ cell.accessibilityIdentifier = .socks5PortCell
cell.contentConfiguration = contentConfiguration
}
@@ -60,6 +62,7 @@ struct SocksSectionHandler {
contentConfiguration.text = itemIdentifier.text
contentConfiguration.isOn = subject.value.socks.authenticate
contentConfiguration.onChange = subject.bindSwitchAction(to: \.socks.authenticate)
+ contentConfiguration.accessibilityIdentifier = .socks5AuthenticationSwitch
cell.contentConfiguration = contentConfiguration
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift
index 55a907677a..710ea4a403 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift
@@ -43,6 +43,7 @@ class EditAccessMethodViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
+ view.accessibilityIdentifier = .editAccessMethodView
view.backgroundColor = .secondaryColor
tableView.backgroundColor = .secondaryColor
navigationItem.largeTitleDisplayMode = .never
@@ -197,6 +198,7 @@ class EditAccessMethodViewController: UITableViewController {
private func configureEnableMethod(_ cell: UITableViewCell, itemIdentifier: EditAccessMethodItemIdentifier) {
var contentConfiguration = SwitchCellContentConfiguration()
+ contentConfiguration.accessibilityIdentifier = .accessMethodEnableSwitch
contentConfiguration.text = itemIdentifier.text
contentConfiguration.isOn = subject.value.isEnabled
contentConfiguration.onChange = UIAction { [weak self] action in
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift
index ac712ef6fa..979a0ad9c3 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsCellConfiguration.swift
@@ -111,6 +111,7 @@ class MethodSettingsCellConfiguration {
contentConfiguration.inputText = subject.value.name
contentConfiguration.editingEvents.onChange = subject.bindTextAction(to: \.name)
+ cell.accessibilityIdentifier = .accessMethodNameTextField
cell.setDisabled(isTesting)
cell.contentConfiguration = contentConfiguration
}
@@ -153,6 +154,7 @@ class MethodSettingsCellConfiguration {
cell.disclosureType = .chevron
}
+ cell.accessibilityIdentifier = .accessMethodProtocolSelectionCell
cell.setDisabled(isTesting)
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift
index 78fc98bc73..44b18807ba 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodSettingsViewController.swift
@@ -76,10 +76,13 @@ class MethodSettingsViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
+ view.accessibilityIdentifier = .addAccessMethodTableView
view.directionalLayoutMargins = UIMetrics.contentLayoutMargins
view.backgroundColor = .secondaryColor
navigationItem.rightBarButtonItem = saveBarButton
+ navigationItem.rightBarButtonItem?.accessibilityIdentifier = .accessMethodAddButton
+ navigationItem.rightBarButtonItem?.isAccessibilityElement = true
isModalInPresentation = true
configureTableView()
@@ -307,6 +310,7 @@ class MethodSettingsViewController: UITableViewController {
case .failed:
let presentation = AlertPresentation(
id: "api-access-methods-testing-status-failed-alert",
+ accessibilityIdentifier: .accessMethodUnreachableAlert,
icon: .warning,
message: NSLocalizedString(
"METHOD_SETTINGS_SAVE_PROMPT",
@@ -323,6 +327,7 @@ class MethodSettingsViewController: UITableViewController {
comment: ""
),
style: .default,
+ accessibilityId: .accessMethodUnreachableSaveButton,
handler: { [weak self] in
self?.onSave()
}
@@ -334,7 +339,8 @@ class MethodSettingsViewController: UITableViewController {
value: "Back to editing",
comment: ""
),
- style: .default
+ style: .default,
+ accessibilityId: .accessMethodUnreachableBackButton
),
]
)
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentView.swift
index b8c9d5f205..425dd0798d 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentView.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/MethodSettings/MethodTestingStatusCellContentView.swift
@@ -136,6 +136,16 @@ class MethodTestingStatusCellContentView: UIView, UIContentView {
progressView.startAnimating()
}
+ // Set accessibility identifier for the text label based on the status it is indicating
+ switch actualConfiguration.status {
+ case .reachable:
+ textLabel.accessibilityIdentifier = .addAccessMethodTestStatusReachableLabel
+ case .unreachable:
+ textLabel.accessibilityIdentifier = .addAccessMethodTestStatusUnreachableLabel
+ case .testing:
+ textLabel.accessibilityIdentifier = .addAccessMethodTestStatusTestingLabel
+ }
+
// Text label is always the last one, so only add it into the stack if it's not there yet.
if textLabel.superview == nil {
horizontalStackView.addArrangedSubview(textLabel)
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodViewController.swift
index f4340e7877..2f32ddf1a9 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodViewController.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/List/ListAccessMethodViewController.swift
@@ -67,6 +67,8 @@ class ListAccessMethodViewController: UIViewController, UITableViewDelegate {
tableView.registerReusableViews(from: CellReuseIdentifier.self)
+ view.accessibilityIdentifier = .apiAccessView
+
view.addConstrainedSubviews([headerView, tableView]) {
headerView.pinEdgesToSuperview(.all().excluding(.bottom))
tableView.pinEdgesToSuperview(.all().excluding(.top))
@@ -117,6 +119,7 @@ class ListAccessMethodViewController: UIViewController, UITableViewDelegate {
button.addAction(UIAction { [weak self] _ in
self?.sendAddNew()
}, for: .touchUpInside)
+ button.accessibilityIdentifier = .addAccessMethodButton
let fontSize = button.titleLabel?.font.pointSize ?? 0
button.titleLabel?.font = UIFont.systemFont(ofSize: fontSize, weight: .regular)
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift
index 3d7cecbe60..8a852719fe 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Pickers/AccessMethodProtocolPicker.swift
@@ -23,6 +23,7 @@ struct AccessMethodProtocolPicker {
let dataSource = AccessMethodProtocolPickerDataSource()
let controller = ListItemPickerViewController(dataSource: dataSource, selectedItemID: currentValue)
+ controller.view.accessibilityIdentifier = .accessMethodProtocolPickerView
controller.navigationItem.title = NSLocalizedString(
"SELECT_PROTOCOL_NAV_TITLE",
diff --git a/ios/MullvadVPN/View controllers/Login/LoginViewController.swift b/ios/MullvadVPN/View controllers/Login/LoginViewController.swift
index a2879b098a..64d4ad01dc 100644
--- a/ios/MullvadVPN/View controllers/Login/LoginViewController.swift
+++ b/ios/MullvadVPN/View controllers/Login/LoginViewController.swift
@@ -267,6 +267,17 @@ class LoginViewController: UIViewController, RootContainment {
private func updateStatusIcon() {
contentView.statusActivityView.state = loginState.statusActivityState
+
+ switch loginState {
+ case .authenticating:
+ contentView.statusActivityView.accessibilityIdentifier = .loginStatusIconAuthenticating
+ case .failure:
+ contentView.statusActivityView.accessibilityIdentifier = .loginStatusIconFailure
+ case .success:
+ contentView.statusActivityView.accessibilityIdentifier = .loginStatusIconSuccess
+ default:
+ break
+ }
}
private func beginLogin(_ action: LoginAction) {
diff --git a/ios/MullvadVPN/Views/CustomSwitchContainer.swift b/ios/MullvadVPN/Views/CustomSwitchContainer.swift
index ae1a290f6e..ed0d9d3b22 100644
--- a/ios/MullvadVPN/Views/CustomSwitchContainer.swift
+++ b/ios/MullvadVPN/Views/CustomSwitchContainer.swift
@@ -31,6 +31,12 @@ class CustomSwitchContainer: UIView {
}
}
+ override var accessibilityIdentifier: String? {
+ didSet {
+ control.accessibilityIdentifier = accessibilityIdentifier
+ }
+ }
+
override var intrinsicContentSize: CGSize {
controlSize()
}
diff --git a/ios/MullvadVPNUITests/ConnectivityTests.swift b/ios/MullvadVPNUITests/ConnectivityTests.swift
index 3caa77dd84..64438308f9 100644
--- a/ios/MullvadVPNUITests/ConnectivityTests.swift
+++ b/ios/MullvadVPNUITests/ConnectivityTests.swift
@@ -13,10 +13,6 @@ import XCTest
class ConnectivityTests: LoggedOutUITestCase {
let firewallAPIClient = FirewallAPIClient()
- override func tearDownWithError() throws {
- super.tearDown()
- }
-
/// Verifies that the app still functions when API has been blocked
func testAPIConnectionViaBridges() throws {
addTeardownBlock {
@@ -97,16 +93,117 @@ class ConnectivityTests: LoggedOutUITestCase {
verifyDeviceHasBeenRemoved(deviceName: deviceName, accountNumber: hasTimeAccountNumber)
}
-}
-private func verifyDeviceHasBeenRemoved(deviceName: String, accountNumber: String) {
- do {
- let devices = try MullvadAPIWrapper().getDevices(accountNumber)
+ // swiftlint:disable function_body_length
+ /// Test that the app is functioning when API is down. To simulate API being down we create a dummy access method
+ func testAppStillFunctioningWhenAPIDown() throws {
+ addTeardownBlock {
+ HeaderBar(self.app)
+ .tapSettingsButton()
+
+ SettingsPage(self.app)
+ .tapAPIAccessCell()
+
+ self.toggleAllAccessMethodsEnabledSwitchesIfOff()
+ }
+
+ // Setup. Create a dummy access method to simulate API being down(unreachable)
+ LoginPage(app)
+ .tapAccountNumberTextField()
+ .enterText(self.hasTimeAccountNumber)
+ .tapAccountNumberSubmitButton()
+
+ TunnelControlPage(app)
+
+ HeaderBar(app)
+ .tapSettingsButton()
+
+ SettingsPage(app)
+ .tapAPIAccessCell()
+
+ toggleAllAccessMethodsEnabledSwitches()
+
+ APIAccessPage(app)
+ .tapAddButton()
+
+ allowLocalNetworkAccessIfAsked()
+
+ AddAccessMethodPage(app)
+ .tapNameCell()
+ .enterText("Disable-access-dummy")
+ .tapTypeCell()
+ .tapSOCKS5TypeValueCell()
+ .tapServerCell()
+ .enterText("123.123.123.123")
+ .dismissKeyboard()
+ .tapPortCell()
+ .enterText("123")
+ .dismissKeyboard()
+ .tapAddButton()
+ .waitForAPIUnreachableLabel()
+
+ AddAccessMethodAPIUnreachableAlert(app)
+ .tapSaveButton()
+
+ SettingsPage(app)
+ .swipeDownToDismissModal()
+
+ // Actual test. Make sure it is possible to connect to a relay
+ TunnelControlPage(app)
+ .tapSecureConnectionButton()
+
+ allowAddVPNConfigurationsIfAsked()
+
+ TunnelControlPage(app)
+ .waitForSecureConnectionLabel()
+
+ HeaderBar(app)
+ .tapAccountButton()
+
+ // Log out will take long because API cannot be reached
+ AccountPage(app)
+ .tapLogOutButton()
+ .waitForSpinnerNoLongerShown()
+
+ // Verify API cannot be reached by doing a login attempt which should fail
+ LoginPage(app)
+ .tapAccountNumberTextField()
+ .enterText(self.hasTimeAccountNumber)
+ .tapAccountNumberSubmitButton()
+ .verifyFailIconShown()
+ }
+
+ private func verifyDeviceHasBeenRemoved(deviceName: String, accountNumber: String) {
+ do {
+ let devices = try MullvadAPIWrapper().getDevices(accountNumber)
+
+ for device in devices where device.name == deviceName {
+ XCTFail("Device has not been removed which tells us that the logout was not successful")
+ }
+ } catch {
+ XCTFail("Failed to get devices from app API")
+ }
+ }
+
+ // swiftlint:enable function_body_length
+
+ /// Toggle enabled switch for all existing access methods. It is a precondition that the app is currently showing API access view.
+ private func toggleAllAccessMethodsEnabledSwitches() {
+ for cell in APIAccessPage(app).getAccessMethodCells() {
+ cell.tap()
+ EditAccessMethodPage(app)
+ .tapEnableMethodSwitch()
+ .tapBackButton()
+ }
+ }
- for device in devices where device.name == deviceName {
- XCTFail("Device has not been removed which tells us that the logout was not successful")
+ /// Toggle enabled switch for all existing access methods if the switch is in off state. It is a precondition that the app is currently showing API access view.
+ private func toggleAllAccessMethodsEnabledSwitchesIfOff() {
+ for cell in APIAccessPage(app).getAccessMethodCells() {
+ cell.tap()
+ EditAccessMethodPage(app)
+ .tapEnableMethodSwitchIfOff()
+ .tapBackButton()
}
- } catch {
- XCTFail("Failed to get devices from app API")
}
}
diff --git a/ios/MullvadVPNUITests/Pages/APIAccessPage.swift b/ios/MullvadVPNUITests/Pages/APIAccessPage.swift
new file mode 100644
index 0000000000..33d8be3393
--- /dev/null
+++ b/ios/MullvadVPNUITests/Pages/APIAccessPage.swift
@@ -0,0 +1,28 @@
+//
+// APIAccessPage.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-04-08.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import XCTest
+
+class APIAccessPage: Page {
+ override init(_ app: XCUIApplication) {
+ super.init(app)
+ self.pageAccessibilityIdentifier = .apiAccessView
+ waitForPageToBeShown()
+ }
+
+ @discardableResult func tapAddButton() -> Self {
+ app.buttons[AccessibilityIdentifier.addAccessMethodButton]
+ .tap()
+ return self
+ }
+
+ func getAccessMethodCells() -> [XCUIElement] {
+ return app.otherElements[AccessibilityIdentifier.apiAccessView].cells.allElementsBoundByIndex
+ }
+}
diff --git a/ios/MullvadVPNUITests/Pages/AccountPage.swift b/ios/MullvadVPNUITests/Pages/AccountPage.swift
index 811f3ef68d..83082f3395 100644
--- a/ios/MullvadVPNUITests/Pages/AccountPage.swift
+++ b/ios/MullvadVPNUITests/Pages/AccountPage.swift
@@ -68,7 +68,12 @@ class AccountPage: Page {
}
XCTAssertEqual(strippedDate, paidUntilLabelDate)
+ return self
+ }
+ @discardableResult func waitForSpinnerNoLongerShown() -> Self {
+ app.otherElements[AccessibilityIdentifier.logOutSpinnerAlertView]
+ .waitForNonExistence(timeout: BaseUITestCase.veryLongTimeout)
return self
}
}
diff --git a/ios/MullvadVPNUITests/Pages/AddAccessMethodPage.swift b/ios/MullvadVPNUITests/Pages/AddAccessMethodPage.swift
new file mode 100644
index 0000000000..698397bbbc
--- /dev/null
+++ b/ios/MullvadVPNUITests/Pages/AddAccessMethodPage.swift
@@ -0,0 +1,92 @@
+//
+// AddAccessMethodPage.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-04-08.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import XCTest
+
+class AddAccessMethodPage: Page {
+ override init(_ app: XCUIApplication) {
+ super.init(app)
+
+ self.pageAccessibilityIdentifier = .addAccessMethodTableView
+ waitForPageToBeShown()
+ }
+
+ @discardableResult func tapNameCell() -> Self {
+ app.cells[AccessibilityIdentifier.accessMethodNameTextField]
+ .tap()
+ return self
+ }
+
+ @discardableResult func tapTypeCell() -> Self {
+ app.cells[AccessibilityIdentifier.accessMethodProtocolSelectionCell]
+ .tap()
+ return self
+ }
+
+ @discardableResult func tapShadowsocksTypeValueCell() -> Self {
+ app.tables[AccessibilityIdentifier.accessMethodProtocolPickerView].staticTexts["Shadowsocks"].tap()
+ return self
+ }
+
+ @discardableResult func tapSOCKS5TypeValueCell() -> Self {
+ app.tables[AccessibilityIdentifier.accessMethodProtocolPickerView].staticTexts["SOCKS5"].tap()
+ return self
+ }
+
+ @discardableResult func tapServerCell() -> Self {
+ app.cells[AccessibilityIdentifier.socks5ServerCell]
+ .tap()
+ return self
+ }
+
+ @discardableResult func tapPortCell() -> Self {
+ app.cells[AccessibilityIdentifier.socks5PortCell]
+ .tap()
+ return self
+ }
+
+ @discardableResult func tapAuthenticationSwitch() -> Self {
+ app.switches[AccessibilityIdentifier.socks5AuthenticationSwitch]
+ .tap()
+ return self
+ }
+
+ @discardableResult func tapAddButton() -> Self {
+ app.buttons[AccessibilityIdentifier.accessMethodAddButton]
+ .tap()
+ return self
+ }
+
+ @discardableResult func waitForAPIUnreachableLabel() -> Self {
+ XCTAssertTrue(
+ app.staticTexts[AccessibilityIdentifier.addAccessMethodTestStatusUnreachableLabel]
+ .waitForExistence(timeout: BaseUITestCase.longTimeout)
+ )
+ return self
+ }
+}
+
+class AddAccessMethodAPIUnreachableAlert: Page {
+ override init(_ app: XCUIApplication) {
+ super.init(app)
+
+ self.pageAccessibilityIdentifier = .accessMethodUnreachableAlert
+ waitForPageToBeShown()
+ }
+
+ @discardableResult func tapSaveButton() -> Self {
+ app.buttons[AccessibilityIdentifier.accessMethodUnreachableSaveButton].tap()
+ return self
+ }
+
+ @discardableResult func tapBackButton() -> Self {
+ app.buttons[AccessibilityIdentifier.accessMethodUnreachableBackButton].tap()
+ return self
+ }
+}
diff --git a/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift b/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift
new file mode 100644
index 0000000000..68f21d35cc
--- /dev/null
+++ b/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift
@@ -0,0 +1,41 @@
+//
+// EditAccessMethodPage.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-04-10.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import XCTest
+
+class EditAccessMethodPage: Page {
+ override init(_ app: XCUIApplication) {
+ super.init(app)
+
+ self.pageAccessibilityIdentifier = .editAccessMethodView
+ waitForPageToBeShown()
+ }
+
+ @discardableResult func tapEnableMethodSwitch() -> Self {
+ app.switches[AccessibilityIdentifier.accessMethodEnableSwitch].tap()
+ return self
+ }
+
+ @discardableResult func tapEnableMethodSwitchIfOff() -> Self {
+ let enableMethodSwitch = app.switches[AccessibilityIdentifier.accessMethodEnableSwitch]
+
+ if enableMethodSwitch.value as? String == "0" {
+ tapEnableMethodSwitch()
+ }
+
+ return self
+ }
+
+ @discardableResult func tapBackButton() -> Self {
+ // Workaround due to the way automatically managed back buttons work. Back button needs to be nil for the automatic back button behaviour in iOS, and since its nil we cannot set accessibilityIdentifier for it
+ let backButton = app.navigationBars.firstMatch.buttons.firstMatch
+ backButton.tap()
+ return self
+ }
+}
diff --git a/ios/MullvadVPNUITests/Pages/LoginPage.swift b/ios/MullvadVPNUITests/Pages/LoginPage.swift
index 96c6ebea89..f7b204b344 100644
--- a/ios/MullvadVPNUITests/Pages/LoginPage.swift
+++ b/ios/MullvadVPNUITests/Pages/LoginPage.swift
@@ -43,11 +43,13 @@ class LoginPage: Page {
@discardableResult public func verifySuccessIconShown() -> Self {
_ = app.images.element(matching: .image, identifier: "IconSuccess")
+ .waitForExistence(timeout: BaseUITestCase.defaultTimeout)
return self
}
@discardableResult public func verifyFailIconShown() -> Self {
- _ = app.images.element(matching: .image, identifier: "IconFail").waitForExistence(timeout: 15)
+ _ = app.images.element(matching: .image, identifier: "IconFail")
+ .waitForExistence(timeout: BaseUITestCase.longTimeout)
return self
}
}
diff --git a/ios/MullvadVPNUITests/Pages/Page.swift b/ios/MullvadVPNUITests/Pages/Page.swift
index 9ac69f8ce0..09a6b5b2ae 100644
--- a/ios/MullvadVPNUITests/Pages/Page.swift
+++ b/ios/MullvadVPNUITests/Pages/Page.swift
@@ -20,7 +20,8 @@ class Page {
func waitForPageToBeShown() {
if let pageAccessibilityIdentifier = self.pageAccessibilityIdentifier {
XCTAssert(
- self.app.otherElements[pageAccessibilityIdentifier]
+ self.app.descendants(matching: .any).matching(identifier: pageAccessibilityIdentifier.rawValue)
+ .firstMatch
.waitForExistence(timeout: BaseUITestCase.defaultTimeout)
)
}
diff --git a/ios/MullvadVPNUITests/Pages/SettingsPage.swift b/ios/MullvadVPNUITests/Pages/SettingsPage.swift
index 6ed383afa9..db28fb33c9 100644
--- a/ios/MullvadVPNUITests/Pages/SettingsPage.swift
+++ b/ios/MullvadVPNUITests/Pages/SettingsPage.swift
@@ -24,6 +24,14 @@ class SettingsPage: Page {
return self
}
+ @discardableResult func tapAPIAccessCell() -> Self {
+ app
+ .cells[AccessibilityIdentifier.apiAccessCell]
+ .tap()
+
+ return self
+ }
+
@discardableResult func tapVPNSettingsCell() -> Self {
app.tables[AccessibilityIdentifier.settingsTableView]
.cells[AccessibilityIdentifier.vpnSettingsCell]
diff --git a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift
index 82feccc89e..3551f482fe 100644
--- a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift
+++ b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift
@@ -12,6 +12,8 @@ import XCTest
class BaseUITestCase: XCTestCase {
let app = XCUIApplication()
static let defaultTimeout = 5.0
+ static let longTimeout = 15.0
+ static let veryLongTimeout = 60.0
static let shortTimeout = 1.0
// swiftlint:disable force_cast
@@ -25,27 +27,32 @@ class BaseUITestCase: XCTestCase {
.infoDictionary?["IOSDevicePinCode"] as! String
// swiftlint:enable force_cast
- /// Handle iOS add VPN configuration permission alert - allow and enter device PIN code
- func allowAddVPNConfigurations() {
+ /// Handle iOS add VPN configuration permission alert if presented, otherwise ignore
+ func allowAddVPNConfigurationsIfAsked() {
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
- let alertAllowButton = springboard.buttons.element(boundBy: 0)
- if alertAllowButton.waitForExistence(timeout: Self.defaultTimeout) {
- alertAllowButton.tap()
- }
+ if springboard.buttons["Allow"].waitForExistence(timeout: Self.shortTimeout) {
+ let alertAllowButton = springboard.buttons.element(boundBy: 0)
+ if alertAllowButton.waitForExistence(timeout: Self.defaultTimeout) {
+ alertAllowButton.tap()
+ }
- if iOSDevicePinCode.isEmpty == false {
- _ = springboard.buttons["1"].waitForExistence(timeout: Self.defaultTimeout)
- springboard.typeText(iOSDevicePinCode)
+ if iOSDevicePinCode.isEmpty == false {
+ _ = springboard.buttons["1"].waitForExistence(timeout: Self.defaultTimeout)
+ springboard.typeText(iOSDevicePinCode)
+ }
}
}
- /// Handle iOS add VPN configuration permission alert if presented, otherwise ignore
- func allowAddVPNConfigurationsIfAsked() {
+ /// Handle iOS local network access permission alert if presented, otherwise ignore
+ func allowLocalNetworkAccessIfAsked() {
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
if springboard.buttons["Allow"].waitForExistence(timeout: Self.shortTimeout) {
- allowAddVPNConfigurations()
+ let alertAllowButton = springboard.buttons["Allow"]
+ if alertAllowButton.waitForExistence(timeout: Self.defaultTimeout) {
+ alertAllowButton.tap()
+ }
}
}
diff --git a/ios/MullvadVPNUITests/XCUIElement+Extensions.swift b/ios/MullvadVPNUITests/XCUIElement+Extensions.swift
index 9f0aa87188..271d5a767c 100644
--- a/ios/MullvadVPNUITests/XCUIElement+Extensions.swift
+++ b/ios/MullvadVPNUITests/XCUIElement+Extensions.swift
@@ -12,7 +12,8 @@ extension XCUIElement {
func waitForNonExistence(timeout: TimeInterval) -> Bool {
let predicate = NSPredicate(format: "exists == FALSE")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self)
- _ = XCTWaiter.wait(for: [expectation], timeout: timeout)
+
+ _ = XCTWaiter().wait(for: [expectation], timeout: timeout)
return !exists
}
}