Skip to content

Commit

Permalink
Merge pull request #844 from Klantinteractie-Servicesysteem/#823-End-…
Browse files Browse the repository at this point in the history
…to-end-tests-met-playwright

eerste opzet met Azure login 2FA base classes opzetten
  • Loading branch information
felixcicatt authored Aug 5, 2024
2 parents 595b38b + a4d0e1c commit e16768b
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 0 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/playwright.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Playwright Tests
on:
schedule:
- cron: '0 23 * * *'
pull_request:
branches: [ main, master ]
paths: ['Kiss.Bff.EndToEndTest/**']
workflow_dispatch:

jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./Kiss.Bff.EndToEndTest
steps:
- uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- run: dotnet build
- name: Ensure browsers are installed
run: pwsh bin/Debug/net8.0/playwright.ps1 install --with-deps
- name: Run your tests
id: e2e
run: dotnet test
env:
'TestSettings:TEST_USERNAME': ${{ secrets.PLAYWRIGHT_USERNAME }}
'TestSettings:TEST_PASSWORD': '${{ secrets.PLAYWRIGHT_PASSWORD }}'
'TestSettings:TEST_TOTP_SECRET': ${{ secrets.PLAYWRIGHT_TOTP_SECRET }}
'TestSettings:TEST_BASE_URL': ${{ secrets.PLAYWRIGHT_BASE_URL }}
- name: Upload test artifacts
if: ${{ failure() && steps.e2e.conclusion == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: playwright-traces
path: '**/playwright-traces/*.zip'
6 changes: 6 additions & 0 deletions KISS-frontend.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
CodeCoverage.runsettings = CodeCoverage.runsettings
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kiss.Bff.EndToEndTest", "Kiss.Bff.EndToEndTest\Kiss.Bff.EndToEndTest.csproj", "{D2EF3BA8-432E-42CE-AE01-04903D2F63FB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -45,6 +47,10 @@ Global
{DEB9BEF6-DC5E-42AD-B13E-7B969C619F65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEB9BEF6-DC5E-42AD-B13E-7B969C619F65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEB9BEF6-DC5E-42AD-B13E-7B969C619F65}.Release|Any CPU.Build.0 = Release|Any CPU
{D2EF3BA8-432E-42CE-AE01-04903D2F63FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2EF3BA8-432E-42CE-AE01-04903D2F63FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2EF3BA8-432E-42CE-AE01-04903D2F63FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2EF3BA8-432E-42CE-AE01-04903D2F63FB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
74 changes: 74 additions & 0 deletions Kiss.Bff.EndToEndTest/AzureAdLoginHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Microsoft.Playwright;
using OtpNet;

namespace PlaywrightTests
{
public class AzureAdLoginHelper
{
private readonly IPage _page;
private readonly Uri _baseUrl;
private readonly string _username;
private readonly string _password;
private readonly string _totpSecret;

public AzureAdLoginHelper(IPage page, Uri baseUrl, string username, string password, string totpSecret)
{
_page = page;
_baseUrl = baseUrl;
_username = username;
_password = password;
_totpSecret = totpSecret;
}

public async Task LoginAsync()
{
await _page.GotoAsync(_baseUrl.ToString());

await _page.FillAsync("input[name='loginfmt']", _username);
await _page.ClickAsync("input[type='submit']");

await _page.WaitForSelectorAsync("input[name='passwd']");
await _page.FillAsync("input[name='passwd']", _password);
await _page.ClickAsync("input[type='submit']");

await Handle2FAAsync();

await _page.WaitForURLAsync($"{_baseUrl}**");
}

private async Task Handle2FAAsync()
{
// Wait for the TOTP input field to appear
await _page.WaitForSelectorAsync("input[name='otc']", new() { Timeout = 30000 });

// Generate TOTP code
var totp = new Totp(Base32Encoding.ToBytes(_totpSecret));
var totpCode = totp.ComputeTotp();

// Check for "Enter Manually" link and click if present
var enterManuallyLink = await _page.QuerySelectorAsync("a:has-text('Ik kan mijn Microsoft Authenticator-app op dit moment niet gebruiken')");
if (enterManuallyLink != null)
{
await enterManuallyLink.ClickAsync();
}

// Fill in the TOTP code
await _page.FillAsync("input[name='otc']", totpCode);
await _page.ClickAsync("input[type='submit']");

// Wait for potential "Stay signed in?" prompt
var declineStaySignedInButton = _page.GetByText("Nee").Or(_page.GetByText("No"));
var homePageSelector = _page.GetByText("Nieuw contactmoment");

// we will either get a decline button, or we will go back to the home page
await declineStaySignedInButton.Or(homePageSelector).WaitForAsync();

// check if the decline button is visible, if so, click it
if (await declineStaySignedInButton.IsVisibleAsync())
{
await declineStaySignedInButton.ClickAsync();
}
}

}
}
58 changes: 58 additions & 0 deletions Kiss.Bff.EndToEndTest/BaseTestInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Microsoft.Extensions.Configuration;


namespace PlaywrightTests
{
[TestClass]
public class BaseTestInitializer : PageTest
{
[TestInitialize]
public virtual async Task TestInitialize()
{
var configuration = new ConfigurationBuilder()
.AddUserSecrets<BaseTestInitializer>()
.AddEnvironmentVariables()
.Build();

var username = GetRequiredConfig(configuration, "TestSettings:TEST_USERNAME");
var password = GetRequiredConfig(configuration, "TestSettings:TEST_PASSWORD");
var totpSecret = GetRequiredConfig(configuration, "TestSettings:TEST_TOTP_SECRET");
var baseUrl = GetRequiredConfig(configuration, "TestSettings:TEST_BASE_URL");
var uri = new Uri(baseUrl);

await Context.Tracing.StartAsync(new()
{
Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
Screenshots = true,
Snapshots = true,
Sources = true
});

var loginHelper = new AzureAdLoginHelper(Page, uri, username, password, totpSecret);
await loginHelper.LoginAsync();
}

[TestCleanup]
public async Task TestCleanup()
{
await Context.Tracing.StopAsync(new()
{
Path = Path.Combine(
Environment.CurrentDirectory,
"playwright-traces",
$"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip"
)
});
}

private string GetRequiredConfig(IConfiguration configuration, string key)
{
var value = configuration[key];
if (string.IsNullOrEmpty(value))
{
throw new InvalidOperationException($"'{key}' is missing from the configuration");
}
return value;
}
}
}
13 changes: 13 additions & 0 deletions Kiss.Bff.EndToEndTest/GespreksresultatenTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace PlaywrightTests
{
[TestClass]
public class GespreksresultatenTests : BaseTestInitializer
{
// dummy test to ensure that the base class functions properly from github actions
[TestMethod]
public async Task DummyTest()
{
await Expect(Page.Locator("a[href='/beheer']")).ToBeVisibleAsync();
}
}
}
4 changes: 4 additions & 0 deletions Kiss.Bff.EndToEndTest/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global using Microsoft.Playwright.MSTest;
global using Microsoft.VisualStudio.TestTools.UnitTesting;
global using System.Text.RegularExpressions;
global using System.Threading.Tasks;
34 changes: 34 additions & 0 deletions Kiss.Bff.EndToEndTest/Kiss.Bff.EndToEndTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<UserSecretsId>11d50565-5002-41ee-b700-0b7168235484</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.5.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.5.0" />
<PackageReference Include="Microsoft.Playwright.MSTest" Version="1.45.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Otp.NET" Version="1.4.0" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions local.runsettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<Playwright>
<LaunchOptions>
<Headless>false</Headless>
</LaunchOptions>
</Playwright>
</RunSettings>

0 comments on commit e16768b

Please sign in to comment.