test: add POST and bytes tests to ApiClientBaseTests

Added 11 new tests covering:
- POST method tests (200 success, 401 unauthorized, no-body variant)
- Bytes tests (GET 200, GET 404, POST 200)
- Non-GET status code tests (POST 400 validation, bytes 500, multipart 401/200)

All 23 ApiClientBaseTests now pass.
This commit is contained in:
Joseph Doherty
2026-01-06 11:25:49 -05:00
parent c626ffbd69
commit 299099f716
@@ -219,4 +219,169 @@ public class ApiClientBaseTests
result.IsError.ShouldBeTrue();
result.Error.StatusCode.ShouldBe(400);
}
// POST tests
[Fact]
public async Task PostAsync_Returns200_MapsToSuccessValue()
{
// Arrange
var expected = new TestDto(99, "Created");
_mockHttp.When(HttpMethod.Post, "/api/test")
.Respond("application/json", JsonSerializer.Serialize(expected));
// Act
var result = await _client.PostAsync<TestDto, TestDto>("/api/test", new TestDto(0, "Input"));
// Assert
result.IsSuccess.ShouldBeTrue();
result.Value.Id.ShouldBe(99);
}
[Fact]
public async Task PostAsync_Returns401_MapsToUnauthorized()
{
// Arrange
_mockHttp.When(HttpMethod.Post, "/api/test")
.Respond(HttpStatusCode.Unauthorized);
// Act
var result = await _client.PostAsync<TestDto, TestDto>("/api/test", new TestDto(0, "Input"));
// Assert
result.IsUnauthorized.ShouldBeTrue();
}
[Fact]
public async Task PostAsync_WithNoBody_Returns200()
{
// Arrange
_mockHttp.When(HttpMethod.Post, "/api/test")
.Respond("application/json", JsonSerializer.Serialize(new Unit()));
// Act
var result = await _client.PostAsync<Unit>("/api/test");
// Assert
result.IsSuccess.ShouldBeTrue();
}
// Bytes tests
[Fact]
public async Task GetBytesAsync_Returns200_MapsToSuccessBytes()
{
// Arrange
var expectedBytes = new byte[] { 0x50, 0x4B, 0x03, 0x04 }; // ZIP header
_mockHttp.When("/api/download")
.Respond("application/octet-stream", new MemoryStream(expectedBytes));
// Act
var result = await _client.GetBytesAsync("/api/download");
// Assert
result.IsSuccess.ShouldBeTrue();
result.Value.ShouldBe(expectedBytes);
}
[Fact]
public async Task GetBytesAsync_Returns404_MapsToNotFound()
{
// Arrange
_mockHttp.When("/api/download")
.Respond(HttpStatusCode.NotFound);
// Act
var result = await _client.GetBytesAsync("/api/download");
// Assert
result.IsNotFound.ShouldBeTrue();
}
[Fact]
public async Task PostForBytesAsync_Returns200_MapsToSuccessBytes()
{
// Arrange
var expectedBytes = new byte[] { 0x50, 0x4B, 0x03, 0x04 };
_mockHttp.When(HttpMethod.Post, "/api/download")
.Respond("application/octet-stream", new MemoryStream(expectedBytes));
// Act
var result = await _client.PostForBytesAsync("/api/download", new { filter = "test" });
// Assert
result.IsSuccess.ShouldBeTrue();
result.Value.ShouldBe(expectedBytes);
}
// Non-GET status code tests
[Fact]
public async Task PostAsync_Returns400_WithValidationErrors_MapsToValidationError()
{
// Arrange
var validationProblem = new Microsoft.AspNetCore.Mvc.ValidationProblemDetails
{
Errors = { ["Field"] = new[] { "Required" } }
};
_mockHttp.When(HttpMethod.Post, "/api/test")
.Respond(HttpStatusCode.BadRequest, "application/json",
JsonSerializer.Serialize(validationProblem, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }));
// Act
var result = await _client.PostAsync<TestDto, TestDto>("/api/test", new TestDto(0, "Input"));
// Assert
result.IsValidationError.ShouldBeTrue();
}
[Fact]
public async Task GetBytesAsync_Returns500_MapsToApiError()
{
// Arrange
_mockHttp.When("/api/download")
.Respond(HttpStatusCode.InternalServerError, "text/plain", "Server error");
// Act
var result = await _client.GetBytesAsync("/api/download");
// Assert
result.IsError.ShouldBeTrue();
result.Error.StatusCode.ShouldBe(500);
}
[Fact]
public async Task PostMultipartAsync_Returns401_MapsToUnauthorized()
{
// Arrange
_mockHttp.When(HttpMethod.Post, "/api/upload")
.Respond(HttpStatusCode.Unauthorized);
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
// Act
var result = await _client.PostMultipartAsync<TestDto>("/api/upload", stream, "test.xlsx");
// Assert
result.IsUnauthorized.ShouldBeTrue();
}
[Fact]
public async Task PostMultipartAsync_Returns200_MapsToSuccessValue()
{
// Arrange
var expected = new TestDto(1, "Uploaded");
_mockHttp.When(HttpMethod.Post, "/api/upload")
.With(req => req.Content?.Headers.ContentType?.MediaType == "multipart/form-data")
.Respond("application/json", JsonSerializer.Serialize(expected));
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
// Act
var result = await _client.PostMultipartAsync<TestDto>("/api/upload", stream, "test.xlsx");
// Assert
result.IsSuccess.ShouldBeTrue();
result.Value.Id.ShouldBe(1);
}
}