Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<Project Sdk="MSTest.Sdk/3.6.1">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!--
Displays error on console in addition to the log file. Note that this feature comes with a performance impact.
For more information, visit https://learn.microsoft.com/dotnet/core/testing/unit-testing-platform-integration-dotnet-test#show-failure-per-test
-->
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
</PropertyGroup>
<PropertyGroup>
<!-- Exclude the project from analysis -->
<SonarQubeExclude>true</SonarQubeExclude>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Moq" Version="4.20.72" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\FrontEnd\AdventureWorksDemo.MudBlazor\AdventureWorksDemo.MudBlazor.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.13.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.Testing.Extensions.CodeCoverage" Version="17.13.1" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.Testing.Extensions.TrxReport" Version="1.5.3" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="MSTest.Analyzers" Version="3.7.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Update="MSTest.TestAdapter" Version="3.7.3" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="MSTest.TestFramework" Version="3.7.3" />
</ItemGroup>

</Project>
92 changes: 92 additions & 0 deletions src/AdventureWorksDemo.MudBlazor.Tests/CommonResponseGetTests.cs
Original file line number Diff line number Diff line change
@@ -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<HttpMessageHandler>? _mockHttpHandler;
private Mock<IUrl>? _mockUrl;
private CommonResponseGet? _service;

[TestMethod]
public async Task FindAllAsync_ReturnsDataOnSuccess()
{
// Arrange
var testData = new List<TestModel>
{
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<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(httpResponse);

var gridState = new GridState<TestModel> { 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<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(httpResponse);

var gridState = new GridState<TestModel> { 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<IUrl>();
_mockUrl.Setup(u => u.Administration_ProductDescription).Returns("https://api.example.com/productdescription");

_mockHttpHandler = new Mock<HttpMessageHandler>();
_httpClient = new HttpClient(_mockHttpHandler.Object);

_service = new CommonResponseGet(_mockUrl.Object);
}

private class TestModel
{
public int Id { get; set; }
public string? Name { get; set; }
}
}
}
1 change: 1 addition & 0 deletions src/AdventureWorksDemo.MudBlazor.Tests/MSTestSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
10 changes: 10 additions & 0 deletions src/AdventureWorksDemo.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<GridData<T>> FindAllAsync<T>(GridState<T> state, string defaultSorting, HttpClient httpClient);
}

public class CommonResponseGet(IUrl Url) : ICommonResponseGet
{
public async Task<GridData<T>> FindAllAsync<T>(GridState<T> state, string defaultSorting, HttpClient httpClient)
{
PageingFilter filter = PageingFilter.SetByGridState<T>(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<T> data = [];

var response = await httpClient.SendAsync(request).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
data = (await response!.Content!.ReadFromJsonAsync<List<T>>()) ?? [];
paging = PagedList.FromIEnumerable(response.Headers.GetValues("X-Pagination").SingleOrDefault());
}

return new GridData<T>
{
TotalItems = paging.TotalCount,
Items = data,
};
}
}
}
11 changes: 11 additions & 0 deletions src/FrontEnd/AdventureWorksDemo.MudBlazor/Common/Url.cs
Original file line number Diff line number Diff line change
@@ -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"]}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,48 @@
@using System.Text
@using System.Net.Mime
@using global::MudBlazor
@inject IConfiguration Configuration
@inject Common.ICommonResponseGet response

<PageTitle>Product Description</PageTitle>

<MudText Typo="Typo.h3" GutterBottom="true">Product Description</MudText>
<MudText Typo="Typo.body1" GutterBottom="true">Modify the product descriptions.</MudText>


<MudDataGrid T="ProductDescriptionModel" ServerData="ServerReload" EditMode="DataGridEditMode.Form" ReadOnly="false"
SortMode="@SortMode.Single"
SortMode="@SortMode.Multiple"
ShowFilterIcons="true"
Filterable="true"
ColumnResizeMode="ResizeMode.Container"

>

<ToolBarContent>
<MudText Typo="Typo.h6">Product Description</MudText>
<MudSpacer />

</ToolBarContent>
<Columns>
<Columns >

<PropertyColumn Property="x => x.ProductDescriptionId" Hidden="true" xs="0" Editable="false" Filterable="false" />
<PropertyColumn Property="x => x.ModifiedDate" Format="d" Title="Modified" xs="3" Sortable="true" Editable="false" Filterable="true"/>
<PropertyColumn Property="x => x.Description" Sortable="true" Editable="true" Filterable="true" Required="true"/>
<PropertyColumn xs="0" Property="x => x.ProductDescriptionId" Hidden="true" Editable="false" Filterable="false" />
<PropertyColumn xs="2" Property="x => x.ModifiedDate" Format="d" Title="Modified" Sortable="true" Editable="false" Filterable="true" Resizable="false" Class="pa-4" />
<PropertyColumn xs="9" Property="x => x.Description" Sortable="true" Editable="true" Filterable="true" Required="true" Resizable="true" />

</Columns>
<PagerContent>
<MudDataGridPager T="ProductDescriptionModel" PageSizeOptions=[5,10,25,50,100]/>
<PagerContent >
<MudDataGridPager T="ProductDescriptionModel" PageSizeOptions=[5,10,25,50,100,250] Class="pa-4" />
</PagerContent>
</MudDataGrid>


@code {


public MudDataGrid<ProductDescriptionModel>? dataGrid ;


private async Task<GridData<ProductDescriptionModel>> ServerReload(GridState<ProductDescriptionModel> state)
{

PagedList paging = new();
IEnumerable<ProductDescriptionModel> data = new List<ProductDescriptionModel>();
PageingFilter filter = PageingFilter.SetByGridState<ProductDescriptionModel>(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<ProductDescriptionModel>? dataGrid ;

var response = await httpClient.SendAsync(request).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
data = (await response!.Content!.ReadFromJsonAsync<List<ProductDescriptionModel>>()) ?? new ();
paging = PagedList.FromIEnumerable(response.Headers.GetValues("X-Pagination").SingleOrDefault());
}

return new GridData<ProductDescriptionModel>
{
TotalItems = paging.TotalCount,
Items = data,
};
private async Task<GridData<ProductDescriptionModel>> ServerReload(GridState<ProductDescriptionModel> state)
{
return await response.FindAllAsync<ProductDescriptionModel>(state, "Description", httpClient);
}

private Task OnClear()
Expand Down
4 changes: 4 additions & 0 deletions src/FrontEnd/AdventureWorksDemo.MudBlazor/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using AdventureWorksDemo.MudBlazor.Common;
using AdventureWorksDemo.MudBlazor.Components;

using MudBlazor.Services;
Expand All @@ -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.
Expand Down