Stage workspace controls after bootstrap
This commit is contained in:
@@ -1,218 +1,74 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Text.Json;
|
||||
using Microsoft.JSInterop;
|
||||
using RpgRoller.Components;
|
||||
|
||||
namespace RpgRoller.Tests;
|
||||
|
||||
public sealed class WorkspaceQueryServiceTests
|
||||
{
|
||||
private sealed class StubGameService : IGameService
|
||||
private sealed class StubJsRuntime(Func<string, object?[]?, Type, object?> handler) : IJSRuntime
|
||||
{
|
||||
public IReadOnlyList<RulesetDefinition> GetRulesets()
|
||||
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object?[]? args)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
return ValueTask.FromResult((TValue)handler(identifier, args, typeof(TValue))!);
|
||||
}
|
||||
|
||||
public ServiceResult<UserSummary> Register(string username, string password, string displayName)
|
||||
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken,
|
||||
object?[]? args)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
return InvokeAsync<TValue>(identifier, args);
|
||||
}
|
||||
|
||||
public ServiceResult<(UserSummary User, string SessionToken)> Login(string username, string password)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void Logout(string sessionToken)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public UserSummary? GetUserBySession(string sessionToken)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<MeResponse> GetMe(string sessionToken)
|
||||
{
|
||||
return GetMeHandler(sessionToken);
|
||||
}
|
||||
|
||||
public ServiceResult<CampaignSummary> CreateCampaign(string sessionToken, string name, string rulesetId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<IReadOnlyList<CampaignSummary>> GetCampaigns(string sessionToken)
|
||||
{
|
||||
return GetCampaignsHandler(sessionToken);
|
||||
}
|
||||
|
||||
public ServiceResult<IReadOnlyList<CampaignOption>> GetCharacterCampaignOptions(string sessionToken)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CampaignRoster> GetCampaign(string sessionToken, Guid campaignId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<bool> DeleteCampaign(string sessionToken, Guid campaignId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<IReadOnlyList<string>> GetUsernames(string sessionToken)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<IReadOnlyList<AdminUserSummary>> GetUsers(string sessionToken)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<AdminUserSummary> UpdateUserRoles(string sessionToken, Guid userId, IReadOnlyList<string> roles)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<bool> DeleteUser(string sessionToken, Guid userId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CharacterSummary> CreateCharacter(string sessionToken, string name, Guid campaignId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CharacterSummary> UpdateCharacter(string sessionToken, Guid characterId, string name, Guid? campaignId, string? ownerUsername = null)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<bool> DeleteCharacter(string sessionToken, Guid characterId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<bool> ActivateCharacter(string sessionToken, Guid characterId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<IReadOnlyList<CharacterSummary>> GetOwnCharacters(string sessionToken)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<SkillGroupSummary> CreateSkillGroup(string sessionToken, Guid characterId, string name, string diceRollDefinition, int wildDice, bool allowFumble, int? fumbleRange = null)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<SkillGroupSummary> UpdateSkillGroup(string sessionToken, Guid skillGroupId, string name, string diceRollDefinition, int wildDice, bool allowFumble, int? fumbleRange = null)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<bool> DeleteSkillGroup(string sessionToken, Guid skillGroupId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<SkillSummary> CreateSkill(string sessionToken, Guid characterId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null, bool rolemasterAutoRetry = false)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<SkillSummary> UpdateSkill(string sessionToken, Guid skillId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null, bool rolemasterAutoRetry = false)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<bool> DeleteSkill(string sessionToken, Guid skillId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CharacterSheet> GetCharacterSheet(string sessionToken, Guid characterId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<RollResult> RollSkill(string sessionToken, Guid skillId, string visibility, int situationalModifier = 0)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<RollResult> RollCustom(string sessionToken, Guid characterId, string expression, string visibility)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<IReadOnlyList<CampaignLogEntry>> GetCampaignLog(string sessionToken, Guid campaignId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CampaignLogPage> GetCampaignLogPage(string sessionToken, Guid campaignId, Guid? afterRollId = null, int? limit = null)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CampaignRollDetail> GetRollDetail(string sessionToken, Guid rollId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public ServiceResult<CampaignStateSnapshot> GetCampaignStateSnapshot(string sessionToken, Guid campaignId)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Func<string, ServiceResult<MeResponse>> GetMeHandler { get; init; } = _ => ServiceResult<MeResponse>.Failure("unexpected_call", "Unexpected GetMe call.");
|
||||
|
||||
public Func<string, ServiceResult<IReadOnlyList<CampaignSummary>>> GetCampaignsHandler { get; init; } = _ => ServiceResult<IReadOnlyList<CampaignSummary>>.Failure("unexpected_call", "Unexpected GetCampaigns call.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionTokenAccessor_ReadsSessionCookieFromHttpContext()
|
||||
public async Task GetCampaignsAsync_UsesCampaignsApiEndpoint()
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Request.Headers.Cookie = "rpgroller_session=session-token";
|
||||
|
||||
var accessor = new HttpContextAccessor { HttpContext = httpContext };
|
||||
var sessionTokenAccessor = new WorkspaceSessionTokenAccessor(accessor);
|
||||
|
||||
Assert.Equal("session-token", sessionTokenAccessor.GetRequiredSessionToken());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCampaignsAsync_UsesCapturedSessionToken()
|
||||
{
|
||||
var service = new StubGameService
|
||||
{
|
||||
GetCampaignsHandler = sessionToken =>
|
||||
var queryService = new WorkspaceQueryService(new RpgRollerApiClient(
|
||||
new StubJsRuntime((identifier, args, returnType) =>
|
||||
{
|
||||
Assert.Equal("server-session", sessionToken);
|
||||
return ServiceResult<IReadOnlyList<CampaignSummary>>.Success([new(Guid.NewGuid(), "Alpha", "d6", new(Guid.NewGuid(), "GM"), 1)]);
|
||||
}
|
||||
};
|
||||
Assert.Equal("rpgRollerApi.request", identifier);
|
||||
Assert.Equal("GET", args![0]);
|
||||
Assert.Equal("/api/campaigns", args[1]);
|
||||
Assert.Null(args[2]);
|
||||
|
||||
return CreateJsApiResponse(args: new
|
||||
{
|
||||
ok = true,
|
||||
status = 200,
|
||||
data = new[]
|
||||
{
|
||||
new CampaignSummary(Guid.NewGuid(), "Alpha", "d6", new CampaignGmSummary(Guid.NewGuid(), "GM"),
|
||||
1)
|
||||
}
|
||||
}, returnType);
|
||||
})));
|
||||
|
||||
var queryService = new WorkspaceQueryService(service, CreateSessionTokenAccessor("server-session"));
|
||||
var campaigns = await queryService.GetCampaignsAsync();
|
||||
|
||||
Assert.Single(campaigns);
|
||||
var campaign = Assert.Single(campaigns);
|
||||
Assert.Equal("Alpha", campaign.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetMeAsync_MapsUnauthorizedServiceResultToApiRequestException()
|
||||
public async Task GetMeAsync_MapsUnauthorizedApiResponseToApiRequestException()
|
||||
{
|
||||
var service = new StubGameService { GetMeHandler = _ => ServiceResult<MeResponse>.Failure("unauthorized", "You must be logged in.") };
|
||||
var queryService = new WorkspaceQueryService(new RpgRollerApiClient(
|
||||
new StubJsRuntime((identifier, args, returnType) =>
|
||||
{
|
||||
Assert.Equal("rpgRollerApi.request", identifier);
|
||||
Assert.Equal("GET", args![0]);
|
||||
Assert.Equal("/api/me", args[1]);
|
||||
|
||||
return CreateJsApiResponse(args: new
|
||||
{
|
||||
ok = false,
|
||||
status = 401,
|
||||
error = "You must be logged in.",
|
||||
code = "unauthorized",
|
||||
data = (object?)null
|
||||
}, returnType);
|
||||
})));
|
||||
|
||||
var queryService = new WorkspaceQueryService(service, CreateSessionTokenAccessor("expired-session"));
|
||||
var exception = await Assert.ThrowsAsync<ApiRequestException>(queryService.GetMeAsync);
|
||||
|
||||
Assert.Equal(401, exception.StatusCode);
|
||||
@@ -220,10 +76,11 @@ public sealed class WorkspaceQueryServiceTests
|
||||
Assert.Equal("unauthorized", exception.ErrorCode);
|
||||
}
|
||||
|
||||
private static WorkspaceSessionTokenAccessor CreateSessionTokenAccessor(string sessionToken)
|
||||
private static object CreateJsApiResponse(object args, Type returnType)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Request.Headers.Cookie = $"rpgroller_session={sessionToken}";
|
||||
return new(new HttpContextAccessor { HttpContext = httpContext });
|
||||
var json = JsonSerializer.Serialize(args);
|
||||
return JsonSerializer.Deserialize(json, returnType, JsonOptions)!;
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
||||
}
|
||||
Reference in New Issue
Block a user