mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-03 22:39:31 -05:00
Add E2E test for unlock mechanism (#60)
This commit is contained in:
113
src/Tests/AliasVault.E2ETests/Common/PlaywrightInputHelper.cs
Normal file
113
src/Tests/AliasVault.E2ETests/Common/PlaywrightInputHelper.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="PlaywrightInputHelper.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.E2ETests.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Playwright input helper class.
|
||||
/// </summary>
|
||||
/// <param name="page">The IPage instance for the current test.</param>
|
||||
public class PlaywrightInputHelper(IPage page)
|
||||
{
|
||||
private static readonly Random Random = new();
|
||||
|
||||
/// <summary>
|
||||
/// Generate a random string of specified length.
|
||||
/// </summary>
|
||||
/// <param name="length">Length of the string.</param>
|
||||
/// <returns>The random generated string.</returns>
|
||||
public static string GenerateRandomString(int length = 10)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[Random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a random email address.
|
||||
/// </summary>
|
||||
/// <returns>The random email address.</returns>
|
||||
public static string GenerateRandomEmail()
|
||||
{
|
||||
return $"{GenerateRandomString(5)}@example.com";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a random number.
|
||||
/// </summary>
|
||||
/// <returns>The random number.</returns>
|
||||
public static string GenerateRandomNumber()
|
||||
{
|
||||
return Random.Next(0, 10000).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a random password of specified length.
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the password.</param>
|
||||
/// <returns>The random generated password.</returns>
|
||||
public static string GenerateRandomPassword(int length = 12)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[Random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to fill specified input fields on a page with given values.
|
||||
/// </summary>
|
||||
/// <param name="fieldValues">Dictionary with html element ids and values to input as field value.</param>
|
||||
/// <returns>Async task.</returns>
|
||||
public async Task FillInputFields(Dictionary<string, string>? 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");
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to fill all empty input fields on a page with random data if not provided.
|
||||
/// </summary>
|
||||
/// <returns>Async task.</returns>
|
||||
public async Task FillEmptyInputFieldsWithRandom()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,11 @@ public class PlaywrightTest
|
||||
/// </summary>
|
||||
protected IPage Page { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input helper for Playwright tests.
|
||||
/// </summary>
|
||||
protected PlaywrightInputHelper InputHelper { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// One time setup for the Playwright test which runs before all tests in the class.
|
||||
/// </summary>
|
||||
@@ -97,6 +102,7 @@ public class PlaywrightTest
|
||||
});
|
||||
|
||||
Page = await Context.NewPageAsync();
|
||||
InputHelper = new(Page);
|
||||
|
||||
// Register a new account via the UI
|
||||
await Register();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.E2ETests;
|
||||
namespace AliasVault.E2ETests.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// End-to-end tests for the alias management.
|
||||
@@ -75,8 +75,7 @@ public class AliasTests : PlaywrightTest
|
||||
|
||||
// Replace the service name with "Alias service after".
|
||||
var serviceNameAfter = "Alias service after";
|
||||
await FillInputFields(
|
||||
page: Page,
|
||||
await InputHelper.FillInputFields(
|
||||
fieldValues: new Dictionary<string, string>
|
||||
{
|
||||
{ "service-name", serviceNameAfter },
|
||||
@@ -91,86 +90,6 @@ public class AliasTests : PlaywrightTest
|
||||
Assert.That(pageContent, Does.Contain(serviceNameAfter), "Alias not updated correctly.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to fill specified input fields on a page with given values.
|
||||
/// </summary>
|
||||
/// <param name="page">IPage instance where to fill the input fields for.</param>
|
||||
/// <param name="fieldValues">Dictionary with html element ids and values to input as field value.</param>
|
||||
/// <returns>Async task.</returns>
|
||||
private static async Task FillInputFields(IPage page, Dictionary<string, string>? 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");
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to fill all empty input fields on a page with random data if not provided.
|
||||
/// </summary>
|
||||
/// <param name="page">IPage instance where to fill the input fields for.</param>
|
||||
/// <returns>Async task.</returns>
|
||||
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)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[Random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
private static string GenerateRandomEmail()
|
||||
{
|
||||
return $"{GenerateRandomString(5)}@example.com";
|
||||
}
|
||||
|
||||
private static string GenerateRandomNumber()
|
||||
{
|
||||
return Random.Next(0, 10000).ToString();
|
||||
}
|
||||
|
||||
private static string GenerateRandomPassword(int length = 12)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[Random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create new alias.
|
||||
/// </summary>
|
||||
@@ -186,8 +105,8 @@ public class AliasTests : PlaywrightTest
|
||||
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);
|
||||
await InputHelper.FillInputFields(formValues);
|
||||
await InputHelper.FillEmptyInputFieldsWithRandom();
|
||||
|
||||
var submitButton = Page.Locator("text=Save Alias").First;
|
||||
await submitButton.ClickAsync();
|
||||
@@ -5,7 +5,7 @@
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.E2ETests;
|
||||
namespace AliasVault.E2ETests.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// End-to-end tests for authentication.
|
||||
49
src/Tests/AliasVault.E2ETests/Tests/UnlockTests.cs
Normal file
49
src/Tests/AliasVault.E2ETests/Tests/UnlockTests.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="UnlockTests.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.E2ETests.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// End-to-end tests for the database unlock functionality.
|
||||
/// </summary>
|
||||
[Parallelizable(ParallelScope.Self)]
|
||||
[TestFixture]
|
||||
public class UnlockTests : PlaywrightTest
|
||||
{
|
||||
private static readonly Random Random = new();
|
||||
|
||||
/// <summary>
|
||||
/// Test that the unlock page is displayed after hard refresh which should
|
||||
/// clear the encryption key from memory.
|
||||
/// </summary>
|
||||
/// <returns>Async task.</returns>
|
||||
[Test]
|
||||
public async Task UnlockPageTest()
|
||||
{
|
||||
// Soft navigate to "aliases" page to test the unlock redirect.
|
||||
var startUrl = "aliases";
|
||||
await NavigateUsingBlazorRouter(startUrl);
|
||||
|
||||
// Hard refresh the page.
|
||||
await Page.ReloadAsync();
|
||||
|
||||
// Check if the unlock page is displayed.
|
||||
await WaitForURLAsync("**/unlock", "unlock");
|
||||
|
||||
// Check if by entering password the unlock page is replaced by the alias listing page.
|
||||
await InputHelper.FillInputFields(new Dictionary<string, string>
|
||||
{
|
||||
{ "password", TestUserPassword },
|
||||
});
|
||||
|
||||
var submitButton = Page.GetByRole(AriaRole.Button, new() { Name = "Unlock" });
|
||||
await submitButton.ClickAsync();
|
||||
|
||||
// Check if we get redirected back to the page we were trying to access.
|
||||
await WaitForURLAsync("**/" + startUrl, "AliasVault");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user