test: add FileApiClientTests with route, success, and error tests
Add comprehensive unit tests for FileApiClient covering: - Route verification tests for all 4 download endpoints (POST method) - Route verification tests for 2 upload endpoints (POST method) - Success tests for downloads returning byte arrays - Success tests verifying existing data can be passed to downloads - Success tests for uploads returning IReadOnlyList<T> - Multipart content-type and filename verification test - Error tests (404 for download, 400 validation error for upload)
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using JdeScoping.Client.Services;
|
||||
using JdeScoping.Core.ApiContracts;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
using RichardSzalay.MockHttp;
|
||||
using Shouldly;
|
||||
|
||||
namespace JdeScoping.Client.Tests.Services;
|
||||
|
||||
public class FileApiClientTests
|
||||
{
|
||||
private readonly MockHttpMessageHandler _mockHttp;
|
||||
private readonly FileApiClient _client;
|
||||
|
||||
public FileApiClientTests()
|
||||
{
|
||||
_mockHttp = new MockHttpMessageHandler();
|
||||
var httpClient = new HttpClient(_mockHttp) { BaseAddress = new Uri("http://localhost/") };
|
||||
_client = new FileApiClient(httpClient);
|
||||
}
|
||||
|
||||
// Route verification tests - Downloads
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadWorkOrdersTemplateAsync_CallsCorrectRoute_WithPostMethod()
|
||||
{
|
||||
// Arrange
|
||||
var request = _mockHttp.Expect(HttpMethod.Post, $"http://localhost/{ApiRoutes.FileIO.DownloadWorkOrders}")
|
||||
.Respond("application/octet-stream", new MemoryStream(new byte[] { 1, 2, 3 }));
|
||||
|
||||
// Act
|
||||
await _client.DownloadWorkOrdersTemplateAsync();
|
||||
|
||||
// Assert
|
||||
_mockHttp.GetMatchCount(request).ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadItemsTemplateAsync_CallsCorrectRoute()
|
||||
{
|
||||
// Arrange
|
||||
var request = _mockHttp.Expect(HttpMethod.Post, $"http://localhost/{ApiRoutes.FileIO.DownloadItems}")
|
||||
.Respond("application/octet-stream", new MemoryStream(new byte[] { 1, 2, 3 }));
|
||||
|
||||
// Act
|
||||
await _client.DownloadItemsTemplateAsync();
|
||||
|
||||
// Assert
|
||||
_mockHttp.GetMatchCount(request).ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadComponentLotsTemplateAsync_CallsCorrectRoute()
|
||||
{
|
||||
// Arrange
|
||||
var request = _mockHttp.Expect(HttpMethod.Post, $"http://localhost/{ApiRoutes.FileIO.DownloadComponentLots}")
|
||||
.Respond("application/octet-stream", new MemoryStream(new byte[] { 1, 2, 3 }));
|
||||
|
||||
// Act
|
||||
await _client.DownloadComponentLotsTemplateAsync();
|
||||
|
||||
// Assert
|
||||
_mockHttp.GetMatchCount(request).ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadPartOperationsTemplateAsync_CallsCorrectRoute()
|
||||
{
|
||||
// Arrange
|
||||
var request = _mockHttp.Expect(HttpMethod.Post, $"http://localhost/{ApiRoutes.FileIO.DownloadPartOperations}")
|
||||
.Respond("application/octet-stream", new MemoryStream(new byte[] { 1, 2, 3 }));
|
||||
|
||||
// Act
|
||||
await _client.DownloadPartOperationsTemplateAsync();
|
||||
|
||||
// Assert
|
||||
_mockHttp.GetMatchCount(request).ShouldBe(1);
|
||||
}
|
||||
|
||||
// Route verification tests - Uploads
|
||||
|
||||
[Fact]
|
||||
public async Task UploadWorkOrdersAsync_CallsCorrectRoute_WithPostMethod()
|
||||
{
|
||||
// Arrange
|
||||
var request = _mockHttp.Expect(HttpMethod.Post, $"http://localhost/{ApiRoutes.FileIO.UploadWorkOrders}")
|
||||
.Respond("application/json", "[]");
|
||||
|
||||
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
|
||||
// Act
|
||||
await _client.UploadWorkOrdersAsync(stream, "test.xlsx");
|
||||
|
||||
// Assert
|
||||
_mockHttp.GetMatchCount(request).ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UploadItemsAsync_CallsCorrectRoute()
|
||||
{
|
||||
// Arrange
|
||||
var request = _mockHttp.Expect(HttpMethod.Post, $"http://localhost/{ApiRoutes.FileIO.UploadItems}")
|
||||
.Respond("application/json", "[]");
|
||||
|
||||
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
|
||||
// Act
|
||||
await _client.UploadItemsAsync(stream, "test.xlsx");
|
||||
|
||||
// Assert
|
||||
_mockHttp.GetMatchCount(request).ShouldBe(1);
|
||||
}
|
||||
|
||||
// Success tests - Downloads
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadWorkOrdersTemplateAsync_Success_ReturnsBytes()
|
||||
{
|
||||
// Arrange
|
||||
var expectedBytes = new byte[] { 0x50, 0x4B, 0x03, 0x04 }; // ZIP header
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.Respond("application/octet-stream", new MemoryStream(expectedBytes));
|
||||
|
||||
// Act
|
||||
var result = await _client.DownloadWorkOrdersTemplateAsync();
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(expectedBytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadWorkOrdersTemplateAsync_WithExistingData_SendsData()
|
||||
{
|
||||
// Arrange
|
||||
var existingData = new List<WorkOrderViewModel>
|
||||
{
|
||||
new() { WorkOrderNumber = 12345 }
|
||||
};
|
||||
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.With(req => req.Content != null) // Verify body is sent
|
||||
.Respond("application/octet-stream", new MemoryStream(new byte[] { 1, 2, 3 }));
|
||||
|
||||
// Act
|
||||
var result = await _client.DownloadWorkOrdersTemplateAsync(existingData);
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
// Success tests - Uploads
|
||||
|
||||
[Fact]
|
||||
public async Task UploadWorkOrdersAsync_Success_ReturnsWorkOrderList()
|
||||
{
|
||||
// Arrange
|
||||
var workOrders = new List<WorkOrderViewModel>
|
||||
{
|
||||
new() { WorkOrderNumber = 12345, ItemNumber = "ITEM001" }
|
||||
};
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.Respond("application/json", JsonSerializer.Serialize(workOrders));
|
||||
|
||||
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
|
||||
// Act
|
||||
var result = await _client.UploadWorkOrdersAsync(stream, "test.xlsx");
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.Count.ShouldBe(1);
|
||||
result.Value[0].WorkOrderNumber.ShouldBe(12345);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UploadItemsAsync_Success_ReturnsItemList()
|
||||
{
|
||||
// Arrange
|
||||
var items = new List<ItemViewModel>
|
||||
{
|
||||
new() { ItemNumber = "ITEM1", Description = "Test Item" }
|
||||
};
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.Respond("application/json", JsonSerializer.Serialize(items));
|
||||
|
||||
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
|
||||
// Act
|
||||
var result = await _client.UploadItemsAsync(stream, "test.xlsx");
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.Count.ShouldBe(1);
|
||||
}
|
||||
|
||||
// Error tests
|
||||
|
||||
[Fact]
|
||||
public async Task DownloadWorkOrdersTemplateAsync_404_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.Respond(HttpStatusCode.NotFound);
|
||||
|
||||
// Act
|
||||
var result = await _client.DownloadWorkOrdersTemplateAsync();
|
||||
|
||||
// Assert
|
||||
result.IsNotFound.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UploadWorkOrdersAsync_VerifiesMultipartContentType_AndFilename()
|
||||
{
|
||||
// Arrange - verify multipart structure and filename
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.With(req =>
|
||||
{
|
||||
var content = req.Content as MultipartFormDataContent;
|
||||
if (content == null) return false;
|
||||
|
||||
// Check content type is multipart/form-data
|
||||
var contentType = req.Content?.Headers.ContentType?.MediaType;
|
||||
if (contentType != "multipart/form-data") return false;
|
||||
|
||||
// Check that filename is passed correctly
|
||||
var contentDisposition = content.First().Headers.ContentDisposition;
|
||||
return contentDisposition?.FileName?.Contains("test.xlsx") == true;
|
||||
})
|
||||
.Respond("application/json", "[]");
|
||||
|
||||
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
|
||||
// Act
|
||||
var result = await _client.UploadWorkOrdersAsync(stream, "test.xlsx");
|
||||
|
||||
// Assert
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UploadWorkOrdersAsync_400_ReturnsValidationError()
|
||||
{
|
||||
// Arrange - use actual ValidationProblemDetails structure
|
||||
var validationProblem = new Microsoft.AspNetCore.Mvc.ValidationProblemDetails
|
||||
{
|
||||
Errors = { ["File"] = new[] { "Invalid file format" } }
|
||||
};
|
||||
_mockHttp.When(HttpMethod.Post, "*")
|
||||
.Respond(HttpStatusCode.BadRequest, "application/json",
|
||||
JsonSerializer.Serialize(validationProblem, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }));
|
||||
|
||||
using var stream = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
|
||||
// Act
|
||||
var result = await _client.UploadWorkOrdersAsync(stream, "test.xlsx");
|
||||
|
||||
// Assert
|
||||
result.IsValidationError.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user