diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index ca2ba8b21114..815b5a268f59 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 01EF6F2A2B6A473900125696 /* MullvadApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EF6F292B6A473900125696 /* MullvadApi.swift */; }; 01EF6F342B6A590700125696 /* libmullvad_api.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01EF6F332B6A590700125696 /* libmullvad_api.a */; }; 062B45A328FD4CA700746E77 /* le_root_cert.cer in Resources */ = {isa = PBXBuildFile; fileRef = 06799AB428F98CE700ACD94E /* le_root_cert.cer */; }; 062B45BC28FD8C3B00746E77 /* RESTDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062B45BB28FD8C3B00746E77 /* RESTDefaults.swift */; }; @@ -608,6 +607,7 @@ 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 */; }; + 85139B2D2B84B4A700734217 /* OutOfTimePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85139B2C2B84B4A700734217 /* OutOfTimePage.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 */; }; @@ -618,16 +618,23 @@ 85557B0E2B591B2600795FE1 /* FirewallAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B0D2B591B2600795FE1 /* FirewallAPIClient.swift */; }; 85557B102B59215F00795FE1 /* FirewallRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B0F2B59215F00795FE1 /* FirewallRule.swift */; }; 85557B122B594FC900795FE1 /* ConnectivityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B112B594FC900795FE1 /* ConnectivityTests.swift */; }; - 85557B142B5983CF00795FE1 /* MullvadAPIWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B132B5983CF00795FE1 /* MullvadAPIWrapper.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 */; }; + 8556EB522B9A1C6900D26DD4 /* MullvadApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8556EB512B9A1C6900D26DD4 /* MullvadApi.swift */; }; + 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 */; }; + 8587A05D2B84D43100152938 /* ChangeLogAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8587A05C2B84D43100152938 /* ChangeLogAlert.swift */; }; 8590896C2B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */; }; 8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.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 */; }; 85D2B0B12B6BD32400DF9DA7 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */; }; 85E3BDE52B70E18C00FA71FD /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E3BDE42B70E18C00FA71FD /* Networking.swift */; }; + 85EC620C2B838D10005AFFB5 /* MullvadAPIWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85557B132B5983CF00795FE1 /* MullvadAPIWrapper.swift */; }; + 85FB5A0C2B6903990015DCED /* WelcomePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85FB5A0B2B6903990015DCED /* WelcomePage.swift */; }; + 85FB5A102B6960A30015DCED /* AccountDeletionPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85FB5A0F2B6960A30015DCED /* AccountDeletionPage.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 */; }; @@ -787,7 +794,6 @@ A9C342C52ACC42130045F00E /* ServerRelaysResponse+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C342C42ACC42130045F00E /* ServerRelaysResponse+Stubs.swift */; }; A9D99B9A2A1F7C3200DE27D3 /* RESTTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FAE67D28F83CA50033DD93 /* RESTTransport.swift */; }; A9DF789B2B7D1DF10094E4AD /* mullvad-api.h in Headers */ = {isa = PBXBuildFile; fileRef = 01EF6F2D2B6A51B100125696 /* mullvad-api.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A9DF789C2B7D1E410094E4AD /* BridgingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 01EF6F352B6A5AEF00125696 /* BridgingHeader.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9DF789D2B7D1E8B0094E4AD /* LoggedInWithTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */; }; A9E031782ACB09930095D843 /* UIApplication+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031762ACB08950095D843 /* UIApplication+Extensions.swift */; }; A9E0317A2ACB0AE70095D843 /* UIApplication+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */; }; @@ -1250,12 +1256,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 01EF6F292B6A473900125696 /* MullvadApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadApi.swift; sourceTree = ""; }; - 01EF6F2D2B6A51B100125696 /* mullvad-api.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "mullvad-api.h"; path = "../../mullvad-api/include/mullvad-api.h"; sourceTree = ""; }; + 01EF6F2D2B6A51B100125696 /* mullvad-api.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "mullvad-api.h"; path = "../mullvad-api/include/mullvad-api.h"; sourceTree = ""; }; 01EF6F2F2B6A588300125696 /* aarch64-apple-ios */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "aarch64-apple-ios"; path = "../target/aarch64-apple-ios"; sourceTree = ""; }; 01EF6F312B6A58F000125696 /* debug */ = {isa = PBXFileReference; lastKnownFileType = folder; name = debug; path = "../target/aarch64-apple-ios/debug"; sourceTree = ""; }; 01EF6F332B6A590700125696 /* libmullvad_api.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmullvad_api.a; path = "../target/aarch64-apple-ios/debug/libmullvad_api.a"; sourceTree = ""; }; - 01EF6F352B6A5AEF00125696 /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; }; 01F1FF1D29F0627D007083C3 /* libshadowsocks_proxy.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libshadowsocks_proxy.a; path = ../target/debug/libshadowsocks_proxy.a; sourceTree = ""; }; 062B45BB28FD8C3B00746E77 /* RESTDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RESTDefaults.swift; sourceTree = ""; }; 063687AF28EB083800BE7161 /* ProxyURLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyURLRequest.swift; sourceTree = ""; }; @@ -1835,6 +1839,7 @@ 850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationPage.swift; sourceTree = ""; }; 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControlPage.swift; sourceTree = ""; }; 850201E22B51A93C00EF8C96 /* SettingsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPage.swift; sourceTree = ""; }; + 85139B2C2B84B4A700734217 /* OutOfTimePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutOfTimePage.swift; sourceTree = ""; }; 8518F6372B60157E009EB113 /* LoggedInWithoutTimeUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedInWithoutTimeUITestCase.swift; sourceTree = ""; }; 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 = ""; }; @@ -1853,13 +1858,20 @@ 85557B152B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCUIElementQuery+Extensions.swift"; sourceTree = ""; }; 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderBar.swift; sourceTree = ""; }; 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPage.swift; sourceTree = ""; }; + 8556EB512B9A1C6900D26DD4 /* MullvadApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MullvadApi.swift; path = MullvadVPNUITests/MullvadApi.swift; sourceTree = ""; }; + 8556EB532B9A1D7100D26DD4 /* BridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; }; + 8556EB552B9B0AC500D26DD4 /* RevokedDevicePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RevokedDevicePage.swift; sourceTree = ""; }; 855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportPage.swift; sourceTree = ""; }; + 8587A05C2B84D43100152938 /* ChangeLogAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeLogAlert.swift; sourceTree = ""; }; 859089682B61763B003AF5F5 /* LoggedInWithoutTimeUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedInWithoutTimeUITestCase.swift; sourceTree = ""; }; 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedInWithTimeUITestCase.swift; sourceTree = ""; }; 8590896A2B61763B003AF5F5 /* BaseUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = ""; }; 8590896B2B61763B003AF5F5 /* LoggedOutUITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutUITestCase.swift; sourceTree = ""; }; + 85B267602B849ADB0098E3CD /* mullvad-api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mullvad-api.h"; path = "../../mullvad-api/include/mullvad-api.h"; sourceTree = ""; }; 85C7A2E82B89024B00035D5A /* SettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTests.swift; sourceTree = ""; }; 85E3BDE42B70E18C00FA71FD /* Networking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Networking.swift; sourceTree = ""; }; + 85FB5A0B2B6903990015DCED /* WelcomePage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomePage.swift; sourceTree = ""; }; + 85FB5A0F2B6960A30015DCED /* AccountDeletionPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountDeletionPage.swift; sourceTree = ""; }; A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountsProxy+Stubs.swift"; sourceTree = ""; }; A900E9B92ACC5D0600C95F67 /* RESTRequestExecutor+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RESTRequestExecutor+Stubs.swift"; sourceTree = ""; }; A900E9BB2ACC609200C95F67 /* DevicesProxy+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DevicesProxy+Stubs.swift"; sourceTree = ""; }; @@ -3102,6 +3114,8 @@ 58CE5E57224146200008646E = { isa = PBXGroup; children = ( + 8556EB512B9A1C6900D26DD4 /* MullvadApi.swift */, + 01EF6F2D2B6A51B100125696 /* mullvad-api.h */, 58F3C0A824A50C0E003E76BE /* Assets */, 58ECD29023F178FD004298B6 /* Configurations */, 589A454A28DDF59B00565204 /* Shared */, @@ -3544,12 +3558,11 @@ 852969262B4D9C1F007EAD4C /* MullvadVPNUITests */ = { isa = PBXGroup; children = ( + 85B267602B849ADB0098E3CD /* mullvad-api.h */, 852969272B4D9C1F007EAD4C /* AccountTests.swift */, + 8556EB532B9A1D7100D26DD4 /* BridgingHeader.h */, 85557B112B594FC900795FE1 /* ConnectivityTests.swift */, - 01EF6F352B6A5AEF00125696 /* BridgingHeader.h */, 852969372B4ED20E007EAD4C /* Info.plist */, - 01EF6F2D2B6A51B100125696 /* mullvad-api.h */, - 01EF6F292B6A473900125696 /* MullvadApi.swift */, 85557B0C2B591B0F00795FE1 /* Networking */, 852969312B4E9220007EAD4C /* Pages */, 850201DA2B503D7700EF8C96 /* RelayTests.swift */, @@ -3563,17 +3576,22 @@ 852969312B4E9220007EAD4C /* Pages */ = { isa = PBXGroup; children = ( + 85FB5A0F2B6960A30015DCED /* AccountDeletionPage.swift */, 85557B1F2B5FBBD700795FE1 /* AccountPage.swift */, 8529693B2B4F0257007EAD4C /* Alert.swift */, + 8587A05C2B84D43100152938 /* ChangeLogAlert.swift */, 85557B1D2B5FB8C700795FE1 /* HeaderBar.swift */, 852969342B4E9270007EAD4C /* LoginPage.swift */, + 85139B2C2B84B4A700734217 /* OutOfTimePage.swift */, 852969322B4E9232007EAD4C /* Page.swift */, 855D9F5A2B63E56B00D7C64D /* ProblemReportPage.swift */, 8532E6862B8CCED600ACECD1 /* ProblemReportSubmittedPage.swift */, + 8556EB552B9B0AC500D26DD4 /* RevokedDevicePage.swift */, 850201DC2B503D8C00EF8C96 /* SelectLocationPage.swift */, 850201E22B51A93C00EF8C96 /* SettingsPage.swift */, 852969392B4F0238007EAD4C /* TermsOfServicePage.swift */, 850201DE2B5040A500EF8C96 /* TunnelControlPage.swift */, + 85FB5A0B2B6903990015DCED /* WelcomePage.swift */, ); path = Pages; sourceTree = ""; @@ -3787,7 +3805,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - A9DF789C2B7D1E410094E4AD /* BridgingHeader.h in Headers */, + 85B267612B849ADB0098E3CD /* mullvad-api.h in Headers */, + 8556EB542B9A1D7100D26DD4 /* BridgingHeader.h in Headers */, A9DF789B2B7D1DF10094E4AD /* mullvad-api.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4271,6 +4290,8 @@ 8529692C2B4D9C1F007EAD4C /* PBXTargetDependency */, ); name = MullvadVPNUITests; + packageProductDependencies = ( + ); productName = MullvadVPNUITests; productReference = 852969252B4D9C1F007EAD4C /* MullvadVPNUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -5526,12 +5547,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8556EB522B9A1C6900D26DD4 /* MullvadApi.swift in Sources */, + 85EC620C2B838D10005AFFB5 /* MullvadAPIWrapper.swift in Sources */, A9DF789D2B7D1E8B0094E4AD /* LoggedInWithTimeUITestCase.swift in Sources */, 85D2B0B12B6BD32400DF9DA7 /* BaseUITestCase.swift in Sources */, 8529693C2B4F0257007EAD4C /* Alert.swift in Sources */, 850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */, 850201DB2B503D7700EF8C96 /* RelayTests.swift in Sources */, - 85557B142B5983CF00795FE1 /* MullvadAPIWrapper.swift in Sources */, + 85139B2D2B84B4A700734217 /* OutOfTimePage.swift in Sources */, 852969362B4E9724007EAD4C /* AccessbilityIdentifier.swift in Sources */, 85E3BDE52B70E18C00FA71FD /* Networking.swift in Sources */, 85C7A2E92B89024B00035D5A /* SettingsTests.swift in Sources */, @@ -5539,14 +5562,17 @@ 8590896F2B61763B003AF5F5 /* LoggedOutUITestCase.swift in Sources */, 85557B202B5FBBD700795FE1 /* AccountPage.swift in Sources */, 852969352B4E9270007EAD4C /* LoginPage.swift in Sources */, + 8556EB562B9B0AC500D26DD4 /* RevokedDevicePage.swift in Sources */, 85557B102B59215F00795FE1 /* FirewallRule.swift in Sources */, 85557B0E2B591B2600795FE1 /* FirewallAPIClient.swift in Sources */, 852969282B4D9C1F007EAD4C /* AccountTests.swift in Sources */, - 01EF6F2A2B6A473900125696 /* MullvadApi.swift in Sources */, + 8587A05D2B84D43100152938 /* ChangeLogAlert.swift in Sources */, + 85FB5A102B6960A30015DCED /* AccountDeletionPage.swift in Sources */, 85557B162B5ABBBE00795FE1 /* XCUIElementQuery+Extensions.swift in Sources */, 855D9F5B2B63E56B00D7C64D /* ProblemReportPage.swift in Sources */, 8529693A2B4F0238007EAD4C /* TermsOfServicePage.swift in Sources */, 8532E6872B8CCED600ACECD1 /* ProblemReportSubmittedPage.swift in Sources */, + 85FB5A0C2B6903990015DCED /* WelcomePage.swift in Sources */, 850201DF2B5040A500EF8C96 /* TunnelControlPage.swift in Sources */, 85557B1E2B5FB8C700795FE1 /* HeaderBar.swift in Sources */, 85557B122B594FC900795FE1 /* ConnectivityTests.swift in Sources */, @@ -6339,6 +6365,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -6903,8 +6930,12 @@ "DEVELOPMENT_TEAM[sdk=macosx*]" = CKG9MXH72F; ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); GENERATE_INFOPLIST_FILE = YES; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../mullvad-api/include"; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/mullvad-api/include"; INFOPLIST_FILE = MullvadVPNUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.2; "LIBRARY_SEARCH_PATHS[sdk=iphoneos*][arch=arm64]" = "$(PROJECT_DIR)/../target/aarch64-apple-ios/debug"; @@ -6937,7 +6968,7 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../mullvad-api/include"; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/mullvad-api/include"; INFOPLIST_FILE = MullvadVPNUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.2; "LIBRARY_SEARCH_PATHS[sdk=iphoneos*][arch=arm64]" = "$(PROJECT_DIR)/../target/aarch64-apple-ios/release"; @@ -7560,11 +7591,14 @@ baseConfigurationReference = 852969382B4ED818007EAD4C /* UITests.xcconfig */; buildSettings = { APPLICATION_IDENTIFIER = net.mullvad.MullvadVPN; + GCC_PREPROCESSOR_DEFINITIONS = ""; + GENERATE_INFOPLIST_FILE = YES; HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../mullvad-api/include"; INFOPLIST_FILE = MullvadVPNUITests/Info.plist; "LIBRARY_SEARCH_PATHS[sdk=iphoneos*][arch=arm64]" = "$(PROJECT_DIR)/../target/aarch64-apple-ios/release"; "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*][arch=arm64]" = "$(PROJECT_DIR)/../target/aarch64-apple-ios-sim/release"; "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*][arch=x86_64]" = "$(PROJECT_DIR)/../target/x86_64-apple-ios/release"; + PRODUCT_BUNDLE_IDENTIFIER = "$(APPLICATION_IDENTIFIER).MullvadVPNUITests"; PRODUCT_NAME = MullvadVPNUITests; SWIFT_ACTIVE_COMPILATION_CONDITIONS = MULLVAD_ENVIRONMENT_PRODUCTION; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/MullvadVPNUITests/BridgingHeader.h"; diff --git a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift index a5dc7f26a5fa..8a911b97c120 100644 --- a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift +++ b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift @@ -17,8 +17,10 @@ public enum AccessibilityIdentifier: String { case cancelButton case connectionPanelButton case collapseButton + case createAccountButton case deleteButton case disconnectButton + case revokedDeviceLoginButton case infoButton case learnAboutPrivacyButton case loginBarButton @@ -47,13 +49,16 @@ public enum AccessibilityIdentifier: String { // Labels case headerDeviceNameLabel case connectionStatusLabel + case welcomeAccountNumberLabel // Views case accountView case alertContainerView case alertTitle + case changeLogAlert case headerBarView case loginView + case outOfTimeView case termsOfServiceView case selectLocationView case selectLocationTableView @@ -61,6 +66,9 @@ public enum AccessibilityIdentifier: String { case tunnelControlView case problemReportView case problemReportSubmittedView + case revokedDeviceView + case welcomeView + case deleteAccountView // Other UI elements case connectionPanelInAddressRow @@ -71,6 +79,7 @@ public enum AccessibilityIdentifier: String { case selectLocationSearchTextField case problemReportEmailTextField case problemReportMessageTextView + case deleteAccountTextField // DNS settings case dnsSettings diff --git a/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift b/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift index c3e53cc9f44b..031ba6a97204 100644 --- a/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift +++ b/ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift @@ -26,6 +26,7 @@ final class ChangeLogCoordinator: Coordinator, Presentable { func start() { let presentation = AlertPresentation( id: "change-log-ok-alert", + accessibilityIdentifier: .changeLogAlert, header: interactor.viewModel.header, title: interactor.viewModel.title, attributedMessage: interactor.viewModel.body, diff --git a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift index 1929b47dd947..f5f0bb2aa802 100644 --- a/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift +++ b/ios/MullvadVPN/View controllers/AccountDeletion/AccountDeletionContentView.swift @@ -81,6 +81,7 @@ class AccountDeletionContentView: UIView { private lazy var accountTextField: AccountTextField = { let groupingStyle = AccountTextField.GroupingStyle.lastPart let textField = AccountTextField(groupingStyle: groupingStyle) + textField.accessibilityIdentifier = .deleteAccountTextField textField.font = .preferredFont(forTextStyle: .body, weight: .bold) textField.placeholder = Array(repeating: "X", count: 4).joined() textField.placeholderTextColor = .lightGray @@ -346,6 +347,7 @@ class AccountDeletionContentView: UIView { } private func setupAppearance() { + accessibilityIdentifier = .deleteAccountView translatesAutoresizingMaskIntoConstraints = false backgroundColor = .secondaryColor directionalLayoutMargins = UIMetrics.contentLayoutMargins diff --git a/ios/MullvadVPN/View controllers/Alert/AlertPresentation.swift b/ios/MullvadVPN/View controllers/Alert/AlertPresentation.swift index b0056b7ea9fc..afd67b6e8113 100644 --- a/ios/MullvadVPN/View controllers/Alert/AlertPresentation.swift +++ b/ios/MullvadVPN/View controllers/Alert/AlertPresentation.swift @@ -24,6 +24,7 @@ struct AlertAction { struct AlertPresentation: Identifiable, CustomDebugStringConvertible { let id: String + var accessibilityIdentifier: AccessibilityIdentifier? var header: String? var icon: AlertIcon? var title: String? diff --git a/ios/MullvadVPN/View controllers/Alert/AlertViewController.swift b/ios/MullvadVPN/View controllers/Alert/AlertViewController.swift index a116e51839a9..bfdb60c70c41 100644 --- a/ios/MullvadVPN/View controllers/Alert/AlertViewController.swift +++ b/ios/MullvadVPN/View controllers/Alert/AlertViewController.swift @@ -56,8 +56,6 @@ class AlertViewController: UIViewController { view.backgroundColor = .secondaryColor view.layer.cornerRadius = 11 - view.accessibilityIdentifier = .alertContainerView - return view }() @@ -112,6 +110,9 @@ class AlertViewController: UIViewController { view.backgroundColor = .black.withAlphaComponent(0.5) + let accessibilityIdentifier = presentation.accessibilityIdentifier ?? .alertContainerView + view.accessibilityIdentifier = accessibilityIdentifier + setContent() setConstraints() } diff --git a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift index 466a6b24ad37..4e055ad2f3c6 100644 --- a/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift +++ b/ios/MullvadVPN/View controllers/CreationAccount/Welcome/WelcomeContentView.swift @@ -54,6 +54,7 @@ final class WelcomeContentView: UIView { private let accountNumberLabel: UILabel = { let label = UILabel() + label.accessibilityIdentifier = .welcomeAccountNumberLabel label.adjustsFontForContentSizeCategory = true label.lineBreakMode = .byWordWrapping label.numberOfLines = .zero @@ -192,6 +193,7 @@ final class WelcomeContentView: UIView { override init(frame: CGRect) { super.init(frame: frame) + accessibilityIdentifier = .welcomeView backgroundColor = .primaryColor directionalLayoutMargins = UIMetrics.contentLayoutMargins backgroundColor = .secondaryColor diff --git a/ios/MullvadVPN/View controllers/Login/LoginContentView.swift b/ios/MullvadVPN/View controllers/Login/LoginContentView.swift index c994286d51c1..5e1bfec865a6 100644 --- a/ios/MullvadVPN/View controllers/Login/LoginContentView.swift +++ b/ios/MullvadVPN/View controllers/Login/LoginContentView.swift @@ -84,6 +84,7 @@ class LoginContentView: UIView { let createAccountButton: AppButton = { let button = AppButton(style: .default) + button.accessibilityIdentifier = .createAccountButton button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(NSLocalizedString( "CREATE_ACCOUNT_BUTTON_LABEL", diff --git a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift index edd3f501058b..843fd0cda4d8 100644 --- a/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift +++ b/ios/MullvadVPN/View controllers/OutOfTime/OutOfTimeContentView.swift @@ -95,6 +95,7 @@ class OutOfTimeContentView: UIView { override init(frame: CGRect) { super.init(frame: frame) + accessibilityIdentifier = .outOfTimeView translatesAutoresizingMaskIntoConstraints = false backgroundColor = .secondaryColor directionalLayoutMargins = UIMetrics.contentLayoutMargins diff --git a/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift b/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift index d4dc37616de8..ea80ff14ef17 100644 --- a/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift +++ b/ios/MullvadVPN/View controllers/RevokedDevice/RevokedDeviceViewController.swift @@ -62,6 +62,7 @@ class RevokedDeviceViewController: UIViewController, RootContainment { private lazy var logoutButton: AppButton = { let button = AppButton(style: .default) + button.accessibilityIdentifier = .revokedDeviceLoginButton button.translatesAutoresizingMaskIntoConstraints = false button.setTitle( NSLocalizedString( @@ -108,6 +109,7 @@ class RevokedDeviceViewController: UIViewController, RootContainment { override func viewDidLoad() { super.viewDidLoad() + view.accessibilityIdentifier = .revokedDeviceView view.backgroundColor = .secondaryColor view.directionalLayoutMargins = UIMetrics.contentLayoutMargins diff --git a/ios/MullvadVPNUITests/AccountTests.swift b/ios/MullvadVPNUITests/AccountTests.swift index f15195b69d57..e12152291b01 100644 --- a/ios/MullvadVPNUITests/AccountTests.swift +++ b/ios/MullvadVPNUITests/AccountTests.swift @@ -9,6 +9,52 @@ import XCTest class AccountTests: LoggedOutUITestCase { + override func setUpWithError() throws { + continueAfterFailure = false + + try super.setUpWithError() + } + + override func tearDownWithError() throws {} + + func testCreateAccount() throws { + LoginPage(app) + .tapCreateAccountButton() + + // Verify welcome page is shown and get account number from it + let accountNumber = WelcomePage(app).getAccountNumber() + + try MullvadAPIWrapper().deleteAccount(accountNumber) + } + + func testDeleteAccount() throws { + let accountNumber = try MullvadAPIWrapper().createAccount() + + LoginPage(app) + .tapAccountNumberTextField() + .enterText(accountNumber) + .tapAccountNumberSubmitButton() + + OutOfTimePage(app) + + HeaderBar(app) + .tapAccountButton() + + AccountPage(app) + .tapDeleteAccountButton() + + AccountDeletionPage(app) + .enterText(String(accountNumber.suffix(4))) + .tapDeleteAccountButton() + + // Attempt to login with deleted account and verify that it fails + LoginPage(app) + .tapAccountNumberTextField() + .enterText(accountNumber) + .tapAccountNumberSubmitButton() + .verifyFailIconShown() + } + func testLogin() throws { LoginPage(app) .tapAccountNumberTextField() diff --git a/ios/MullvadVPNUITests/MullvadApi.swift b/ios/MullvadVPNUITests/MullvadApi.swift index 3c23f8209d23..a1a22b5c4031 100644 --- a/ios/MullvadVPNUITests/MullvadApi.swift +++ b/ios/MullvadVPNUITests/MullvadApi.swift @@ -38,6 +38,10 @@ struct InitMutableBufferError: Error { class MullvadApi { private var clientContext = MullvadApiClient() + /// Initialize the Mullvad API client + /// - Parameters: + /// - apiAddress: Address of the Mullvad API server in the format \:\ + /// - hostname: Hostname of the Mullvad API server init(apiAddress: String, hostname: String) throws { let result = mullvad_api_client_initialize( &clientContext, diff --git a/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift b/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift index 71343dd4f39a..ba870b0ba7b8 100644 --- a/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift +++ b/ios/MullvadVPNUITests/Networking/MullvadAPIWrapper.swift @@ -1,5 +1,5 @@ // -// AppAPI.swift +// MullvadAPIWrapper.swift // MullvadVPNUITests // // Created by Niklas Berglund on 2024-01-18. @@ -10,7 +10,8 @@ import Foundation import XCTest enum MullvadAPIError: Error { - case incorrectConfigurationFormat + case invalidEndpointFormatError + case requestError } class MullvadAPIWrapper { @@ -18,18 +19,22 @@ class MullvadAPIWrapper { static let hostName = Bundle(for: MullvadAPIWrapper.self) .infoDictionary?["ApiHostName"] as! String + private var mullvadAPI: MullvadApi + /// API endpoint configuration value in the format : static let endpoint = Bundle(for: MullvadAPIWrapper.self) .infoDictionary?["ApiEndpoint"] as! String // swiftlint:enable force_cast - public static func getAPIHostname() -> String { - return hostName + init() throws { + let apiAddress = try Self.getAPIIPAddress() + ":" + Self.getAPIPort() + let hostname = Self.hostName + mullvadAPI = try MullvadApi(apiAddress: apiAddress, hostname: hostname) } public static func getAPIIPAddress() throws -> String { guard let ipAddress = endpoint.components(separatedBy: ":").first else { - throw MullvadAPIError.incorrectConfigurationFormat + throw MullvadAPIError.invalidEndpointFormatError } return ipAddress @@ -37,9 +42,57 @@ class MullvadAPIWrapper { public static func getAPIPort() throws -> String { guard let port = endpoint.components(separatedBy: ":").last else { - throw MullvadAPIError.incorrectConfigurationFormat + throw MullvadAPIError.invalidEndpointFormatError } return port } + + /// Generate a mock WireGuard key + private func generateMockWireGuardKey() -> Data { + var bytes = [UInt8]() + + for _ in 0 ..< 44 { + bytes.append(UInt8.random(in: 0 ..< 255)) + } + + return Data(bytes) + } + + func createAccount() -> String { + do { + let accountNumber = try mullvadAPI.createAccount() + return accountNumber + } catch { + XCTFail("Failed to create account using app API") + return String() + } + } + + func deleteAccount(_ accountNumber: String) { + do { + try mullvadAPI.delete(account: accountNumber) + } catch { + XCTFail("Failed to delete account using app API") + } + } + + /// Add another device to specified account. A dummy WireGuard key will be generated. + func addDevice(_ account: String) throws { + let devicePublicKey = generateMockWireGuardKey() + + do { + try mullvadAPI.addDevice(forAccount: account, publicKey: devicePublicKey) + } catch { + throw MullvadAPIError.requestError + } + } + + func getAccountExpiry(_ account: String) throws -> UInt64 { + do { + return try mullvadAPI.getExpiry(forAccount: account) + } catch { + throw MullvadAPIError.requestError + } + } } diff --git a/ios/MullvadVPNUITests/Pages/AccountDeletionPage.swift b/ios/MullvadVPNUITests/Pages/AccountDeletionPage.swift new file mode 100644 index 000000000000..30bf01034ebd --- /dev/null +++ b/ios/MullvadVPNUITests/Pages/AccountDeletionPage.swift @@ -0,0 +1,39 @@ +// +// AccountDeletionPage.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-30. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +class AccountDeletionPage: Page { + @discardableResult override init(_ app: XCUIApplication) { + super.init(app) + + self.pageAccessibilityIdentifier = .deleteAccountView + waitForPageToBeShown() + } + + @discardableResult func tapTextField() -> Self { + app.textFields[AccessibilityIdentifier.deleteAccountTextField].tap() + return self + } + + @discardableResult func tapDeleteAccountButton() -> Self { + guard let pageAccessibilityIdentifier = self.pageAccessibilityIdentifier else { + XCTFail("Page's accessibility identifier not set") + return self + } + + app.otherElements[pageAccessibilityIdentifier].buttons[AccessibilityIdentifier.deleteButton].tap() + return self + } + + @discardableResult func tapCancelButton() -> Self { + app.buttons[AccessibilityIdentifier.cancelButton].tap() + return self + } +} diff --git a/ios/MullvadVPNUITests/Pages/ChangeLogAlert.swift b/ios/MullvadVPNUITests/Pages/ChangeLogAlert.swift new file mode 100644 index 000000000000..70d67d0294fc --- /dev/null +++ b/ios/MullvadVPNUITests/Pages/ChangeLogAlert.swift @@ -0,0 +1,24 @@ +// +// ChangeLogAlert.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-02-20. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +class ChangeLogAlert: Page { + @discardableResult override init(_ app: XCUIApplication) { + super.init(app) + + self.pageAccessibilityIdentifier = .changeLogAlert + waitForPageToBeShown() + } + + @discardableResult func tapOkay() -> Self { + app.buttons[AccessibilityIdentifier.alertOkButton].tap() + return self + } +} diff --git a/ios/MullvadVPNUITests/Pages/HeaderBar.swift b/ios/MullvadVPNUITests/Pages/HeaderBar.swift index cf0473af8ccd..129d721b3745 100644 --- a/ios/MullvadVPNUITests/Pages/HeaderBar.swift +++ b/ios/MullvadVPNUITests/Pages/HeaderBar.swift @@ -10,6 +10,9 @@ import Foundation import XCTest class HeaderBar: Page { + lazy var accountButton = app.buttons[AccessibilityIdentifier.accountButton] + lazy var settingsButton = app.buttons[AccessibilityIdentifier.settingsButton] + @discardableResult override init(_ app: XCUIApplication) { super.init(app) @@ -18,12 +21,12 @@ class HeaderBar: Page { } @discardableResult func tapAccountButton() -> Self { - app.buttons[AccessibilityIdentifier.accountButton.rawValue].tap() + accountButton.tap() return self } @discardableResult func tapSettingsButton() -> Self { - app.buttons[AccessibilityIdentifier.settingsButton.rawValue].tap() + settingsButton.tap() return self } } diff --git a/ios/MullvadVPNUITests/Pages/LoginPage.swift b/ios/MullvadVPNUITests/Pages/LoginPage.swift index 399943fe527c..96c6ebea8936 100644 --- a/ios/MullvadVPNUITests/Pages/LoginPage.swift +++ b/ios/MullvadVPNUITests/Pages/LoginPage.swift @@ -27,6 +27,11 @@ class LoginPage: Page { return self } + @discardableResult public func tapCreateAccountButton() -> Self { + app.buttons[AccessibilityIdentifier.createAccountButton].tap() + return self + } + @discardableResult public func verifyDeviceLabelShown() -> Self { XCTAssertTrue( app.staticTexts[AccessibilityIdentifier.headerDeviceNameLabel] diff --git a/ios/MullvadVPNUITests/Pages/OutOfTimePage.swift b/ios/MullvadVPNUITests/Pages/OutOfTimePage.swift new file mode 100644 index 000000000000..0950aa9147ce --- /dev/null +++ b/ios/MullvadVPNUITests/Pages/OutOfTimePage.swift @@ -0,0 +1,19 @@ +// +// OutOfTimePage.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-02-20. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +class OutOfTimePage: Page { + @discardableResult override init(_ app: XCUIApplication) { + super.init(app) + + self.pageAccessibilityIdentifier = .outOfTimeView + waitForPageToBeShown() + } +} diff --git a/ios/MullvadVPNUITests/Pages/RevokedDevicePage.swift b/ios/MullvadVPNUITests/Pages/RevokedDevicePage.swift new file mode 100644 index 000000000000..4b8dd6dd7206 --- /dev/null +++ b/ios/MullvadVPNUITests/Pages/RevokedDevicePage.swift @@ -0,0 +1,26 @@ +// +// RevokedDevicePage.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-03-08. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +class RevokedDevicePage: Page { + @discardableResult override init(_ app: XCUIApplication) { + super.init(app) + + self.pageAccessibilityIdentifier = .revokedDeviceView + waitForPageToBeShown() + } + + @discardableResult func tapGoToLogin() -> Self { + app.buttons[AccessibilityIdentifier.revokedDeviceLoginButton] + .tap() + + return self + } +} diff --git a/ios/MullvadVPNUITests/Pages/SelectLocationPage.swift b/ios/MullvadVPNUITests/Pages/SelectLocationPage.swift index f841101ff630..c5c54325adf2 100644 --- a/ios/MullvadVPNUITests/Pages/SelectLocationPage.swift +++ b/ios/MullvadVPNUITests/Pages/SelectLocationPage.swift @@ -14,6 +14,7 @@ class SelectLocationPage: Page { super.init(app) self.pageAccessibilityIdentifier = .selectLocationView + waitForPageToBeShown() } @discardableResult func tapLocationCell(withName name: String) -> Self { diff --git a/ios/MullvadVPNUITests/Pages/SettingsPage.swift b/ios/MullvadVPNUITests/Pages/SettingsPage.swift index 72acac4019a6..63b3227d2965 100644 --- a/ios/MullvadVPNUITests/Pages/SettingsPage.swift +++ b/ios/MullvadVPNUITests/Pages/SettingsPage.swift @@ -14,6 +14,7 @@ class SettingsPage: Page { super.init(app) self.pageAccessibilityIdentifier = .settingsTableView + waitForPageToBeShown() } @discardableResult func tapVPNSettingsCell() -> Self { diff --git a/ios/MullvadVPNUITests/Pages/TermsOfServicePage.swift b/ios/MullvadVPNUITests/Pages/TermsOfServicePage.swift index b1a569290db6..0f32bf7be6be 100644 --- a/ios/MullvadVPNUITests/Pages/TermsOfServicePage.swift +++ b/ios/MullvadVPNUITests/Pages/TermsOfServicePage.swift @@ -14,6 +14,7 @@ class TermsOfServicePage: Page { super.init(app) self.pageAccessibilityIdentifier = .termsOfServiceView + waitForPageToBeShown() } @discardableResult func tapAgreeButton() -> Self { diff --git a/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift b/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift index 860b9280240c..37813b36c47d 100644 --- a/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift +++ b/ios/MullvadVPNUITests/Pages/TunnelControlPage.swift @@ -14,6 +14,7 @@ class TunnelControlPage: Page { super.init(app) self.pageAccessibilityIdentifier = .tunnelControlView + waitForPageToBeShown() } @discardableResult func tapSelectLocationButton() -> Self { diff --git a/ios/MullvadVPNUITests/Pages/WelcomePage.swift b/ios/MullvadVPNUITests/Pages/WelcomePage.swift new file mode 100644 index 000000000000..d6e8048413b1 --- /dev/null +++ b/ios/MullvadVPNUITests/Pages/WelcomePage.swift @@ -0,0 +1,34 @@ +// +// WelcomePage.swift +// MullvadVPNUITests +// +// Created by Niklas Berglund on 2024-01-30. +// Copyright © 2024 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import XCTest + +class WelcomePage: Page { + @discardableResult override init(_ app: XCUIApplication) { + super.init(app) + + self.pageAccessibilityIdentifier = .welcomeView + waitForPageToBeShown() + } + + @discardableResult func tapAddTimeButton() -> Self { + app.buttons[AccessibilityIdentifier.purchaseButton].tap() + return self + } + + @discardableResult func tapRedeemButton() -> Self { + app.buttons[AccessibilityIdentifier.redeemVoucherButton].tap() + return self + } + + func getAccountNumber() -> String { + let labelValue = app.staticTexts[AccessibilityIdentifier.welcomeAccountNumberLabel].label + return labelValue.replacingOccurrences(of: " ", with: "") + } +} diff --git a/ios/MullvadVPNUITests/README.md b/ios/MullvadVPNUITests/README.md index 8602409322c8..6f2b4f0f085e 100644 --- a/ios/MullvadVPNUITests/README.md +++ b/ios/MullvadVPNUITests/README.md @@ -25,10 +25,10 @@ - `brew install go@1.19` ## GitHub runner setup -1. Ask GitHub admin for new runner token and set it up according to the steps presented, pass `--labels ios-test` to `config.sh` when running it. By default it will also have the labels `self-hosted` and `macOS` which are required as well. +1. Ask GitHub admin for new runner token and setup steps from GitHub. Set it up according to the steps, pass `--labels ios-test` to `config.sh` when running it. By default it will also have the labels `self-hosted` and `macOS` which are required as well. 2. Make sure GitHub actions secrets for the repository are correctly set up: - `IOS_DEVICE_PIN_CODE` - Device passcode if the device require it, otherwise leave blank. Devices used with CI should not require passcode. - `IOS_HAS_TIME_ACCOUNT_NUMBER` - Production server account without time left - `IOS_NO_TIME_ACCOUNT_NUMBER` - Production server account with time added to it - `IOS_TEST_DEVICE_IDENTIFIER_UUID` - unique identifier for the test device. Create new identifier with `uuidgen`. - - `IOS_TEST_DEVICE_UDID` - the iOS device's UDID. \ No newline at end of file + - `IOS_TEST_DEVICE_UDID` - the iOS device's UDID. diff --git a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift index c99f25463ec1..2e4a252c76e1 100644 --- a/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift +++ b/ios/MullvadVPNUITests/Test base classes/BaseUITestCase.swift @@ -76,11 +76,17 @@ class BaseUITestCase: XCTestCase { if termsOfServiceIsShown { TermsOfServicePage(app) .tapAgreeButton() + } + } - Alert(app) // Changes alert - .tapOkay() + func dismissChangeLogIfShown() { + let changeLogIsShown = app + .otherElements[AccessibilityIdentifier.changeLogAlert.rawValue] + .waitForExistence(timeout: 1.0) - LoginPage(app) + if changeLogIsShown { + ChangeLogAlert(app) + .tapOkay() } } @@ -95,11 +101,17 @@ class BaseUITestCase: XCTestCase { func logoutIfLoggedIn() { if isLoggedIn() { - HeaderBar(app) - .tapAccountButton() - - AccountPage(app) - .tapLogOutButton() + if app.buttons[AccessibilityIdentifier.accountButton].exists { + HeaderBar(app) + .tapAccountButton() + + AccountPage(app) + .tapLogOutButton() + } else { + // Workaround for revoked device view not showing account button + RevokedDevicePage(app) + .tapGoToLogin() + } LoginPage(app) } diff --git a/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift index fc1fa747f8eb..fcf6d0f5e2cb 100644 --- a/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift +++ b/ios/MullvadVPNUITests/Test base classes/LoggedInWithTimeUITestCase.swift @@ -14,6 +14,7 @@ class LoggedInWithTimeUITestCase: BaseUITestCase { super.setUp() agreeToTermsOfServiceIfShown() + dismissChangeLogIfShown() logoutIfLoggedIn() login(accountNumber: hasTimeAccountNumber) diff --git a/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift index c7ab76e31bca..8c40c4e76abe 100644 --- a/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift +++ b/ios/MullvadVPNUITests/Test base classes/LoggedInWithoutTimeUITestCase.swift @@ -14,6 +14,7 @@ class LoggedInWithoutTimeUITestCase: BaseUITestCase { super.setUp() agreeToTermsOfServiceIfShown() + dismissChangeLogIfShown() logoutIfLoggedIn() login(accountNumber: noTimeAccountNumber) diff --git a/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift b/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift index a89c6e732ef2..64d04142962f 100644 --- a/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift +++ b/ios/MullvadVPNUITests/Test base classes/LoggedOutUITestCase.swift @@ -14,6 +14,7 @@ class LoggedOutUITestCase: BaseUITestCase { super.setUp() agreeToTermsOfServiceIfShown() + dismissChangeLogIfShown() logoutIfLoggedIn() // Relaunch app so that tests start from a deterministic state diff --git a/ios/TestPlans/MullvadVPNUITestsAll.xctestplan b/ios/TestPlans/MullvadVPNUITestsAll.xctestplan index 29951c80fe1b..14cb0990dc0c 100644 --- a/ios/TestPlans/MullvadVPNUITestsAll.xctestplan +++ b/ios/TestPlans/MullvadVPNUITestsAll.xctestplan @@ -17,9 +17,11 @@ }, "testTargets" : [ { - "selectedTests" : [ - "AccountTests\/testLogin()", - "AccountTests\/testLoginWithIncorrectAccountNumber()" + "skippedTests" : [ + "BaseUITestCase", + "LoggedInWithTimeUITestCase", + "LoggedInWithoutTimeUITestCase", + "LoggedOutUITestCase" ], "target" : { "containerPath" : "container:MullvadVPN.xcodeproj",