Light/Dark theming
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
namespace RpgRoller.Tests;
|
||||
namespace RpgRoller.Tests;
|
||||
|
||||
public sealed class AuthApiTests(WebApplicationFactory<Program> factory) : ApiTestBase(factory)
|
||||
{
|
||||
@@ -12,8 +12,7 @@ public sealed class AuthApiTests(WebApplicationFactory<Program> factory) : ApiTe
|
||||
Assert.Equal("alice", registerResult.Username);
|
||||
Assert.Contains(registerResult.Roles, role => string.Equals(role, "admin", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var duplicate = await client.PostAsJsonAsync("/api/auth/register",
|
||||
new RegisterRequest("alice", "Password123", "Alice 2"));
|
||||
var duplicate = await client.PostAsJsonAsync("/api/auth/register", new RegisterRequest("alice", "Password123", "Alice 2"));
|
||||
Assert.Equal(HttpStatusCode.BadRequest, duplicate.StatusCode);
|
||||
|
||||
var loginResult = await client.PostAsJsonAsync("/api/auth/login", new LoginRequest("alice", "Password123"));
|
||||
@@ -21,13 +20,39 @@ public sealed class AuthApiTests(WebApplicationFactory<Program> factory) : ApiTe
|
||||
|
||||
var me = await GetAsync<MeResponse>(client, "/api/me");
|
||||
Assert.Equal(registerResult.Id, me.User.Id);
|
||||
Assert.Null(me.User.ThemePreference);
|
||||
Assert.Null(me.ActiveCharacterId);
|
||||
Assert.Null(me.CurrentCampaignId);
|
||||
|
||||
var themeUser = await PutAsync<UpdateThemePreferenceRequest, UserSummary>(client, "/api/me/theme", new("dark"));
|
||||
Assert.Equal("dark", themeUser.ThemePreference);
|
||||
|
||||
var themedMe = await GetAsync<MeResponse>(client, "/api/me");
|
||||
Assert.Equal("dark", themedMe.User.ThemePreference);
|
||||
|
||||
var invalidLogin = await client.PostAsJsonAsync("/api/auth/login", new LoginRequest("alice", "wrong-password"));
|
||||
Assert.Equal(HttpStatusCode.BadRequest, invalidLogin.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ThemePreferenceEndpoint_RequiresAuthAndValidTheme()
|
||||
{
|
||||
using var factory = CreateFactory();
|
||||
using var client = factory.CreateClient(new() { AllowAutoRedirect = false });
|
||||
|
||||
var unauthorized = await client.PutAsJsonAsync("/api/me/theme", new UpdateThemePreferenceRequest("dark"));
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, unauthorized.StatusCode);
|
||||
|
||||
var unauthorizedInvalid = await client.PutAsJsonAsync("/api/me/theme", new UpdateThemePreferenceRequest("sepia"));
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, unauthorizedInvalid.StatusCode);
|
||||
|
||||
await RegisterAsync(client, "theme-api", "Password123", "Theme Api");
|
||||
await LoginAsync(client, "theme-api", "Password123");
|
||||
|
||||
var invalid = await client.PutAsJsonAsync("/api/me/theme", new UpdateThemePreferenceRequest("sepia"));
|
||||
Assert.Equal(HttpStatusCode.BadRequest, invalid.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UsernamesEndpoint_RequiresAuthAndReturnsAlphabeticalList()
|
||||
{
|
||||
@@ -54,10 +79,7 @@ public sealed class AuthApiTests(WebApplicationFactory<Program> factory) : ApiTe
|
||||
|
||||
await RegisterAsync(client, "proxy-user", "Password123", "Proxy User");
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, "/api/auth/login")
|
||||
{
|
||||
Content = JsonContent.Create(new LoginRequest("proxy-user", "Password123"))
|
||||
};
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, "/api/auth/login") { Content = JsonContent.Create(new LoginRequest("proxy-user", "Password123")) };
|
||||
request.Headers.TryAddWithoutValidation("X-Forwarded-Proto", "https");
|
||||
|
||||
using var response = await client.SendAsync(request);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@@ -159,6 +159,7 @@ public sealed class HostingCoverageTests
|
||||
usersColumns.Add(usersTableInfoReader.GetString(1));
|
||||
|
||||
Assert.Contains("Roles", usersColumns);
|
||||
Assert.Contains("ThemePreference", usersColumns);
|
||||
|
||||
using var usersRoleCommand = verifyConnection.CreateCommand();
|
||||
usersRoleCommand.CommandText = "SELECT Roles FROM Users WHERE UsernameNormalized = 'LEGACY-ADMIN';";
|
||||
@@ -214,6 +215,11 @@ public sealed class HostingCoverageTests
|
||||
retryHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260414204309_AddRolemasterAutoRetry';";
|
||||
var retryHistoryCount = Convert.ToInt32(retryHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, retryHistoryCount);
|
||||
|
||||
using var themeHistoryCommand = verifyConnection.CreateCommand();
|
||||
themeHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260518183838_AddUserThemePreference';";
|
||||
var themeHistoryCount = Convert.ToInt32(themeHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, themeHistoryCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -359,6 +365,11 @@ public sealed class HostingCoverageTests
|
||||
retryHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260414204309_AddRolemasterAutoRetry';";
|
||||
var retryHistoryCount = Convert.ToInt32(retryHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, retryHistoryCount);
|
||||
|
||||
using var themeHistoryCommand = verifyConnection.CreateCommand();
|
||||
themeHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260518183838_AddUserThemePreference';";
|
||||
var themeHistoryCount = Convert.ToInt32(themeHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, themeHistoryCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -481,6 +492,15 @@ public sealed class HostingCoverageTests
|
||||
|
||||
Assert.Contains("FumbleRange", skillGroupColumns);
|
||||
|
||||
using var usersTableInfoCommand = verifyConnection.CreateCommand();
|
||||
usersTableInfoCommand.CommandText = "PRAGMA table_info('Users');";
|
||||
using var usersTableInfoReader = usersTableInfoCommand.ExecuteReader();
|
||||
var usersColumns = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
while (usersTableInfoReader.Read())
|
||||
usersColumns.Add(usersTableInfoReader.GetString(1));
|
||||
|
||||
Assert.Contains("ThemePreference", usersColumns);
|
||||
|
||||
using var authorizationRolesHistoryCommand = verifyConnection.CreateCommand();
|
||||
authorizationRolesHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260226170000_AddAuthorizationRoles';";
|
||||
var authorizationRolesHistoryCount = Convert.ToInt32(authorizationRolesHistoryCommand.ExecuteScalar());
|
||||
@@ -490,5 +510,10 @@ public sealed class HostingCoverageTests
|
||||
retryHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260414204309_AddRolemasterAutoRetry';";
|
||||
var retryHistoryCount = Convert.ToInt32(retryHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, retryHistoryCount);
|
||||
|
||||
using var themeHistoryCommand = verifyConnection.CreateCommand();
|
||||
themeHistoryCommand.CommandText = "SELECT COUNT(*) FROM \"__EFMigrationsHistory\" WHERE \"MigrationId\" = '20260518183838_AddUserThemePreference';";
|
||||
var themeHistoryCount = Convert.ToInt32(themeHistoryCommand.ExecuteScalar());
|
||||
Assert.Equal(1, themeHistoryCount);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace RpgRoller.Tests;
|
||||
namespace RpgRoller.Tests;
|
||||
|
||||
public sealed class ServiceAuthTests
|
||||
{
|
||||
@@ -74,4 +74,26 @@ public sealed class ServiceAuthTests
|
||||
var usernames = ServiceTestSupport.GetValue(service.GetUsernames(session));
|
||||
Assert.Equal(["amy", "bob", "zoe"], usernames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateThemePreference_RequiresAuthAndPersistsSupportedTheme()
|
||||
{
|
||||
using var harness = ServiceTestSupport.CreateHarness();
|
||||
var service = harness.Service;
|
||||
|
||||
service.Register("theme-user", "Password123", "Theme User");
|
||||
var session = ServiceTestSupport.GetValue(service.Login("theme-user", "Password123")).SessionToken;
|
||||
|
||||
var unauthorized = service.UpdateThemePreference(string.Empty, "dark");
|
||||
var invalid = service.UpdateThemePreference(session, "sepia");
|
||||
var updated = service.UpdateThemePreference(session, "DARK");
|
||||
|
||||
Assert.False(unauthorized.Succeeded);
|
||||
Assert.False(invalid.Succeeded);
|
||||
Assert.True(updated.Succeeded);
|
||||
Assert.Equal("dark", ServiceTestSupport.GetValue(updated).ThemePreference);
|
||||
|
||||
var me = ServiceTestSupport.GetValue(service.GetMe(session));
|
||||
Assert.Equal("dark", me.User.ThemePreference);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace RpgRoller.Tests;
|
||||
namespace RpgRoller.Tests;
|
||||
|
||||
public sealed class ServicePersistenceTests
|
||||
{
|
||||
@@ -22,8 +22,7 @@ public sealed class ServicePersistenceTests
|
||||
var otherSession = ServiceTestSupport.GetValue(service.Login("other", "Password123")).SessionToken;
|
||||
|
||||
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Main", "d6"));
|
||||
var ownerCharacter =
|
||||
ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Owner Character", campaign.Id));
|
||||
var ownerCharacter = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Owner Character", campaign.Id));
|
||||
|
||||
Assert.False(service.GetMe(string.Empty).Succeeded);
|
||||
Assert.False(service.CreateCampaign(gmSession, "", "d6").Succeeded);
|
||||
@@ -80,8 +79,7 @@ public sealed class ServicePersistenceTests
|
||||
Assert.NotNull(db.Users.Single(u => u.UsernameNormalized == "OWNER").ActiveCharacterId);
|
||||
}
|
||||
|
||||
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, ownerCharacter.Id, "Stealth", "2D+1",
|
||||
1, true));
|
||||
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, ownerCharacter.Id, "Stealth", "2D+1", 1, true));
|
||||
Assert.False(service.UpdateSkill(ownerSession, skill.Id, "", "2D+1", 1, true).Succeeded);
|
||||
Assert.False(service.UpdateSkill(string.Empty, skill.Id, "Stealth", "2D+1", 1, true).Succeeded);
|
||||
Assert.False(service.UpdateSkill(ownerSession, skill.Id, "Stealth", "bad", 1, true).Succeeded);
|
||||
@@ -111,17 +109,13 @@ public sealed class ServicePersistenceTests
|
||||
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-rm-persist", "Password123")).SessionToken;
|
||||
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-rm-persist", "Password123")).SessionToken;
|
||||
|
||||
var campaign =
|
||||
ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Rolemaster Persistence", "rolemaster"));
|
||||
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Rolemaster Persistence", "rolemaster"));
|
||||
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Loremaster", campaign.Id));
|
||||
var group = ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Perception",
|
||||
"d100!+25", 0, false, 5));
|
||||
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Read Runes",
|
||||
"d100!+35", 0, false, group.Id, 3, true));
|
||||
var group = ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Perception", "d100!+25", 0, false, 5));
|
||||
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Read Runes", "d100!+35", 0, false, group.Id, 3, true));
|
||||
|
||||
using var reloadedHarness = ServiceTestSupport.CreateHarnessFromPath(harness.DbPath);
|
||||
var reloadedSheet =
|
||||
ServiceTestSupport.GetValue(reloadedHarness.Service.GetCharacterSheet(ownerSession, character.Id));
|
||||
var reloadedSheet = ServiceTestSupport.GetValue(reloadedHarness.Service.GetCharacterSheet(ownerSession, character.Id));
|
||||
|
||||
var reloadedGroup = Assert.Single(reloadedSheet.SkillGroups, current => current.Id == group.Id);
|
||||
Assert.Equal(5, reloadedGroup.FumbleRange);
|
||||
@@ -130,4 +124,22 @@ public sealed class ServicePersistenceTests
|
||||
Assert.Equal(3, reloadedSkill.FumbleRange);
|
||||
Assert.True(reloadedSkill.RolemasterAutoRetry);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UserThemePreference_PersistsAcrossDatabaseReload()
|
||||
{
|
||||
using var harness = ServiceTestSupport.CreateHarness();
|
||||
var service = harness.Service;
|
||||
|
||||
service.Register("theme-persist", "Password123", "Theme Persist");
|
||||
var session = ServiceTestSupport.GetValue(service.Login("theme-persist", "Password123")).SessionToken;
|
||||
|
||||
var updated = ServiceTestSupport.GetValue(service.UpdateThemePreference(session, "dark"));
|
||||
Assert.Equal("dark", updated.ThemePreference);
|
||||
|
||||
using var reloadedHarness = ServiceTestSupport.CreateHarnessFromPath(harness.DbPath);
|
||||
var me = ServiceTestSupport.GetValue(reloadedHarness.Service.GetMe(session));
|
||||
|
||||
Assert.Equal("dark", me.User.ThemePreference);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user