Improve website tests (#842)

* Improve website tests

* Use DefaultLang instead of hard coding English
This commit is contained in:
Josh 2023-08-03 20:09:32 -05:00 committed by GitHub
parent 17022c36b8
commit 65f317d9bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 27 deletions

View file

@ -11,8 +11,6 @@ public static class LocalizationManager
public static string GetLocalizedString(TranslationAreas translationArea, string language, string key)
{
// return $"{translationArea.ToString()}.{language}.{key}";
// ASP.NET requires specific names for certain languages (like ja for japanese as opposed to the standard ja-JP)
// We map that value back here.
language = mapLanguageBack(language);

View file

@ -1,6 +1,6 @@
@model (string Title, string Message)
<div class="ui negative message">
<div class="ui negative message" id="error-message">
<div class="header">
@Model.Title
</div>

View file

@ -0,0 +1,13 @@
using System;
using OpenQA.Selenium;
namespace ProjectLighthouse.Tests.WebsiteTests.Extensions;
public static class WebDriverExtensions
{
private static Uri GetUri(this IWebDriver driver) => new(driver.Url);
public static string GetPath(this IWebDriver driver) => driver.GetUri().AbsolutePath;
public static string GetErrorMessage(this IWebDriver driver) => driver.FindElement(By.CssSelector("#error-message > p")).Text;
}

View file

@ -14,14 +14,15 @@ namespace ProjectLighthouse.Tests.WebsiteTests.Integration;
[Trait("Category", "Integration")]
public class AdminTests : LighthouseWebTest
{
private const string adminPanelButtonXPath = "/html/body/div/header/div/div/div/a[2]";
private const string adminPanelButtonXPath = "/html/body/div/header/div/div/div/a[2]/span";
[Fact]
public async Task ShouldShowAdminPanelButtonWhenAdmin()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
Random random = new();
UserEntity user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
this.Driver.Manage().Cookies.DeleteAllCookies();
UserEntity user = await database.CreateUser($"unitTestUser{CryptoHelper.GenerateRandomInt32()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
WebTokenEntity webToken = new()
{
@ -39,15 +40,16 @@ public class AdminTests : LighthouseWebTest
this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken));
this.Driver.Navigate().Refresh();
Assert.Contains("Admin", this.Driver.FindElement(By.XPath(adminPanelButtonXPath)).Text);
Assert.Equal("Admin", this.Driver.FindElement(By.XPath(adminPanelButtonXPath)).Text);
}
[Fact]
public async Task ShouldNotShowAdminPanelButtonWhenNotAdmin()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
Random random = new();
UserEntity user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
this.Driver.Manage().Cookies.DeleteAllCookies();
UserEntity user = await database.CreateUser($"unitTestUser{CryptoHelper.GenerateRandomInt32()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
WebTokenEntity webToken = new()
{
@ -65,6 +67,6 @@ public class AdminTests : LighthouseWebTest
this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken));
this.Driver.Navigate().Refresh();
Assert.DoesNotContain("Admin", this.Driver.FindElement(By.XPath(adminPanelButtonXPath)).Text);
Assert.Empty(this.Driver.FindElements(By.XPath(adminPanelButtonXPath)));
}
}

View file

@ -3,11 +3,13 @@ using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Localization.StringLists;
using LBPUnion.ProjectLighthouse.Tests.Helpers;
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
using Microsoft.EntityFrameworkCore;
using OpenQA.Selenium;
using ProjectLighthouse.Tests.WebsiteTests.Extensions;
using Xunit;
namespace ProjectLighthouse.Tests.WebsiteTests.Integration;
@ -19,10 +21,10 @@ public class AuthenticationTests : LighthouseWebTest
public async Task ShouldLoginWithPassword()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
Random random = new();
this.Driver.Manage().Cookies.DeleteAllCookies();
string password = CryptoHelper.Sha256Hash(CryptoHelper.GenerateRandomBytes(64).ToArray());
UserEntity user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash(CryptoHelper.Sha256Hash(password)));
UserEntity user = await database.CreateUser($"unitTestUser{CryptoHelper.GenerateRandomInt32()}", CryptoHelper.BCryptHash(CryptoHelper.Sha256Hash(password)));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -33,16 +35,15 @@ public class AuthenticationTests : LighthouseWebTest
WebTokenEntity? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId);
Assert.NotNull(webToken);
await database.RemoveUser(user);
}
[Fact]
public async Task ShouldNotLoginWithNoPassword()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
Random random = new();
UserEntity user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("just like the hindenberg,"));
this.Driver.Manage().Cookies.DeleteAllCookies();
UserEntity user = await database.CreateUser($"unitTestUser{CryptoHelper.GenerateRandomInt32()}", CryptoHelper.BCryptHash("just like the hindenberg,"));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -53,15 +54,17 @@ public class AuthenticationTests : LighthouseWebTest
WebTokenEntity? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId);
Assert.Null(webToken);
await database.RemoveUser(user);
Assert.Equal("/login", this.Driver.GetPath());
Assert.Equal("The username or password you entered is invalid.", this.Driver.GetErrorMessage());
}
[Fact]
public async Task ShouldNotLoginWithWrongPassword()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
Random random = new();
UserEntity user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
this.Driver.Manage().Cookies.DeleteAllCookies();
UserEntity user = await database.CreateUser($"unitTestUser{CryptoHelper.GenerateRandomInt32()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
@ -72,8 +75,6 @@ public class AuthenticationTests : LighthouseWebTest
WebTokenEntity? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId);
Assert.Null(webToken);
await database.RemoveUser(user);
}
[Fact]
@ -82,8 +83,7 @@ public class AuthenticationTests : LighthouseWebTest
const string loggedInAsUsernameTextXPath = "/html/body/div/div/div/div/p[1]";
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
Random random = new();
UserEntity user = await database.CreateUser($"unitTestUser{random.Next()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
UserEntity user = await database.CreateUser($"unitTestUser{CryptoHelper.GenerateRandomInt32()}", CryptoHelper.BCryptHash("i'm an engineering failure"));
WebTokenEntity webToken = new()
{
@ -102,8 +102,7 @@ public class AuthenticationTests : LighthouseWebTest
Assert.DoesNotContain(user.Username, this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text);
this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken));
navigation.Refresh();
Assert.Contains(user.Username, this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text);
await database.RemoveUser(user);
Assert.Equal(Translate(LandingPageStrings.LoggedInAs, user.Username), this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text);
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Linq;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Localization;
using LBPUnion.ProjectLighthouse.Servers.Website.Startup;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
@ -21,6 +22,8 @@ public class LighthouseWebTest : IDisposable
protected LighthouseWebTest()
{
ServerConfiguration.Instance.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse_tests;database=lighthouse_tests";
ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled = false;
this.webHost.Start();
IServerAddressesFeature? serverAddressesFeature = this.webHost.ServerFeatures.Get<IServerAddressesFeature>();
@ -38,8 +41,14 @@ public class LighthouseWebTest : IDisposable
}
this.Driver = new ChromeDriver(chromeOptions);
this.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1);
}
protected static string Translate(TranslatableString translatableString) => translatableString.Translate(LocalizationManager.DefaultLang);
protected static string Translate(TranslatableString translatableString, params object?[] objects) =>
translatableString.Translate(LocalizationManager.DefaultLang, objects);
public void Dispose()
{
this.Driver.Close();

View file

@ -3,10 +3,12 @@ using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Localization.StringLists;
using LBPUnion.ProjectLighthouse.Tests.Helpers;
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
using Microsoft.EntityFrameworkCore;
using OpenQA.Selenium;
using ProjectLighthouse.Tests.WebsiteTests.Extensions;
using Xunit;
namespace ProjectLighthouse.Tests.WebsiteTests.Integration;
@ -18,6 +20,7 @@ public class RegisterTests : LighthouseWebTest
public async Task ShouldRegister()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
this.Driver.Manage().Cookies.DeleteAllCookies();
ServerConfiguration.Instance.Authentication.RegistrationEnabled = true;
@ -38,7 +41,7 @@ public class RegisterTests : LighthouseWebTest
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
Assert.NotNull(user);
await database.RemoveUser(user);
Assert.Equal("/", this.Driver.GetPath());
ServerConfiguration.Instance.Authentication.RegistrationEnabled = false;
}
@ -47,6 +50,7 @@ public class RegisterTests : LighthouseWebTest
public async Task ShouldNotRegisterWithMismatchingPasswords()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
this.Driver.Manage().Cookies.DeleteAllCookies();
ServerConfiguration.Instance.Authentication.RegistrationEnabled = true;
@ -67,6 +71,9 @@ public class RegisterTests : LighthouseWebTest
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
Assert.Null(user);
Assert.Equal("/register", this.Driver.GetPath());
Assert.Equal(Translate(ErrorStrings.PasswordDoesntMatch), this.Driver.GetErrorMessage());
ServerConfiguration.Instance.Authentication.RegistrationEnabled = false;
}
@ -74,6 +81,7 @@ public class RegisterTests : LighthouseWebTest
public async Task ShouldNotRegisterWithTakenUsername()
{
await using DatabaseContext database = await IntegrationHelper.GetIntegrationDatabase();
this.Driver.Manage().Cookies.DeleteAllCookies();
ServerConfiguration.Instance.Authentication.RegistrationEnabled = true;
@ -95,7 +103,9 @@ public class RegisterTests : LighthouseWebTest
this.Driver.FindElement(By.Id("submit")).Click();
Assert.Contains("The username you've chosen is already taken.", this.Driver.PageSource);
Assert.Equal("/register", this.Driver.GetPath());
Assert.Equal(Translate(ErrorStrings.UsernameTaken), this.Driver.GetErrorMessage());
ServerConfiguration.Instance.Authentication.RegistrationEnabled = false;
}

View file

@ -32,6 +32,7 @@
<ProjectReference Include="..\ProjectLighthouse.Servers.Website\ProjectLighthouse.Servers.Website.csproj" />
<ProjectReference Include="..\ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj" />
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj" />
<ProjectReference Include="..\ProjectLighthouse.Localization\ProjectLighthouse.Localization.csproj"/>
</ItemGroup>
</Project>

View file

@ -60,6 +60,12 @@ public static class CryptoHelper
/// <returns>The randomly generated integer</returns>
public static int GenerateRandomInt32(int fromInclusive, int toExclusive) => RandomNumberGenerator.GetInt32(fromInclusive, toExclusive);
/// <summary>
/// Generates a random 32 bit integer between 0 and 2^32 - 1
/// </summary>
/// <returns>The randomly generated integer</returns>
public static int GenerateRandomInt32() => RandomNumberGenerator.GetInt32(0, int.MaxValue);
public static string ToBase64(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);