Skip to content

Commit

Permalink
feat: Pin/unpin, UX- and E2E testing improvements (#50)
Browse files Browse the repository at this point in the history
* feat: Added simple "pin" feature for notes.

* feat: Added "Save & Close" option for notes.

* refactor: Unified date formatting

* feat: Added "Save & Close" for task lists.

* feat: Removed "saved"-message

* fix: Added missing word-wrap style for notes.

* feat: Task list and category filters are now sorted.

* feat: Improved Playwright E2E testing environment.

* feat: Improved Playwright setup

* feat: Improved Playwright E2E tests.

* chore: Updated README.md
  • Loading branch information
philipp-meier authored Apr 1, 2024
1 parent dcabe01 commit 2cf5279
Show file tree
Hide file tree
Showing 24 changed files with 1,783 additions and 3,966 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ dotnet ef migrations add Initial
dotnet ef database update
```

## E2E Testing

E2E testing is done via [Playwright](https://playwright.dev/dotnet/docs/writing-tests). The test suite automatically
spawns the test server and shuts it down after all tests are completed.

## Technology

- **Backend**: ASP.NET Core Web API
Expand Down
46 changes: 36 additions & 10 deletions src/Chrono.Tests/E2E/00_E2ETestBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
using Microsoft.Extensions.Configuration;
using Chrono.Shared.Services;
using Chrono.Tests.Helper;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Playwright;
using Microsoft.Playwright.NUnit;
using NUnit.Framework;
Expand All @@ -12,6 +18,7 @@ public partial class E2ETests : PlaywrightTest
private static readonly string[] PlaywrightArgs = ["install"];
private IBrowser _browser;
private IConfiguration _config;
private IHost _host;
private IPage _page;

[OneTimeSetUp]
Expand All @@ -23,14 +30,33 @@ public async Task Init()
.AddJsonFile("config.Local.json", true)
.Build();

_host = BuildTestApp();

await _host.StartAsync();

await InitPlaywright();
await Login_User();
}

private WebApplication BuildTestApp()
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
Environment.SetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUPASSEMBLIES", "Microsoft.AspNetCore.SpaProxy");
Environment.SetEnvironmentVariable("ConnectionStrings:DefaultConnection",
$"Data Source={_config["DatabaseFullPath"]}");

var builder = Program.CreateBuilder([$"urls={_config["BackendUrl"]!}"]);

// Disables Authentication for E2E tests (= no 2FA etc.)
builder.Services.AddScoped<ICurrentUserService, FakeCurrentUserService>();
builder.Services.AddSingleton<IPolicyEvaluator, FakePolicyEvaluator>();

return Program.BuildApp(builder);
}

private async Task InitPlaywright()
{
// Ensure the required web driver is installed.
Program.Main(PlaywrightArgs);
Microsoft.Playwright.Program.Main(PlaywrightArgs);

await PlaywrightSetup();

Expand All @@ -44,13 +70,13 @@ private async Task InitPlaywright()
});
}

private async Task Login_User()
[OneTimeTearDown]
public async Task TearDownWebApplication()
{
await _page.GotoAsync(_config["WebAppUrl"]!);
await _page.Locator("text=Login").ClickAsync();

await _page.GetByLabel("Email address").FillAsync(_config["TestUser:Username"]!);
await _page.GetByLabel("Password").FillAsync(_config["TestUser:Password"]!);
await _page.GetByRole(AriaRole.Button, new PageGetByRoleOptions { Name = "Continue" }).ClickAsync();
if (_host is not null)
{
await _host.StopAsync();
_host.Dispose();
}
}
}
10 changes: 10 additions & 0 deletions src/Chrono.Tests/Helper/FakeCurrentUserService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Chrono.Shared.Services;

namespace Chrono.Tests.Helper;

public class FakeCurrentUserService : ICurrentUserService
{
public string UserId => "Testing";
public string UserName => "Testing";
public bool IsAuthenticated => true;
}
25 changes: 25 additions & 0 deletions src/Chrono.Tests/Helper/FakePolicyEvaluator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;

namespace Chrono.Tests.Helper;

public class FakePolicyEvaluator : IPolicyEvaluator
{
public virtual async Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
{
var principal = new ClaimsPrincipal();
principal.AddIdentity(new ClaimsIdentity(Array.Empty<Claim>(), "FakeScheme"));

return await Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal,
new AuthenticationProperties(), "FakeScheme")));
}

public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy,
AuthenticateResult authenticationResult, HttpContext context, object resource)
{
return await Task.FromResult(PolicyAuthorizationResult.Success());
}
}
8 changes: 3 additions & 5 deletions src/Chrono.Tests/config.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
{
"WebAppUrl": "https://localhost:7151",
"BackendUrl": "https://localhost:7151",
"WebAppUrl": "https://localhost:44463",
"DatabaseFullPath": "/home/.../.../.../data/chrono_test.db",
"Options": {
"Headless": false,
"IgnoreHTTPSErrors": true
},
"TestUser": {
"Username": "<TODO>",
"Password": "<TODO>"
}
}
8 changes: 6 additions & 2 deletions src/Chrono/Chrono.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,18 @@
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**"/>
</ItemGroup>

<!-- Make internals visible to Chrono.Tests -->
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<_ContentIncludedByDefault Remove="Pages\Error.cshtml"/>
<_ContentIncludedByDefault Remove="Pages\_ViewImports.cshtml"/>

</ItemGroup>


<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
Expand Down
Loading

0 comments on commit 2cf5279

Please sign in to comment.