diff --git a/ci/test.yml b/ci/test.yml
index 664f5b72..2f1e9baf 100644
--- a/ci/test.yml
+++ b/ci/test.yml
@@ -1,6 +1,4 @@
-
---
-
lint:
stage: test
extends:
@@ -33,8 +31,6 @@ lint-bug-report-preview:
paths:
- coverage/**
-
-
test-linux:
extends:
- .image-linux-test
@@ -93,7 +89,6 @@ test-integration-race:
paths:
- integration-race-job.log
-
test-integration-nightly:
extends:
- test-integration
@@ -131,12 +126,38 @@ test-coverage:
paths:
- coverage*
- coverage/**
- when: 'always'
+ when: "always"
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
+test-e2e-ui:
+ stage: test
+ extends:
+ - .rules-branch-and-MR-manual
+ tags:
+ - inbox-virt-windows-ui-v1
+ variables:
+ REQUIRES_GRAPHICAL_CONSOLE: true
+ before_script:
+ - echo "Downloading dotnet dependencies"
+ - cd ./tests/e2e/ui_tests/windows_os/
+ - dotnet restore ./ProtonMailBridge.UI.Tests.csproj
+ - dotnet list package
+ script:
+ - pwsh $CI_PROJECT_DIR/tests/e2e/ui_tests/windows_os/InstallerScripts/Get-BridgeInstaller.ps1
+ - no_grpc_proxy=127.0.0.1 dotnet test ./ProtonMailBridge.UI.Tests.csproj -- NUnit.Where="cat != TemporarilyExcluded"
+
+ after_script:
+ - cp /c/users/gitlab-runner/AppData/Roaming/protonmail/bridge-v3/logs/* $CI_PROJECT_DIR/tests/e2e/ui_tests/windows_os/Results/artifacts/Logs/
+ - pwsh $CI_PROJECT_DIR/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-Bridge.ps1
+
+ artifacts:
+ paths:
+ - tests/e2e/ui_tests/windows_os/Results/artifacts/*
+ when: always
+
go-vuln-check:
extends:
- .image-linux-test
@@ -150,4 +171,3 @@ go-vuln-check:
when: always
paths:
- vulns*
-
diff --git a/tests/e2e/ui_tests/windows_os/InstallerScripts/Get-BridgeInstaller.ps1 b/tests/e2e/ui_tests/windows_os/InstallerScripts/Get-BridgeInstaller.ps1
new file mode 100644
index 00000000..ee6ccd8c
--- /dev/null
+++ b/tests/e2e/ui_tests/windows_os/InstallerScripts/Get-BridgeInstaller.ps1
@@ -0,0 +1,45 @@
+# Download the Bridge installer, and install it
+
+# Set variables with Bridge's download link and the download path
+# to be used later on
+$bridgeDownloadURL = $env:BRIDGE_DOWNLOAD_URL
+$bridgeDownloadPath = "$env:CI_PROJECT_DIR/tests/e2e/ui_tests/windows_os/InstallerScripts/Bridge-Installer.exe"
+
+# Write the download link of Bridge to use it if manual re-tests are needed
+Write-Output $bridgeDownloadURL
+
+# Download the Bridge-Installer.exe file
+Invoke-WebRequest -Uri $bridgeDownloadURL -OutFile $bridgeDownloadPath
+
+if (Test-Path -Path $bridgeDownloadPath) {
+ Write-Output "Bridge Installer downloaded."
+ $file = Get-Item $bridgeDownloadPath | Select-Object Name, Length
+ $size = $file.Length
+ $sizeMB = "{0:N2}" -f ($size / 1MB)
+ Write-Output "File size in MB: $sizeMB"
+} else {
+ Write-Output "Bridge installer NOT DOWNLOADED"
+}
+# Install the downloaded Bridge-Installer.exe file
+# The installer is passive, meaning no user interaction is needed
+# If the user does not have admin rights, it will still show the UAC prompt
+# where a user needs to click on "Yes",
+# but this will be not needed since the image in the pipeline will be an
+# Admin account
+
+# Argument list for passive install
+# $argList = "/passive INSTALLSHORTCUT=yes INSTALLDESKTOPSHORTCUT=yes"
+
+# Install Bridge
+$process = Start-Process -Wait -ArgumentList "/passive INSTALLSHORTCUT=yes INSTALLDESKTOPSHORTCUT=yes" -PassThru -FilePath $bridgeDownloadPath
+
+# Check exit code of the installation process to confirm installation
+if ($process.ExitCode -eq "0") {
+ Write-Output "Bridge installed successfully"
+} else {
+ Write-Error "Bridge not installed successfully!"
+ Write-Error "Installer Exit Code: $($process.ExitCode)"
+}
+
+# Delete the installer after installation to clean up the space
+Remove-Item -Path $bridgeDownloadPath
diff --git a/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-Bridge.ps1 b/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-Bridge.ps1
new file mode 100644
index 00000000..675cffee
--- /dev/null
+++ b/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-Bridge.ps1
@@ -0,0 +1,156 @@
+<#
+PowerShell script for uninstalling Bridge
+And removing all other files (vault, cache, updates, etc)
+#>
+
+
+# Define variables with path to Bridge files (vault, cache, startup entry etc)
+$RoamProtonmail = "$env:APPDATA\protonmail"
+$RoamProtonAG = "$env:APPDATA\Proton AG"
+$LocalProtonmail = "$env:LOCALAPPDATA\protonmail"
+$LocalProtonAG = "$env:LOCALAPPDATA\Proton AG"
+$StartUpProtonBridge = "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\Proton Mail Bridge.lnk"
+
+function Uninstall-PMBridge {
+ # Uninstalling REBRANDED version of Bridge
+ # Find the UninstallSTring in the registry (64bit & 32bit)
+ # Use the UninstallString with `msiexec.exe` to uninstall Bridge
+
+ $registry64 = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | ForEach-Object { Get-ItemProperty $_.PSPath } | Where-Object { $_ -match "Proton Mail Bridge" } | Select-Object UninstallString
+
+ if ($registry64) {
+ $registry64 = $registry64 | Select-Object -Last 1
+ $registry64 = $registry64.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
+ $registry64 = $registry64.Trim()
+ Start-Process "msiexec.exe" -arg "/X $registry64 /passive" -Wait
+ }
+
+ $registry32 = Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | ForEach-Object { Get-ItemProperty $_.PSPath } | Where-Object { $_ -match "Proton Mail Bridge" } | Select-Object UninstallString
+
+ if ($registry32) {
+ $registry32 = $registry32 | Select-Object -Last 1
+ $registry32 = $registry32.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
+ $registry32 = $registry32.Trim()
+ Start-Process "msiexec.exe" -arg "/X $registry32 /passive" -Wait
+ }
+
+
+ # Uninstalling PRE-REBRANDED version of Bridge
+ # Find the UninstallSTring in the registry (64bit & 32bit)
+ # Use the UninstallString with `msiexec.exe` to uninstall Bridge
+
+ $preRebrandRegistry64 = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | ForEach-Object { Get-ItemProperty $_.PSPath } | Where-Object { $_ -match "ProtonMail Bridge" } | Select-Object UninstallString
+
+ if ($preRebrandRegistry64) {
+ $preRebrandRegistry64 = $preRebrandRegistry64 | Select-Object -Last 1
+ $preRebrandRegistry64 = $preRebrandRegistry64.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
+ $preRebrandRegistry64 = $preRebrandRegistry64.Trim()
+ Start-Process "msiexec.exe" -arg "/X $preRebrandRegistry64 /passive" -Wait
+ }
+
+ $preRebrandRegistry32 = Get-ChildItem "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | ForEach-Object { Get-ItemProperty $_.PSPath } | Where-Object { $_ -match "ProtonMail Bridge" } | Select-Object UninstallString
+
+ if ($preRebrandRegistry32) {
+ $preRebrandRegistry32 = $preRebrandRegistry32 | Select-Object -Last 1
+ $preRebrandRegistry32 = $preRebrandRegistry32.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
+ $preRebrandRegistry32 = $preRebrandRegistry32.Trim()
+ Start-Process "msiexec.exe" -arg "/X $preRebrandRegistry32 /passive" -Wait
+ }
+
+}
+
+
+function Stop-PMBridge {
+ # Stop the `bridge` process to completely quit Bridge
+
+ $bridge = Get-Process "bridge" -ErrorAction SilentlyContinue
+
+ if ($bridge){
+
+ $bridge | Stop-Process -Force
+
+ }
+
+}
+
+
+function Remove-PMBridgeResources {
+ # Delete all the Bridge resource folders
+ # They should be deleted with uninstalling Bridge
+ # But to just make sure do this again
+
+ Remove-Item $RoamProtonmail -Force -Recurse -ErrorAction SilentlyContinue
+ Remove-Item $RoamProtonAG -Force -Recurse -ErrorAction SilentlyContinue
+ Remove-Item $LocalProtonmail -Force -Recurse -ErrorAction SilentlyContinue
+ Remove-Item $LocalProtonAG -Force -Recurse -ErrorAction SilentlyContinue
+ Remove-Item $StartUpProtonBridge -Force -Recurse -ErrorAction SilentlyContinue
+
+}
+
+
+function Find-PMBridgeResources {
+ # Search and check if the Bridge resource folders
+ # Are deleted
+ # Write to Output the result
+
+ $FolderExists = $false
+
+ if ( Test-Path -Path $RoamProtonmail ){
+ Write-Host "`r`n'$RoamProtonmail' is not deleted!" -ForegroundColor Red
+ $FolderExists = $true
+ }
+
+ if ( Test-Path -Path $RoamProtonAG ) {
+ Write-Host "`r`n'$RoamProtonAG' is not deleted!" -ForegroundColor Red
+ $FolderExists = $true
+ }
+
+ if ( Test-Path -Path $LocalProtonmail ) {
+ Write-Host "`r`n'$LocalProtonmail' is not deleted!" -ForegroundColor Red
+ $FolderExists = $true
+ }
+
+ if ( Test-Path -Path $LocalProtonAG ) {
+ Write-Host "`r`n'$LocalProtonAG' is not deleted!" -ForegroundColor Red
+ $FolderExists = $true
+ }
+
+ if ( Test-Path -Path $StartUpProtonBridge ) {
+ Write-Host "`r`n'$StartUpProtonBridge' is not deleted!" -ForegroundColor Red
+ $FolderExists = $true
+ }
+
+ if ( $FolderExists ) {
+ Write-Host "`r`nSome directories were not deleted properly!`r`n" -ForegroundColor Red
+ }
+
+ else {
+ Write-Host "`r`nAll Bridge resource folders deleted!`r`n" -ForegroundColor Green
+ }
+
+}
+
+
+function Remove-PMBridgeCredentials {
+ # Delete the entries in the credential manager
+
+ $CredentialsData = @((cmdkey /listall | Where-Object{$_ -like "*LegacyGeneric:target=protonmail*"}).replace("Target: ",""))
+
+ for($i =0; $i -le ($CredentialsData.Count -1); $i++){
+ [string]$DeleteData = $CredentialsData[$i].trim()
+ cmdkey /delete:$DeleteData
+ }
+
+}
+
+
+function Invoke-BridgeFunctions {
+ Stop-PMBridge
+ Uninstall-PMBridge
+ Remove-PMBridgeResources
+ Find-PMBridgeResources
+ Remove-PMBridgeCredentials
+}
+
+
+Invoke-BridgeFunctions
diff --git a/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-BridgeCredentials.ps1 b/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-BridgeCredentials.ps1
new file mode 100644
index 00000000..e8f2f011
--- /dev/null
+++ b/tests/e2e/ui_tests/windows_os/InstallerScripts/Remove-BridgeCredentials.ps1
@@ -0,0 +1,34 @@
+<#
+PowerShell script for removing Bridge credentials from
+Microsoft Credentials manager
+#>
+
+$Bridge = Get-Process "bridge" -ErrorAction SilentlyContinue
+$CredentialsData = @((cmdkey /listall | Where-Object{$_ -like "*LegacyGeneric:target=protonmail*"}).replace("Target: ",""))
+
+
+function Remove-BridgeCredentials {
+ # Delete the entries in the credential manager
+
+ for($i=0; $i -le ($CredentialsData.Count -1); $i++){
+ [string]$DeleteData = $CredentialsData[$i].trim()
+ cmdkey /delete:$DeleteData
+ }
+}
+
+function Stop-PMBridge {
+ # Stop the `bridge` process to completely quit Bridge
+
+ if ($Bridge){
+
+ $Bridge | Stop-Process -Force
+
+ }
+}
+
+function Invoke-Functions{
+ Stop-PMBridge
+ Remove-BridgeCredentials
+}
+
+Invoke-Functions
diff --git a/tests/e2e/ui_tests/windows_os/ProtonMailBridge.UI.Tests.csproj b/tests/e2e/ui_tests/windows_os/ProtonMailBridge.UI.Tests.csproj
index 30fee0b2..df924f52 100644
--- a/tests/e2e/ui_tests/windows_os/ProtonMailBridge.UI.Tests.csproj
+++ b/tests/e2e/ui_tests/windows_os/ProtonMailBridge.UI.Tests.csproj
@@ -18,14 +18,17 @@
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
+
diff --git a/tests/e2e/ui_tests/windows_os/Results/HomeResult.cs b/tests/e2e/ui_tests/windows_os/Results/HomeResult.cs
index a176b32e..bda9b122 100644
--- a/tests/e2e/ui_tests/windows_os/Results/HomeResult.cs
+++ b/tests/e2e/ui_tests/windows_os/Results/HomeResult.cs
@@ -16,42 +16,44 @@ namespace ProtonMailBridge.UI.Tests.Results
private Button OkToAcknowledgeAccountAlreadySignedIn => NotificationWindow.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("OK"))).AsButton();
private AutomationElement[] TextFields => Window.FindAllDescendants(cf => cf.ByControlType(ControlType.Text));
private TextBox SynchronizingField => TextFields[4].AsTextBox();
- private TextBox AccountDisabledErrorText => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Text).And(cf.ByName("failed to create new API client: 422 POST https://mail-api.proton.me/auth/v4: This account has been suspended due to a potential policy violation. If you believe this is in error, please contact us at https://proton.me/support/appeal-abuse (Code=10003, Status=422)"))).AsTextBox();
- private TextBox AccountDelinquentErrorText => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Text).And(cf.ByName("failed to create new API client: 422 POST https://mail-api.proton.me/auth/v4: Use of this client requires permissions not available to your account (Code=2011, Status=422)"))).AsTextBox();
+ private TextBox AccountDisabledErrorText => Window.FindAllDescendants(cf => cf.ByControlType(ControlType.Text)).FirstOrDefault(e =>!string.IsNullOrEmpty(e.Name) && e.Name.IndexOf("This account has been suspended due to a potential policy violation.", StringComparison.OrdinalIgnoreCase) >= 0)?.AsTextBox();
private TextBox IncorrectLoginCredentialsErrorText => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Text).And(cf.ByName("Incorrect login credentials"))).AsTextBox();
private TextBox EnterEmailOrUsernameErrorText => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Text).And(cf.ByName("Enter email or username"))).AsTextBox();
private TextBox EnterPasswordErrorText => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Text).And(cf.ByName("Enter password"))).AsTextBox();
private TextBox ConnectedStateText => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Text).And(cf.ByName("Connected"))).AsTextBox();
private CheckBox SplitAddressesToggle => AccountView.FindFirstDescendant(cf => cf.ByControlType(ControlType.CheckBox).And(cf.ByName("Split addresses toggle"))).AsCheckBox();
+
+
public HomeResult CheckConnectedState()
{
- Assert.That(ConnectedStateText.IsAvailable, Is.True);
+ RetryHelper.Eventually(() => ConnectedStateText.IsAvailable);
return this;
}
public HomeResult CheckIfLoggedIn()
{
- Assert.That(SignOutButton.IsAvailable, Is.True);
+ RetryHelper.Eventually(() => SignOutButton.IsAvailable);
return this;
}
public HomeResult CheckIfSynchronizingBarIsShown()
{
- Assert.That(SynchronizingField.IsAvailable && SynchronizingField.Name.StartsWith("Synchronizing"), Is.True);
+ RetryHelper.Eventually(() => SynchronizingField.IsAvailable && SynchronizingField.Name.StartsWith("Synchronizing"));
return this;
}
public HomeResult CheckIfFreeAccountErrorIsDisplayed(string ErrorText)
{
- Assert.That(FreeAccountErrorText.Name == ErrorText, Is.True);
+ RetryHelper.Eventually(() => FreeAccountErrorText.Name == ErrorText);
return this;
}
public HomeResult CheckIfAccountIsSignedOut()
{
- Assert.That(SignedOutAccount.IsAvailable, Is.True);
+ RetryHelper.Eventually(() => SignedOutAccount.IsAvailable);
return this;
}
public HomeResult CheckIfAccountAlreadySignedInIsDisplayed()
{
- Assert.That(AlreadySignedInText.IsAvailable, Is.True);
+
+ RetryHelper.Eventually(() => AlreadySignedInText.IsAvailable);
return this;
}
public HomeResult ClickOkToAcknowledgeAccountAlreadySignedIn ()
@@ -67,32 +69,30 @@ namespace ProtonMailBridge.UI.Tests.Results
}
public HomeResult CheckIfEnterUsernameAndEnterPasswordErrorMsgsAreDisplayed()
- {
- Assert.That(EnterEmailOrUsernameErrorText.IsAvailable && EnterPasswordErrorText.IsAvailable, Is.True);
+ {
+ RetryHelper.Eventually(() => EnterEmailOrUsernameErrorText.IsAvailable && EnterPasswordErrorText.IsAvailable);
return this;
}
public HomeResult CheckIfDsabledAccountErrorIsDisplayed()
{
- Assert.That(AccountDisabledErrorText.IsAvailable, Is.True);
- return this;
- }
-
- public HomeResult CheckIfDelinquentAccountErrorIsDisplayed()
- {
- Assert.That(AccountDelinquentErrorText.IsAvailable, Is.True);
+ RetryHelper.Eventually(() => AccountDisabledErrorText.IsAvailable);
return this;
}
public HomeResult CheckIfNotificationTextIsShown()
{
- Assert.That(AlreadySignedInText.IsAvailable, Is.True);
+ RetryHelper.Eventually(() => AlreadySignedInText.IsAvailable);
return this;
}
public HomeResult CheckIfSplitAddressesIsDisabledByDefault()
{
- Assert.That(SplitAddressesToggle.IsToggled, Is.False);
+ RetryHelper.Eventually(() =>
+ {
+ bool isNotToggled = SplitAddressesToggle.IsToggled == null || !(bool)SplitAddressesToggle.IsToggled;
+ return isNotToggled;
+ });
return this;
}
}
diff --git a/tests/e2e/ui_tests/windows_os/Results/artifacts/Logs/.gitkeep b/tests/e2e/ui_tests/windows_os/Results/artifacts/Logs/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/e2e/ui_tests/windows_os/Results/artifacts/README.md b/tests/e2e/ui_tests/windows_os/Results/artifacts/README.md
new file mode 100644
index 00000000..59f5c741
--- /dev/null
+++ b/tests/e2e/ui_tests/windows_os/Results/artifacts/README.md
@@ -0,0 +1 @@
+# This is a folder where all files that are needed for debugging purposes will be saved in regards to failing tests
diff --git a/tests/e2e/ui_tests/windows_os/Results/artifacts/Screenshots/.gitkeep b/tests/e2e/ui_tests/windows_os/Results/artifacts/Screenshots/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/e2e/ui_tests/windows_os/TestSession.cs b/tests/e2e/ui_tests/windows_os/TestSession.cs
index d2418e1a..fd0cb59a 100644
--- a/tests/e2e/ui_tests/windows_os/TestSession.cs
+++ b/tests/e2e/ui_tests/windows_os/TestSession.cs
@@ -1,11 +1,16 @@
using System;
using System.Threading;
+using System.Management.Automation;
+using System.Management.Automation.Runspaces;
using FlaUI.Core.AutomationElements;
using FlaUI.Core;
using FlaUI.UIA3;
using ProtonMailBridge.UI.Tests.TestsHelper;
using FlaUI.Core.Input;
using System.Diagnostics;
+using System.Drawing.Text;
+using System.Collections.ObjectModel;
+using FlaUI.Core.Tools;
namespace ProtonMailBridge.UI.Tests
{
@@ -17,13 +22,57 @@ namespace ProtonMailBridge.UI.Tests
protected static Window Window;
protected static Window ChromeWindow;
protected static Window FileExplorerWindow;
+ protected static Runspace? myRunSpace;
+ protected static string? bridgeDownloadURL;
+ protected static string downloadEnvVariable = "BRIDGE_DOWNLOAD_URL";
+ private static readonly DebugTests debugTests = new();
+ protected static string atlasEnvironment = "https://mail-api.proton.pink/";
+
protected static void ClientCleanup()
{
- App.Kill();
- App.Dispose();
+ var outcome = TestContext.CurrentContext.Result.Outcome.Status;
+ if (outcome == NUnit.Framework.Interfaces.TestStatus.Failed)
+ {
+ try
+ {
+ debugTests.TakeScreenshot();
+ }
+ catch (Exception ex)
+ {
+ TestContext.Out.WriteLine(ex.ToString());
+ }
+ }
+
+ try
+ {
+ App.Kill();
+ }
+ catch (Exception ex)
+ {
+ TestContext.Out.WriteLine(ex.ToString());
+ }
+
+ try
+ {
+ App.Dispose();
+ }
+ catch (Exception ex)
+ {
+ TestContext.Out.WriteLine(ex.ToString());
+ }
+
// Give some time to properly exit the app
Thread.Sleep(10000);
+ try
+ {
+ RemoveBridgeCredentials();
+ }
+ catch (Exception ex)
+ {
+ TestContext.Out.WriteLine($"Failed to remove Bridge credentials: {ex}");
+ }
+
}
public static void switchToFileExplorerWindow()
@@ -60,28 +109,117 @@ namespace ProtonMailBridge.UI.Tests
}
// Cast the found element to a Window object
- ChromeWindow = _chromeWindow.AsWindow();
+ ChromeWindow = _chromeWindow.AsWindow();
// Focus on the Chrome window
ChromeWindow.Focus();
}
+ protected static void RefreshWindow(TimeSpan? timeout = null)
+ {
+ Window = null;
+ TimeSpan refreshTimeout = timeout ?? TestData.ThirtySecondsTimeout;
+ RetryResult retry = Retry.WhileNull(
+ () =>
+ {
+ try
+ {
+ Window = App.GetMainWindow(new UIA3Automation(), refreshTimeout);
+ }
+ catch (System.TimeoutException)
+ {
+ // Ignore
+ }
+ return Window;
+ },
+ refreshTimeout, TestData.RetryInterval);
+
+ if (!retry.Success)
+ {
+ Assert.Fail($"Failed to refresh window in {refreshTimeout.TotalSeconds} seconds.");
+ }
+ }
+
public static void LaunchApp()
{
+ TestContext.Out.WriteLine($"[RUNNING TEST] {TestContext.CurrentContext.Test.FullName}");
+ System.Environment.SetEnvironmentVariable("BRIDGE_HOST_URL", $"{atlasEnvironment}");
string appExecutable = TestData.AppExecutable;
Application.Launch(appExecutable);
Wait.UntilInputIsProcessed(TestData.FiveSecondsTimeout);
App = Application.Attach("bridge-gui.exe");
+ RefreshWindow(TestData.OneMinuteTimeout);
+ Window.Focus();
+ }
- try
+ private static RetryResult WaitUntilAppIsRunning()
+ {
+ RetryResult retry = Retry.WhileFalse(
+ () =>
+ {
+ Process[] pname = Process.GetProcessesByName("Proton Mail Bridge");
+ return pname.Length > 0;
+ },
+ TimeSpan.FromSeconds(30), TestData.RetryInterval);
+
+ return retry;
+ }
+ public static void CreateRunSpace()
+ {
+ bridgeDownloadURL = Environment.GetEnvironmentVariable($"{downloadEnvVariable}");
+ myRunSpace = RunspaceFactory.CreateRunspace();
+ myRunSpace.Open();
+ Pipeline cmd = myRunSpace.CreatePipeline($"New-Item env:{downloadEnvVariable} -Value {bridgeDownloadURL} -Force");
+ cmd.Invoke();
+ cmd = myRunSpace.CreatePipeline(@"Set-Location $env:CI_PROJECT_DIR\tests\e2e\ui_tests\windows_os\InstallerScripts");
+ cmd.Invoke();
+ cmd = myRunSpace.CreatePipeline(@"Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser");
+ cmd.Invoke();
+ }
+
+ public static Collection? InstallBridge()
+ {
+ CreateRunSpace();
+ if (myRunSpace is not null)
{
- Window = App.GetMainWindow(new UIA3Automation(), TestData.ThirtySecondsTimeout);
+ Pipeline cmd = myRunSpace.CreatePipeline("Get-Location");
+ cmd.Invoke();
+ cmd = myRunSpace.CreatePipeline(@".\Get-BridgeInstaller.ps1");
+ var objects = cmd.Invoke();
+
+ return objects;
}
- catch (System.TimeoutException)
+
+ return null;
+ }
+
+ public static Collection? UninstallBridge()
+ {
+ CreateRunSpace();
+ if (myRunSpace is not null)
{
- Assert.Fail("Failed to get window of application!");
+ Pipeline cmd = myRunSpace.CreatePipeline(@".\Remove-Bridge.ps1");
+ var objects = cmd.Invoke();
+
+ return objects;
}
+
+ return null;
+ }
+
+ public static Collection? RemoveBridgeCredentials()
+ {
+ CreateRunSpace();
+ if (myRunSpace is not null)
+ {
+ Pipeline cmd = myRunSpace.CreatePipeline(@".\Remove-BridgeCredentials.ps1");
+ var objects = cmd.Invoke();
+
+ return objects;
+ }
+
+ return null;
}
}
}
\ No newline at end of file
diff --git a/tests/e2e/ui_tests/windows_os/Tests/HelpMenuTests.cs b/tests/e2e/ui_tests/windows_os/Tests/HelpMenuTests.cs
index fbfdb59f..b55c0048 100644
--- a/tests/e2e/ui_tests/windows_os/Tests/HelpMenuTests.cs
+++ b/tests/e2e/ui_tests/windows_os/Tests/HelpMenuTests.cs
@@ -33,7 +33,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_homeResult.CheckIfLoggedIn();
}
- [Test]
+ [Test, Category("TemporarilyExcluded")]
public void OpenGoToHelpTopics()
{
_loginWindow.SignIn(TestUserData.GetPaidUser());
@@ -46,7 +46,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_helpMenuWindow.ClickBackFromHelpMenu();
}
- [Test]
+ [Test, Category("TemporarilyExcluded")]
public void CheckForUpdates()
{
_loginWindow.SignIn(TestUserData.GetPaidUser());
@@ -58,7 +58,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
Wait.UntilInputIsProcessed(TimeSpan.FromSeconds(1));
_helpMenuWindow.ClickBackFromHelpMenu();
}
- [Test]
+ [Test, Category("TemporarilyExcluded")]
public void OpenLogs()
{
_loginWindow.SignIn(TestUserData.GetPaidUser());
@@ -134,7 +134,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
[TearDown]
public void TestCleanup()
{
- _mainWindow.RemoveAccount();
+ _mainWindow.RemoveAccountTestCleanup();
ClientCleanup();
}
}
diff --git a/tests/e2e/ui_tests/windows_os/Tests/LoginLogoutTests.cs b/tests/e2e/ui_tests/windows_os/Tests/LoginLogoutTests.cs
index 3a4dcafe..3b076cbb 100644
--- a/tests/e2e/ui_tests/windows_os/Tests/LoginLogoutTests.cs
+++ b/tests/e2e/ui_tests/windows_os/Tests/LoginLogoutTests.cs
@@ -3,25 +3,39 @@ using ProtonMailBridge.UI.Tests.TestsHelper;
using ProtonMailBridge.UI.Tests.Windows;
using ProtonMailBridge.UI.Tests.Results;
using FlaUI.Core.Input;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
namespace ProtonMailBridge.UI.Tests.Tests
{
[TestFixture]
+ [Category("LoginLogoutTests")]
public class LoginLogoutTests : TestSession
{
private readonly LoginWindow _loginWindow = new();
private readonly HomeWindow _mainWindow = new();
private readonly HomeResult _homeResult = new();
private readonly string FreeAccountErrorText = "Bridge is exclusive to our mail paid plans. Upgrade your account to use Bridge.";
+ private bool removeAccount = true;
[Test]
+ [Category("NOOP")]
+ public void Noop()
+ {
+ TestContext.Out.WriteLine("NoOP");
+ removeAccount = false;
+ }
+
+ [Test]
+ [Category("DebugTests")]
public void LoginAsFreeUser()
{
_loginWindow.SignIn(TestUserData.GetFreeUser());
_homeResult.CheckIfFreeAccountErrorIsDisplayed(FreeAccountErrorText);
+ removeAccount = false;
}
[Test]
+ [Category("DebugTests")]
public void LoginAsPaidUser()
{
_loginWindow.SignIn(TestUserData.GetPaidUser());
@@ -46,13 +60,8 @@ namespace ProtonMailBridge.UI.Tests.Tests
[Test]
public void AddAliasAddress()
{
- _loginWindow.SignIn(TestUserData.GetPaidUser());
- _homeResult.CheckIfLoggedIn();
- _mainWindow.AddNewAccount();
_loginWindow.SignIn(TestUserData.GetAliasUser());
- _homeResult.CheckIfAccountAlreadySignedInIsDisplayed();
- _homeResult.ClickOkToAcknowledgeAccountAlreadySignedIn();
- _loginWindow.ClickCancelToSignIn();
+ _homeResult.CheckIfLoggedIn();
}
[Test]
@@ -83,6 +92,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_loginWindow.SignIn(TestUserData.GetIncorrectCredentialsUser());
_homeResult.CheckIfIncorrectCredentialsErrorIsDisplayed();
_loginWindow.ClickCancelToSignIn();
+ removeAccount = false;
}
[Test, Order (1)]
@@ -91,8 +101,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_loginWindow.SignIn(TestUserData.GetEmptyCredentialsUser());
_homeResult.CheckIfEnterUsernameAndEnterPasswordErrorMsgsAreDisplayed();
_loginWindow.ClickCancelToSignIn();
- _loginWindow.SignIn(TestUserData.GetPaidUser());
- _homeResult.CheckIfLoggedIn();
+ removeAccount = false;
}
[Test]
@@ -114,14 +123,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_loginWindow.SignIn(TestUserData.GetDisabledUser());
_homeResult.CheckIfDsabledAccountErrorIsDisplayed();
_loginWindow.ClickCancelToSignIn();
- }
-
- [Test]
- public void AddDeliquentAccount()
- {
- _loginWindow.SignIn(TestUserData.GetDeliquentUser());
- _homeResult.CheckIfDelinquentAccountErrorIsDisplayed();
- _loginWindow.ClickCancelToSignIn();
+ removeAccount = false;
}
[Test]
@@ -143,14 +145,18 @@ namespace ProtonMailBridge.UI.Tests.Tests
[SetUp]
public void TestInitialize()
- {
+ {
LaunchApp();
+ Thread.Sleep(5000);
}
[TearDown]
public void TestCleanup()
{
- _mainWindow.RemoveAccount();
+ if (removeAccount)
+ {
+ _mainWindow.RemoveAccountTestCleanup();
+ }
ClientCleanup();
}
}
diff --git a/tests/e2e/ui_tests/windows_os/Tests/SettingsMenuTests.cs b/tests/e2e/ui_tests/windows_os/Tests/SettingsMenuTests.cs
index 72e04aaa..f642cbd6 100644
--- a/tests/e2e/ui_tests/windows_os/Tests/SettingsMenuTests.cs
+++ b/tests/e2e/ui_tests/windows_os/Tests/SettingsMenuTests.cs
@@ -14,6 +14,7 @@ using FlaUI.UIA3;
namespace ProtonMailBridge.UI.Tests.Tests
{
[TestFixture]
+ [Category("SettingsMenuTests")]
public class SettingsMenuTests : TestSession
{
private readonly LoginWindow _loginWindow = new();
@@ -175,7 +176,6 @@ namespace ProtonMailBridge.UI.Tests.Tests
_settingsMenuWindow.ClickSettingsButton();
_settingsMenuWindow.ExpandAdvancedSettings();
Mouse.Scroll(-20);
- //Thread.Sleep(3000);
_settingsMenuResults.CollectUsageDiagnosticsIsEnabledByDefault();
Mouse.Scroll(20);
_settingsMenuWindow.CollapseAdvancedSettings();
@@ -189,8 +189,10 @@ namespace ProtonMailBridge.UI.Tests.Tests
_settingsMenuWindow.ClickSettingsButton();
_settingsMenuWindow.ExpandAdvancedSettings();
Mouse.Scroll(-20);
+ Thread.Sleep(5000);
_settingsMenuWindow.DisableAndEnableCollectUsageDiagnostics();
Mouse.Scroll(20);
+ Thread.Sleep(5000);
_settingsMenuWindow.CollapseAdvancedSettings();
_settingsMenuWindow.ClickBackFromSettingsMenu();
}
@@ -270,7 +272,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_settingsMenuWindow.ClickBackFromSettingsMenu();
}
- [Test]
+ [Test, Category("TemporarilyExcluded")]
public void ChangeLocationSwitchBackToDefaultAndDeleteOldLocalCacheLocation()
{
_loginWindow.SignIn(TestUserData.GetPaidUser());
@@ -284,7 +286,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
_settingsMenuWindow.ClickBackFromSettingsMenu();
}
- [Test]
+ [Test, Category("TemporarilyExcluded")]
public void ExportTlsCertificatesVerifyExportAndDeleteTheExportFolder()
{
_loginWindow.SignIn(TestUserData.GetPaidUser());
@@ -325,7 +327,15 @@ namespace ProtonMailBridge.UI.Tests.Tests
[TearDown]
public void TestCleanup()
{
- _mainWindow.RemoveAccount();
+ try
+ {
+ _mainWindow.RemoveAccountTestCleanup();
+ }
+ catch (Exception ex)
+ {
+ TestContext.Out.WriteLine("Teardown error on test account cleanup: " + ex);
+ }
+
ClientCleanup();
}
}
diff --git a/tests/e2e/ui_tests/windows_os/Tests/ZeroPercentUpdateTest.cs b/tests/e2e/ui_tests/windows_os/Tests/ZeroPercentUpdateTest.cs
index cb4a4e25..8641be2d 100644
--- a/tests/e2e/ui_tests/windows_os/Tests/ZeroPercentUpdateTest.cs
+++ b/tests/e2e/ui_tests/windows_os/Tests/ZeroPercentUpdateTest.cs
@@ -26,8 +26,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
LaunchApp();
}
- [Test]
- [Category("ZeroPercentUpdateRollout")]
+ [Test, Category("TemporarilyExcluded")]
public void EnableBetaAccessVerifyBetaIsEnabledVerifyNotificationAndRestartBridge()
{
_zeroPercentWindow.ClickStartSetupButton();
@@ -52,6 +51,7 @@ namespace ProtonMailBridge.UI.Tests.Tests
public void TestCleanup()
{
ClientCleanup();
+
}
}
}
diff --git a/tests/e2e/ui_tests/windows_os/TestsHelper/DebugTests.cs b/tests/e2e/ui_tests/windows_os/TestsHelper/DebugTests.cs
new file mode 100644
index 00000000..ca0817f5
--- /dev/null
+++ b/tests/e2e/ui_tests/windows_os/TestsHelper/DebugTests.cs
@@ -0,0 +1,24 @@
+using FlaUI.Core.Capturing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ProtonMailBridge.UI.Tests.TestsHelper
+{
+ internal class DebugTests
+ {
+ public void TakeScreenshot()
+ {
+ string testName = TestContext.CurrentContext.Test.Name;
+ string Timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
+ string ScreenshotName = "Screenshot_" + testName + "_" + Timestamp + ".png";
+ string Query = "%CI_PROJECT_DIR%\\tests\\e2e\\ui_tests\\windows_os\\Results\\artifacts\\Screenshots\\" + ScreenshotName;
+ string ScreenshotLocation = Environment.ExpandEnvironmentVariables(Query);
+ var ScreenshotFile = Capture.Screen();
+ ScreenshotFile.ToFile(ScreenshotLocation);
+ }
+ }
+}
diff --git a/tests/e2e/ui_tests/windows_os/TestsHelper/RetryHelper.cs b/tests/e2e/ui_tests/windows_os/TestsHelper/RetryHelper.cs
new file mode 100644
index 00000000..c386abd3
--- /dev/null
+++ b/tests/e2e/ui_tests/windows_os/TestsHelper/RetryHelper.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ProtonMailBridge.UI.Tests.TestsHelper
+{
+ public class RetryHelper
+ {
+ public static void Eventually(Func condition, int retries = 10, int delaySeconds = 5)
+ {
+ for (int i = 0; i < retries; i++)
+ {
+ if (condition()) return;
+
+ Thread.Sleep(TimeSpan.FromSeconds(delaySeconds));
+ }
+
+ Assert.Fail();
+ }
+
+ public static void EventuallyAction(Action action, int retries = 20, int delaySeconds = 2)
+ {
+ Exception? lastException = null;
+ for (int i = 0; i < retries; i++)
+ {
+ try
+ {
+ action();
+ return;
+ } catch (Exception e)
+ {
+ lastException = e;
+ Thread.Sleep(TimeSpan.FromSeconds(delaySeconds));
+ }
+ }
+
+ throw new Exception("Eventually failed after retries", lastException);
+ }
+ }
+}
diff --git a/tests/e2e/ui_tests/windows_os/UIActions.cs b/tests/e2e/ui_tests/windows_os/UIActions.cs
index 5adbbdda..1199778b 100644
--- a/tests/e2e/ui_tests/windows_os/UIActions.cs
+++ b/tests/e2e/ui_tests/windows_os/UIActions.cs
@@ -1,14 +1,60 @@
using System;
+using System.Runtime.InteropServices;
using FlaUI.Core.AutomationElements;
using FlaUI.Core.Definitions;
using FlaUI.Core.Input;
using FlaUI.Core.Tools;
using NUnit.Framework;
+using ProtonMailBridge.UI.Tests.TestsHelper;
namespace ProtonMailBridge.UI.Tests
{
public class UIActions : TestSession
{
public AutomationElement AccountView => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane));
+
+ protected dynamic WaitUntilElementExistsByName(string name, TimeSpan time)
+ {
+ WaitForElement(() =>
+ {
+ RefreshWindow();
+ return Window.FindFirstDescendant(cf => cf.ByName(name)) != null;
+ }, time, name);
+
+ return this;
+ }
+ protected AutomationElement ElementByName(string name, TimeSpan? timeout = null)
+ {
+ WaitUntilElementExistsByName(name, timeout ?? TestData.TenSecondsTimeout);
+ return Window.FindFirstDescendant(cf => cf.ByName(name));
+ }
+ private void WaitForElement(Func function, TimeSpan time, string selector, string customMessage = null)
+ {
+ RetryResult retry = Retry.WhileFalse(
+ () => {
+ try
+ {
+ App.WaitWhileBusy();
+ return function();
+ }
+ catch (COMException)
+ {
+ return false;
+ }
+ },
+ time, TestData.RetryInterval);
+
+ if (!retry.Success)
+ {
+ if(customMessage == null)
+ {
+ Assert.Fail($"Failed to get {selector} element within {time.TotalSeconds} seconds.");
+ }
+ else
+ {
+ Assert.Fail(customMessage);
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/tests/e2e/ui_tests/windows_os/Windows/HelpMenuWindow.cs b/tests/e2e/ui_tests/windows_os/Windows/HelpMenuWindow.cs
index f4b67162..76bf352b 100644
--- a/tests/e2e/ui_tests/windows_os/Windows/HelpMenuWindow.cs
+++ b/tests/e2e/ui_tests/windows_os/Windows/HelpMenuWindow.cs
@@ -32,7 +32,7 @@ namespace ProtonMailBridge.UI.Tests.Windows
private Button LogsButton => HomeButtons[9].AsButton();
private Button ReportProblemButton => HomeButtons[10].AsButton();
private Button ICannotFindEmailInClient => HomeButtons[7].AsButton();
- private TextBox DescriptionOnWhatHappened => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Edit)).AsTextBox();
+ private TextBox DescriptionOnWhatHappened => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane)).FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane)).FindFirstDescendant(cf => cf.ByControlType(ControlType.Edit)).AsTextBox();
private RadioButton MissingEmails => ReportProblemPane[0].FindFirstDescendant(cf => cf.ByControlType(ControlType.RadioButton).And(cf.ByName("Old emails are missing"))).AsRadioButton();
private RadioButton FindEmails => ReportProblemPane[0].FindFirstDescendant(cf => cf.ByControlType(ControlType.RadioButton).And(cf.ByName("Yes"))).AsRadioButton();
private CheckBox VPNSoftware => ReportProblemPane[0].FindFirstDescendant(cf => cf.ByControlType(ControlType.CheckBox).And(cf.ByName("VPN"))).AsCheckBox();
diff --git a/tests/e2e/ui_tests/windows_os/Windows/HomeWindow.cs b/tests/e2e/ui_tests/windows_os/Windows/HomeWindow.cs
index 259ff0d8..1ef48863 100644
--- a/tests/e2e/ui_tests/windows_os/Windows/HomeWindow.cs
+++ b/tests/e2e/ui_tests/windows_os/Windows/HomeWindow.cs
@@ -11,6 +11,7 @@ namespace ProtonMailBridge.UI.Tests.Windows
public class HomeWindow : UIActions
{
private AutomationElement[] AccountViewButtons => AccountView.FindAllChildren(cf => cf.ByControlType(ControlType.Button));
+
private AutomationElement[] HomeButtons => Window.FindAllDescendants(cf => cf.ByControlType(ControlType.Button));
private Button AddNewAccountButton => HomeButtons[6].AsButton();
private Button RemoveAccountButton => AccountViewButtons[1].AsButton();
@@ -21,14 +22,14 @@ namespace ProtonMailBridge.UI.Tests.Windows
private CheckBox SplitAddressesToggle => AccountView.FindFirstDescendant(cf => cf.ByControlType(ControlType.CheckBox).And(cf.ByName("Split addresses toggle"))).AsCheckBox();
private Button EnableSplitAddressButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Enable split mode"))).AsButton();
- public HomeWindow RemoveAccount()
+ public HomeWindow RemoveAccountTestCleanup()
{
try
{
RemoveAccountButton.Click();
ConfirmRemoveAccountButton.Click();
}
- catch (System.NullReferenceException)
+ catch (System.IndexOutOfRangeException)
{
ClientCleanup();
}
diff --git a/tests/e2e/ui_tests/windows_os/Windows/LoginWindow.cs b/tests/e2e/ui_tests/windows_os/Windows/LoginWindow.cs
index 3ba8806d..a9535aab 100644
--- a/tests/e2e/ui_tests/windows_os/Windows/LoginWindow.cs
+++ b/tests/e2e/ui_tests/windows_os/Windows/LoginWindow.cs
@@ -4,6 +4,7 @@ using FlaUI.Core.Definitions;
using ProtonMailBridge.UI.Tests.TestsHelper;
using ProtonMailBridge.UI.Tests.Results;
using System.Diagnostics;
+using System.ComponentModel.DataAnnotations;
namespace ProtonMailBridge.UI.Tests.Windows
{
@@ -11,7 +12,8 @@ namespace ProtonMailBridge.UI.Tests.Windows
{
private AutomationElement[] InputFields => Window.FindAllDescendants(cf => cf.ByControlType(ControlType.Edit));
private TextBox UsernameInput => InputFields[0].AsTextBox();
- private TextBox PasswordInput => InputFields[1].AsTextBox();
+ private AutomationElement PasswordGroup => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Group).And(cf.ByName("Password")));
+ private TextBox PasswordInput => PasswordGroup.FindFirstDescendant(cf => cf.ByControlType(ControlType.Edit)).AsTextBox();
private Button SignInButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Sign in"))).AsButton();
private Button SigningInButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Signing in"))).AsButton();
private Button StartSetupButton => Window.FindFirstDescendant(cf => cf.ByName("Start setup")).AsButton();
@@ -20,11 +22,17 @@ namespace ProtonMailBridge.UI.Tests.Windows
private Button UnlockButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Unlock"))).AsButton();
private Button CancelSignIn => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Cancel"))).AsButton();
+ private Button UnlockingButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Unlocking"))).AsButton();
+
+ private static readonly int loginTimeout = 500;
+
public LoginWindow SignIn(TestUserData user)
{
ClickStartSetupButton();
+
+ TestContext.Out.WriteLine($"Trying to login with '{user.Username}':'{user.Password}'. Attempt {i}.");
EnterCredentials(user);
- WaitForAuthorizationToComplete(60);
+ WaitForAuthorizationToComplete(loginTimeout);
SetUpLater?.Click();
@@ -33,11 +41,9 @@ namespace ProtonMailBridge.UI.Tests.Windows
public LoginWindow SignInMailbox(TestUserData user)
{
- ClickStartSetupButton();
- EnterCredentials(user);
- Wait.UntilInputIsProcessed(TestData.TenSecondsTimeout);
+ SignIn(user);
EnterMailboxPassword(user);
- Wait.UntilInputIsProcessed(TestData.TenSecondsTimeout);
+ WaitForUnlockToComplete(loginTimeout);
SetUpLater?.Click();
@@ -59,8 +65,14 @@ namespace ProtonMailBridge.UI.Tests.Windows
public LoginWindow EnterCredentials(TestUserData user)
{
+ for (int i = 0; i < InputFields.Length; i++)
+ {
+ Console.WriteLine($"---------- {InputFields[i].Name} ----------");
+ }
+
UsernameInput.Text = user.Username;
PasswordInput.Text = user.Password;
+ TestContext.Out.WriteLine($"Trying to sign in with username '{user.Username}' and password '{user.Password}'");
SignInButton.Click();
return this;
}
@@ -68,6 +80,7 @@ namespace ProtonMailBridge.UI.Tests.Windows
public LoginWindow EnterMailboxPassword(TestUserData user)
{
MailboxPasswordInput.Text = user.MailboxPassword;
+ TestContext.Out.WriteLine($"Entering mailbox password '{user.MailboxPassword}'");
UnlockButton.Click();
return this;
}
@@ -97,5 +110,25 @@ namespace ProtonMailBridge.UI.Tests.Windows
}
}
+
+ private void WaitForUnlockToComplete(int numOfSeconds)
+ {
+ TimeSpan timeout = TimeSpan.FromSeconds(numOfSeconds);
+ Stopwatch stopwatch = Stopwatch.StartNew();
+
+
+ while (stopwatch.Elapsed < timeout)
+ {
+ //if Signing in button is not visible authorization process is finished
+ if (UnlockingButton == null)
+ {
+ return;
+ }
+
+ Wait.UntilInputIsProcessed();
+ Thread.Sleep(500);
+ }
+
+ }
}
}
\ No newline at end of file
diff --git a/tests/e2e/ui_tests/windows_os/Windows/SettingsMenuWindow.cs b/tests/e2e/ui_tests/windows_os/Windows/SettingsMenuWindow.cs
index 2176f448..908ec7c3 100644
--- a/tests/e2e/ui_tests/windows_os/Windows/SettingsMenuWindow.cs
+++ b/tests/e2e/ui_tests/windows_os/Windows/SettingsMenuWindow.cs
@@ -19,7 +19,6 @@ using ProtonMailBridge.UI.Tests.TestsHelper;
using Keyboard = FlaUI.Core.Input.Keyboard;
using Mouse = FlaUI.Core.Input.Mouse;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
-//using System.Windows.Forms;
using CheckBox = FlaUI.Core.AutomationElements.CheckBox;
using FlaUI.Core.Tools;
using System.Diagnostics;
@@ -87,125 +86,127 @@ namespace ProtonMailBridge.UI.Tests.Windows
private Button ResetButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Reset Bridge button"))).AsButton();
private Button ResetAndRestartButtonInPopUp => NotificationWindow.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Reset and restart"))).AsButton();
private Button StartSetUpButton => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Button).And(cf.ByName("Start setup"))).AsButton();
-
+
public SettingsMenuWindow ClickSettingsButton()
{
- SettingsButton.Click();
+ RetryHelper.EventuallyAction(() => SettingsButton.Click());
return this;
}
public SettingsMenuWindow ClickBackFromSettingsMenu()
{
- BackToAccountViewButton.Click();
+ RetryHelper.EventuallyAction(() => BackToAccountViewButton.Click());
return this;
}
public SettingsMenuWindow DisableAndEnableAutomaticUpdates()
{
- AutomaticUpdates.Click();
- Assert.That(AutomaticUpdates.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => AutomaticUpdates.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(AutomaticUpdates.IsToggled, Is.False));
Thread.Sleep(1000);
- AutomaticUpdates.Click();
- Assert.That(AutomaticUpdates.IsToggled, Is.True);
+ RetryHelper.EventuallyAction(() => AutomaticUpdates.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(AutomaticUpdates.IsToggled, Is.True));
return this;
}
public SettingsMenuWindow DisableAndEnableOpenOnStartUp()
{
- OpenOnStartUp.Click();
- Assert.That(OpenOnStartUp.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => OpenOnStartUp.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(OpenOnStartUp.IsToggled, Is.False));
Thread.Sleep(1000);
- OpenOnStartUp.Click();
- Assert.That(OpenOnStartUp.IsToggled, Is.True);
+ RetryHelper.EventuallyAction(() => OpenOnStartUp.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(OpenOnStartUp.IsToggled, Is.True));
return this;
}
-
public SettingsMenuWindow EnableAndDisableBetaAccess()
{
- BetaAccess.Click();
- EnableBetaAccessButtonInPopUp.Click();
+ RetryHelper.EventuallyAction(() => BetaAccess.Click());
+ RetryHelper.EventuallyAction(() => EnableBetaAccessButtonInPopUp.Click());
Thread.Sleep(1000);
- Assert.That(BetaAccess.IsToggled, Is.True);
- BetaAccess.Click();
- Assert.That(BetaAccess.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => Assert.That(BetaAccess.IsToggled, Is.True));
+ RetryHelper.EventuallyAction(() => BetaAccess.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(BetaAccess.IsToggled, Is.False));
return this;
}
public SettingsMenuWindow ExpandAdvancedSettings()
{
- AdvancedSettings.Click();
+ RetryHelper.EventuallyAction(() => AdvancedSettings.Click());
Thread.Sleep(1000);
- Assert.That(AlternativeRouting != null && AlternativeRouting.IsAvailable, Is.True);
+ RetryHelper.EventuallyAction(() => Assert.That(AlternativeRouting != null && AlternativeRouting.IsAvailable, Is.True));
return this;
}
public SettingsMenuWindow CollapseAdvancedSettings()
{
- AdvancedSettings.Click();
+ RetryHelper.EventuallyAction(() => AdvancedSettings.Click());
return this;
}
+
public SettingsMenuWindow EnableAndDisableAlternativeRouting()
{
- AlternativeRouting.Click();
- Assert.That(AlternativeRouting.IsToggled, Is.True);
+ RetryHelper.EventuallyAction(() => AlternativeRouting.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(AlternativeRouting.IsToggled, Is.True));
Thread.Sleep(1000);
- AlternativeRouting.Click();
- Assert.That(AlternativeRouting?.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => AlternativeRouting.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(AlternativeRouting?.IsToggled, Is.False));
return this;
}
public SettingsMenuWindow CheckEnableAndDisableDarkMode()
{
- DarkMode.Click();
- Assert.That(DarkMode.IsToggled, Is.True);
+ RetryHelper.EventuallyAction(() => DarkMode.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(DarkMode.IsToggled, Is.True));
Thread.Sleep(1000);
- DarkMode.Click();
- Assert.That(DarkMode.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => DarkMode.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(DarkMode.IsToggled, Is.False));
return this;
}
+
public SettingsMenuWindow DisableAndEnableShowAllMail()
{
- ShowAllMail.Click();
- HideAllMailFolderInPopUp.Click();
- Assert.That(ShowAllMail.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => ShowAllMail.Click());
+ RetryHelper.EventuallyAction(() => HideAllMailFolderInPopUp.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(ShowAllMail.IsToggled, Is.False));
Thread.Sleep(1000);
- ShowAllMail.Click();
+ RetryHelper.EventuallyAction(() => ShowAllMail.Click());
Thread.Sleep(1000);
- ShowAllMailFolderInPopUp.Click();
- Assert.That(ShowAllMail?.IsToggled, Is.True);
+ RetryHelper.EventuallyAction(() => ShowAllMailFolderInPopUp.Click());
+ RetryHelper.EventuallyAction(() => Assert.That(ShowAllMail?.IsToggled, Is.True));
return this;
}
public SettingsMenuWindow DisableAndEnableCollectUsageDiagnostics()
{
- CollectUsageDiagnostics.Click();
+ RetryHelper.EventuallyAction(() => CollectUsageDiagnostics.Click());
Thread.Sleep(3000);
- Assert.That(CollectUsageDiagnostics.IsToggled, Is.False);
+ RetryHelper.EventuallyAction(() => Assert.That(CollectUsageDiagnostics.IsToggled, Is.False));
Thread.Sleep(1000);
- CollectUsageDiagnostics.Click();
+ RetryHelper.EventuallyAction(() => CollectUsageDiagnostics.Click());
Thread.Sleep(1000);
- Assert.That(CollectUsageDiagnostics?.IsToggled, Is.True);
+ RetryHelper.EventuallyAction(() => Assert.That(CollectUsageDiagnostics?.IsToggled, Is.True));
return this;
}
-
public SettingsMenuWindow OpenChangeDefaultPorts()
{
- ChangeDefaultPortsButton.Click();
+ RetryHelper.EventuallyAction(() => ChangeDefaultPortsButton.Click());
return this;
}
public SettingsMenuWindow CancelChangingDefaultPorts()
{
- CancelDefaultPorts.Click();
+ RetryHelper.EventuallyAction(() => CancelDefaultPorts.Click());
+
return this;
}
private int GenerateUniqueRandomPort()
{
- return random.Next(MinPort, MaxPort +1);
+ return random.Next(MinPort, MaxPort + 1);
}
public SettingsMenuWindow ChangeDefaultPorts()
{
- ChangeDefaultPortsButton.Click();
+ RetryHelper.EventuallyAction(() => ChangeDefaultPortsButton.Click());
+
Thread.Sleep(2000);
- ImapPort.Click();
+ RetryHelper.EventuallyAction(() => ImapPort.Click());
int imapPort = GenerateUniqueRandomPort();
int smtpPort;
@@ -226,7 +227,8 @@ namespace ProtonMailBridge.UI.Tests.Windows
public SettingsMenuWindow SwitchBackToDefaultPorts()
{
- ChangeDefaultPortsButton.Click();
+ RetryHelper.EventuallyAction(() => ChangeDefaultPortsButton.Click());
+
Thread.Sleep(2000);
ImapPort.Click();
ImapPort.Patterns.Value.Pattern.SetValue("");
@@ -241,17 +243,18 @@ namespace ProtonMailBridge.UI.Tests.Windows
public SettingsMenuWindow OpenChangeConnectionMode()
{
- ChangeConnectionModeButton.Click();
+ RetryHelper.EventuallyAction(() => ChangeConnectionModeButton.Click());
return this;
}
public SettingsMenuWindow CancelChangeConnectionMode()
{
- CancelChangeConnectionModeButton.Click();
+ RetryHelper.EventuallyAction(() => CancelChangeConnectionModeButton.Click());
return this;
}
public SettingsMenuWindow ChangeConnectionMode()
{
- ImapSslMode.Click();
+ RetryHelper.EventuallyAction(() => ImapSslMode.Click());
+
SmtpSslMode.Click();
Thread.Sleep(2000);
SaveChangedConnectionMode.Click();
@@ -259,7 +262,8 @@ namespace ProtonMailBridge.UI.Tests.Windows
}
public SettingsMenuWindow SwitchBackToDefaultConnectionMode()
{
- ImapStarttlsMode.Click();
+ RetryHelper.EventuallyAction(() => ImapStarttlsMode.Click());
+
SmtpStarttlsMode.Click();
Thread.Sleep(2000);
SaveChangedConnectionMode.Click();
@@ -268,7 +272,7 @@ namespace ProtonMailBridge.UI.Tests.Windows
public SettingsMenuWindow ConfigureLocalCache()
{
- ConfigureLocalCacheButton.Click();
+ RetryHelper.EventuallyAction(() => ConfigureLocalCacheButton.Click());
return this;
}
public SettingsMenuWindow CancelToConfigureLocalCache()
@@ -319,14 +323,15 @@ namespace ProtonMailBridge.UI.Tests.Windows
public SettingsMenuWindow ChangeAndSwitchBackLocalCacheLocation()
{
string? userProfilePath = Environment.GetEnvironmentVariable("USERPROFILE");
- ChangeLocalCacheLocationButton.Click();
+ RetryHelper.EventuallyAction(() => ChangeLocalCacheLocationButton.Click());
+
Thread.Sleep(2000);
FocusOnSelectCacheLocationWindow();
ClickNewFolder.Click();
Wait.UntilInputIsProcessed(TimeSpan.FromMilliseconds(2000));
Keyboard.TypeVirtualKeyCode(0x0D);
AutomationElement pane = Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane));
- AutomationElement pane2 = pane.FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane).And(cf.ByName("Shell Folder View")));
+ AutomationElement pane2 = pane.FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane).And(cf.ByName("Shell Folder View")));
AutomationElement list = pane2.FindFirstDescendant(cf => cf.ByControlType(ControlType.List).And(cf.ByName("Items View")));
AutomationElement listItem = list.FindFirstDescendant(cf => cf.ByControlType(ControlType.ListItem).And(cf.ByName("New folder")));
TextBox folderName = listItem.FindFirstDescendant(cf => cf.ByControlType(ControlType.Edit)).AsTextBox();
@@ -409,7 +414,8 @@ namespace ProtonMailBridge.UI.Tests.Windows
}
public SettingsMenuWindow ExportAssertDeleteTLSCertificates()
{
- ExportTLSCertificatesButton.Click();
+ RetryHelper.EventuallyAction(() => ExportTLSCertificatesButton.Click());
+
Thread.Sleep(2000);
ClickNewFolder.Click();
Wait.UntilInputIsProcessed(TimeSpan.FromMilliseconds(2000));
@@ -472,7 +478,8 @@ namespace ProtonMailBridge.UI.Tests.Windows
}
public SettingsMenuWindow VerifyRepairRestartsSync()
{
- RepairBridgeButton.Click();
+ RetryHelper.EventuallyAction(() => RepairBridgeButton.Click());
+
RepairButtonInPopUp.Click();
bool syncRestarted = WaitForCondition(() =>
{
@@ -509,7 +516,7 @@ namespace ProtonMailBridge.UI.Tests.Windows
public SettingsMenuWindow VerifyResetAndRestartBridge()
{
- ResetButton.Click();
+ RetryHelper.EventuallyAction(() => ResetButton.Click());
ResetAndRestartButtonInPopUp.Click();
Thread.Sleep(5000);
LaunchApp();