diff --git a/PIA VPN.xcodeproj/project.pbxproj b/PIA VPN.xcodeproj/project.pbxproj index 93ebd151..77f84c68 100644 --- a/PIA VPN.xcodeproj/project.pbxproj +++ b/PIA VPN.xcodeproj/project.pbxproj @@ -147,6 +147,8 @@ 3545E98426AADC7E00B812CC /* ServerSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3545E97F26AAD60C00B812CC /* ServerSelectionDelegate.swift */; }; 35950B312ADD2996006F3CD9 /* Quick in Frameworks */ = {isa = PBXBuildFile; productRef = 35950B302ADD2996006F3CD9 /* Quick */; }; 35950B342ADD2EE5006F3CD9 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = 35950B332ADD2EE5006F3CD9 /* Nimble */; }; + 35DC7A5E2B0B325700502BED /* VPNServerListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35DC7A5D2B0B325700502BED /* VPNServerListTests.swift */; }; + 35DC7A602B0B440200502BED /* RegionSelectionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35DC7A5F2B0B440200502BED /* RegionSelectionScreen.swift */; }; 35EDD6282ADE5D31007B9ACB /* BaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6272ADE5D31007B9ACB /* BaseTest.swift */; }; 35EDD62A2ADE5F08007B9ACB /* SignInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6292ADE5F08007B9ACB /* SignInTests.swift */; }; 35EDD6332ADE7281007B9ACB /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35EDD6322ADE7281007B9ACB /* OnboardingTests.swift */; }; @@ -700,6 +702,8 @@ 3524670D26B432ED00E3F0AC /* DashboardViewController+ServerSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DashboardViewController+ServerSelection.swift"; sourceTree = ""; }; 3545E97F26AAD60C00B812CC /* ServerSelectionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionDelegate.swift; sourceTree = ""; }; 3545E98126AADB2B00B812CC /* ServerSelectingTileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectingTileCell.swift; sourceTree = ""; }; + 35DC7A5D2B0B325700502BED /* VPNServerListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNServerListTests.swift; sourceTree = ""; }; + 35DC7A5F2B0B440200502BED /* RegionSelectionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionSelectionScreen.swift; sourceTree = ""; }; 35EDD6272ADE5D31007B9ACB /* BaseTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTest.swift; sourceTree = ""; }; 35EDD6292ADE5F08007B9ACB /* SignInTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInTests.swift; sourceTree = ""; }; 35EDD6322ADE7281007B9ACB /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; @@ -1308,6 +1312,7 @@ 35EDD6292ADE5F08007B9ACB /* SignInTests.swift */, 35EDD6322ADE7281007B9ACB /* OnboardingTests.swift */, 35EDD65B2B047839007B9ACB /* QuickSettingsTests.swift */, + 35DC7A5D2B0B325700502BED /* VPNServerListTests.swift */, ); path = Tests; sourceTree = ""; @@ -1322,6 +1327,7 @@ 35EDD6412AE7A83D007B9ACB /* WelcomeScreen.swift */, 35EDD6432AE7B480007B9ACB /* Common.swift */, 35EDD6592B035B51007B9ACB /* SideMenuScreen.swift */, + 35DC7A5F2B0B440200502BED /* RegionSelectionScreen.swift */, ); path = Screens; sourceTree = ""; @@ -2517,6 +2523,7 @@ 35EDD6372ADE761A007B9ACB /* HomeScreen.swift in Sources */, 35EDD63B2AE62D15007B9ACB /* ElementHelper.swift in Sources */, 69C587FD2AD00C6300B95EF9 /* PIAExampleWithAuthenticatedAppTest.swift in Sources */, + 35DC7A602B0B440200502BED /* RegionSelectionScreen.swift in Sources */, 699F23B22AFBA66000EBC5E6 /* SettingsScreen.swift in Sources */, 35EDD6422AE7A83D007B9ACB /* WelcomeScreen.swift in Sources */, 699F23B92AFBAC0B00EBC5E6 /* UpdateSettingsTests.swift in Sources */, @@ -2527,6 +2534,7 @@ 35EDD6332ADE7281007B9ACB /* OnboardingTests.swift in Sources */, 699F23B52AFBA66000EBC5E6 /* ProtocolsSettingsScreen.swift in Sources */, 69B70AC02ACC2CFE0072A09D /* AccessibilityId.swift in Sources */, + 35DC7A5E2B0B325700502BED /* VPNServerListTests.swift in Sources */, 699F23B62AFBA66000EBC5E6 /* GeneralSettingsScreen.swift in Sources */, 699F23B72AFBA66000EBC5E6 /* PrivacySettingsScreen.swift in Sources */, ); diff --git a/PIA VPN/Tiles/RegionTileCollectionViewCell.swift b/PIA VPN/Tiles/RegionTileCollectionViewCell.swift index 64a9289f..23fa6a33 100644 --- a/PIA VPN/Tiles/RegionTileCollectionViewCell.swift +++ b/PIA VPN/Tiles/RegionTileCollectionViewCell.swift @@ -46,6 +46,7 @@ class RegionTileCollectionViewCell: UICollectionViewCell, TileableCell { } func setupCellForStatus(_ status: TileStatus) { + self.accessibilityIdentifier = "RegionTileCollectionViewCell" self.accessibilityLabel = L10n.Tiles.Region.title Theme.current.applyPrincipalBackground(self) Theme.current.applyPrincipalBackground(self.contentView) diff --git a/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift b/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift index 684a180f..0c1b95c0 100644 --- a/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift +++ b/PIA-VPN_E2E_Tests/Screens/HomeScreen.swift @@ -45,6 +45,10 @@ extension XCUIApplication { button(with: "Disable VPN Kill Switch") } + var vpnServerButton: XCUIElement { + cell(with: "RegionTileCollectionViewCell") + } + func logOut() { guard dashboardMenuButton.exists else { return } dashboardMenuButton.tap() @@ -54,7 +58,8 @@ extension XCUIApplication { if confirmationDialogButton.waitForExistence(timeout: shortTimeout) { confirmationDialogButton.tap() } - welcomeLoginButton.waitForExistence(timeout: defaultTimeout) + WaitHelper.waitForElementToBeVisible(welcomeLoginButton, timeout: defaultTimeout, + onSuccess:{print("successful logout")}, onFailure:{error in print("welcomeLoginButton is not visible")}) } } @@ -80,7 +85,13 @@ extension XCUIApplication { func navigateToHome() { closeButton.tap() - dashboardMenuButton.waitForExistence(timeout: defaultTimeout) + WaitHelper.waitForElementToBeVisible(dashboardMenuButton, timeout: defaultTimeout, + onSuccess:{print("successfully navigate to Home")}, onFailure:{error in print("dashboardMenuButton is not visible")}) + } + + func navigateToRegionSelection(){ + guard vpnServerButton.exists else { return } + vpnServerButton.tap() } func enableVPNKillSwitchOnHome() { diff --git a/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift b/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift index 408a18fb..ced4c437 100644 --- a/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift +++ b/PIA-VPN_E2E_Tests/Screens/LoginScreen.swift @@ -50,6 +50,8 @@ extension XCUIApplication { swipeUp() - connectionButton.waitForExistence(timeout: defaultTimeout) + WaitHelper.waitForElementToBeVisible(connectionButton, timeout: defaultTimeout, + onSuccess:{print("successful login")}, onFailure:{error in print("connectionButton is not visible")}) + } } diff --git a/PIA-VPN_E2E_Tests/Screens/RegionSelectionScreen.swift b/PIA-VPN_E2E_Tests/Screens/RegionSelectionScreen.swift new file mode 100644 index 00000000..6685e2c0 --- /dev/null +++ b/PIA-VPN_E2E_Tests/Screens/RegionSelectionScreen.swift @@ -0,0 +1,87 @@ +// +// RegionSelectionScreen.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 20/11/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import XCTest + +extension XCUIApplication { + var searchRegionField: XCUIElement { + searchField(with: "Search for a region") + } + + var cancelSearchButton: XCUIElement { + button(with: "Cancel") + } + + var sortButton: XCUIElement { + button(with: "Filter") + } + + var sortPopUpHeader: XCUIElement { + staticText(with: "SORT REGIONS BY") + } + + func searchRegion(regionName: String) -> XCUIElementQuery { + while(!searchRegionField.isHittable) { + swipeDown() + } + searchRegionField.tap() + searchRegionField.typeText(regionName) + + return getRegionList() + } + + func cancelSearch() { + cancelSearchButton.tap() + WaitHelper.waitForElementToBeVisible(sortButton, timeout: defaultTimeout, onSuccess: {}, onFailure: {error in print("sortButton is not displayed")}) + } + + func getRegionList() -> XCUIElementQuery { + let query = cells.matching(NSPredicate(format: "identifier == %@", "uitests.regions.region_name")) + return query + } + + func addRegionAsFavourite(regionName: String) { + let region = searchRegion(regionName: regionName).firstMatch + + let regionAddAsAFavouriteButton = region.buttons["Add a favorite region"] + let regionRemoveAsAFavouriteButton = region.buttons["Remove a favorite region"] + + if(regionRemoveAsAFavouriteButton.exists) { + regionRemoveAsAFavouriteButton.tap() + } + WaitHelper.waitForElementToBeVisible(regionAddAsAFavouriteButton, timeout: defaultTimeout, onSuccess: {}, onFailure: {error in print("regionRemoveAsAFavouriteButton is not visible")}) + WaitHelper.waitForElementToNotBeVisible(regionRemoveAsAFavouriteButton, timeout: defaultTimeout, onSuccess: {}, onFailure: {error in print("regionAddAsAFavouriteButton is not visible")}) + + } + + func removeRegionAsFavourite(regionName: String) { + + } + + func isRegionFavourite(regionName: String) -> Bool { + var isFavourite: Bool = false + + let region = getRegionList().firstMatch + + let regionAddAsAFavouriteButton = region.buttons["Add a favorite region"] + let regionRemoveAsAFavouriteButton = region.buttons["Remove a favorite region"] + + if(regionAddAsAFavouriteButton.exists && !regionRemoveAsAFavouriteButton.exists) { + isFavourite = true + } + + return isFavourite + } + + func sortRegionsBy(sortType: String) { + guard sortButton.exists else {return} + sortButton.tap() + WaitHelper.waitForElementToBeVisible(sortPopUpHeader, timeout: defaultTimeout, onSuccess: {}, onFailure: {error in print("sortPopUpHeader is not visible")}) + button(with: sortType).tap() + } +} diff --git a/PIA-VPN_E2E_Tests/Screens/Settings/PrivacySettingsScreen.swift b/PIA-VPN_E2E_Tests/Screens/Settings/PrivacySettingsScreen.swift index 51be69ee..378f8d60 100644 --- a/PIA-VPN_E2E_Tests/Screens/Settings/PrivacySettingsScreen.swift +++ b/PIA-VPN_E2E_Tests/Screens/Settings/PrivacySettingsScreen.swift @@ -33,4 +33,16 @@ extension XCUIApplication { privacySettingsButton.tap() } } + + func enableVPNKillSwitch(){ + if ((vpnKillSwitch.value as! String) != "1") { + vpnKillSwitch.tap() + } + } + + func disableVPNKillSwitch(){ + if ((vpnKillSwitch.value as! String) != "0") { + vpnKillSwitch.tap() + } + } } diff --git a/PIA-VPN_E2E_Tests/Tests/QuickSettingsTests.swift b/PIA-VPN_E2E_Tests/Tests/QuickSettingsTests.swift index 068180f3..15295137 100644 --- a/PIA-VPN_E2E_Tests/Tests/QuickSettingsTests.swift +++ b/PIA-VPN_E2E_Tests/Tests/QuickSettingsTests.swift @@ -7,7 +7,6 @@ // import Nimble -import Foundation class QuickSettingsTests : BaseTest { override class func spec() { diff --git a/PIA-VPN_E2E_Tests/Tests/UpdateSettingsTests.swift b/PIA-VPN_E2E_Tests/Tests/UpdateSettingsTests.swift index c72f1f92..04c2824d 100644 --- a/PIA-VPN_E2E_Tests/Tests/UpdateSettingsTests.swift +++ b/PIA-VPN_E2E_Tests/Tests/UpdateSettingsTests.swift @@ -51,7 +51,7 @@ class UpdateSettingsTests : BaseTest { it("should revert changes made on privacy features settings to default after logging out and logging back in") { app.navigateToPrivacySettings() - app.vpnKillSwitch.tap() + app.disableVPNKillSwitch() expect((app.vpnKillSwitch.value as! String)) != vpnKillSwitchDefaultValue app.navigateToHomeFromSettings() app.logOut() diff --git a/PIA-VPN_E2E_Tests/Tests/VPNServerListTests.swift b/PIA-VPN_E2E_Tests/Tests/VPNServerListTests.swift new file mode 100644 index 00000000..b550870e --- /dev/null +++ b/PIA-VPN_E2E_Tests/Tests/VPNServerListTests.swift @@ -0,0 +1,88 @@ +// +// VPNServerListTests.swift +// PIA-VPN_E2E_Tests +// +// Created by Geneva Parayno on 20/11/23. +// Copyright © 2023 Private Internet Access Inc. All rights reserved. +// + +import Nimble + +class VPNServerListTests : BaseTest { + override class func spec() { + let regionKeyword = "australia" + let characterKey = "au" + let favouriteRegionKeyword = "Philippines" + + super.spec() + + describe("vpn server list tests") { + context("when the user navigates to region selection screen") { + it("should show the search region field when the user scrolls down") { + app.navigateToRegionSelection() + while(!app.searchRegionField.isHittable) { + app.swipeDown() + } + + expect(app.searchRegionField.isHittable).to(beTrue()) + } + } + + context("when the user performs search") { + it("should return results based on searched keyword \(regionKeyword)") { + app.navigateToRegionSelection() + let cellsQuery = app.searchRegion(regionName: regionKeyword) + + for cell in cellsQuery.allElementsBoundByIndex { + expect(cell.label.lowercased().contains(regionKeyword)).to(beTrue()) + } + } + it("should return results based on searched \(characterKey)") { + app.navigateToRegionSelection() + let cellsQuery = app.searchRegion(regionName: characterKey) + + for cell in cellsQuery.allElementsBoundByIndex { + expect(cell.label.lowercased().contains(characterKey)).to(beTrue()) + } + } + } + + context("when the user selects a region as a favorite") { + it("should be displayed as a favourite region") { + app.navigateToRegionSelection() + app.addRegionAsFavourite(regionName: favouriteRegionKeyword) + expect(app.isRegionFavourite(regionName: favouriteRegionKeyword)).to(beTrue()) + } + } + + context("when the user sorts the region selection") { + it("should sort the regions by name, when 'name' is selected") { + app.navigateToRegionSelection() + app.sortRegionsBy(sortType: "NAME") + let regionList = app.getRegionList().allElementsBoundByIndex.prefix(21).map{$0.label}.filter{$0 != "Automatic"} + expect(regionList).to(equal(regionList.sorted(by: <))) + } + + it("should sort the regions by latency, when 'latency' is selected") { + app.navigateToRegionSelection() + app.sortRegionsBy(sortType: "LATENCY") + let regionList = app.getRegionList().allElementsBoundByIndex.prefix(21).map{$0.label}.filter{$0 != "Automatic"} + expect(regionList) == regionList.sorted { + let latency01 = Int($0.components(separatedBy: ", ").last?.dropLast(2) ?? "") ?? 0 + let latency02 = Int($1.components(separatedBy: ", ").last?.dropLast(2) ?? "") ?? 0 + return latency01