From fe4b11cf4d736ce401c000e8c64cc14c4e8aa406 Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Tue, 11 Mar 2025 08:59:50 +0100 Subject: [PATCH] Add TOTP E2E tests (#181) --- .../Main/Components/TotpCodes/TotpCodes.razor | 4 +- .../Tests/Client/Shard5/TotpTests.cs | 124 ++++++++++++++++++ 2 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/Tests/AliasVault.E2ETests/Tests/Client/Shard5/TotpTests.cs diff --git a/src/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor b/src/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor index 48abdd6e5..c445e4d73 100644 --- a/src/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor +++ b/src/AliasVault.Client/Main/Components/TotpCodes/TotpCodes.razor @@ -23,7 +23,7 @@ @if ((TotpCodeList.Count == 0 || TotpCodeList.All(t => t.IsDeleted)) && !IsAddFormVisible) {
-

Add a two-factor authenticator code

+

Add a two-factor authenticator code

} else @@ -54,7 +54,7 @@
-
diff --git a/src/Tests/AliasVault.E2ETests/Tests/Client/Shard5/TotpTests.cs b/src/Tests/AliasVault.E2ETests/Tests/Client/Shard5/TotpTests.cs new file mode 100644 index 000000000..0aa088b87 --- /dev/null +++ b/src/Tests/AliasVault.E2ETests/Tests/Client/Shard5/TotpTests.cs @@ -0,0 +1,124 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasVault.E2ETests.Tests.Client.Shard5; + +/// +/// End-to-end tests for uploading and downloading attachments. +/// +[Parallelizable(ParallelScope.Self)] +[Category("ClientTests")] +[TestFixture] +public class TotpTests : ClientPlaywrightTest +{ + /// + /// Test that adding and verifying a TOTP code works correctly. + /// + /// Async task. + [Test] + [Order(1)] + public async Task AddAndVerifyTotpCode() + { + // Create a new credential with service name = "Test Service TOTP" + var serviceName = "Test Service TOTP"; + await CreateCredentialEntry( + new Dictionary + { + { "service-name", serviceName }, + }); + + // Open the edit page again by clicking the button that contains the text "Edit" + await Page.ClickAsync("text=Edit"); + await WaitForUrlAsync("credentials/**/edit", "Edit the existing credentials"); + + // Click the "Add TOTP Code" button + var addButton = Page.Locator("button[id='add-totp-code'], a[id='add-totp-code']"); + await addButton.ClickAsync(); + + // Fill in the TOTP code details + var secretKeyInput = Page.Locator("input[id='secretKey']"); + var nameInput = Page.Locator("input[id='name']"); + + await nameInput.FillAsync("Test TOTP"); + await secretKeyInput.FillAsync("JBSWY3DPEHPK3PXP"); // Example secret key + + // Submit the form + var saveButton = Page.Locator("button[id='save-totp-code']"); + await saveButton.ClickAsync(); + + // Save the credential + var submitButton = Page.Locator("text=Save Credentials").First; + await submitButton.ClickAsync(); + + await WaitForUrlAsync("credentials/**", "Credential updated successfully"); + + // Verify that the TOTP code appears in the list + var pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Contain("Test TOTP"), "TOTP code name does not appear on the page"); + + // Verify that a 6-digit code is generated and displayed + var codeElement = Page.Locator(".text-2xl.font-bold"); + var code = await codeElement.TextContentAsync(); + Assert.That(code, Does.Match(@"^\d{6}$"), "Generated TOTP code is not a 6-digit number"); + } + + /// + /// Test that deleting a TOTP code works correctly. + /// + /// Async task. + [Test] + [Order(2)] + public async Task DeleteTotpCode() + { + // Create a new credential with service name = "Test Service TOTP Delete" + var serviceName = "Test Service TOTP Delete"; + await CreateCredentialEntry( + new Dictionary + { + { "service-name", serviceName }, + }); + + // Open the edit page again by clicking the button that contains the text "Edit" + await Page.ClickAsync("text=Edit"); + await WaitForUrlAsync("credentials/**/edit", "Edit the existing credentials"); + + // Add a TOTP code + var addButton = Page.Locator("button[id='add-totp-code'], a[id='add-totp-code']"); + await addButton.ClickAsync(); + + await Page.Locator("input[id='name']").FillAsync("TOTP to Delete"); + await Page.Locator("input[id='secretKey']").FillAsync("JBSWY3DPEHPK3PXP"); + + await Page.Locator("button[id='save-totp-code']").ClickAsync(); + + // Save the credential + var submitButton = Page.Locator("text=Save Credentials").First; + await submitButton.ClickAsync(); + + await WaitForUrlAsync("credentials/**", "Credential updated successfully"); + + // Verify the TOTP code was added + var pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Contain("TOTP to Delete"), "TOTP code was not added successfully"); + + // Open the edit page again by clicking the button that contains the text "Edit" + await Page.ClickAsync("text=Edit"); + await WaitForUrlAsync("credentials/**/edit", "Edit the existing credentials"); + + // Click the delete button for the TOTP code + var deleteButton = Page.Locator("button.delete-totp-code").First; + await deleteButton.ClickAsync(); + + // Confirm deletion in the modal + var confirmButton = Page.Locator("button:has-text('Confirm')"); + await confirmButton.ClickAsync(); + + // Verify the TOTP code was deleted + pageContent = await Page.TextContentAsync("body"); + Assert.That(pageContent, Does.Not.Contain("TOTP to Delete"), "TOTP code was not deleted successfully"); + } +}