Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eerste opzet met Azure login 2FA base classes opzetten #844

Merged
merged 13 commits into from
Aug 5, 2024
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
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>
Loading