/* * Copyright (c) 2026 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System; using System.Threading; using System.Collections.Generic; using FlaUI.Core.Input; using NUnit.Framework; using ProtonVPN.UI.Tests.Enums; using ProtonVPN.UI.Tests.UiTools; using ProtonVPN.UI.Tests.TestsHelper; namespace ProtonVPN.UI.Tests.Robots; public class HomeRobot { protected Element EmptyIpAddress = Element.ByName("Your IP address").And(Element.ByName("-")); protected Element EmptyCountry = Element.ByName("Country").And(Element.ByName("-")); protected Element EmptyProvider = Element.ByName("Provider").And(Element.ByName("-")); protected Element UnprotectedLabel = Element.ByName("Unprotected"); protected Element ConnectingLabel = Element.ByName("Connecting"); protected Element ProtectedLabel = Element.ByName("Protected"); protected Element CancelConnectionButton = Element.ByName("Cancel"); protected Element GetStartedButton = Element.ByName("Get started"); protected Element ConnectionDetailsProtocol = Element.ByAutomationId("ShowProtocolFlyoutButton"); protected Element ChangeProtocolButton = Element.ByAutomationId("ChangeProtocolFlyoutButton"); protected Element KebabMenuButton = Element.ByAutomationId("TitleBarMenuButton"); protected Element HelpButton = Element.ByAutomationId("HelpMenu"); protected Element KebabMenuSettingsItem = Element.ByAutomationId("KebabMenuSettingsItem"); protected Element KebabMenuExitItem = Element.ByAutomationId("KebabMenuExitItem"); protected Element ExitButton = Element.ByName("Exit"); protected Element MaximizeClientSizeButton = Element.ByAutomationId("Maximize"); protected Element RestoreClientSizeButton = Element.ByAutomationId("Restore"); protected Element CloseClientButton = Element.ByAutomationId("Close"); protected Element MinimizeClientButton = Element.ByAutomationId("Minimize"); protected Element ConnectionCardTitle = Element.ByAutomationId("ConnectionCardTitle"); protected Element ConnectionCardDescription = Element.ByAutomationId("ConnectionCardDescription"); protected Element ConnectionCardP2PTag = Element.ByAutomationId("ConnectionCardP2PTag"); protected Element ConnectionCardTorTag = Element.ByAutomationId("ConnectionCardTorTag"); protected Element ConnectionCardFreeConnectionsTagline = Element.ByAutomationId("ConnectionCardFreeConnectionsTagline"); protected Element ConnectionCardConnectButton = Element.ByAutomationId("ConnectionCardConnectButton"); protected Element ConnectionCardCancelButton = Element.ByAutomationId("ConnectionCardCancelButton"); protected Element ConnectionCardDisconnectButton = Element.ByAutomationId("ConnectionCardDisconnectButton"); protected Element ConnectionCardChangeServerButton = Element.ByAutomationId("ConnectionCardChangeServerButton"); protected Element ConnectionCardChangeServerTimeoutButton = Element.ByAutomationId("ConnectionCardChangeServerTimeoutButton"); protected Element ConnectionCardUpsellBanner = Element.ByAutomationId("ConnectionCardUpsellBanner"); protected Element NotTheCountryWantedLabel = Element.ByName("Not the country you wanted?"); protected Element UpgradeYourServerLabel = Element.ByName("Upgrade to choose any server."); protected Element ServerChangesUpsellLabel = Element.ByName("Get unlimited server changes with VPN Plus."); protected Element UpgradeButton = Element.ByName("Upgrade"); protected Element DefaultConnectionSelectorButton = Element.ByAutomationId("DefaultConnectionSelectorButton"); protected Element DefaultConnectionDropdown = Element.ByAutomationId("DefaultConnectionDropdown"); protected Element FastestCountryOption = Element.ByName("Fastest country"); protected Element RandomCountryOption = Element.ByName("Random country"); protected Element LastConnectionOption = Element.ByName("Last connection"); protected Element ProtectedLabelAdvancedKillSwitch = Element.ByName("Advanced kill switch activated"); protected Element ConnectionErrorPanel = Element.ByAutomationId("ConnectionErrorPanel"); protected Element WireGuardConnectionErrorPanelTitle => ConnectionErrorPanel.FindChild(Element.ByName("Connection failed")); protected Element WireGuardConnectionErrorPanelDescription => ConnectionErrorPanel.FindChild(Element.ByName("Your device's WireGuard adapter is in use. Disconnect from any other VPN running on your device, then try again.")); protected Element ConnectionErrorPanelTryAgainButton => ConnectionErrorPanel.FindChild(Element.ByName("Try again")); protected Element ConnectionErrorPanelCloseButton => ConnectionErrorPanel.FindChild(Element.ByName("Close")); protected Element ShowIpFlyoutButton => Element.ByAutomationId("ShowIpFlyoutButton"); public HomeRobot DismissWelcomeModal() { Thread.Sleep(TestConstants.AnimationDelay); GetStartedButton.ClickUntilElementDisappears(); Thread.Sleep(TestConstants.AnimationDelay); return this; } public HomeRobot ClickOnConnectionCardTitle() { ConnectionCardTitle.Click(); return this; } public string? GetVpnServerIp() { return ShowIpFlyoutButton.GetAutomationElementName(); } public HomeRobot ConnectViaConnectionCard(TimeSpan? retryIntervalOverload = null) { ConnectionCardConnectButton.Click(retryIntervalOverload); return this; } public HomeRobot CancelConnection(TimeSpan? retryIntervalOverload = null) { ConnectionCardCancelButton.ClickUntilElementDisappears(retryIntervalOverload); return this; } public HomeRobot Disconnect() { ConnectionCardDisconnectButton.Click(); return this; } public HomeRobot ClickOnProtocolConnectionDetails() { ConnectionDetailsProtocol.Click(); return this; } public HomeRobot ClickChangeProtocolButton() { ChangeProtocolButton.Click(); // Remove when VPNWIN-2599 is implemented. Thread.Sleep(TestConstants.AnimationDelay); return this; } public HomeRobot ExpandKebabMenuButton() { KebabMenuButton.Click(); // Remove when VPNWIN-2599 is implemented. Thread.Sleep(TestConstants.AnimationDelay); return this; } public HomeRobot ClickOnHelpButton() { HelpButton.DoubleClick(); return this; } public HomeRobot NavigateToSettingsViaKebabMenu() { KebabMenuSettingsItem.DoubleClick(); return this; } public HomeRobot ExitViaKebabMenu() { KebabMenuExitItem.DoubleClick(); return this; } public HomeRobot ExitViaKebabMenuWithConfirmation() { KebabMenuExitItem.DoubleClick(); ExitButton.Click(); return this; } public HomeRobot ChangeServer() { ConnectionCardChangeServerButton.Click(); return this; } public HomeRobot ClickLockedChangedServer() { ConnectionCardChangeServerTimeoutButton.Click(); return this; } public HomeRobot CloseClientViaCloseButton() { CloseClientButton.Click(); return this; } public HomeRobot MinimizeClientViaMinimizeButton() { MinimizeClientButton.Click(); return this; } public HomeRobot MaximizeClientSizeViaMaximizeButton() { MaximizeClientSizeButton.Click(); return this; } public HomeRobot RestoreClientSizeViaRestoreButton() { RestoreClientSizeButton.Click(); return this; } public HomeRobot SelectDefaultConnectionOption(VpnConnectionOption option) { DefaultConnectionSelectorButton.Click(); Thread.Sleep(TestConstants.AnimationDelay); string optionName = option switch { VpnConnectionOption.Fastest => "Fastest country", VpnConnectionOption.Random => "Random country", VpnConnectionOption.Last => "Last connection", _ => throw new NotImplementedException($"VpnConnectionOption '{option}' is not supported on the home page ComboBox."), }; Element.ByName(optionName).Click(); Thread.Sleep(TestConstants.AnimationDelay); return this; } public HomeRobot SelectDefaultConnectionCountry(string countryName, string? specificInfo = null) { DefaultConnectionSelectorButton.Click(); Thread.Sleep(TestConstants.AnimationDelay); DefaultConnectionDropdown.SelectDropdownItem(countryName, specificInfo); return this; } public HomeRobot CloseConnectionError() { ConnectionErrorPanelCloseButton.Click(); return this; } public class Verifications : HomeRobot { public Verifications IsLocationDetailsPanelEmpty() { EmptyIpAddress.WaitUntilDisplayed(); EmptyCountry.WaitUntilDisplayed(); EmptyProvider.WaitUntilDisplayed(); return this; } public Verifications AreLocationDetailsShown() { EmptyIpAddress.DoesNotExist(); EmptyCountry.DoesNotExist(); EmptyProvider.DoesNotExist(); return this; } public Verifications IsWelcomeModalDisplayed() { GetStartedButton.WaitUntilDisplayed(TestConstants.TwoMinutesTimeout); return this; } public Verifications IsDisconnected(TimeSpan? timeout = null) { timeout ??= TestConstants.ThirtySecondsTimeout; UnprotectedLabel.WaitUntilDisplayed(timeout); ConnectionCardConnectButton.WaitUntilDisplayed(timeout); return this; } public Verifications IsWireGuardErrorDisplayed() { WireGuardConnectionErrorPanelTitle.WaitUntilDisplayed(TestConstants.OneMinuteTimeout); WireGuardConnectionErrorPanelDescription.WaitUntilDisplayed(TestConstants.ThirtySecondsTimeout); ConnectionErrorPanelTryAgainButton.WaitUntilDisplayed(TestConstants.ThirtySecondsTimeout); ConnectionErrorPanelCloseButton.WaitUntilDisplayed(TestConstants.ThirtySecondsTimeout); return this; } public Verifications IsAdvancedKillSwitchActivated(bool isExpectedToBeActive = true) { if (isExpectedToBeActive) { ProtectedLabelAdvancedKillSwitch.WaitUntilDisplayed(); } else { ProtectedLabelAdvancedKillSwitch.DoesNotExist(); } ConnectionCardConnectButton.WaitUntilDisplayed(); return this; } public Verifications AssertAllVpnConnectionOptions() { DefaultConnectionSelectorButton.Click(); Thread.Sleep(TestConstants.AnimationDelay); FastestCountryOption.WaitUntilDisplayed(); RandomCountryOption.WaitUntilDisplayed(); LastConnectionOption.WaitUntilDisplayed(); Mouse.Click(); return this; } public Verifications IsConnecting() { ConnectingLabel.WaitUntilDisplayed(TestConstants.OneMinuteTimeout, TestConstants.MoreFrequentRetryInterval); return this; } public Verifications IsConnected() { ProtectedLabel.WaitUntilDisplayed(TestConstants.OneMinuteTimeout); ConnectionCardDisconnectButton.WaitUntilDisplayed(TestConstants.ThirtySecondsTimeout); return this; } public Verifications IsChangeServerNotLocked() { ConnectionCardConnectButton.DoesNotExist(); ConnectionCardChangeServerTimeoutButton.DoesNotExist(); ConnectionCardChangeServerButton.WaitUntilDisplayed(); return this; } public Verifications IsChangeServerLocked() { ConnectionCardChangeServerTimeoutButton.WaitUntilDisplayed(); return this; } public Verifications IsNotTheCountryWantedBannerDisplayed() { NotTheCountryWantedLabel.WaitUntilDisplayed(); UpgradeYourServerLabel.WaitUntilDisplayed(); return this; } public Verifications IsUnlimitedServersChangesUpsellDisplayed() { ServerChangesUpsellLabel.WaitUntilDisplayed(); UpgradeButton.WaitUntilDisplayed(); return this; } public Verifications IsConnectionCardFreeConnectionsTaglineDisplayed() { ConnectionCardFreeConnectionsTagline.WaitUntilDisplayed(); return this; } public Verifications IsP2PConnection() { ConnectionCardP2PTag.WaitUntilDisplayed(); return this; } public Verifications IsTorConnection() { ConnectionCardTorTag.WaitUntilDisplayed(); return this; } public Verifications ConnectionCardTitleEquals(string title) { ConnectionCardTitle.TextEquals(title); return this; } public Verifications ConnectionCardDescriptionContainsOneOf(List countries) { ConnectionCardDescription.TextContainsOneOf(countries); return this; } public Verifications ConnectionCardDescriptionContains(string description) { ConnectionCardDescription.TextContains(description); return this; } public Verifications IsProtocolDisplayed(Protocol protocol) { switch (protocol) { case Protocol.WireGuardUdp: ConnectionDetailsProtocol.TextEquals("WireGuard (UDP)"); break; case Protocol.ProTunUdp: ConnectionDetailsProtocol.TextEquals("Proton WireGuard (UDP)"); break; case Protocol.OpenVpnUdp: ConnectionDetailsProtocol.TextEquals("OpenVPN (UDP)"); break; case Protocol.ProTunTcp: ConnectionDetailsProtocol.TextEquals("Proton WireGuard (TCP)"); break; case Protocol.ProTunTls: ConnectionDetailsProtocol.TextEquals("Proton Stealth"); break; case Protocol.WireGuardTcp: ConnectionDetailsProtocol.TextEquals("WireGuard (TCP)"); break; case Protocol.WireGuardTls: ConnectionDetailsProtocol.TextEquals("Stealth"); break; case Protocol.OpenVpnTcp: ConnectionDetailsProtocol.TextEquals("OpenVPN (TCP)"); break; } return this; } public Verifications AssertVPNIpAndExternalIpMatch(string vpnIpAddress, string externalIpAddress) { Assert.That(vpnIpAddress.Equals(externalIpAddress), Is.True); return this; } public Verifications AssertVpnConnectionEstablished(string ipAddressBefore, string ipAddressAfter) { Assert.That(ipAddressBefore.Equals(ipAddressAfter), Is.False, $"User was not connected to VPN server. IP Address not connected: {ipAddressBefore}. " + $"IP Address connected: {ipAddressAfter}"); return this; } public Verifications AssertVpnConnectionAfterKill(string ipAddressBeforeKill, string ipAddressAfterKill) { Assert.That(ipAddressBeforeKill.Equals(ipAddressAfterKill), Is.True, $"VPN Connection was lost after app was killed. " + $"IP Address before client was killed: {ipAddressBeforeKill}. " + $"IP Address after client was killed: {ipAddressAfterKill}"); return this; } public Verifications AssertVpnConnectionAfterRestored(string ipAddressBeforeKill, string ipAddressAfterRestore) { Assert.That(ipAddressBeforeKill.Equals(ipAddressAfterRestore), Is.True, $"VPN Connection was lost/reconnected after client was resumed. " + $"IP Address before client was killed: {ipAddressBeforeKill}. " + $"IP Address after client was restored: {ipAddressAfterRestore}"); return this; } } public Verifications Verify => new(); }