Skip to content

Commit

Permalink
merge results
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmoradi committed Sep 24, 2024
2 parents 6af9c70 + 6ec645e commit acc26e1
Show file tree
Hide file tree
Showing 25 changed files with 197 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<OutputType>WinExe</OutputType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ private async Task ConnectSignalR()
hubConnection = new HubConnectionBuilder()
.WithUrl($"{Configuration.GetServerAddress()}/app-hub?access_token={access_token}", options =>
{
options.HttpMessageHandlerFactory = httpClientHandler =>
options.HttpMessageHandlerFactory = signalrHttpMessageHandler =>
{
return serviceProvider.GetRequiredService<Func<HttpMessageHandler, HttpMessageHandler>>()
.Invoke(httpClientHandler);
.Invoke(signalrHttpMessageHandler);
};
})
.Build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,22 @@ public static IServiceCollection AddClientCoreProjectServices(this IServiceColle
});
services.TryAddSessioned<HttpClientHandler>();

// The following code build chain of http message handlers, it uses HttpClientHandler to send requests to the server by default,
// but you can also use other http message handlers such as aspnetcore's test host's http message handler for integration tests.
// This code constructs a chain of HTTP message handlers. By default, it uses `HttpClientHandler`
// to send requests to the server. However, you can replace `HttpClientHandler` with other HTTP message
// handlers, such as ASP.NET Core's `HttpMessageHandler` from the Test Host, which is useful for integration tests.
services.TryAddTransient<Func<HttpMessageHandler, HttpMessageHandler>>(serviceProvider => underlyingHttpMessageHandler =>
{
return ActivatorUtilities.CreateInstance<RequestHeadersDelegationHandler>(serviceProvider,
var constructedHttpMessageHandler = ActivatorUtilities.CreateInstance<RequestHeadersDelegationHandler>(serviceProvider,
[ActivatorUtilities.CreateInstance<AuthDelegatingHandler>(serviceProvider,
[ActivatorUtilities.CreateInstance<RetryDelegatingHandler>(serviceProvider,
[ActivatorUtilities.CreateInstance<ExceptionDelegatingHandler>(serviceProvider, [underlyingHttpMessageHandler])])])]);
return constructedHttpMessageHandler;
});
services.TryAddTransient(serviceProvider =>
{
var underlyingHttpMessageHandler = serviceProvider.GetRequiredService<HttpClientHandler>();
return serviceProvider.GetRequiredService<Func<HttpMessageHandler, HttpMessageHandler>>().Invoke(underlyingHttpMessageHandler);
var constructedHttpMessageHandler = serviceProvider.GetRequiredService<Func<HttpMessageHandler, HttpMessageHandler>>().Invoke(underlyingHttpMessageHandler);
return constructedHttpMessageHandler;
});

services.AddSessioned<AuthenticationStateProvider, AuthenticationManager>(); // Use 'Add' instead of 'TryAdd' to override the aspnetcore's default AuthenticationStateProvider.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<OutputType>WinExe</OutputType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public MainWindow()
{
AppPlatform.IsBlazorHybrid = true;
var services = new ServiceCollection();
services.ConfigureServices();
services.AddClientWindowsProjectServices();
InitializeComponent();
AppWebView.Services = services.BuildServiceProvider();
if (CultureInfoManager.MultilingualEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Boilerplate.Client.Windows;

public static partial class Program
{
public static void ConfigureServices(this IServiceCollection services)
public static void AddClientWindowsProjectServices(this IServiceCollection services)
{
// Services being registered here can get injected in windows project only.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static partial class Program
/// <summary>
/// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0#middleware-order
/// </summary>
public static void ConfiureMiddlewares(this WebApplication app)
private static void ConfiureMiddlewares(this WebApplication app)
{
var configuration = app.Configuration;
var env = app.Environment;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//+:cnd:noEmit
//+:cnd:noEmit
using System.IO.Compression;
using Microsoft.AspNetCore.ResponseCompression;
using Boilerplate.Server.Api.Services;
Expand All @@ -21,7 +21,7 @@ namespace Boilerplate.Server.Api;

public static partial class Program
{
public static void ConfigureApiServices(this WebApplicationBuilder builder)
public static void AddServerApiProjectServices(this WebApplicationBuilder builder)
{
// Services being registered here can get injected in server project only.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static async Task Main(string[] args)
builder.WebHost.UseUrls("http://localhost:5031", "http://*:5031");
}

builder.ConfigureApiServices();
builder.AddServerApiProjectServices();
builder.Services.AddSharedProjectServices();

var app = builder.Build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static partial class Program
/// <summary>
/// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0#middleware-order
/// </summary>
private static void ConfiureMiddlewares(this WebApplication app)
public static void ConfiureMiddlewares(this WebApplication app)
{
var configuration = app.Configuration;
var env = app.Environment;
Expand Down Expand Up @@ -81,6 +81,7 @@ private static void ConfiureMiddlewares(this WebApplication app)
await next.Invoke();
});
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

if (string.IsNullOrEmpty(env.WebRootPath) is false && Path.Exists(Path.Combine(env.WebRootPath, @".well-known")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Boilerplate.Server.Web;

public static partial class Program
{
private static void ConfigureServices(this WebApplicationBuilder builder)
public static void AddServerWebProjectServices(this WebApplicationBuilder builder)
{
// Services being registered here can get injected in server project only.

Expand All @@ -24,7 +24,7 @@ private static void ConfigureServices(this WebApplicationBuilder builder)
AddBlazor(builder);

//#if (api == "Integrated")
builder.ConfigureApiServices();
builder.AddServerApiProjectServices();
//#else
services.AddOptions<ForwardedHeadersOptions>()
.Bind(configuration.GetRequiredSection("ForwardedHeaders"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static async Task Main(string[] args)
builder.WebHost.UseUrls("http://localhost:5030", "http://*:5030");
}

builder.ConfigureServices();
builder.AddServerWebProjectServices();

var app = builder.Build();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.TestHost;
using Boilerplate.Server.Api;
using Boilerplate.Server.Api;
using Boilerplate.Server.Web;
using Boilerplate.Server.Api.Data;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;

namespace Boilerplate.Tests;

public partial class AppTestServer : IAsyncDisposable
{
private TestServer? testServer;
private WebApplication? webApp;

public AppTestServer Build(Action<IServiceCollection>? configureTestServices = null)
Expand All @@ -18,18 +17,19 @@ public AppTestServer Build(Action<IServiceCollection>? configureTestServices = n

var builder = WebApplication.CreateBuilder(options: new()
{
EnvironmentName = Environments.Development
EnvironmentName = Environments.Development,
Args = Environment.GetCommandLineArgs()
});

AppEnvironment.Set(builder.Environment.EnvironmentName);

builder.Configuration.AddSharedConfigurations();
builder.Configuration.AddClientConfigurations();

builder.WebHost.UseTestServer();
builder.WebHost.UseUrls("http://127.0.0.1:0" /* 0 means random port */);

configureTestServices?.Invoke(builder.Services);
builder.ConfigureApiServices();
builder.Services.AddSharedProjectServices();

builder.AddTestProjectServices();

var app = webApp = builder.Build();

Expand All @@ -38,6 +38,8 @@ public AppTestServer Build(Action<IServiceCollection>? configureTestServices = n
return this;
}

public IServiceProvider Services => (webApp ?? throw new InvalidOperationException("Web app is null.")).Services;

public async Task Start()
{
if (webApp == null)
Expand All @@ -52,27 +54,7 @@ public async Task Start()

await webApp.StartAsync();

testServer = webApp.GetTestServer();
}

public HttpClient CreateClient()
{
return (testServer ?? throw new InvalidOperationException()).CreateClient();
}

public HttpMessageHandler CreateHandler()
{
return (testServer ?? throw new InvalidOperationException()).CreateHandler();
}

public RequestBuilder CreateRequest(string path)
{
return (testServer ?? throw new InvalidOperationException()).CreateRequest(path);
}

public WebSocketClient CreateWebSocketClient()
{
return (testServer ?? throw new InvalidOperationException()).CreateWebSocketClient();
webApp.Configuration["ServerAddress"] = GetServerAddress().ToString();
}

public async ValueTask DisposeAsync()
Expand All @@ -81,6 +63,14 @@ public async ValueTask DisposeAsync()
{
await webApp.DisposeAsync();
}
testServer?.Dispose();
}

internal Uri GetServerAddress()
{
if (webApp == null)
throw new InvalidOperationException($"web app is null");

return new Uri(webApp.Services.GetRequiredService<IServer>()
.Features.Get<IServerAddressesFeature>()!.Addresses.First());
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
</PropertyGroup>

<ItemGroup>
Expand All @@ -14,19 +14,22 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FakeItEasy" Version="8.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-rc.1.24452.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Microsoft.Playwright.MSTest" Version="1.47.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.0" />
<PackageReference Include="Bit.CodeAnalyzers" Version="8.11.1-pre-02" PrivateAssets="all" />
<PackageReference Include="Bit.SourceGenerators" Version="8.11.1-pre-02" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Server\Boilerplate.Server.Api\Boilerplate.Server.Api.csproj" />
<ProjectReference Include="..\Server\Boilerplate.Server.Web\Boilerplate.Server.Web.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="System.Net.Http.Headers" />
<Using Include="System.Net.Http.Json" />
<Using Include="Boilerplate.Shared" />
<Using Include="Boilerplate.Shared.Enums" />
<Using Include="Microsoft.AspNetCore.Components" />
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Boilerplate.Server.Web;
using Boilerplate.Tests.Services;
using Boilerplate.Client.Core.Services.Contracts;

namespace Microsoft.AspNetCore.Builder;

public static partial class WebApplicationBuilderExtensions
{
public static void AddTestProjectServices(this WebApplicationBuilder builder)
{
var services = builder.Services;

services.TryAddScoped<IStorageService, TestStorageService>();
services.TryAddTransient<IAuthTokenProvider, TestTokenProvider>();

services.TryAddTransient(sp =>
{
return new HttpClient(sp.GetRequiredService<HttpMessageHandler>())
{
BaseAddress = new Uri(sp.GetRequiredService<IConfiguration>().GetServerAddress(), UriKind.Absolute)
};
});

builder.AddServerWebProjectServices();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Boilerplate.Client.Core.Services;
using Boilerplate.Shared.Controllers.Identity;

namespace Boilerplate.Tests;

[TestClass]
public partial class IdentityApiTests
{
[TestMethod]
public async Task SignInTest()
{
await using var server = new AppTestServer();

await server.Build(services =>
{
// Services registered in this test project will be used instead of the application's services, allowing you to fake certain behaviors during testing.
}).Start();

await using var scope = server.Services.CreateAsyncScope();

var authenticationManager = scope.ServiceProvider.GetRequiredService<AuthenticationManager>();

var signInResponse = await authenticationManager.SignIn(new()
{
Email = "[email protected]",
Password = "123456"
}, default);

var userController = scope.ServiceProvider.GetRequiredService<IUserController>();

var user = await userController.GetCurrentUser(default);

Assert.AreEqual(Guid.Parse("8ff71671-a1d6-4f97-abb9-d87d7b47d6e7"), user.Id);
}

[TestMethod, ExpectedException(typeof(UnauthorizedException))]
public async Task UnauthorizedAccessTest()
{
await using var server = new AppTestServer();

await server.Build().Start();

await using var scope = server.Services.CreateAsyncScope();

var userController = scope.ServiceProvider.GetRequiredService<IUserController>();

var user = await userController.GetCurrentUser(default);
}
}
Loading

0 comments on commit acc26e1

Please sign in to comment.