6cb852c164
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)
264 lines
8.5 KiB
C#
264 lines
8.5 KiB
C#
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();
|
|
}
|
|
}
|