summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNiklas Berglund <niklas.berglund@gmail.com>2024-01-22 17:57:48 +0100
committerBug Magnet <marco.nikic@mullvad.net>2024-01-31 16:21:05 +0100
commitac131e3b68998baf24889defe4532d9fd8fcf294 (patch)
treeeb943a2694f19cb21bb9d37efa85306a037fa661
parent894f9ee16841292a722076be9ea6db2397f6f15c (diff)
downloadmullvadvpn-ac131e3b68998baf24889defe4532d9fd8fcf294.tar.xz
mullvadvpn-ac131e3b68998baf24889defe4532d9fd8fcf294.zip
Add setup and teardown for iOS UI tests
-rw-r--r--ios/Configurations/Base.xcconfig.template3
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj44
-rw-r--r--ios/MullvadVPN/Classes/AccessbilityIdentifier.swift3
-rw-r--r--ios/MullvadVPN/Containers/Root/HeaderBarView.swift1
-rw-r--r--ios/MullvadVPN/Supporting Files/Info.plist100
-rw-r--r--ios/MullvadVPN/View controllers/Account/AccountContentView.swift2
-rw-r--r--ios/MullvadVPNUITests/AccountTests.swift24
-rw-r--r--ios/MullvadVPNUITests/BaseUITestCase.swift40
-rw-r--r--ios/MullvadVPNUITests/Info.plist2
-rw-r--r--ios/MullvadVPNUITests/Pages/AccountPage.swift44
-rw-r--r--ios/MullvadVPNUITests/Pages/HeaderBar.swift29
-rw-r--r--ios/MullvadVPNUITests/Pages/TunnelControlPage.swift5
-rw-r--r--ios/MullvadVPNUITests/RelayTests.swift20
-rw-r--r--ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift138
-rw-r--r--ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift25
-rw-r--r--ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift25
-rw-r--r--ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift23
17 files changed, 388 insertions, 140 deletions
diff --git a/ios/Configurations/Base.xcconfig.template b/ios/Configurations/Base.xcconfig.template
index 7ba421b459..bb222523f0 100644
--- a/ios/Configurations/Base.xcconfig.template
+++ b/ios/Configurations/Base.xcconfig.template
@@ -4,6 +4,9 @@
// Development team
DEVELOPMENT_TEAM = CKG9MXH72F
+// Product display name
+DISPLAY_NAME = Mullvad VPN
+
// Bundle ID
APPLICATION_IDENTIFIER = net.mullvad.MullvadVPN
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index b84f9dba52..eaa1f58e83 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -565,8 +565,8 @@
850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DA2B503D7700EF8C96 /* RelayTests.swift */; };
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */; };
850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */; };
- 850201E12B51389500EF8C96 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201E02B51389500EF8C96 /* BaseUITestCase.swift */; };
850201E32B51A93C00EF8C96 /* SettingsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850201E22B51A93C00EF8C96 /* SettingsPage.swift */; };
+ 8518F6382B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8518F6372B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift */; };
852969282B4D9C1F007EAD4C /* AccountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969272B4D9C1F007EAD4C /* AccountTests.swift */; };
852969332B4E9232007EAD4C /* Page.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969322B4E9232007EAD4C /* Page.swift */; };
852969352B4E9270007EAD4C /* LoginPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969342B4E9270007EAD4C /* LoginPage.swift */; };
@@ -574,6 +574,12 @@
8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */; };
8529693C2B4F0257007EAD4C /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8529693B2B4F0257007EAD4C /* Alert.swift */; };
85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */; };
+ 85557B1E2B5FB8C700795FE1 /* HeaderBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */; };
+ 85557B202B5FBBD700795FE1 /* AccountPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */; };
+ 8590896C2B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */; };
+ 8590896D2B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */; };
+ 8590896E2B61763B003AF5F5 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */; };
+ 8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */; };
A900E9B82ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */; };
A900E9BA2ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */; };
A900E9BC2ACC609200C95F67 /* DevicesProxy+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */; };
@@ -1718,8 +1724,8 @@
850201DA2B503D7700EF8C96 /* RelayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayTests.swift; sourceTree = "<group>"; };
850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationPage.swift; sourceTree = "<group>"; };
850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControlPage.swift; sourceTree = "<group>"; };
- 850201E02B51389500EF8C96 /* BaseUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; };
850201E22B51A93C00EF8C96 /* SettingsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPage.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 /* MullvadVPNUITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MullvadVPNUITests.xctestplan; sourceTree = "<group>"; };
@@ -1730,6 +1736,12 @@
852969392B4F0238007EAD4C /* TermsOfServicePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfServicePage.swift; sourceTree = "<group>"; };
8529693B2B4F0257007EAD4C /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = "<group>"; };
85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIElementQuery+Extensions.swift"; sourceTree = "<group>"; };
+ 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderBar.swift; sourceTree = "<group>"; };
+ 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPage.swift; sourceTree = "<group>"; };
+ 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedInWithoutTimeUITestCase.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>"; };
A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountsProxy+Stubs.swift"; sourceTree = "<group>"; };
A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RESTRequestExecutor+Stubs.swift"; sourceTree = "<group>"; };
A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DevicesProxy+Stubs.swift"; sourceTree = "<group>"; };
@@ -3300,15 +3312,27 @@
path = RelayFilter;
sourceTree = "<group>";
};
+ 8518F6392B601910009EB113 /* Test base classes */ = {
+ isa = PBXGroup;
+ children = (
+ 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */,
+ 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */,
+ 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */,
+ 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */,
+ 8518F6372B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift */,
+ );
+ path = "Test base classes";
+ sourceTree = "<group>";
+ };
852969262B4D9C1F007EAD4C /* MullvadVPNUITests */ = {
isa = PBXGroup;
children = (
- 852969372B4ED20E007EAD4C /* Info.plist */,
+ 8518F6392B601910009EB113 /* Test base classes */,
852969312B4E9220007EAD4C /* Pages */,
852969272B4D9C1F007EAD4C /* AccountTests.swift */,
- 850201E02B51389500EF8C96 /* BaseUITestCase.swift */,
850201DA2B503D7700EF8C96 /* RelayTests.swift */,
85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */,
+ 852969372B4ED20E007EAD4C /* Info.plist */,
);
path = MullvadVPNUITests;
sourceTree = "<group>";
@@ -3321,8 +3345,10 @@
852969322B4E9232007EAD4C /* Page.swift */,
850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */,
850201E22B51A93C00EF8C96 /* SettingsPage.swift */,
- 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */,
850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */,
+ 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */,
+ 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */,
+ 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */,
);
path = Pages;
sourceTree = "<group>";
@@ -5178,17 +5204,23 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 8590896D2B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift in Sources */,
8529693C2B4F0257007EAD4C /* Alert.swift in Sources */,
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */,
850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */,
852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */,
+ 8590896C2B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift in Sources */,
+ 8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */,
+ 85557B202B5FBBD700795FE1 /* AccountPage.swift in Sources */,
852969352B4E9270007EAD4C /* LoginPage.swift in Sources */,
- 850201E12B51389500EF8C96 /* BaseUITestCase.swift in Sources */,
+ 8590896E2B61763B003AF5F5 /* BaseUITestCase.swift in Sources */,
850201E32B51A93C00EF8C96 /* SettingsPage.swift in Sources */,
+ 8518F6382B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift in Sources */,
852969282B4D9C1F007EAD4C /* AccountTests.swift in Sources */,
85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */,
8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */,
850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */,
+ 85557B1E2B5FB8C700795FE1 /* HeaderBar.swift in Sources */,
852969332B4E9232007EAD4C /* Page.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
index dd0fe98a35..4f31461e5e 100644
--- a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
+++ b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
@@ -26,6 +26,7 @@ public enum AccessibilityIdentifier: String {
case logoutButton
case purchaseButton
case redeemVoucherButton
+ case restorePurchasesButton
case selectLocationButton
case settingsButton
case startUsingTheAppButton
@@ -44,8 +45,10 @@ public enum AccessibilityIdentifier: String {
case headerDeviceNameLabel
// Views
+ case accountView
case alertContainerView
case alertTitle
+ case headerBarView
case loginView
case termsOfServiceView
case selectLocationView
diff --git a/ios/MullvadVPN/Containers/Root/HeaderBarView.swift b/ios/MullvadVPN/Containers/Root/HeaderBarView.swift
index 1f701cbede..476ec47eb5 100644
--- a/ios/MullvadVPN/Containers/Root/HeaderBarView.swift
+++ b/ios/MullvadVPN/Containers/Root/HeaderBarView.swift
@@ -170,6 +170,7 @@ class HeaderBarView: UIView {
)
accessibilityContainerType = .semanticGroup
+ accessibilityIdentifier = .headerBarView
let brandImageSize = brandNameImage?.size ?? .zero
let brandNameAspectRatio = brandImageSize.width / max(brandImageSize.height, 1)
diff --git a/ios/MullvadVPN/Supporting Files/Info.plist b/ios/MullvadVPN/Supporting Files/Info.plist
index 3c3dd00b6f..b6b1ffa003 100644
--- a/ios/MullvadVPN/Supporting Files/Info.plist
+++ b/ios/MullvadVPN/Supporting Files/Info.plist
@@ -6,8 +6,6 @@
<string>The app needs this to connect and test a new method.</string>
<key>ApplicationSecurityGroupIdentifier</key>
<string>$(SECURITY_GROUP_IDENTIFIER)</string>
- <key>MainApplicationIdentifier</key>
- <string>$(APPLICATION_IDENTIFIER)</string>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>$(APPLICATION_IDENTIFIER).AppRefresh</string>
@@ -17,7 +15,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
- <string>Mullvad VPN</string>
+ <string>$(DISPLAY_NAME)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -36,12 +34,61 @@
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
+ <key>MainApplicationIdentifier</key>
+ <string>$(APPLICATION_IDENTIFIER)</string>
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ <key>NSExceptionDomains</key>
+ <dict>
+ <key>127.0.0.1</key>
+ <dict>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
+ <true/>
+ </dict>
+ <key>45.83.223.196</key>
+ <dict>
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
+ <true/>
+ </dict>
+ </dict>
+ <key>NSPinnedDomains</key>
+ <dict>
+ <key>am.i.mullvad.net</key>
+ <dict>
+ <key>NSIncludesSubdomains</key>
+ <true/>
+ <key>NSPinnedCAIdentities</key>
+ <array>
+ <dict>
+ <key>SPKI-SHA256-BASE64</key>
+ <string>C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=</string>
+ </dict>
+ </array>
+ </dict>
+ </dict>
+ </dict>
<key>NSUserActivityTypes</key>
<array>
<string>StartVPNIntent</string>
<string>StopVPNIntent</string>
<string>ReconnectVPNIntent</string>
</array>
+ <key>OSLogPreferences</key>
+ <dict>
+ <key>com.apple.VectorKit</key>
+ <dict>
+ <key>DEFAULT-OPTIONS</key>
+ <dict>
+ <key>Level</key>
+ <dict>
+ <key>Enable</key>
+ <string>Off</string>
+ </dict>
+ </dict>
+ </dict>
+ </dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
@@ -71,52 +118,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
- <key>NSAppTransportSecurity</key>
- <dict>
- <key>NSAllowsArbitraryLoads</key>
- <true/>
- <key>NSPinnedDomains</key>
- <dict>
- <key>am.i.mullvad.net</key>
- <dict>
- <key>NSIncludesSubdomains</key>
- <true/>
- <key>NSPinnedCAIdentities</key>
- <array>
- <dict>
- <key>SPKI-SHA256-BASE64</key>
- <string>C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=</string>
- </dict>
- </array>
- </dict>
- </dict>
- <key>NSExceptionDomains</key>
- <dict>
- <key>127.0.0.1</key>
- <dict>
- <key>NSExceptionAllowsInsecureHTTPLoads</key>
- <true/>
- </dict>
- <key>45.83.223.196</key>
- <dict>
- <key>NSExceptionAllowsInsecureHTTPLoads</key>
- <true/>
- </dict>
- </dict>
- </dict>
- <key>OSLogPreferences</key>
- <dict>
- <key>com.apple.VectorKit</key>
- <dict>
- <key>DEFAULT-OPTIONS</key>
- <dict>
- <key>Level</key>
- <dict>
- <key>Enable</key>
- <string>Off</string>
- </dict>
- </dict>
- </dict>
- </dict>
</dict>
</plist>
diff --git a/ios/MullvadVPN/View controllers/Account/AccountContentView.swift b/ios/MullvadVPN/View controllers/Account/AccountContentView.swift
index 55cb501096..3d8ae81512 100644
--- a/ios/MullvadVPN/View controllers/Account/AccountContentView.swift
+++ b/ios/MullvadVPN/View controllers/Account/AccountContentView.swift
@@ -19,6 +19,7 @@ class AccountContentView: UIView {
let restorePurchasesButton: AppButton = {
let button = AppButton(style: .default)
button.translatesAutoresizingMaskIntoConstraints = false
+ button.accessibilityIdentifier = .restorePurchasesButton
button.setTitle(NSLocalizedString(
"RESTORE_PURCHASES_BUTTON_TITLE",
tableName: "Account",
@@ -121,6 +122,7 @@ class AccountContentView: UIView {
super.init(frame: frame)
directionalLayoutMargins = UIMetrics.contentLayoutMargins
+ accessibilityIdentifier = .accountView
addConstrainedSubviews([contentStackView, buttonStackView]) {
contentStackView.pinEdgesToSuperviewMargins(.all().excluding(.bottom))
diff --git a/ios/MullvadVPNUITests/AccountTests.swift b/ios/MullvadVPNUITests/AccountTests.swift
index bb719c91a9..319ce23509 100644
--- a/ios/MullvadVPNUITests/AccountTests.swift
+++ b/ios/MullvadVPNUITests/AccountTests.swift
@@ -8,23 +8,14 @@
import XCTest
-class AccountTests: BaseUITestCase {
+class AccountTests: LoggedOutUITestCase {
override func setUpWithError() throws {
continueAfterFailure = false
- }
- override func tearDownWithError() throws {}
+ try super.setUpWithError()
+ }
func testLogin() throws {
- let app = XCUIApplication()
- app.launch()
-
- TermsOfServicePage(app)
- .tapAgreeButton()
-
- Alert(app)
- .tapOkay()
-
LoginPage(app)
.tapAccountNumberTextField()
.enterText(self.noTimeAccountNumber)
@@ -34,15 +25,6 @@ class AccountTests: BaseUITestCase {
}
func testLoginWithIncorrectAccountNumber() throws {
- let app = XCUIApplication()
- app.launch()
-
- TermsOfServicePage(app)
- .tapAgreeButton()
-
- Alert(app)
- .tapOkay()
-
LoginPage(app)
.tapAccountNumberTextField()
.enterText("0000000000000000")
diff --git a/ios/MullvadVPNUITests/BaseUITestCase.swift b/ios/MullvadVPNUITests/BaseUITestCase.swift
deleted file mode 100644
index 83df4591cf..0000000000
--- a/ios/MullvadVPNUITests/BaseUITestCase.swift
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// BaseTestCase.swift
-// MullvadVPNUITests
-//
-// Created by Niklas Berglund on 2024-01-12.
-// Copyright © 2024 Mullvad VPN AB. All rights reserved.
-//
-
-import Foundation
-import XCTest
-
-class BaseUITestCase: XCTestCase {
- public static let defaultTimeout = 10.0
-
- // swiftlint:disable force_cast
- let noTimeAccountNumber = Bundle(for: BaseUITestCase.self)
- .infoDictionary?["MullvadNoTimeAccountNumber"] as! String
- let hasTimeAccountNumber = Bundle(for: BaseUITestCase.self)
- .infoDictionary?["MullvadHasTimeAccountNumber"] as! String
- let fiveWireGuardKeysAccountNumber = Bundle(for: BaseUITestCase.self)
- .infoDictionary?["MullvadFiveWireGuardKeysAccountNumber"] as! String
- let iOSDevicePinCode = Bundle(for: BaseUITestCase.self)
- .infoDictionary?["MullvadIOSDevicePinCode"] as! String
- let adServingDomain = Bundle(for: BaseUITestCase.self)
- .infoDictionary?["MullvadAdServingDomain"] as! String
- // swiftlint:enable force_cast
-
- /// Handle iOS add VPN configuration permission alert - allow and enter device PIN code
- func allowAddVPNConfigurations() {
- let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
-
- let alertAllowButton = springboard.buttons.element(boundBy: 0)
- if alertAllowButton.waitForExistence(timeout: Self.defaultTimeout) {
- alertAllowButton.tap()
- }
-
- _ = springboard.buttons["1"].waitForExistence(timeout: Self.defaultTimeout)
- springboard.typeText(iOSDevicePinCode)
- }
-}
diff --git a/ios/MullvadVPNUITests/Info.plist b/ios/MullvadVPNUITests/Info.plist
index 568e195a8f..85eb161b49 100644
--- a/ios/MullvadVPNUITests/Info.plist
+++ b/ios/MullvadVPNUITests/Info.plist
@@ -4,6 +4,8 @@
<dict>
<key>MullvadAdServingDomain</key>
<string>$(MULLVAD_AD_SERVING_DOMAIN)</string>
+ <key>MullvadDisplayName</key>
+ <string>$(DISPLAY_NAME)</string>
<key>MullvadFiveWireGuardKeysAccountNumber</key>
<string>$(MULLVAD_FIVE_WIREGUARD_KEYS_ACCOUNT_NUMBER)</string>
<key>MullvadHasTimeAccountNumber</key>
diff --git a/ios/MullvadVPNUITests/Pages/AccountPage.swift b/ios/MullvadVPNUITests/Pages/AccountPage.swift
new file mode 100644
index 0000000000..8ff5e935af
--- /dev/null
+++ b/ios/MullvadVPNUITests/Pages/AccountPage.swift
@@ -0,0 +1,44 @@
+//
+// AccountPage.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-01-23.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import XCTest
+
+class AccountPage: Page {
+ @discardableResult override init(_ app: XCUIApplication) {
+ super.init(app)
+
+ self.pageAccessibilityIdentifier = .accountView
+ waitForPageToBeShown()
+ }
+
+ @discardableResult func tapRedeemVoucherButton() -> Self {
+ app.buttons[AccessibilityIdentifier.redeemVoucherButton.rawValue].tap()
+ return self
+ }
+
+ @discardableResult func tapAdd30DaysTimeButton() -> Self {
+ app.buttons[AccessibilityIdentifier.purchaseButton.rawValue].tap()
+ return self
+ }
+
+ @discardableResult func tapRestorePurchasesButton() -> Self {
+ app.buttons[AccessibilityIdentifier.restorePurchasesButton.rawValue].tap()
+ return self
+ }
+
+ @discardableResult func tapLogOutButton() -> Self {
+ app.buttons[AccessibilityIdentifier.logoutButton.rawValue].tap()
+ return self
+ }
+
+ @discardableResult func tapDeleteAccountButton() -> Self {
+ app.buttons[AccessibilityIdentifier.deleteButton.rawValue].tap()
+ return self
+ }
+}
diff --git a/ios/MullvadVPNUITests/Pages/HeaderBar.swift b/ios/MullvadVPNUITests/Pages/HeaderBar.swift
new file mode 100644
index 0000000000..cf0473af8c
--- /dev/null
+++ b/ios/MullvadVPNUITests/Pages/HeaderBar.swift
@@ -0,0 +1,29 @@
+//
+// HeaderBar.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-01-23.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import XCTest
+
+class HeaderBar: Page {
+ @discardableResult override init(_ app: XCUIApplication) {
+ super.init(app)
+
+ self.pageAccessibilityIdentifier = .headerBarView
+ waitForPageToBeShown()
+ }
+
+ @discardableResult func tapAccountButton() -> Self {
+ app.buttons[AccessibilityIdentifier.accountButton.rawValue].tap()
+ return self
+ }
+
+ @discardableResult func tapSettingsButton() -> Self {
+ app.buttons[AccessibilityIdentifier.settingsButton.rawValue].tap()
+ return self
+ }
+}
diff --git a/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift b/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift
index 8fbee875bf..6469ed2232 100644
--- a/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift
+++ b/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift
@@ -20,9 +20,4 @@ class TunnelControlPage: Page {
app.buttons[AccessibilityIdentifier.selectLocationButton].tap()
return self
}
-
- @discardableResult func tapSettingsButton() -> Self {
- app.buttons[AccessibilityIdentifier.settingsButton].tap()
- return self
- }
}
diff --git a/ios/MullvadVPNUITests/RelayTests.swift b/ios/MullvadVPNUITests/RelayTests.swift
index 45d3477e2c..c4e2ab777a 100644
--- a/ios/MullvadVPNUITests/RelayTests.swift
+++ b/ios/MullvadVPNUITests/RelayTests.swift
@@ -9,24 +9,8 @@
import Foundation
import XCTest
-class RelayTests: BaseUITestCase {
+class RelayTests: LoggedInWithTimeUITestCase {
func testAdBlockingViaDNS() throws {
- let app = XCUIApplication()
- app.launch()
-
- TermsOfServicePage(app)
- .tapAgreeButton()
-
- Alert(app)
- .tapOkay()
-
- LoginPage(app)
- .tapAccountNumberTextField()
- .enterText(self.hasTimeAccountNumber)
- .tapAccountNumberSubmitButton()
- .verifySuccessIconShown()
- .verifyDeviceLabelShown()
-
TunnelControlPage(app)
.tapSelectLocationButton()
@@ -41,7 +25,7 @@ class RelayTests: BaseUITestCase {
verifyCanReachAdServingDomain()
- TunnelControlPage(app)
+ HeaderBar(app)
.tapSettingsButton()
SettingsPage(app)
diff --git a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift
new file mode 100644
index 0000000000..cedba952dc
--- /dev/null
+++ b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift
@@ -0,0 +1,138 @@
+//
+// BaseTestCase.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-01-12.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import XCTest
+
+class BaseUITestCase: XCTestCase {
+ let app = XCUIApplication()
+ static let defaultTimeout = 5.0
+
+ // swiftlint:disable force_cast
+ let displayName = Bundle(for: BaseUITestCase.self)
+ .infoDictionary?["MullvadDisplayName"] as! String
+ let noTimeAccountNumber = Bundle(for: BaseUITestCase.self)
+ .infoDictionary?["MullvadNoTimeAccountNumber"] as! String
+ let hasTimeAccountNumber = Bundle(for: BaseUITestCase.self)
+ .infoDictionary?["MullvadHasTimeAccountNumber"] as! String
+ let fiveWireGuardKeysAccountNumber = Bundle(for: BaseUITestCase.self)
+ .infoDictionary?["MullvadFiveWireGuardKeysAccountNumber"] as! String
+ let iOSDevicePinCode = Bundle(for: BaseUITestCase.self)
+ .infoDictionary?["MullvadIOSDevicePinCode"] as! String
+ let adServingDomain = Bundle(for: BaseUITestCase.self)
+ .infoDictionary?["MullvadAdServingDomain"] as! String
+ // swiftlint:enable force_cast
+
+ /// Handle iOS add VPN configuration permission alert - allow and enter device PIN code
+ func allowAddVPNConfigurations() {
+ let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
+
+ let alertAllowButton = springboard.buttons.element(boundBy: 0)
+ if alertAllowButton.waitForExistence(timeout: Self.defaultTimeout) {
+ alertAllowButton.tap()
+ }
+
+ _ = springboard.buttons["1"].waitForExistence(timeout: Self.defaultTimeout)
+ springboard.typeText(iOSDevicePinCode)
+ }
+
+ // MARK: - Setup & teardown
+
+ /// Suite level teardown ran after test have executed
+ override class func tearDown() {
+ uninstallApp()
+ }
+
+ /// Test level setup
+ override func setUp() {
+ app.launch()
+ }
+
+ /// Test level teardown
+ override func tearDown() {
+ app.terminate()
+ }
+
+ /// Check if currently logged on to an account. Note that it is assumed that we are logged in if login view isn't currently shown.
+ func isLoggedIn() -> Bool {
+ return !app
+ .otherElements[AccessibilityIdentifier.loginView.rawValue]
+ .waitForExistence(timeout: 1.0)
+ }
+
+ func agreeToTermsOfServiceIfShown() {
+ let termsOfServiceIsShown = app.otherElements[
+ AccessibilityIdentifier
+ .termsOfServiceView.rawValue
+ ]
+ .waitForExistence(timeout: 1)
+
+ if termsOfServiceIsShown {
+ TermsOfServicePage(app)
+ .tapAgreeButton()
+
+ Alert(app) // Changes alert
+ .tapOkay()
+
+ LoginPage(app)
+ }
+ }
+
+ /// Login with specified account number. It is a prerequisite that the login page is currently shown.
+ func login(accountNumber: String) {
+ LoginPage(app)
+ .tapAccountNumberTextField()
+ .enterText(accountNumber)
+ .tapAccountNumberSubmitButton()
+ .verifyDeviceLabelShown()
+ }
+
+ func logoutIfLoggedIn() {
+ if isLoggedIn() {
+ HeaderBar(app)
+ .tapAccountButton()
+
+ AccountPage(app)
+ .tapLogOutButton()
+
+ LoginPage(app)
+ }
+ }
+
+ static func uninstallApp() {
+ let appName = "Mullvad VPN"
+
+ let timeout = TimeInterval(5)
+ let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
+ let spotlight = XCUIApplication(bundleIdentifier: "com.apple.Spotlight")
+
+ springboard.swipeDown()
+ spotlight.textFields["SpotlightSearchField"].typeText(appName)
+
+ let appIcon = spotlight.icons[appName].firstMatch
+ if appIcon.waitForExistence(timeout: timeout) {
+ appIcon.press(forDuration: 2)
+ } else {
+ XCTFail("Failed to find app icon named \(appName)")
+ }
+
+ let deleteAppButton = spotlight.buttons["Delete App"]
+ if deleteAppButton.waitForExistence(timeout: timeout) {
+ deleteAppButton.tap()
+ } else {
+ XCTFail("Failed to find 'Delete App'")
+ }
+
+ let finalDeleteButton = springboard.alerts.buttons["Delete"]
+ if finalDeleteButton.waitForExistence(timeout: timeout) {
+ finalDeleteButton.tap()
+ } else {
+ XCTFail("Failed to find 'Delete'")
+ }
+ }
+}
diff --git a/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift
new file mode 100644
index 0000000000..fc1fa747f8
--- /dev/null
+++ b/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift
@@ -0,0 +1,25 @@
+//
+// LoggedInUITestCase.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-01-22.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+
+/// Base class for tests that should start from a state of being logged on to an account with time left
+class LoggedInWithTimeUITestCase: BaseUITestCase {
+ override func setUp() {
+ super.setUp()
+
+ agreeToTermsOfServiceIfShown()
+ logoutIfLoggedIn()
+
+ login(accountNumber: hasTimeAccountNumber)
+
+ // Relaunch app so that tests start from a deterministic state
+ app.terminate()
+ app.launch()
+ }
+}
diff --git a/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift
new file mode 100644
index 0000000000..c7ab76e31b
--- /dev/null
+++ b/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift
@@ -0,0 +1,25 @@
+//
+// LoggedInWithoutTimeUITestCase.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-01-23.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+
+/// Base class for tests that should start from a state of being logged on to an account without time left
+class LoggedInWithoutTimeUITestCase: BaseUITestCase {
+ override func setUp() {
+ super.setUp()
+
+ agreeToTermsOfServiceIfShown()
+ logoutIfLoggedIn()
+
+ login(accountNumber: noTimeAccountNumber)
+
+ // Relaunch app so that tests start from a deterministic state
+ app.terminate()
+ app.launch()
+ }
+}
diff --git a/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift
new file mode 100644
index 0000000000..a89c6e732e
--- /dev/null
+++ b/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift
@@ -0,0 +1,23 @@
+//
+// LoggedOutUITestCase.swift
+// MullvadVPNUITests
+//
+// Created by Niklas Berglund on 2024-01-22.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+
+/// Base class for tests which should start from a logged out state
+class LoggedOutUITestCase: BaseUITestCase {
+ override func setUp() {
+ super.setUp()
+
+ agreeToTermsOfServiceIfShown()
+ logoutIfLoggedIn()
+
+ // Relaunch app so that tests start from a deterministic state
+ app.terminate()
+ app.launch()
+ }
+}