From e64c2233ff0961b03d71a3d081cac90d9eab89d6 Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Mon, 17 Jun 2024 14:14:07 +0200 Subject: [PATCH 1/2] Add E2E test for AddEdit page (#17) --- .../Components/EditFormRow.razor | 12 +- .../Pages/Aliases/AddEdit.razor | 36 ++-- src/Tests/AliasVault.E2ETests/AliasTests.cs | 183 ++++++++++++------ src/Tests/AliasVault.E2ETests/AuthTests.cs | 9 +- .../Common/PlaywrightTest.cs | 15 ++ .../Infrastructure/BlazorWasmAppManager.cs | 1 - 6 files changed, 172 insertions(+), 84 deletions(-) diff --git a/src/AliasVault.WebApp/Components/EditFormRow.razor b/src/AliasVault.WebApp/Components/EditFormRow.razor index 49a0d0f9f..e790b18c7 100644 --- a/src/AliasVault.WebApp/Components/EditFormRow.razor +++ b/src/AliasVault.WebApp/Components/EditFormRow.razor @@ -2,12 +2,18 @@ @inject ClipboardCopyService ClipboardCopyService @inject IJSRuntime JsRuntime - +
- +
@code { + /// + /// Id for the input field. + /// + [Parameter] + public string Id { get; set; } = string.Empty; + /// /// Label for the input field. /// @@ -26,8 +32,6 @@ [Parameter] public EventCallback ValueChanged { get; set; } - private string _inputId = Guid.NewGuid().ToString(); - private async Task OnInputChanged(ChangeEventArgs e) { Value = e.Value?.ToString() ?? string.Empty; diff --git a/src/AliasVault.WebApp/Pages/Aliases/AddEdit.razor b/src/AliasVault.WebApp/Pages/Aliases/AddEdit.razor index c0ced68f6..0a28987cc 100644 --- a/src/AliasVault.WebApp/Pages/Aliases/AddEdit.razor +++ b/src/AliasVault.WebApp/Pages/Aliases/AddEdit.razor @@ -51,10 +51,10 @@ else

Service

- +
- +
@@ -72,14 +72,14 @@ else
- +
- +
- +
@@ -94,43 +94,43 @@ else

Identity

- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
diff --git a/src/Tests/AliasVault.E2ETests/AliasTests.cs b/src/Tests/AliasVault.E2ETests/AliasTests.cs index a911a953c..6c539f968 100644 --- a/src/Tests/AliasVault.E2ETests/AliasTests.cs +++ b/src/Tests/AliasVault.E2ETests/AliasTests.cs @@ -16,50 +16,15 @@ public class AliasTests : PlaywrightTest { private static readonly Random Random = new(); - /// - /// Helper method to fill all input fields on a page with random data. - /// - /// IPage instance where to fill the input fields for. - /// Async task. - public static async Task FillAllInputFields(IPage page) - { - // Locate all input fields - var inputFields = page.Locator("input"); - - // Get the count of input fields - var count = await inputFields.CountAsync(); - - // Iterate through each input field and fill with random data - for (int i = 0; i < count; i++) - { - var input = inputFields.Nth(i); - var inputType = await input.GetAttributeAsync("type"); - - // Generate appropriate random data based on input type - string randomData = inputType switch - { - "email" => GenerateRandomEmail(), - "number" => GenerateRandomNumber(), - "password" => GenerateRandomPassword(), - _ => GenerateRandomString(), // Default for all other types - }; - - await input.FillAsync(randomData); - } - } - /// /// Test if the alias listing index page works. /// /// Async task. [Test] - public async Task AliasListingCorrect() + public async Task AliasListingTest() { await Page.GotoAsync(AppBaseUrl + "aliases"); - await WaitForURLAsync("**/aliases"); - - // Wait for the content to load. - await Page.WaitForSelectorAsync("text=AliasVault"); + await WaitForURLAsync("**/aliases", "AliasVault"); // Check if the expected content is present. var pageContent = await Page.TextContentAsync("body"); @@ -71,34 +36,115 @@ public class AliasTests : PlaywrightTest /// /// Async task. [Test] - public async Task CreateAlias() + public async Task CreateAliasTest() { - await Page.GotoAsync(AppBaseUrl + "add-alias"); - await WaitForURLAsync("**/add-alias"); + // Create a new alias with service name = "Test Service". + var serviceName = "Test Service"; + await CreateAlias(new Dictionary + { + { "service-name", serviceName }, + }); - // Wait for the content to load. - await Page.WaitForSelectorAsync("text=AliasVault"); + // Check that the service name is present in the content. + var pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Contain(serviceName), "Created alias service name does not appear on alias page."); + } - // Check if a button with text "Generate Random Identity" appears - var generateButton = Page.Locator("text=Generate Random Identity"); - Assert.That(generateButton, Is.Not.Null, "Generate button not found."); + /// + /// Test if editing a created alias works. + /// + /// Async task. + [Test] + public async Task EditAliasTest() + { + // Create a new alias with service name = "Alias service before". + var serviceNameBefore = "Alias service before"; + await CreateAlias(new Dictionary + { + { "service-name", serviceNameBefore }, + }); - // Fill all input fields with random data - await FillAllInputFields(Page); + // Check that the service name is present in the content. + var pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Contain(serviceNameBefore), "Created alias service name does not appear on alias page."); + + // Click the edit button. + var editButton = Page.Locator("text=Edit alias").First; + await editButton.ClickAsync(); + await WaitForURLAsync("**/edit", "Save Alias"); + + // Replace the service name with "Alias service after". + var serviceNameAfter = "Alias service after"; + await FillInputFields( + page: Page, + fieldValues: new Dictionary + { + { "service-name", serviceNameAfter }, + }); - // Press submit button with text "Create Alias" var submitButton = Page.Locator("text=Save Alias").First; await submitButton.ClickAsync(); - await WaitForURLAsync("**/alias/**"); + await WaitForURLAsync("**/alias/**", "View alias"); - // Wait for the content to load. - await Page.WaitForSelectorAsync("text=Login credentials"); + // Check if the alias was correctly updated. + pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Contain(serviceNameAfter), "Alias not updated correctly."); + } - // Check if the alias was created - var pageContent = await Page.TextContentAsync("body"); - Assert.That(pageContent, Does.Contain("Login credentials"), "Alias not created."); + /// + /// Helper method to fill specified input fields on a page with given values. + /// + /// IPage instance where to fill the input fields for. + /// Dictionary with html element ids and values to input as field value. + /// Async task. + private static async Task FillInputFields(IPage page, Dictionary? fieldValues = null) + { + var inputFields = page.Locator("input"); + var count = await inputFields.CountAsync(); + for (int i = 0; i < count; i++) + { + var input = inputFields.Nth(i); + var inputId = await input.GetAttributeAsync("id"); - // TODO: Implement proper data input and verification if what was created is correct. + // If fieldValues dictionary is provided and the inputId is found in it, fill the input with the value. + if (inputId is not null && fieldValues is not null && fieldValues.TryGetValue(inputId, out var fieldValue)) + { + await input.FillAsync(fieldValue); + } + } + } + + /// + /// Helper method to fill all empty input fields on a page with random data if not provided. + /// + /// IPage instance where to fill the input fields for. + /// Async task. + private static async Task FillEmptyInputFieldsWithRandom(IPage page) + { + var inputFields = page.Locator("input"); + var count = await inputFields.CountAsync(); + for (int i = 0; i < count; i++) + { + var input = inputFields.Nth(i); + var inputType = await input.GetAttributeAsync("type"); + + // If is not empty, skip. + if (!string.IsNullOrEmpty(await input.InputValueAsync())) + { + continue; + } + + // Generate appropriate random data based on input type. + string randomData = inputType switch + { + "email" => GenerateRandomEmail(), + "number" => GenerateRandomNumber(), + "password" => GenerateRandomPassword(), + _ => GenerateRandomString(), // Default for all other types. + }; + + await input.FillAsync(randomData); + } } private static string GenerateRandomString(int length = 10) @@ -124,4 +170,31 @@ public class AliasTests : PlaywrightTest return new string(Enumerable.Repeat(chars, length) .Select(s => s[Random.Next(s.Length)]).ToArray()); } + + /// + /// Create new alias. + /// + /// Dictionary with html element ids and values to input as field value. + /// Async task. + private async Task CreateAlias(Dictionary? formValues = null) + { + await Page.GotoAsync(AppBaseUrl + "add-alias"); + await WaitForURLAsync("**/add-alias", "Add alias"); + + // Check if a button with text "Generate Random Identity" appears + var generateButton = Page.Locator("text=Generate Random Identity"); + Assert.That(generateButton, Is.Not.Null, "Generate button not found."); + + // Fill all input fields with specified values and remaining empty fields with random data. + await FillInputFields(Page, formValues); + await FillEmptyInputFieldsWithRandom(Page); + + var submitButton = Page.Locator("text=Save Alias").First; + await submitButton.ClickAsync(); + await WaitForURLAsync("**/alias/**", "Login credentials"); + + // Check if the alias was created + var pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Contain("Login credentials"), "Alias not created."); + } } diff --git a/src/Tests/AliasVault.E2ETests/AuthTests.cs b/src/Tests/AliasVault.E2ETests/AuthTests.cs index 240d8c3de..740e10e89 100644 --- a/src/Tests/AliasVault.E2ETests/AuthTests.cs +++ b/src/Tests/AliasVault.E2ETests/AuthTests.cs @@ -17,7 +17,7 @@ namespace AliasVault.E2ETests; public class AuthTests : PlaywrightTest { /// - /// Test if registering a new account works. + /// Test if logging out and logging in works. /// /// Async task. [Test] @@ -25,13 +25,10 @@ public class AuthTests : PlaywrightTest { // Logout. await Page.GotoAsync(AppBaseUrl + "user/logout"); - await Page.WaitForURLAsync("**/user/logout", new PageWaitForURLOptions() { Timeout = 2000 }); - - // Wait for the content to load. - await Page.WaitForSelectorAsync("text=AliasVault"); + await WaitForURLAsync("**/user/logout", "AliasVault"); // Wait and check if we get redirected to /user/login. - await Page.WaitForURLAsync("**/user/login", new PageWaitForURLOptions() { Timeout = 2000 }); + await WaitForURLAsync("**/user/login"); await Login(); } diff --git a/src/Tests/AliasVault.E2ETests/Common/PlaywrightTest.cs b/src/Tests/AliasVault.E2ETests/Common/PlaywrightTest.cs index 6cf0f0481..871e6b7cd 100644 --- a/src/Tests/AliasVault.E2ETests/Common/PlaywrightTest.cs +++ b/src/Tests/AliasVault.E2ETests/Common/PlaywrightTest.cs @@ -138,6 +138,21 @@ public class PlaywrightTest await Page.WaitForURLAsync(url, new PageWaitForURLOptions() { Timeout = timeoutInMs }); } + /// + /// Wait for the specified URL to be loaded with a custom timeout. + /// + /// The URL to wait for. This may also contains wildcard such as "**/user/login". + /// Wait until a certain text appears on the page. + /// This can be useful for content that is loaded via AJAX after navigation. + /// Async task. + protected async Task WaitForURLAsync(string url, string waitForText) + { + await Page.WaitForURLAsync(url, new PageWaitForURLOptions() { Timeout = TestDefaults.DefaultTimeout }); + + // Wait for actual content to load (web API calls, etc.) + await Page.WaitForSelectorAsync("text=" + waitForText, new PageWaitForSelectorOptions() { Timeout = TestDefaults.DefaultTimeout }); + } + /// /// Register a new random account. /// diff --git a/src/Tests/AliasVault.E2ETests/Infrastructure/BlazorWasmAppManager.cs b/src/Tests/AliasVault.E2ETests/Infrastructure/BlazorWasmAppManager.cs index 75c213c14..af3a81d11 100644 --- a/src/Tests/AliasVault.E2ETests/Infrastructure/BlazorWasmAppManager.cs +++ b/src/Tests/AliasVault.E2ETests/Infrastructure/BlazorWasmAppManager.cs @@ -113,7 +113,6 @@ public class BlazorWasmAppManager } Console.WriteLine(e.Message); - await Task.Delay(500); } } } From 62cbd26526857bbaca3efe0aee500a014db0bc98 Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Mon, 17 Jun 2024 14:17:13 +0200 Subject: [PATCH 2/2] Update AuthTests.cs (#17) --- src/Tests/AliasVault.E2ETests/AuthTests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Tests/AliasVault.E2ETests/AuthTests.cs b/src/Tests/AliasVault.E2ETests/AuthTests.cs index 740e10e89..752d52939 100644 --- a/src/Tests/AliasVault.E2ETests/AuthTests.cs +++ b/src/Tests/AliasVault.E2ETests/AuthTests.cs @@ -5,8 +5,6 @@ // //----------------------------------------------------------------------- -using Microsoft.Playwright; - namespace AliasVault.E2ETests; /// @@ -37,7 +35,7 @@ public class AuthTests : PlaywrightTest /// Test if logging in works. /// /// Async task. - public async Task Login() + private async Task Login() { await Page.GotoAsync(AppBaseUrl);