diff --git a/src/AdventureWorksDemo.MudBlazor.Tests/AdventureWorksDemo.MudBlazor.Tests.csproj b/src/AdventureWorksDemo.MudBlazor.Tests/AdventureWorksDemo.MudBlazor.Tests.csproj new file mode 100644 index 0000000..1493528 --- /dev/null +++ b/src/AdventureWorksDemo.MudBlazor.Tests/AdventureWorksDemo.MudBlazor.Tests.csproj @@ -0,0 +1,54 @@ + + + + net9.0 + latest + enable + enable + + true + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs b/src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs new file mode 100644 index 0000000..71f3c0f --- /dev/null +++ b/src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs @@ -0,0 +1,92 @@ +using System.Net; +using System.Text.Json; + +using AdventureWorksDemo.MudBlazor.Common; + +using Moq; +using Moq.Protected; + +using MudBlazor; + +namespace AdventureWorksDemo.MudBlazor.Tests +{ + [TestClass] + public sealed class CommonResponseGetTests + { + private HttpClient? _httpClient; + private Mock? _mockHttpHandler; + private Mock? _mockUrl; + private CommonResponseGet? _service; + + [TestMethod] + public async Task FindAllAsync_ReturnsDataOnSuccess() + { + // Arrange + var testData = new List + { + new() { Id = 1, Name = "Test1" }, + new() { Id = 2, Name = "Test2" } + }; + + var jsonResponse = JsonSerializer.Serialize(testData); + var httpResponse = new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(jsonResponse, System.Text.Encoding.UTF8, "application/json") + }; + httpResponse.Headers.Add("X-Pagination", "CurrentPage:1,PageSize:25,TotalCount:50,TotalPages:2"); + + _mockHttpHandler!.Protected() + .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) + .ReturnsAsync(httpResponse); + + var gridState = new GridState { Page = 0, PageSize = 25 }; + + // Act + var result = await _service!.FindAllAsync(gridState, "Id ASC", _httpClient!); + + // Assert + Assert.AreEqual(50, result.TotalItems); + Assert.AreEqual(2, result.Items.Count()); + Assert.AreEqual("Test1", result.Items.First().Name); + } + + [TestMethod] + public async Task FindAllAsync_ReturnsEmptyDataOnFailure() + { + // Arrange + var httpResponse = new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest }; + + _mockHttpHandler!.Protected() + .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) + .ReturnsAsync(httpResponse); + + var gridState = new GridState { Page = 0, PageSize = 25 }; + + // Act + var result = await _service!.FindAllAsync(gridState, "Id ASC", _httpClient!); + + // Assert + Assert.AreEqual(0, result.TotalItems); + Assert.AreEqual(0, result.Items.Count()); + } + + [TestInitialize] + public void Setup() + { + _mockUrl = new Mock(); + _mockUrl.Setup(u => u.Administration_ProductDescription).Returns("https://api.example.com/productdescription"); + + _mockHttpHandler = new Mock(); + _httpClient = new HttpClient(_mockHttpHandler.Object); + + _service = new CommonResponseGet(_mockUrl.Object); + } + + private class TestModel + { + public int Id { get; set; } + public string? Name { get; set; } + } + } +} \ No newline at end of file diff --git a/src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs b/src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs new file mode 100644 index 0000000..aaf278c --- /dev/null +++ b/src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/src/AdventureWorksDemo.sln b/src/AdventureWorksDemo.sln index dc3ccbf..7ebc3d7 100644 --- a/src/AdventureWorksDemo.sln +++ b/src/AdventureWorksDemo.sln @@ -30,6 +30,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdventureWorksDemo.Data.Tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdventureWorksDemo.MudBlazor", "FrontEnd\AdventureWorksDemo.MudBlazor\AdventureWorksDemo.MudBlazor.csproj", "{C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{56ED2B2C-32A6-4251-A025-22CD1DC336FA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdventureWorksDemo.MudBlazor.Tests", "AdventureWorksDemo.MudBlazor.Tests\AdventureWorksDemo.MudBlazor.Tests.csproj", "{27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -64,6 +68,10 @@ Global {C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}.Debug|Any CPU.Build.0 = Debug|Any CPU {C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}.Release|Any CPU.ActiveCfg = Release|Any CPU {C4D0ABE5-0E84-4112-B4C7-3067B23A2F26}.Release|Any CPU.Build.0 = Release|Any CPU + {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -77,6 +85,8 @@ Global {8F4D9C82-7600-48A8-B8D0-19BF96DDE28C} = {9D6855CA-A743-45EC-BB4B-8BDE8A160DBD} {AA4A04F0-04B2-46BF-917D-6B4E40CB56BF} = {9D6855CA-A743-45EC-BB4B-8BDE8A160DBD} {C4D0ABE5-0E84-4112-B4C7-3067B23A2F26} = {B922BF81-0D47-41E8-BDC8-37C09BFA6167} + {56ED2B2C-32A6-4251-A025-22CD1DC336FA} = {B922BF81-0D47-41E8-BDC8-37C09BFA6167} + {27DADAD3-7848-4EB1-9E47-A6A38E6BAE07} = {56ED2B2C-32A6-4251-A025-22CD1DC336FA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6B392A9A-E58C-44EB-BA80-051A0183B5DE} diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/CommonResponseGet.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/CommonResponseGet.cs new file mode 100644 index 0000000..01d9ee5 --- /dev/null +++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/CommonResponseGet.cs @@ -0,0 +1,47 @@ +using System.Net.Mime; +using System.Text; + +using AdventureWorksDemo.MudBlazor.Models; + +using MudBlazor; + +namespace AdventureWorksDemo.MudBlazor.Common +{ + public interface ICommonResponseGet + { + Task> FindAllAsync(GridState state, string defaultSorting, HttpClient httpClient); + } + + public class CommonResponseGet(IUrl Url) : ICommonResponseGet + { + public async Task> FindAllAsync(GridState state, string defaultSorting, HttpClient httpClient) + { + PageingFilter filter = PageingFilter.SetByGridState(state, defaultSorting); + + var request = new HttpRequestMessage + { + Method = HttpMethod.Get, + RequestUri = new Uri(Url.Administration_ProductDescription), + Content = new StringContent(filter.ToJSON(), + Encoding.UTF8, + MediaTypeNames.Application.Json), + }; + + PagedList paging = new(); + IEnumerable data = []; + + var response = await httpClient.SendAsync(request).ConfigureAwait(false); + if (response.IsSuccessStatusCode) + { + data = (await response!.Content!.ReadFromJsonAsync>()) ?? []; + paging = PagedList.FromIEnumerable(response.Headers.GetValues("X-Pagination").SingleOrDefault()); + } + + return new GridData + { + TotalItems = paging.TotalCount, + Items = data, + }; + } + } +} \ No newline at end of file diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs new file mode 100644 index 0000000..3634fd6 --- /dev/null +++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs @@ -0,0 +1,11 @@ +namespace AdventureWorksDemo.MudBlazor.Common +{ + public interface IUrl + { + string Administration_ProductDescription { get; } + } + public class Url(IConfiguration configuration) : IUrl + { + public string Administration_ProductDescription => $"{configuration["Api:base"]}{configuration["Api:productdescription"]}"; + } +} diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor index a8efc82..1990f28 100644 --- a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor +++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Components/Pages/ProductDescription.razor @@ -2,18 +2,19 @@ @using System.Text @using System.Net.Mime @using global::MudBlazor -@inject IConfiguration Configuration +@inject Common.ICommonResponseGet response Product Description Product Description Modify the product descriptions. - @@ -21,52 +22,28 @@ Filterable="true" - + - - - + + @code { - - public MudDataGrid? dataGrid ; - - - private async Task> ServerReload(GridState state) - { - PagedList paging = new(); - IEnumerable data = new List(); - PageingFilter filter = PageingFilter.SetByGridState(state, "Description"); - string url = $"{Configuration["Api:base"]}{Configuration["Api:productdescription"]}"; - var request = new HttpRequestMessage - { - Method= HttpMethod.Get, - RequestUri = new Uri(url), - Content = new StringContent(filter.ToJSON(), - Encoding.UTF8, - MediaTypeNames.Application.Json), - }; + private MudDataGrid? dataGrid ; - var response = await httpClient.SendAsync(request).ConfigureAwait(false); - if (response.IsSuccessStatusCode) - { - data = (await response!.Content!.ReadFromJsonAsync>()) ?? new (); - paging = PagedList.FromIEnumerable(response.Headers.GetValues("X-Pagination").SingleOrDefault()); - } - return new GridData - { - TotalItems = paging.TotalCount, - Items = data, - }; + private async Task> ServerReload(GridState state) + { + return await response.FindAllAsync(state, "Description", httpClient); } private Task OnClear() diff --git a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs index 193d1e0..37a9237 100644 --- a/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs +++ b/src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs @@ -1,3 +1,4 @@ +using AdventureWorksDemo.MudBlazor.Common; using AdventureWorksDemo.MudBlazor.Components; using MudBlazor.Services; @@ -22,6 +23,9 @@ public static void Main(string[] args) { BaseAddress = new Uri(builder.Configuration["Api:Base"] ?? "") }); + builder.Services.AddSingleton(typeof(IUrl), typeof(Url)); + builder.Services.AddScoped(typeof(ICommonResponseGet), typeof(CommonResponseGet)); + var app = builder.Build(); // Configure the HTTP request pipeline.