convert to blazor server side render

This commit is contained in:
2025-12-24 16:43:51 -06:00
parent 357c3d9932
commit dcbf8a3ac3
215 changed files with 1867 additions and 2350 deletions

View File

@@ -1,16 +1,11 @@
using FluentAssertions.Execution;
using Shogi.AcceptanceTests.TestSetup;
using Shogi.Contracts.Api.Commands;
using Shogi.Contracts.Types;
using Shogi.Types;
using System.Net;
using System.Net.Http.Json;
using Xunit.Abstractions;
namespace Shogi.AcceptanceTests;
//#pragma warning disable xUnit1033 // There is a bug which provides a false positive of xUnit1033.
//#pragma warning restore xUnit1033
public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClassFixture<AatTestFixture>
public class ApiTests(AatTestFixture fixture) : IClassFixture<AatTestFixture>
{
private readonly HttpClient httpClient = fixture.HttpClient;
private readonly HttpClient player2HttpClient = fixture.OtherHttpClient;
@@ -28,16 +23,16 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
var response = await this.ReadTestSession();
// Assert
response.Should().NotBeNull();
response!.BoardState.Board.Should().NotBeEmpty();
Assert.NotNull(response);
Assert.NotEmpty(response!.BoardState.Board);
ValidateBoard(response.BoardState.Board);
response.BoardState.Player1Hand.Should().BeEmpty();
response.BoardState.Player2Hand.Should().BeEmpty();
response.BoardState.PlayerInCheck.Should().BeNull();
response.BoardState.WhoseTurn.Should().Be(WhichPlayer.Player1);
response.Player1.Should().NotBeNull();
response.Player2.Should().BeNullOrEmpty();
response.SessionId.Should().NotBeEmpty();
Assert.Empty(response.BoardState.Player1Hand);
Assert.Empty(response.BoardState.Player2Hand);
Assert.Null(response.BoardState.PlayerInCheck);
Assert.Equal(WhichPlayer.Player1, response.BoardState.WhoseTurn);
Assert.NotNull(response.Player1);
Assert.True(string.IsNullOrEmpty(response.Player2));
Assert.NotEqual(Guid.Empty, response.SessionId);
}
finally
{
@@ -47,176 +42,175 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
static void ValidateBoard(Dictionary<string, Piece?> board)
{
using var scope = new AssertionScope();
board["A1"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["A1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["A1"]!.IsPromoted.Should().Be(false);
board["B1"]!.WhichPiece.Should().Be(WhichPiece.Knight);
board["B1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["B1"]!.IsPromoted.Should().Be(false);
board["C1"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral);
board["C1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["C1"]!.IsPromoted.Should().Be(false);
board["D1"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral);
board["D1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["D1"]!.IsPromoted.Should().Be(false);
board["E1"]!.WhichPiece.Should().Be(WhichPiece.King);
board["E1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["E1"]!.IsPromoted.Should().Be(false);
board["F1"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral);
board["F1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["F1"]!.IsPromoted.Should().Be(false);
board["G1"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral);
board["G1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["G1"]!.IsPromoted.Should().Be(false);
board["H1"]!.WhichPiece.Should().Be(WhichPiece.Knight);
board["H1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["H1"]!.IsPromoted.Should().Be(false);
board["I1"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["I1"]!.Owner.Should().Be(WhichPlayer.Player1);
board["I1"]!.IsPromoted.Should().Be(false);
Assert.Equal(WhichPiece.Lance, board["A1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["A1"]!.Owner);
Assert.False(board["A1"]!.IsPromoted);
Assert.Equal(WhichPiece.Knight, board["B1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["B1"]!.Owner);
Assert.False(board["B1"]!.IsPromoted);
Assert.Equal(WhichPiece.SilverGeneral, board["C1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["C1"]!.Owner);
Assert.False(board["C1"]!.IsPromoted);
Assert.Equal(WhichPiece.GoldGeneral, board["D1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["D1"]!.Owner);
Assert.False(board["D1"]!.IsPromoted);
Assert.Equal(WhichPiece.King, board["E1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["E1"]!.Owner);
Assert.False(board["E1"]!.IsPromoted);
Assert.Equal(WhichPiece.GoldGeneral, board["F1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["F1"]!.Owner);
Assert.False(board["F1"]!.IsPromoted);
Assert.Equal(WhichPiece.SilverGeneral, board["G1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["G1"]!.Owner);
Assert.False(board["G1"]!.IsPromoted);
Assert.Equal(WhichPiece.Knight, board["H1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["H1"]!.Owner);
Assert.False(board["H1"]!.IsPromoted);
Assert.Equal(WhichPiece.Lance, board["I1"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["I1"]!.Owner);
Assert.False(board["I1"]!.IsPromoted);
board["A2"].Should().BeNull();
board["B2"]!.WhichPiece.Should().Be(WhichPiece.Bishop);
board["B2"]!.Owner.Should().Be(WhichPlayer.Player1);
board["B2"]!.IsPromoted.Should().Be(false);
board["C2"].Should().BeNull();
board["D2"].Should().BeNull();
board["E2"].Should().BeNull();
board["F2"].Should().BeNull();
board["G2"].Should().BeNull();
board["H2"]!.WhichPiece.Should().Be(WhichPiece.Rook);
board["H2"]!.Owner.Should().Be(WhichPlayer.Player1);
board["H2"]!.IsPromoted.Should().Be(false);
board["I2"].Should().BeNull();
Assert.Null(board["A2"]);
Assert.Equal(WhichPiece.Bishop, board["B2"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["B2"]!.Owner);
Assert.False(board["B2"]!.IsPromoted);
Assert.Null(board["C2"]);
Assert.Null(board["D2"]);
Assert.Null(board["E2"]);
Assert.Null(board["F2"]);
Assert.Null(board["G2"]);
Assert.Equal(WhichPiece.Rook, board["H2"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["H2"]!.Owner);
Assert.False(board["H2"]!.IsPromoted);
Assert.Null(board["I2"]);
board["A3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["A3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["A3"]!.IsPromoted.Should().Be(false);
board["B3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["B3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["B3"]!.IsPromoted.Should().Be(false);
board["C3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["C3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["C3"]!.IsPromoted.Should().Be(false);
board["D3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["D3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["D3"]!.IsPromoted.Should().Be(false);
board["E3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["E3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["E3"]!.IsPromoted.Should().Be(false);
board["F3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["F3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["F3"]!.IsPromoted.Should().Be(false);
board["G3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["G3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["G3"]!.IsPromoted.Should().Be(false);
board["H3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["H3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["H3"]!.IsPromoted.Should().Be(false);
board["I3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["I3"]!.Owner.Should().Be(WhichPlayer.Player1);
board["I3"]!.IsPromoted.Should().Be(false);
Assert.Equal(WhichPiece.Pawn, board["A3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["A3"]!.Owner);
Assert.False(board["A3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["B3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["B3"]!.Owner);
Assert.False(board["B3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["C3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["C3"]!.Owner);
Assert.False(board["C3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["D3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["D3"]!.Owner);
Assert.False(board["D3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["E3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["E3"]!.Owner);
Assert.False(board["E3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["F3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["F3"]!.Owner);
Assert.False(board["F3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["G3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["G3"]!.Owner);
Assert.False(board["G3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["H3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["H3"]!.Owner);
Assert.False(board["H3"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["I3"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player1, board["I3"]!.Owner);
Assert.False(board["I3"]!.IsPromoted);
board["A4"].Should().BeNull();
board["B4"].Should().BeNull();
board["C4"].Should().BeNull();
board["D4"].Should().BeNull();
board["E4"].Should().BeNull();
board["F4"].Should().BeNull();
board["G4"].Should().BeNull();
board["H4"].Should().BeNull();
board["I4"].Should().BeNull();
Assert.Null(board["A4"]);
Assert.Null(board["B4"]);
Assert.Null(board["C4"]);
Assert.Null(board["D4"]);
Assert.Null(board["E4"]);
Assert.Null(board["F4"]);
Assert.Null(board["G4"]);
Assert.Null(board["H4"]);
Assert.Null(board["I4"]);
board["A5"].Should().BeNull();
board["B5"].Should().BeNull();
board["C5"].Should().BeNull();
board["D5"].Should().BeNull();
board["E5"].Should().BeNull();
board["F5"].Should().BeNull();
board["G5"].Should().BeNull();
board["H5"].Should().BeNull();
board["I5"].Should().BeNull();
Assert.Null(board["A5"]);
Assert.Null(board["B5"]);
Assert.Null(board["C5"]);
Assert.Null(board["D5"]);
Assert.Null(board["E5"]);
Assert.Null(board["F5"]);
Assert.Null(board["G5"]);
Assert.Null(board["H5"]);
Assert.Null(board["I5"]);
board["A6"].Should().BeNull();
board["B6"].Should().BeNull();
board["C6"].Should().BeNull();
board["D6"].Should().BeNull();
board["E6"].Should().BeNull();
board["F6"].Should().BeNull();
board["G6"].Should().BeNull();
board["H6"].Should().BeNull();
board["I6"].Should().BeNull();
Assert.Null(board["A6"]);
Assert.Null(board["B6"]);
Assert.Null(board["C6"]);
Assert.Null(board["D6"]);
Assert.Null(board["E6"]);
Assert.Null(board["F6"]);
Assert.Null(board["G6"]);
Assert.Null(board["H6"]);
Assert.Null(board["I6"]);
board["A7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["A7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["A7"]!.IsPromoted.Should().Be(false);
board["B7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["B7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["B7"]!.IsPromoted.Should().Be(false);
board["C7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["C7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["C7"]!.IsPromoted.Should().Be(false);
board["D7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["D7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["D7"]!.IsPromoted.Should().Be(false);
board["E7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["E7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["E7"]!.IsPromoted.Should().Be(false);
board["F7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["F7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["F7"]!.IsPromoted.Should().Be(false);
board["G7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["G7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["G7"]!.IsPromoted.Should().Be(false);
board["H7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["H7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["H7"]!.IsPromoted.Should().Be(false);
board["I7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["I7"]!.Owner.Should().Be(WhichPlayer.Player2);
board["I7"]!.IsPromoted.Should().Be(false);
Assert.Equal(WhichPiece.Pawn, board["A7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["A7"]!.Owner);
Assert.False(board["A7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["B7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["B7"]!.Owner);
Assert.False(board["B7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["C7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["C7"]!.Owner);
Assert.False(board["C7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["D7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["D7"]!.Owner);
Assert.False(board["D7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["E7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["E7"]!.Owner);
Assert.False(board["E7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["F7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["F7"]!.Owner);
Assert.False(board["F7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["G7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["G7"]!.Owner);
Assert.False(board["G7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["H7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["H7"]!.Owner);
Assert.False(board["H7"]!.IsPromoted);
Assert.Equal(WhichPiece.Pawn, board["I7"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["I7"]!.Owner);
Assert.False(board["I7"]!.IsPromoted);
board["A8"].Should().BeNull();
board["B8"]!.WhichPiece.Should().Be(WhichPiece.Rook);
board["B8"]!.Owner.Should().Be(WhichPlayer.Player2);
board["B8"]!.IsPromoted.Should().Be(false);
board["C8"].Should().BeNull();
board["D8"].Should().BeNull();
board["E8"].Should().BeNull();
board["F8"].Should().BeNull();
board["G8"].Should().BeNull();
board["H8"]!.WhichPiece.Should().Be(WhichPiece.Bishop);
board["H8"]!.Owner.Should().Be(WhichPlayer.Player2);
board["H8"]!.IsPromoted.Should().Be(false);
board["I8"].Should().BeNull();
Assert.Null(board["A8"]);
Assert.Equal(WhichPiece.Rook, board["B8"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["B8"]!.Owner);
Assert.False(board["B8"]!.IsPromoted);
Assert.Null(board["C8"]);
Assert.Null(board["D8"]);
Assert.Null(board["E8"]);
Assert.Null(board["F8"]);
Assert.Null(board["G8"]);
Assert.Equal(WhichPiece.Bishop, board["H8"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["H8"]!.Owner);
Assert.False(board["H8"]!.IsPromoted);
Assert.Null(board["I8"]);
board["A9"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["A9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["A9"]!.IsPromoted.Should().Be(false);
board["B9"]!.WhichPiece.Should().Be(WhichPiece.Knight);
board["B9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["B9"]!.IsPromoted.Should().Be(false);
board["C9"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral);
board["C9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["C9"]!.IsPromoted.Should().Be(false);
board["D9"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral);
board["D9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["D9"]!.IsPromoted.Should().Be(false);
board["E9"]!.WhichPiece.Should().Be(WhichPiece.King);
board["E9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["E9"]!.IsPromoted.Should().Be(false);
board["F9"]!.WhichPiece.Should().Be(WhichPiece.GoldGeneral);
board["F9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["F9"]!.IsPromoted.Should().Be(false);
board["G9"]!.WhichPiece.Should().Be(WhichPiece.SilverGeneral);
board["G9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["G9"]!.IsPromoted.Should().Be(false);
board["H9"]!.WhichPiece.Should().Be(WhichPiece.Knight);
board["H9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["H9"]!.IsPromoted.Should().Be(false);
board["I9"]!.WhichPiece.Should().Be(WhichPiece.Lance);
board["I9"]!.Owner.Should().Be(WhichPlayer.Player2);
board["I9"]!.IsPromoted.Should().Be(false);
Assert.Equal(WhichPiece.Lance, board["A9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["A9"]!.Owner);
Assert.False(board["A9"]!.IsPromoted);
Assert.Equal(WhichPiece.Knight, board["B9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["B9"]!.Owner);
Assert.False(board["B9"]!.IsPromoted);
Assert.Equal(WhichPiece.SilverGeneral, board["C9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["C9"]!.Owner);
Assert.False(board["C9"]!.IsPromoted);
Assert.Equal(WhichPiece.GoldGeneral, board["D9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["D9"]!.Owner);
Assert.False(board["D9"]!.IsPromoted);
Assert.Equal(WhichPiece.King, board["E9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["E9"]!.Owner);
Assert.False(board["E9"]!.IsPromoted);
Assert.Equal(WhichPiece.GoldGeneral, board["F9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["F9"]!.Owner);
Assert.False(board["F9"]!.IsPromoted);
Assert.Equal(WhichPiece.SilverGeneral, board["G9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["G9"]!.Owner);
Assert.False(board["G9"]!.IsPromoted);
Assert.Equal(WhichPiece.Knight, board["H9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["H9"]!.Owner);
Assert.False(board["H9"]!.IsPromoted);
Assert.Equal(WhichPiece.Lance, board["I9"]!.WhichPiece);
Assert.Equal(WhichPlayer.Player2, board["I9"]!.Owner);
Assert.False(board["I9"]!.IsPromoted);
}
}
@@ -231,12 +225,11 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
// Act
var readAllResponse = await this.httpClient.GetFromJsonAsync<SessionMetadata[]>(
new Uri("Sessions", UriKind.Relative),
Contracts.ShogiApiJsonSerializerSettings.SystemTextJsonSerializerOptions);
new Uri("Sessions", UriKind.Relative));
// Assert
readAllResponse.Should().NotBeNull();
readAllResponse!.First().SessionId.Should().Be(testSession.SessionId);
Assert.NotNull(readAllResponse);
Assert.Equal(testSession.SessionId, readAllResponse!.First().SessionId);
}
finally
{
@@ -257,9 +250,9 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
var joinResponse = await this.player2HttpClient.PatchAsync(new Uri($"Sessions/{this.sessionId}/Join", UriKind.Relative), null);
// Assert
joinResponse.StatusCode.Should().Be(HttpStatusCode.OK);
Assert.Equal(HttpStatusCode.OK, joinResponse.StatusCode);
var readSessionResponse = await this.ReadTestSession();
readSessionResponse.Player2.Should().NotBeNullOrEmpty();
Assert.False(string.IsNullOrEmpty(readSessionResponse.Player2));
}
finally
{
@@ -275,15 +268,15 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
// Arrange
await this.SetupTestSession();
var joinResponse = await this.player2HttpClient.PatchAsync(new Uri($"Sessions/{this.sessionId}/Join", UriKind.Relative), null);
joinResponse.StatusCode.Should().Be(HttpStatusCode.OK);
Assert.Equal(HttpStatusCode.OK, joinResponse.StatusCode);
var readSessionResponse = await this.ReadTestSession();
readSessionResponse.Player2.Should().NotBeNull();
Assert.NotNull(readSessionResponse.Player2);
// Act
joinResponse = await this.player2HttpClient.PatchAsync(new Uri($"Sessions/{this.sessionId}/Join", UriKind.Relative), null);
// Assert
joinResponse.StatusCode.Should().Be(HttpStatusCode.Conflict);
Assert.Equal(HttpStatusCode.Conflict, joinResponse.StatusCode);
}
finally
{
@@ -306,16 +299,16 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
// Act
var response = await this.httpClient.PatchAsync(new Uri($"Sessions/{this.sessionId}/Move", UriKind.Relative), JsonContent.Create(movePawnCommand));
response.StatusCode.Should().Be(HttpStatusCode.NoContent, because: await response.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
// Assert
var session = await this.ReadTestSession();
session.BoardState.Board.Should().ContainKey("A3");
session.BoardState.Board["A3"].Should().BeNull();
session.BoardState.Board["A4"].Should().NotBeNull();
session.BoardState.Board["A4"]!.IsPromoted.Should().BeFalse();
session.BoardState.Board["A4"]!.Owner.Should().Be(WhichPlayer.Player1);
session.BoardState.Board["A4"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
Assert.Contains("A3", session.BoardState.Board.Keys);
Assert.Null(session.BoardState.Board["A3"]);
Assert.NotNull(session.BoardState.Board["A4"]);
Assert.False(session.BoardState.Board["A4"]!.IsPromoted);
Assert.Equal(WhichPlayer.Player1, session.BoardState.Board["A4"]!.Owner);
Assert.Equal(WhichPiece.Pawn, session.BoardState.Board["A4"]!.WhichPiece);
}
finally
{
@@ -327,7 +320,7 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
private async Task SetupTestSession()
{
var createResponse = await this.httpClient.PostAsync(new Uri("Sessions", UriKind.Relative), null);
createResponse.StatusCode.Should().Be(HttpStatusCode.Created);
Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode);
this.sessionId = await createResponse.Content.ReadAsStringAsync();
}
@@ -339,7 +332,6 @@ public class ApiTests(AatTestFixture fixture, ITestOutputHelper console) : IClas
private async Task DeleteTestSession()
{
var response = await this.httpClient.DeleteAsync(new Uri($"Sessions/{Uri.EscapeDataString(this.sessionId)}", UriKind.Relative));
response.StatusCode.Should().Be(HttpStatusCode.NoContent, because: await response.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
}
}
}

View File

@@ -1,51 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<UserSecretsId>96d6281d-a75b-4181-b535-ea34b26dc8a2</UserSecretsId>
<IsTestProject>true</IsTestProject>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.Development.json" />
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.1" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="8.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shogi.Contracts\Shogi.Contracts.csproj" />
<ProjectReference Include="..\..\Shogi\Shogi.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<UserSecretsId>96d6281d-a75b-4181-b535-ea34b26dc8a2</UserSecretsId>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0-preview.4.25258.110" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Shogi\Shogi.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,114 +1,105 @@
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Shogi.Identity;
using System.Net.Http.Json;
using System.Text.Json;
namespace Shogi.AcceptanceTests.TestSetup;
/// <summary>
/// Acceptance Test fixture for tests which assert features for Microsoft accounts.
/// Integration test fixture using WebApplicationFactory for in-process testing.
/// </summary>
public class AatTestFixture : IAsyncLifetime, IDisposable
public class AatTestFixture : WebApplicationFactory<Program>, IAsyncLifetime
{
protected static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
private readonly string testAccountPassword;
private bool disposedValue;
private const string TestPassword = "TestPassword123!";
public AatTestFixture()
public HttpClient HttpClient { get; private set; } = null!;
public HttpClient OtherHttpClient { get; private set; } = null!;
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
this.Configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.Development.json", optional: true)
.Build();
builder.UseEnvironment("Development");
var baseUrl = this.Configuration["ServiceUrl"] ?? throw new InvalidOperationException();
this.HttpClient = new HttpClient
builder.ConfigureServices(services =>
{
BaseAddress = new Uri(baseUrl, UriKind.Absolute)
};
this.OtherHttpClient = new HttpClient
{
BaseAddress = new Uri(baseUrl, UriKind.Absolute)
};
// Remove the existing DbContext registration
var descriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));
this.testAccountPassword = this.Configuration["TestUserPassword"]!;
if (string.IsNullOrWhiteSpace(this.testAccountPassword))
{
throw new InvalidOperationException("TestUserPassword is not configured.");
}
}
public IConfiguration Configuration { get; private set; }
public HttpClient HttpClient { get; }
public HttpClient OtherHttpClient { get; }
protected async Task LoginToTestAccounts()
{
var response = await this.HttpClient.PostAsJsonAsync(
RelativeUri("login"),
new
if (descriptor != null)
{
email = "aat-account",
password = this.testAccountPassword,
},
options: SerializerOptions);
services.Remove(descriptor);
}
response.IsSuccessStatusCode.Should().BeTrue(because: "The test account should exist. If it does not, use the /Account/TestAccount route to create it.");
var bearerToken = (await response.Content.ReadFromJsonAsync<LoginResponse>())?.AccessToken;
this.HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken);
response = await this.HttpClient.PostAsJsonAsync(
RelativeUri("login"),
new
// Add in-memory database for testing
services.AddDbContext<ApplicationDbContext>(options =>
{
email = "aat-account-2",
password = this.testAccountPassword,
},
options: SerializerOptions);
options.UseInMemoryDatabase("IntegrationTestDb_" + Guid.NewGuid().ToString());
});
response.IsSuccessStatusCode.Should().BeTrue(because: "The test account should exist. If it does not, use the /Account/TestAccount route to create it.");
bearerToken = (await response.Content.ReadFromJsonAsync<LoginResponse>())?.AccessToken;
this.OtherHttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken);
// Ensure the database is created and seeded
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
db.Database.EnsureCreated();
});
}
public async Task InitializeAsync()
{
await this.LoginToTestAccounts();
this.HttpClient = this.CreateClient();
this.OtherHttpClient = this.CreateClient();
await this.SetupTestAccountsAndLogin();
}
protected virtual void Dispose(bool disposing)
private async Task SetupTestAccountsAndLogin()
{
if (!this.disposedValue)
{
if (disposing)
{
this.HttpClient.Dispose();
}
// Register and login first test account
await RegisterAndLogin(this.HttpClient, "aat-account@test.com", TestPassword);
this.disposedValue = true;
// Register and login second test account
await RegisterAndLogin(this.OtherHttpClient, "aat-account-2@test.com", TestPassword);
}
private static async Task RegisterAndLogin(HttpClient client, string email, string password)
{
// Try to register (may already exist)
await client.PostAsJsonAsync(
new Uri("register", UriKind.Relative),
new { email, password },
options: SerializerOptions);
// Login
var loginResponse = await client.PostAsJsonAsync(
new Uri("login", UriKind.Relative),
new { email, password },
options: SerializerOptions);
if (loginResponse.IsSuccessStatusCode)
{
var tokenResponse = await loginResponse.Content.ReadFromJsonAsync<LoginResponse>(SerializerOptions);
if (tokenResponse?.AccessToken != null)
{
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken);
}
}
}
public Task DisposeAsync()
async Task IAsyncLifetime.DisposeAsync()
{
this.Dispose(true);
return Task.CompletedTask;
this.HttpClient?.Dispose();
this.OtherHttpClient?.Dispose();
await base.DisposeAsync();
}
public void Dispose()
{
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
protected static Uri RelativeUri(string s) => new(s, UriKind.Relative);
private class LoginResponse
{
public string AccessToken { get; set; } = string.Empty;
}
}

View File

@@ -1,2 +1 @@
global using Xunit;
global using FluentAssertions;
global using Xunit;

View File

@@ -1,3 +0,0 @@
{
"TestUserPassword": "I'mAToysRUsK1d"
}

View File

@@ -1,4 +0,0 @@
{
"ServiceUrl": "https://localhost:5001",
"TestUserPassword": ""
}