"
- echo "$result"
- echo "$result" > index.html
- - name: Deploy to GitHub Pages
- if: ${{ failure() && steps.e2e.conclusion == 'failure' }}
- uses: peaceiris/actions-gh-pages@v4
+ - name: Upload artifact
+ if: ${{ always() }}
+ uses: actions/upload-pages-artifact@v3
with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ./Kiss.Bff.EndToEndTest/bin/Debug/net8.0/playwright-traces # directory of your reports
- publish_branch: gh-pages/e2e # deploying to gh-pages branch
\ No newline at end of file
+ # directory of your reports
+ path: './Kiss.Bff.EndToEndTest/bin/Debug/net8.0/playwright-traces'
+ deploy:
+ if: ${{ always() && github.ref == 'refs/heads/main' && github.event_name != 'pull_request' }}
+ needs: test
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
\ No newline at end of file
diff --git a/Kiss.Bff.EndToEndTest/Helpers/AcceptAllDialogs.cs b/Kiss.Bff.EndToEndTest/Helpers/AcceptAllDialogs.cs
new file mode 100644
index 00000000..a421fe72
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/Helpers/AcceptAllDialogs.cs
@@ -0,0 +1,19 @@
+namespace Kiss.Bff.EndToEndTest.Helpers
+{
+ public static class AcceptAllDialogsExtension
+ {
+ public static IDisposable AcceptAllDialogs(this IPage page)
+ {
+ page.Dialog += Accept;
+ return new DoOnDispose(() => page.Dialog -= Accept);
+ }
+
+ private static async void Accept(object? _, IDialog dialog) => await dialog.AcceptAsync();
+
+
+ private sealed class DoOnDispose(Action action) : IDisposable
+ {
+ public void Dispose() => action();
+ }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/Helpers/Pagination.cs b/Kiss.Bff.EndToEndTest/Helpers/Pagination.cs
new file mode 100644
index 00000000..f2b0c084
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/Helpers/Pagination.cs
@@ -0,0 +1,25 @@
+namespace Kiss.Bff.EndToEndTest.Helpers
+{
+ internal static class Pagination
+ {
+ public static ILocator GetCurrentPageLink(this ILocator locator) => locator.Locator("[aria-current=page]").First;
+ public static ILocator GetNextPageLink(this ILocator locator) => locator.Locator("[rel='next']").First;
+ public static ILocator GetPreviousPageLink(this ILocator locator) => locator.Locator("[rel='prev']").First;
+ public static async Task IsDisabledPageLink(this ILocator locator)
+ {
+ await locator.WaitForAsync();
+
+ var classes = await locator.GetAttributeAsync("class");
+ if (classes == null) return false;
+ // when the page is disabled it doesn't get a disabled attribute.
+ // TODO: research if there is a better pattern for this that is compatible with the den haag pagination component:
+ // https://nl-design-system.github.io/denhaag/?path=/docs/react-navigation-pagination--docs
+ // Note that their component renders invalid html: a button with a rel attribute.
+ // this might serve as a source of inspiration:
+ // https://design.homeoffice.gov.uk/components?name=Pagination
+ // https://design-system.w3.org/components/pagination.html
+ return classes.Contains("denhaag-pagination__link--disabled")
+ || classes.Contains("denhaag-pagination__link--current");
+ }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/Infrastructure/BaseTestInitializer.cs b/Kiss.Bff.EndToEndTest/Infrastructure/BaseTestInitializer.cs
deleted file mode 100644
index 87438247..00000000
--- a/Kiss.Bff.EndToEndTest/Infrastructure/BaseTestInitializer.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using Microsoft.Extensions.Configuration;
-
-
-namespace Kiss.Bff.EndToEndTest
-{
- [TestClass]
- public class BaseTestInitializer : PageTest
- {
- private const string StoragePath = "./auth.json";
-
- private static readonly IConfiguration s_configuration = new ConfigurationBuilder()
- .AddUserSecrets()
- .AddEnvironmentVariables()
- .Build();
-
- private static readonly UniqueOtpHelper s_uniqueOtpHelper = new(GetRequiredConfig("TestSettings:TEST_TOTP_SECRET"));
-
- [TestInitialize]
- public virtual async Task TestInitialize()
- {
- var username = GetRequiredConfig("TestSettings:TEST_USERNAME");
- var password = GetRequiredConfig("TestSettings:TEST_PASSWORD");
-
- await Context.Tracing.StartAsync(new()
- {
- Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
- Screenshots = true,
- Snapshots = true,
- Sources = true
- });
-
- var loginHelper = new AzureAdLoginHelper(Page, username, password, s_uniqueOtpHelper);
- await loginHelper.LoginAsync();
- await Context.StorageStateAsync(new() { Path = StoragePath });
- }
-
- [TestCleanup]
- public async Task TestCleanup()
- {
- var options = TestContext.CurrentTestOutcome != UnitTestOutcome.Passed
- ? new TracingStopOptions
- {
- Path = Path.Combine(
- Environment.CurrentDirectory,
- "playwright-traces",
- $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip"
- )
- }
- : null;
-
- await Context.Tracing.StopAsync(options);
- }
-
- public override BrowserNewContextOptions ContextOptions()
- {
- return new(base.ContextOptions())
- {
- BaseURL = GetRequiredConfig("TestSettings:TEST_BASE_URL"),
- // save auth state so we don't need to log in in every single test
- StorageStatePath = File.Exists(StoragePath) ? StoragePath : null,
- };
- }
-
- private static string GetRequiredConfig(string key)
- {
- var value = s_configuration[key];
- if (string.IsNullOrEmpty(value))
- {
- throw new InvalidOperationException($"'{key}' is missing from the configuration");
- }
- return value;
- }
- }
-}
diff --git a/Kiss.Bff.EndToEndTest/Infrastructure/KissPlaywrightTest.cs b/Kiss.Bff.EndToEndTest/Infrastructure/KissPlaywrightTest.cs
new file mode 100644
index 00000000..ce418a07
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/Infrastructure/KissPlaywrightTest.cs
@@ -0,0 +1,155 @@
+using System.Collections.Concurrent;
+using System.Text.Encodings.Web;
+using Microsoft.Extensions.Configuration;
+
+
+namespace Kiss.Bff.EndToEndTest
+{
+ ///
+ /// Inherit this class in each test class. This does the following:
+ /// 1. Makes sure the user is logged in before each test starts
+ /// 2. Makes sure Playwright records traces for each test
+ /// 3. Exposes a method to define test steps. These show up in the Playwright traces and in the test report.
+ /// 4. Builds a html test report after all tests in a test class are done.
+ /// We upload these to github pages
+ ///
+ [TestClass]
+ public class KissPlaywrightTest : PageTest
+ {
+ private const string StoragePath = "./auth.json";
+
+ private static readonly IConfiguration s_configuration = new ConfigurationBuilder()
+ .AddUserSecrets()
+ .AddEnvironmentVariables()
+ .Build();
+
+ private static readonly UniqueOtpHelper s_uniqueOtpHelper = new(GetRequiredConfig("TestSettings:TEST_TOTP_SECRET"));
+
+ // this is used to build a test report for each test
+ private static readonly ConcurrentDictionary s_testReports = [];
+
+ private readonly List _steps = [];
+
+ ///
+ /// This is run before each test
+ ///
+ ///
+ [TestInitialize]
+ public virtual async Task TestInitialize()
+ {
+ // log in with azure ad
+ var username = GetRequiredConfig("TestSettings:TEST_USERNAME");
+ var password = GetRequiredConfig("TestSettings:TEST_PASSWORD");
+
+ var loginHelper = new AzureAdLoginHelper(Page, username, password, s_uniqueOtpHelper);
+ await loginHelper.LoginAsync();
+ // store the cookie so we stay logged in in each test
+ await Context.StorageStateAsync(new() { Path = StoragePath });
+
+ // start tracing. we do this AFTER logging in so the password doesn't end up in the tracing
+ await Context.Tracing.StartAsync(new()
+ {
+ Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
+ Screenshots = true,
+ Snapshots = true,
+ Sources = true,
+ });
+ }
+
+ ///
+ /// Start a test step. This ends up in the test report and as group in the playwright tracing
+ ///
+ ///
+ ///
+ protected async Task Step(string description)
+ {
+ await Context.Tracing.GroupEndAsync();
+ await Context.Tracing.GroupAsync(description);
+ _steps.Add(description);
+ }
+
+ ///
+ /// This is run after each test
+ ///
+ ///
+ [TestCleanup]
+ public async Task TestCleanup()
+ {
+ // if we are in a group, end it
+ await Context.Tracing.GroupEndAsync();
+ var fileName = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip";
+ var fullPath = Path.Combine(Environment.CurrentDirectory, "playwright-traces", fileName);
+
+ // stop tracing and save a zip file in the output directory
+ await Context.Tracing.StopAsync(new()
+ {
+ Path = fullPath
+ });
+
+ // build a html report containing the test steps and a link to the playwright traces viewer
+ var html = $"""
+
+ """;
+
+ s_testReports.TryAdd(TestContext.TestName!, html);
+ }
+
+ ///
+ /// This is run after all tests in a test class are done
+ ///
+ ///
+ [ClassCleanup(InheritanceBehavior.BeforeEachDerivedClass)]
+ public static async Task ClassCleanup()
+ {
+ // combine the reports for each test in a single html file
+ var html = $$"""
+
+
+
+
+
+
+ Playwright traces
+
+
+
+
+
+ {{string.Join("", s_testReports.OrderBy(x=> x.Key).Select(x=> x.Value))}}
+
+
+ """;
+
+ using var writer = File.CreateText(Path.Combine(Environment.CurrentDirectory, "playwright-traces", "index.html"));
+ await writer.WriteLineAsync(html);
+ }
+
+ private static string GetRequiredConfig(string key)
+ {
+ var value = s_configuration[key];
+ if (string.IsNullOrEmpty(value))
+ {
+ throw new InvalidOperationException($"'{key}' is missing from the configuration");
+ }
+ return value;
+ }
+
+ public override BrowserNewContextOptions ContextOptions()
+ {
+ return new(base.ContextOptions())
+ {
+ BaseURL = GetRequiredConfig("TestSettings:TEST_BASE_URL"),
+ // save auth state so we don't need to log in in every single test
+ StorageStatePath = File.Exists(StoragePath) ? StoragePath : null,
+ };
+ }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/Kiss.Bff.EndToEndTest.csproj b/Kiss.Bff.EndToEndTest/Kiss.Bff.EndToEndTest.csproj
index ea08e376..5af80391 100644
--- a/Kiss.Bff.EndToEndTest/Kiss.Bff.EndToEndTest.csproj
+++ b/Kiss.Bff.EndToEndTest/Kiss.Bff.EndToEndTest.csproj
@@ -1,4 +1,4 @@
-
+net8.0
@@ -12,12 +12,12 @@
-
-
-
-
-
-
+
+
+
+
+
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies.cs
deleted file mode 100644
index d62bd682..00000000
--- a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies.cs
+++ /dev/null
@@ -1,544 +0,0 @@
-namespace Kiss.Bff.EndToEndTest;
-
-[TestClass]
-public class NieuwsEnWerkInstructies : BaseTestInitializer
-{
- //[TestMethod]
- //public async Task Als_ik_op_de_paginering_links_klik_navigeer_ik_naar_een_nieuwe_pagina()
- //{
- // // Locate the 'Nieuws' section
- // await Expect(NieuwsSection).ToBeVisibleAsync();
-
- // // Locate the 'Next' page button using the pagination structure
- // var nextPageButton = NieuwsSection.Locator("[rel='next']").First;
-
- // await Expect(nextPageButton).ToBeVisibleAsync();
-
- // // Click the 'Next' page button
- // await nextPageButton.ClickAsync();
-
- // // Wait for the button to ensure the page navigation has started
- // await nextPageButton.WaitForAsync();
-
- // // Verify that the first page button is still visible after navigation
- // var firstPageButton = NieuwsSection.GetByLabel("Pagina 1");
- // // TODO fix the pagination component. numbers should always have an aria label with the number in it
- // //await Expect(firstPageButton).ToBeVisibleAsync();
-
- // // Verify that the current page button reflects the correct page number
- // var currentPageButton = NieuwsSection.Locator("[aria-current=page]");
- // var page2Button = NieuwsSection.GetByLabel("Pagina 2");
- // var page2ButtonWithAriaCurrentPage = currentPageButton.And(page2Button);
-
- // // Ensure the current page button's aria-label attribute is 'Pagina 2'
- // await Expect(page2ButtonWithAriaCurrentPage).ToBeVisibleAsync();
- //}
-
-
- //[TestMethod]
- //public async Task Als_ik_skill_filters_selecteer_worden_de_nieuwberichten_hierop_gefilterd()
- //{
- // // Example: Test filtering by skill
- // var categorieFilterSection = Page.Locator("details").Filter(new() { HasText = "Filter op categorie" });
- // await Expect(categorieFilterSection).ToBeVisibleAsync();
- // await categorieFilterSection.Locator("summary").ClickAsync();
- // var algemeenCheckbox = categorieFilterSection.GetByRole(AriaRole.Checkbox, new() { Name = "Algemeen" });
- // var belastingenCheckbox = categorieFilterSection.GetByRole(AriaRole.Checkbox, new() { Name = "Belastingen" });
-
- // await algemeenCheckbox.CheckAsync();
- // await belastingenCheckbox.CheckAsync();
-
- // // Verify results are filtered
- // var articles = Page.GetByRole(AriaRole.Article);
- // await Expect(articles.First).ToBeVisibleAsync();
-
- // var resultCount = await articles.CountAsync();
-
- // Assert.IsTrue(resultCount > 0, "Expected to find articles after filtering by skills.");
-
- // // Loop through each article and verify it contains at least one of the selected skills
- // for (var i = 0; i < resultCount; i++)
- // {
- // var article = articles.Nth(i);
- // var algemeenSkill = article.Locator("small.category-Algemeen");
- // var belastingenSkill = article.Locator("small.category-Belastingen");
- // await Expect(algemeenSkill.Or(belastingenSkill).First).ToBeVisibleAsync();
- // }
-
- // // Reset filters
- // await algemeenCheckbox.UncheckAsync();
- // await belastingenCheckbox.UncheckAsync();
- //}
-
- // Dit test Stap 2. 8. 9. 10. 15.
- [TestMethod]
- public async Task Als_ik_een_oud_bericht_update_komt_deze_bovenaan()
- {
- try
- {
- // Check if old test messages exist
- var oldTestMessageLocator = Page.Locator("article:has-text('8e600d44-81fb-4302-9675-31b687619026')");
- if (await oldTestMessageLocator.IsVisibleAsync())
- {
- await DeleteBericht("8e600d44-81fb-4302-9675-31b687619026");
- await DeleteBericht("724e44a3-6ba1-4e92-85c3-d44e35238f4a");
- await DeleteBericht("5b8277a7-fb1a-4358-8099-24b9487b29bc");
- }
-
-
- // Step 2: Create Message A with the publish date one minute in the past
- await CreateBericht("Message A: 8e600d44-81fb-4302-9675-31b687619026", false, "", TimeSpan.FromMinutes(-1));
-
- // Create Message B and C with the current publish date
- await CreateBericht("Message B: 724e44a3-6ba1-4e92-85c3-d44e35238f4a", false, "");
- await CreateBericht("Important Message C: 5b8277a7-fb1a-4358-8099-24b9487b29bc", true, "");
-
- // Go to the page and retrieve the order of articles
- await Page.GotoAsync("/");
-
- await Page.WaitForSelectorAsync("article:has-text('Message A')");
- await Page.WaitForSelectorAsync("article:has-text('Message B')");
- await Page.WaitForSelectorAsync("article:has-text('Message C')");
-
- var allArticles = NieuwsSection.GetByRole(AriaRole.Article);
-
- // Dictionary to hold article positions
- var initialOrderOnPage = new Dictionary();
-
- for (var index = 0; index < await allArticles.CountAsync(); index++)
- {
- var element = allArticles.Nth(index);
- var innerHtml = await element.InnerTextAsync();
-
- if (innerHtml.Contains("Message A: 8e600d44-81fb-4302-9675-31b687619026"))
- {
- initialOrderOnPage.Add("Message A", index);
- }
- if (innerHtml.Contains("Message B: 724e44a3-6ba1-4e92-85c3-d44e35238f4a"))
- {
- initialOrderOnPage.Add("Message B", index);
- }
- if (innerHtml.Contains("Message C: 5b8277a7-fb1a-4358-8099-24b9487b29bc"))
- {
- initialOrderOnPage.Add("Message C", index);
- }
- }
-
- var indexVanA = initialOrderOnPage["Message A"];
- var indexVanB = initialOrderOnPage["Message B"];
- var indexVanC = initialOrderOnPage["Message C"];
-
- Assert.IsTrue(indexVanC < indexVanB && indexVanB < indexVanA, "Initial order should be C, B, A.");
-
- // Act: Update message A
- await UpdateBericht("Message A: 8e600d44-81fb-4302-9675-31b687619026", "Updated Message A: 8e600d44-81fb-4302-9675-31b687619026");
-
- // Refresh page and retrieve articles again
- await Page.GotoAsync("/");
-
- await Page.WaitForSelectorAsync("article:has-text('Message A')");
- await Page.WaitForSelectorAsync("article:has-text('Message B')");
- await Page.WaitForSelectorAsync("article:has-text('Message C')");
-
- allArticles = NieuwsSection.GetByRole(AriaRole.Article);
-
- // Rebuild the dictionary for updated positions
- var orderOnPageAfterMessageUpdate = new Dictionary();
- for (var index = 0; index < await allArticles.CountAsync(); index++)
- {
- var element = allArticles.Nth(index);
- var innerHtml = await element.InnerTextAsync();
-
- if (innerHtml.Contains("Updated Message A: 8e600d44-81fb-4302-9675-31b687619026"))
- {
- orderOnPageAfterMessageUpdate.Add("Message A", index);
- }
- if (innerHtml.Contains("Message B: 724e44a3-6ba1-4e92-85c3-d44e35238f4a"))
- {
- orderOnPageAfterMessageUpdate.Add("Message B", index);
- }
- if (innerHtml.Contains("Message C: 5b8277a7-fb1a-4358-8099-24b9487b29bc"))
- {
- orderOnPageAfterMessageUpdate.Add("Message C", index);
- }
- }
-
- // Assert the updated order: C (highest), B, A (lowest)
- indexVanA = orderOnPageAfterMessageUpdate["Message A"];
- indexVanB = orderOnPageAfterMessageUpdate["Message B"];
- indexVanC = orderOnPageAfterMessageUpdate["Message C"];
-
- Assert.IsTrue(indexVanC < indexVanB && indexVanB > indexVanA, "Updated order should be C, A, B.");
- }
- finally
- {
- // Clean up test messages
- await DeleteBericht("8e600d44-81fb-4302-9675-31b687619026");
- await DeleteBericht("724e44a3-6ba1-4e92-85c3-d44e35238f4a");
- await DeleteBericht("5b8277a7-fb1a-4358-8099-24b9487b29bc");
- }
- }
-
- // 9. Publiceer een bericht met markering Belangrijk
- [TestMethod]
- public async Task Als_ik_een_belangrijk_bericht_publiceer_komt_deze_bovenaan()
- {
- var titel = $"End to end test {Guid.NewGuid()}";
- // Step 1: Get the initial featured indicator count
- var initialFeatureCount = await GetFeaturedCount();
-
- // Step 2: Create a new important message
- await CreateBericht(titel, true, "");
-
- try
- {
- // Step 3: Go to the page and ensure the news section is visible
- await Page.GotoAsync("/");
-
- await Expect(NieuwsSection).ToBeVisibleAsync();
-
- // Step 4: Check if the newly created important message appears at the top
- var firstArticle = NieuwsSection.GetByRole(AriaRole.Article).First;
- await Expect(firstArticle).ToContainTextAsync(titel);
- var isBelangrijk = await firstArticle.Locator(".featured").IsVisibleAsync();
-
- // Ensure the first article contains "Belangrijk" only if it's supposed to
- if (isBelangrijk)
- {
- await Expect(firstArticle.Locator(".featured")).ToContainTextAsync("Belangrijk");
- }
- else
- {
- Console.WriteLine("This article does not contain the 'Belangrijk' tag.");
- }
-
- // Step 5: Get the new featured count
- var updatedCount = await GetFeaturedCount();
- Assert.IsTrue(updatedCount >= initialFeatureCount + 1, $"Expected featured count to be at least {initialFeatureCount + 1}, but got {updatedCount}");
-
- // Step 6: Mark the article as read
- await firstArticle.GetByRole(AriaRole.Button, new() { Name = "Markeer als gelezen" }).ClickAsync();
-
- // Step 7: Validate that the featured count is now back to the initial count
- var reUpdatedCount = await GetFeaturedCount();
- Assert.IsTrue(reUpdatedCount == initialFeatureCount, $"Expected featured count to be equal to the initial count {initialFeatureCount} again, but instead got {reUpdatedCount}");
- }
- finally
- {
- // Step 8: Clean up by deleting the created message
- await DeleteBericht(titel);
- }
- }
-
- private async Task GetFeaturedCount()
- {
- // Declare featuredIndicator outside the try block so it's accessible throughout the method
- var featuredIndicator = Page.Locator(".featured-indicator");
- await Page.WaitForResponseAsync(x => x.Url.Contains("featuredcount"));
- if (await featuredIndicator.IsVisibleAsync())
- {
- var featureText = await featuredIndicator.TextContentAsync();
- return int.Parse(featureText!);
- }
- return 0;
- }
-
-
- // This test covers Step 12. 13. 14.
- [TestMethod]
- public async Task Als_ik_een_skill_toevoeg_wordt_deze_vermeld_in_de_filter()
- {
- // Define the new skill name to be added and tested
- var newSkill = "Playwright Test Skill";
-
- try
- {
- // Step 1: Navigate to the Skills management page
- await NavigateToSkillsBeheer();
-
- // Step 2: Add the new skill
- await CreateSkill(newSkill);
- await Page.GotoAsync("/");
- // Step 3: Open the filter dropdown to verify the skill
- await Page.ClickAsync("summary:has-text('Filter op categorie')");
-
- // Step 4: Verify the newly added skill appears in the filter list as a checkbox option
- var addedSkillCheckbox = Page.GetByRole(AriaRole.Checkbox, new() { Name = newSkill }).First;
- await Expect(addedSkillCheckbox).ToBeVisibleAsync();
-
- }
- finally
- {
- // clean-up: Remove the skill after test completion
- await DeleteSkill(newSkill);
- }
- }
-
- //// Made private because the test isn't done yet, this is just a stepping stone made with the playwright editor
- //[TestMethod]
- //public async Task Als_ik_een_skill_en_nieuws_item_toevoeg_zou_ik_deze_moeten_zien_bij_filteren()
- //{
- // var newSkill = "Test Skill";
- // var newsTitle = "Test Nieuws Item";
- // bool isImportant = false;
-
- // try
- // {
- // // Step 1: Create a new skill
- // await CreateSkill(newSkill);
-
- // // Step 2: Create a news item with the new skill
- // await CreateBericht(newsTitle, isImportant, newSkill);
-
- // // Step 3: Verify that the news item appears when filtering by the new skill
- // await Page.GotoAsync("/");
-
- // await Page.ClickAsync("summary:has-text('Filter op categorie')"); // Open the filter dropdown
- // var skillCheckbox = Page.GetByRole(AriaRole.Checkbox, new() { Name = newSkill }).First;
- // await skillCheckbox.CheckAsync(); // Check the skill in the filter
-
- // // Step 4: Verify the news item appears
- // await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = newsTitle })).ToBeVisibleAsync();
- // }
- // finally
- // {
- // await DeleteBericht(newsTitle);
- // await DeleteSkill(newSkill);
- // }
- //}
-
- private ILocator NieuwsSection => Page.Locator("section").Filter(new() { HasText = "Nieuws" });
-
- private async Task MarkAllNewsItems(bool read)
- {
- // Locate the 'Nieuws' section
- await Expect(NieuwsSection).ToBeVisibleAsync();
-
- var firstGelezenButton = NieuwsSection.GetByTitle("Markeer als gelezen").First;
- var firstOnGelezenButton = NieuwsSection.GetByTitle("Markeer als ongelezen").First;
-
- var buttonToClick = read
- ? firstGelezenButton
- : firstOnGelezenButton;
-
- var firstPage = NieuwsSection.GetByRole(AriaRole.Link).Filter(new() { HasTextRegex = new("^1$") });
-
- if (!await IsDisabledPage(firstPage))
- {
- await firstPage.ClickAsync();
- }
-
- while (true)
- {
- await Expect(firstOnGelezenButton.Or(firstGelezenButton).First).ToBeVisibleAsync();
-
- // Mark all news items as read on the current page
- while (await buttonToClick.IsVisibleAsync())
- {
- await buttonToClick.ClickAsync();
- }
-
- var nextPage = NieuwsSection.Locator("[rel='next']").First;
-
- if (await IsDisabledPage(nextPage))
- {
- break;
- }
-
- await nextPage.ClickAsync();
- }
-
- if (!await IsDisabledPage(firstPage))
- {
- await firstPage.ClickAsync();
- }
- }
-
- private async Task NavigateToNieuwsWerkinstructiesBeheer()
- {
- var beheerlink = Page.GetByRole(AriaRole.Link, new() { Name = "Beheer" });
- var berichtenlink = Page.GetByRole(AriaRole.Link, new() { Name = "Nieuws en werkinstructies" });
-
- await Expect(beheerlink.Or(berichtenlink).First).ToBeVisibleAsync();
-
- if (await beheerlink.IsVisibleAsync())
- {
- await beheerlink.ClickAsync();
- }
-
- await Expect(beheerlink).ToBeVisibleAsync(new() { Visible = false });
-
- if (await berichtenlink.GetAttributeAsync("aria-current") != "page")
- {
- await berichtenlink.ClickAsync();
- }
- }
-
- private async Task NavigateToSkillsBeheer()
- {
- var beheerlink = Page.GetByRole(AriaRole.Link, new() { Name = "Beheer" });
- var skillslink = Page.GetByRole(AriaRole.Link, new() { Name = "Skills" });
-
- await Expect(beheerlink.Or(skillslink).First).ToBeVisibleAsync();
-
- if (await beheerlink.IsVisibleAsync())
- {
- await beheerlink.ClickAsync();
- }
-
- await Expect(beheerlink).ToBeVisibleAsync(new() { Visible = false });
-
- if (await skillslink.GetAttributeAsync("aria-current") != "page")
- {
- await skillslink.ClickAsync();
- }
- }
-
- private async Task CreateBericht(string titel, bool isBelangrijk, string skill, TimeSpan? publishDateOffset = null)
- {
- await NavigateToNieuwsWerkinstructiesBeheer();
- var toevoegenLink = Page.GetByRole(AriaRole.Link, new() { Name = "Toevoegen" });
- await toevoegenLink.ClickAsync();
- await Page.GetByRole(AriaRole.Radio, new() { Name = "Nieuws" }).CheckAsync();
-
- await Page.GetByRole(AriaRole.Textbox, new() { Name = "Titel" }).FillAsync(titel);
-
- // Fill in the content area
- await Page.Locator(".ck-content").WaitForAsync();
- await Page.Locator("textarea").FillAsync(titel);
-
- if (isBelangrijk)
- {
- await Page.GetByRole(AriaRole.Checkbox, new() { Name = "Belangrijk" }).CheckAsync();
- }
-
- if (!string.IsNullOrEmpty(skill))
- {
- var skillCheckbox = Page.GetByRole(AriaRole.Checkbox, new() { Name = skill });
- await skillCheckbox.CheckAsync(); // Ensure the skill checkbox is checked
- }
-
- // Use the current time as the base publish date
- DateTime publishDate = DateTime.Now;
-
- // Apply the provided offset to the publish date
- if (publishDateOffset.HasValue)
- {
- publishDate = publishDate.Add(publishDateOffset.Value);
- }
-
- // Set the publish date in the input field
- var publishDateInput = Page.Locator("#publicatieDatum");
- await publishDateInput.FillAsync(publishDate.ToString("yyyy-MM-ddTHH:mm"));
-
- var opslaanKnop = Page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
- while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
- {
- await opslaanKnop.ClickAsync();
- }
-
- await Expect(Page.GetByRole(AriaRole.Table)).ToBeVisibleAsync();
- }
-
- private async Task UpdateBericht(string oldTitle, string newTitle)
- {
- // Navigate to the news management page
- await NavigateToNieuwsWerkinstructiesBeheer();
-
- // Find the news item by its old title
- var nieuwsRows = Page.GetByRole(AriaRole.Row)
- .Filter(new()
- {
- Has = Page.GetByRole(AriaRole.Cell, new() { Name = oldTitle, Exact = true })
- });
-
- // Click the "Details" link for the news item
- await nieuwsRows.GetByRole(AriaRole.Link, new() { Name = "Details" }).ClickAsync();
-
- // Update the title to the new one
- await Page.GetByLabel("Titel").FillAsync(newTitle);
-
- // Save the changes
- await Page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" }).ClickAsync();
- await Expect(Page.GetByRole(AriaRole.Table)).ToBeVisibleAsync();
- }
-
-
- private async Task DeleteBericht(string titel)
- {
- await NavigateToNieuwsWerkinstructiesBeheer();
- var nieuwsRows = Page.GetByRole(AriaRole.Row)
- .Filter(new()
- {
- Has = Page.GetByRole(AriaRole.Cell, new() { Name = "Nieuws" }).First
- })
- .Filter(new()
- {
- Has = Page.GetByRole(AriaRole.Cell, new() { Name = titel, Exact = false }).First
- });
-
- var deleteButton = nieuwsRows.GetByTitle("Verwijder").First;
-
- Page.Dialog += Accept;
- await deleteButton.ClickAsync();
- Page.Dialog -= Accept;
- await Expect(Page.GetByRole(AriaRole.Table)).ToBeVisibleAsync();
- }
-
- private async Task CreateSkill(string skillName)
- {
- // Step 1: Navigate to the "Skills" beheer page
- await NavigateToSkillsBeheer();
-
- // Step 2: Click on the "Toevoegen" button to add a new skill
- var toevoegenLink = Page.GetByRole(AriaRole.Link, new() { Name = "toevoegen" });
- await toevoegenLink.ClickAsync();
-
- // Step 3: Fill in the skill name in the input field
- await Page.GetByRole(AriaRole.Textbox, new() { Name = "Naam" }).FillAsync(skillName);
-
- // Step 4: Locate and click the "Opslaan" button to save the new skill
- var opslaanKnop = Page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
-
- // Ensure that the save button is visible and enabled before clicking
- while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
- {
- await opslaanKnop.ClickAsync();
- }
-
- // Step 5: Optionally verify that the new skill has been added
- await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Skills" })).ToBeVisibleAsync();
- }
-
- private async Task DeleteSkill(string skillName)
- {
- // Step 1: Navigate to the Skills management page
- await NavigateToSkillsBeheer();
-
- // Step 2: Locate the skill listitem by its name
- var skillLocator = Page.GetByRole(AriaRole.Listitem).Filter(new() { HasText = skillName });
-
- // Step 3: Locate the delete button within the listitem
- var deleteButton = skillLocator.GetByRole(AriaRole.Button).And(Page.GetByTitle("Verwijderen"));
-
- // Step 4: Click the delete button and accept the dialog
- Page.Dialog += Accept;
- await deleteButton.ClickAsync();
-
- // Step 5: Verify the skill is no longer present in the list
- await Expect(skillLocator).ToBeHiddenAsync();
- }
-
- static async void Accept(object? _, IDialog dialog) => await dialog.AcceptAsync();
-
- private async Task IsDisabledPage(ILocator locator)
- {
- await Expect(locator).ToBeVisibleAsync();
-
- var classes = await locator.GetAttributeAsync("class");
- if (classes == null) return false;
- // we always have a next page link, but sometimes it is disabled. TO DO: use disabled attribute so we don't have to rely on classes
- return classes.Contains("denhaag-pagination__link--disabled")
- || classes.Contains("denhaag-pagination__link--current");
- }
-}
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/CreateBericht.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/CreateBericht.cs
new file mode 100644
index 00000000..494e3e5c
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/CreateBericht.cs
@@ -0,0 +1,151 @@
+using Kiss.Bff.EndToEndTest.Helpers;
+
+namespace Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies.Helpers
+{
+ internal static class CreateBerichtExtension
+ {
+ public static async Task CreateBerichten(this IPage page, IEnumerable requests)
+ {
+ var berichten = new List();
+ async ValueTask Dispose()
+ {
+ if (berichten.Count == 0) return;
+ await page.Context.Tracing.GroupEndAsync();
+ await page.Context.Tracing.GroupAsync("Cleanup berichten");
+ await page.Context.Tracing.GroupAsync("Start cleanup");
+ foreach (var item in berichten)
+ {
+ try
+ {
+ await item.DisposeAsync();
+ }
+ catch (Exception)
+ {
+ }
+ }
+ await page.Context.Tracing.GroupEndAsync();
+ }
+ try
+ {
+ foreach (var item in requests)
+ {
+ var bericht = await page.CreateBericht(item);
+ berichten.Add(bericht);
+ }
+ return new DoOnDisposeAsync(Dispose);
+ }
+ catch (Exception)
+ {
+ await Dispose();
+ throw;
+ }
+ }
+
+ private class DoOnDisposeAsync(Func thingToDo) : IAsyncDisposable
+ {
+ public ValueTask DisposeAsync() => thingToDo();
+ }
+
+ public static async Task CreateBericht(this IPage page, CreateBerichtRequest request)
+ {
+ request = request with { Body = !string.IsNullOrWhiteSpace(request.Body) ? request.Body : request.Title };
+ await page.NavigateToNieuwsWerkinstructiesBeheer();
+ var toevoegenLink = page.GetByRole(AriaRole.Link, new() { Name = "Toevoegen" });
+ await toevoegenLink.ClickAsync();
+ await page.GetByRole(AriaRole.Radio, new() { Name = request.BerichtType.ToString() }).CheckAsync();
+
+ await page.GetByRole(AriaRole.Textbox, new() { Name = "Titel" }).FillAsync(request.Title);
+
+ await page.GetByRole(AriaRole.Textbox, new() { Name = "Rich Text Editor" }).FillAsync(request.Body);
+
+ if (request.IsImportant)
+ {
+ await page.GetByRole(AriaRole.Checkbox, new() { Name = "Belangrijk" }).CheckAsync();
+ }
+
+ if (!string.IsNullOrEmpty(request.Skill))
+ {
+ var skillCheckbox = page.GetByRole(AriaRole.Checkbox, new() { Name = request.Skill });
+ await skillCheckbox.CheckAsync(); // Ensure the skill checkbox is checked
+ }
+
+ // Use the current time as the base publish date
+ var publishDate = DateTime.Now;
+
+ // Apply the provided offset to the publish date
+ if (request.PublishDateOffset.HasValue)
+ {
+ publishDate = publishDate.Add(request.PublishDateOffset.Value);
+ }
+
+ // Set the publish date in the input field
+ var publishDateInput = page.GetByLabel("Publicatiedatum");
+ await publishDateInput.FillAsync(publishDate.ToString("yyyy-MM-ddTHH:mm"));
+
+ var opslaanKnop = page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
+ while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
+ {
+ await opslaanKnop.ClickAsync();
+ }
+
+ await page.GetByRole(AriaRole.Table).WaitForAsync();
+ return new(page)
+ {
+ IsImportant = request.IsImportant,
+ Title = request.Title,
+ PublishDateOffset = request.PublishDateOffset,
+ PublicatieDatum = publishDate,
+ PublicatieEinddatum = publishDate.AddYears(1),
+ Skill = request.Skill,
+ Body = request.Body,
+ BerichtType = request.BerichtType,
+ };
+ }
+ }
+
+ internal record class Bericht(IPage Page) : CreateBerichtRequest, IAsyncDisposable
+ {
+ public required new string Body { get; init; }
+ public DateTime PublicatieDatum { get; init; }
+ public DateTime PublicatieEinddatum { get; init; }
+ public async ValueTask DisposeAsync()
+ {
+ await Page.Context.Tracing.GroupEndAsync();
+ await Page.Context.Tracing.GroupAsync("Cleanup artikel");
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+ var nieuwsRows = Page.GetByRole(AriaRole.Row)
+ .Filter(new()
+ {
+ Has = Page.GetByRole(AriaRole.Cell, new() { Name = BerichtType.ToString() }).First
+ })
+ .Filter(new()
+ {
+ Has = Page.GetByRole(AriaRole.Cell, new() { Name = Title, Exact = true }).First
+ });
+
+ var deleteButton = nieuwsRows.GetByTitle("Verwijder").First;
+ using (var _ = Page.AcceptAllDialogs())
+ {
+ await deleteButton.ClickAsync();
+ }
+ await Page.GetByRole(AriaRole.Table).WaitForAsync();
+ }
+ }
+
+ internal enum BerichtType
+ {
+ Nieuws,
+ Werkinstructie
+ }
+
+ internal record class CreateBerichtRequest()
+ {
+ public required string Title { get; init; }
+ public virtual string? Body { get; init; }
+ public bool IsImportant { get; init; }
+ public string? Skill { get; init; }
+ public BerichtType BerichtType { get; init; } = BerichtType.Nieuws;
+
+ public TimeSpan? PublishDateOffset { get; init; }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/CreateSkill.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/CreateSkill.cs
new file mode 100644
index 00000000..323dbd94
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/CreateSkill.cs
@@ -0,0 +1,71 @@
+using Kiss.Bff.EndToEndTest.Helpers;
+
+namespace Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies.Helpers
+{
+ internal static class CreateSkillExtension
+ {
+
+ private class DoOnDisposeAsync(Func thingToDo) : IAsyncDisposable
+ {
+ public ValueTask DisposeAsync() => thingToDo();
+ }
+
+ public static async Task CreateSkill(this IPage page, string skillName)
+ {
+ // Step 1: Navigate to the "Skills" beheer page
+ await page.NavigateToSkillsBeheer();
+
+ // Step 2: Click on the "Toevoegen" button to add a new skill
+ var toevoegenLink = page.GetByRole(AriaRole.Link, new() { Name = "toevoegen" });
+ await toevoegenLink.ClickAsync();
+
+ // Step 3: Fill in the skill name in the input field
+ await page.GetByRole(AriaRole.Textbox, new() { Name = "Naam" }).FillAsync(skillName);
+
+ // Step 4: Locate and click the "Opslaan" button to save the new skill
+ var opslaanKnop = page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
+
+ // Ensure that the save button is visible and enabled before clicking
+ while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
+ {
+ await opslaanKnop.ClickAsync();
+ }
+
+ await page.GetByRole(AriaRole.Listitem).Filter(new () { HasText = skillName }).WaitForAsync();
+ return new(page)
+ {
+ Naam = skillName
+ };
+ }
+ }
+
+ internal record class Skill(IPage Page) : IAsyncDisposable
+ {
+ public required string Naam { get; init; }
+
+ public async ValueTask DisposeAsync()
+ {
+ await Page.Context.Tracing.GroupEndAsync();
+ await Page.Context.Tracing.GroupAsync("Cleanup skill");
+ // Step 1: Navigate to the Skills management page
+ await Page.NavigateToSkillsBeheer();
+
+ // Step 2: Locate the skill listitem by its name
+ var skillLocator = Page.GetByRole(AriaRole.Listitem).Filter(new() { HasText = Naam });
+
+ // Step 3: Locate the delete button within the listitem
+ var deleteButton = skillLocator.GetByRole(AriaRole.Button).And(skillLocator.GetByTitle("Verwijderen"));
+
+ // Step 4: Click the delete button and accept the dialog
+ using (var _ = Page.AcceptAllDialogs())
+ {
+ await deleteButton.ClickAsync();
+ }
+
+ // Step 5: Verify the skill is no longer present in the list
+ await Page.GetByRole(AriaRole.Heading, new () { Name = "Skills"}).WaitForAsync();
+ await skillLocator.WaitForAsync(new() { State = WaitForSelectorState.Hidden });
+ await Page.Context.Tracing.GroupEndAsync();
+ }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/FeaturedCount.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/FeaturedCount.cs
new file mode 100644
index 00000000..b39f9952
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/FeaturedCount.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies.Helpers
+{
+ internal static class FeaturedCount
+ {
+ public static async Task GetFeaturedCount(this IPage page)
+ {
+ // Declare featuredIndicator outside the try block so it's accessible throughout the method
+ var featuredIndicator = page.Locator(".featured-indicator");
+ await page.WaitForResponseAsync(x => x.Url.Contains("featuredcount"));
+ if (await featuredIndicator.IsVisibleAsync())
+ {
+ var featureText = await featuredIndicator.TextContentAsync();
+ return int.Parse(featureText!);
+ }
+ return 0;
+ }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/Locators.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/Locators.cs
new file mode 100644
index 00000000..8a06dc8a
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/Locators.cs
@@ -0,0 +1,26 @@
+namespace Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies.Helpers
+{
+ internal static class Locators
+ {
+ public static ILocator GetNieuwsSection(this IPage page) => page.Locator("section").Filter(new() { Has = page.GetByRole(AriaRole.Heading, new() { Name = "Nieuws" }) });
+ public static ILocator GetWerkinstructiesSection(this IPage page) => page.Locator("section").Filter(new() { Has = page.GetByRole(AriaRole.Heading, new() { Name = "Werkinstructies" }) });
+ public static ILocator GetBerichtOnHomePage(this IPage page, Bericht bericht) => page.GetByRole(AriaRole.Article).Filter(new() { Has = page.GetByRole(AriaRole.Heading, new() { Name = bericht.Title }) });
+ public static ILocator GetSummaryElement(this IPage page) => page.Locator("summary");
+ public static ILocator GetSkillsSummaryElement(this IPage page) => page.GetSummaryElement().Filter(new() { HasText = "Filter op categorie" });
+ public static ILocator GetSkillsFieldset(this IPage page) => page.GetByRole(AriaRole.Group, new() { Name = "Filter op categorie" });
+ public static ILocator GetWerkberichtTypeSelector(this IPage page) => page.Locator($"#werkbericht-type-input");
+ public static ILocator GetNieuwsAndWerkinstructiesSearch(this IPage page) => page.Locator($"#search-input");
+
+ public static ILocator GetSearchResult(this IPage page) => page.Locator("section").Filter(new() { Has = page.GetByRole(AriaRole.Heading, new() { Name = "Zoekresultaten" }) });
+ public static ILocator GetSearchResultFilteredByType(this IPage page,string type) => page.GetSearchResult().GetByRole(AriaRole.Article).Filter(new() { Has = page.Locator("small", new() { HasText = type }) });
+
+ public static ILocator GetBeheerRowByValue(this IPage page, string title) => page.GetByRole(AriaRole.Row)
+ .Filter(new()
+ {
+ Has = page.GetByRole(AriaRole.Cell, new() { Name = title, Exact = true }).First
+ });
+ public static ILocator GetBeheerTableCell(this IPage page, int col, int row) =>
+ page.Locator($"table tbody tr:nth-child({row}) td:nth-child({col})");
+
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/Navigation.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/Navigation.cs
new file mode 100644
index 00000000..7956b504
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/Helpers/Navigation.cs
@@ -0,0 +1,46 @@
+namespace Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies.Helpers
+{
+ internal static class Navigation
+ {
+ public static async Task NavigateToNieuwsWerkinstructiesBeheer(this IPage page)
+ {
+ var beheerlink = page.GetByRole(AriaRole.Link, new() { Name = "Beheer" });
+ var berichtenlink = page.GetByRole(AriaRole.Link, new() { Name = "Nieuws en werkinstructies" });
+
+ await beheerlink.Or(berichtenlink).First.WaitForAsync();
+
+ if (await beheerlink.IsVisibleAsync())
+ {
+ await beheerlink.ClickAsync();
+ }
+
+ await beheerlink.WaitForAsync(new() { State = WaitForSelectorState.Hidden });
+
+ if (await berichtenlink.GetAttributeAsync("aria-current") != "page")
+ {
+ await berichtenlink.ClickAsync();
+ await page.GetByRole(AriaRole.Heading, new() { Name = "Berichten" }).WaitForAsync();
+ }
+ }
+
+ public static async Task NavigateToSkillsBeheer(this IPage page)
+ {
+ var beheerlink = page.GetByRole(AriaRole.Link, new() { Name = "Beheer" });
+ var skillslink = page.GetByRole(AriaRole.Link, new() { Name = "Skills" });
+ await beheerlink.Or(skillslink).First.WaitForAsync();
+
+ if (await beheerlink.IsVisibleAsync())
+ {
+ await beheerlink.ClickAsync();
+ }
+
+ await beheerlink.WaitForAsync(new() { State = WaitForSelectorState.Hidden });
+
+ if (await skillslink.GetAttributeAsync("aria-current") != "page")
+ {
+ await skillslink.ClickAsync();
+ await page.GetByRole(AriaRole.Heading, new() { Name = "Skills" }).WaitForAsync();
+ }
+ }
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/NieuwsEnWerkInstructiesScenarios.cs b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/NieuwsEnWerkInstructiesScenarios.cs
new file mode 100644
index 00000000..887f76ea
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/NieuwsEnWerkInstructies/NieuwsEnWerkInstructiesScenarios.cs
@@ -0,0 +1,971 @@
+
+using Kiss.Bff.EndToEndTest.Helpers;
+using Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies.Helpers;
+
+namespace Kiss.Bff.EndToEndTest.NieuwsEnWerkInstructies;
+
+[TestClass]
+public class NieuwsEnWerkInstructiesScenarios : KissPlaywrightTest
+{
+ [TestMethod]
+ public async Task Scenario01()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+ await using var news = await Page.CreateBericht(new() { Title = "Playwright test nieuwsbericht", BerichtType = BerichtType.Nieuws });
+
+ await Step("And there is at least 1 werkinstructie");
+ await using var werkbericht = await Page.CreateBericht(new() { Title = "Playwright test werkinstructie", BerichtType = BerichtType.Werkinstructie });
+
+ await Step("When the user navigates to the HOME Page");
+ await Page.GotoAsync("/");
+
+ await Step("Then nieuwsberichten are displayed");
+ await Expect(Page.GetNieuwsSection().GetByRole(AriaRole.Article).First).ToBeVisibleAsync();
+
+ await Step("And werkinstructies are displayed");
+ await Expect(Page.GetWerkinstructiesSection().GetByRole(AriaRole.Article).First).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario02()
+ {
+ await Step("Given there is at least 1 important message");
+ await using var testbericht = await Page.CreateBericht(new() { Title = "Playwright test bericht belangrijk", IsImportant = true });
+
+ await Step("When navigates to the HOME Page");
+ await Page.GotoAsync("/");
+
+ await Step("Then the count of the important messages is displayed in the News and Instructions tabs.");
+ var count = await Page.GetFeaturedCount();
+ Assert.AreNotEqual(0, count);
+ }
+
+ [TestMethod]
+ public async Task Scenario03()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+ await using var testbericht = await Page.CreateBericht(new() { Title = "Playwright test bericht", Body = "Inhoud die we gaan verbergen" });
+ var article = Page.GetBerichtOnHomePage(testbericht);
+ var markeerGelezenButton = article.GetByRole(AriaRole.Button).And(article.GetByTitle("Markeer als gelezen"));
+ var markeerOngelezenButton = article.GetByRole(AriaRole.Button).And(article.GetByTitle("Markeer als ongelezen"));
+ var body = article.GetByText(testbericht.Body!);
+
+ await Step("When the user navigates to the HOME Page");
+ await Page.GotoAsync("/");
+
+ await Step("And clicks on the book icon within the nieuwsbericht card");
+ await markeerGelezenButton.ClickAsync();
+
+ await Step("Then the button title on hover changes to 'markeer ongelezen'");
+ await Expect(markeerGelezenButton).ToBeHiddenAsync();
+ await Expect(markeerOngelezenButton).ToBeVisibleAsync();
+
+ await Step("And the body of the nieuwsbericht is hidden");
+ await Expect(body).ToBeHiddenAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario04()
+ {
+ var newsArticles = Page.GetNieuwsSection().GetByRole(AriaRole.Article);
+
+ await Step("Given there are at least 20 nieuwsberichten");
+ var berichtRequests = Enumerable.Range(1, 20)
+ .Select(x => new CreateBerichtRequest
+ {
+ Title = "Playwright test bericht" + x
+ });
+ await using var berichten = await Page.CreateBerichten(berichtRequests);
+
+ await Step("When the user navigates to the HOME Page");
+ await Page.GotoAsync("/");
+
+ var initialFirstArticleAriaSnapshot = await newsArticles.First.AriaSnapshotAsync();
+
+ await Step("And clicks on the \"Next page\" button for the 'Nieuws' section to go to the next page");
+ var nextPageButton = Page.GetNieuwsSection().GetNextPageLink();
+ await nextPageButton.ClickAsync();
+
+ await Step("Then the user should see 10 new articles on the next page");
+ await Expect(newsArticles).ToHaveCountAsync(10);
+ await Expect(newsArticles.First).Not.ToMatchAriaSnapshotAsync(initialFirstArticleAriaSnapshot);
+
+ await Step("And the current page number should be 2");
+ var currentPageButton = Page.GetNieuwsSection().GetCurrentPageLink();
+ var page2Button = Page.GetNieuwsSection().GetByLabel("Pagina 2");
+ var aButtonThatIsTheCurrentPageAndHasLabelPagina2 = currentPageButton.And(page2Button);
+ await Expect(aButtonThatIsTheCurrentPageAndHasLabelPagina2).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario05()
+ {
+ var newSection = Page.GetNieuwsSection();
+ var newsArticles = Page.GetNieuwsSection().GetByRole(AriaRole.Article);
+
+ await Step("Given there are at least 20 nieuwsberichten");
+ var berichtRequests = Enumerable.Range(1, 20)
+ .Select(x => new CreateBerichtRequest
+ {
+ Title = "Playwright test bericht" + x
+ });
+ await using var berichten = await Page.CreateBerichten(berichtRequests);
+
+ await Step("And the user is on the HOME page");
+ await Page.GotoAsync("/");
+ await Expect(Page.GetNieuwsSection()).ToBeVisibleAsync();
+
+ // Locate the 'Next' page button using the pagination structure
+ await Step("And is on page 2 with 10 articles displayed");
+ var nextPageButton = Page.GetNieuwsSection().GetNextPageLink();
+ await nextPageButton.ClickAsync();
+ await Expect(newsArticles).ToHaveCountAsync(10);
+
+ var intialAriaSnapshot = await newsArticles.First.AriaSnapshotAsync();
+
+ await Step("When the user clicks on the \"Previous\" button for the 'Nieuws' section to go to the next page");
+ var previousPageButton = Page.GetNieuwsSection().GetPreviousPageLink();
+ await previousPageButton.ClickAsync();
+
+ await Step("Then the user should see 10 different articles on the first page");
+ await Expect(newsArticles).ToHaveCountAsync(10);
+ await Expect(newsArticles.First).Not.ToMatchAriaSnapshotAsync(intialAriaSnapshot);
+
+ await Step("And the current page number should be 1");
+ var currentPageButton = Page.GetNieuwsSection().GetCurrentPageLink();
+ var page1Button = Page.GetNieuwsSection().GetByLabel("Pagina 1");
+ var aButtonThatIsTheCurrentPageAndHasLabelPagina1 = currentPageButton.And(page1Button);
+ await Expect(aButtonThatIsTheCurrentPageAndHasLabelPagina1).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario06()
+ {
+ await Step("Given there are at least 20 werkinstructies");
+ var berichtRequests = Enumerable.Range(1, 20)
+ .Select(x => new CreateBerichtRequest
+ {
+ Title = "Playwright test bericht" + x,
+ BerichtType = BerichtType.Werkinstructie
+ });
+ await using var berichten = await Page.CreateBerichten(berichtRequests);
+ var articles = Page.GetWerkinstructiesSection().GetByRole(AriaRole.Article);
+
+ await Step("And the user is on the HOME Page");
+ await Page.GotoAsync("/");
+ await Expect(Page.GetWerkinstructiesSection()).ToBeVisibleAsync();
+
+ await Step("And is on page 2 with 10 werkinstructies displayed");
+ var nextPageButton = Page.GetWerkinstructiesSection().GetNextPageLink();
+ await nextPageButton.ClickAsync();
+ await Expect(articles).ToHaveCountAsync(10);
+
+ var intialFirstArticleAriaSnapshot = await articles.First.AriaSnapshotAsync();
+
+ await Step("When the user clicks on the \"Previous\" button for the 'Werkinstructies' section to go to the next page");
+ var previousPageButton = Page.GetWerkinstructiesSection().GetPreviousPageLink();
+ await previousPageButton.ClickAsync();
+
+ await Step("Then the user should see 10 different werkinstructies on the first page");
+ await Expect(articles).ToHaveCountAsync(10);
+ await Expect(articles.First).Not.ToMatchAriaSnapshotAsync(intialFirstArticleAriaSnapshot);
+
+ await Step("And the current page number should be 1");
+ var currentPageButton = Page.GetWerkinstructiesSection().GetCurrentPageLink();
+ var page1Button = Page.GetWerkinstructiesSection().GetByLabel("Pagina 1");
+ var aButtonThatIsTheCurrentPageAndHasLabelPagina1 = currentPageButton.And(page1Button);
+ await Expect(aButtonThatIsTheCurrentPageAndHasLabelPagina1).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario07()
+ {
+ await Step("Given there are at least 20 werkinstructies");
+ var berichtRequests = Enumerable.Range(1, 20)
+ .Select(x => new CreateBerichtRequest
+ {
+ Title = "Playwright test bericht" + x,
+ BerichtType = BerichtType.Werkinstructie
+ });
+
+ await using var berichten = await Page.CreateBerichten(berichtRequests);
+ var articles = Page.GetWerkinstructiesSection().GetByRole(AriaRole.Article);
+
+ await Step("And the user is on the HOME Page");
+ await Page.GotoAsync("/");
+ await Expect(Page.GetWerkinstructiesSection()).ToBeVisibleAsync();
+
+ // Locate the 'Next' page button using the pagination structure
+ var nextPageButton = Page.GetWerkinstructiesSection().GetNextPageLink();
+ var werkinstructies = Page.GetWerkinstructiesSection().GetByRole(AriaRole.Article);
+
+ await Step("And is on the last page of werkinstructies");
+
+ // keep clicking on the next page button until it's disabled
+ while (!await nextPageButton.IsDisabledPageLink())
+ {
+ await nextPageButton.ClickAsync();
+ await werkinstructies.First.WaitForAsync();
+ }
+
+ var initialFirstArticleAriaSnapshot = await articles.First.AriaSnapshotAsync();
+
+ await Step("When the user clicks on the \"Next\" button for the ‘Werkinstructies’ section");
+
+ await Assert.ThrowsExceptionAsync(
+ () => nextPageButton.ClickAsync(new() { Timeout = 1000 }),
+ "Expected the button to not be clickable, but it was");
+
+ await Step("Then the user remains on the last page");
+
+ await Step("And no additional werkinstructies are displayed");
+ await Expect(articles.First).ToMatchAriaSnapshotAsync(initialFirstArticleAriaSnapshot);
+ }
+
+ [TestMethod]
+ public async Task Scenario08()
+ {
+ await Step("Given there is a nieuwsbericht that is read");
+ await using var bericht = await Page.CreateBericht(new() { Title = "Bericht playwright gelezen/ongelezen", Body = "Text to look for" });
+ await Page.GotoAsync("/");
+ var article = Page.GetBerichtOnHomePage(bericht);
+ var articleBody = article.GetByText(bericht.Body);
+ var markeerGelezenButton = article.GetByRole(AriaRole.Button).And(article.GetByTitle("Markeer als gelezen"));
+ var markeerOngelezenButton = article.GetByRole(AriaRole.Button).And(article.GetByTitle("Markeer als ongelezen"));
+ var articleHeading = article.GetByRole(AriaRole.Heading);
+ await markeerGelezenButton.ClickAsync();
+ await Expect(articleBody).ToBeHiddenAsync();
+
+ await Step("And the user is on the HOME Page");
+ await Page.GotoAsync("/");
+
+ await Step("When the user clicks the 'Markeer als ongelezen' button");
+ await markeerOngelezenButton.ClickAsync();
+
+ await Step("Then content of the nieuwsbericht is visible");
+ await Expect(article).ToContainTextAsync(bericht.Body);
+ }
+
+ [TestMethod]
+ public async Task Scenario09()
+ {
+ await Step("Given there are at least two skills");
+ await using var skill1 = await Page.CreateSkill(Guid.NewGuid().ToString());
+ await using var skill2 = await Page.CreateSkill(Guid.NewGuid().ToString());
+
+ await Step("And there is exactly one nieuwsbericht related to the first skill");
+ await using var berichtWithSkill1 = await Page.CreateBericht(new CreateBerichtRequest { Title = Guid.NewGuid().ToString(), Skill = skill1.Naam });
+
+ await Step("And there is exactly one nieuwsbericht related to the second skill");
+ await using var berichtWithSkill2 = await Page.CreateBericht(new CreateBerichtRequest { Title = Guid.NewGuid().ToString() });
+
+ await Step("And there is at least one nieuwsbericht without a relation to any skill");
+ await using var berichtWithoutSkill = await Page.CreateBericht(new CreateBerichtRequest { Title = Guid.NewGuid().ToString(), Skill = skill2.Naam });
+
+ await Step("And the user is on the HOME Page");
+ await Page.GotoAsync("/");
+
+ await Step("When the user selects the first skill from the filter options");
+ await Page.GetSkillsSummaryElement().ClickAsync();
+ await Page.GetSkillsFieldset().GetByRole(AriaRole.Checkbox, new() { Name = skill1.Naam }).CheckAsync();
+
+ await Step("Then only the article related to the first skill is visible");
+ var articles = Page.GetNieuwsSection().GetByRole(AriaRole.Article);
+ await Expect(articles).ToHaveCountAsync(1);
+ await Expect(articles.GetByRole(AriaRole.Heading, new() { Name = berichtWithSkill1.Title })).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario10()
+ {
+ await Step("Given there is a skill that is not linked to any article");
+ await using var skill = await Page.CreateSkill(Guid.NewGuid().ToString());
+
+ await Step("And the user is on the HOME Page");
+ await Page.GotoAsync("/");
+
+ await Step("When the user selects the skill from the filter options");
+ await Page.GetSkillsSummaryElement().ClickAsync();
+ await Page.GetSkillsFieldset().GetByRole(AriaRole.Checkbox, new() { Name = skill.Naam }).CheckAsync();
+
+ await Step("Then no articles are visible");
+ // wait until the spinner is gone
+ await Expect(Page.Locator(".spinner")).ToBeHiddenAsync();
+ var articles = Page.GetByRole(AriaRole.Article);
+ await Expect(articles).ToBeHiddenAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario11()
+ {
+ await Step("Given a unique text (uuid)");
+
+ var uniqueTitle = Guid.NewGuid().ToString();
+
+ await Step("Given there is exactly 1 werkinstructie with this text in the title");
+
+ var werkbericht = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And there is exactly 1 nieuwsbericht with this text in the title");
+
+ var nieuws = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws });
+
+ await Step("And the user is on the HOME Page");
+
+ await Page.GotoAsync("/");
+
+ await Step("When the user selects 'Nieuws' from the filter dropdown");
+
+ await Page.GetWerkberichtTypeSelector().SelectOptionAsync("Nieuws");
+
+ await Step("And searches for the unique text");
+
+ await Page.GetNieuwsAndWerkinstructiesSearch().FillAsync(uniqueTitle);
+ await Page.GetNieuwsAndWerkinstructiesSearch().PressAsync("Enter");
+
+
+ await Step("Then exactly one news article should be displayed");
+
+ await Expect(Page.GetSearchResult().GetByRole(AriaRole.Article)).ToHaveCountAsync(1);
+
+ await Step("And no work instructions should be visible");
+
+ await Expect(Page.GetWerkinstructiesSection()).ToBeHiddenAsync();
+
+
+ }
+
+ [TestMethod]
+ public async Task Scenario12()
+ {
+ await Step("Given a unique text (uuid)");
+
+ var uniqueTitle = Guid.NewGuid().ToString();
+
+ await Step("Given there is exactly 1 werkinstructie with this text in the title");
+
+ await using var werkbericht = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And there is exactly 1 nieuwsbericht with this text in the title");
+
+ await using var nieuws = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws });
+
+ await Step("And the user is on the HOME Page");
+
+ await Page.GotoAsync("/");
+
+ await Step("When the user selects 'Werkinstructie' from the filter dropdown");
+
+ await Page.GetWerkberichtTypeSelector().SelectOptionAsync("Werkinstructie");
+
+ await Step("And searches for the unique text");
+
+ await Page.GetNieuwsAndWerkinstructiesSearch().FillAsync(uniqueTitle);
+ await Page.GetNieuwsAndWerkinstructiesSearch().PressAsync("Enter");
+
+ await Step("Then exactly 1 work instruction should be displayed");
+
+ await Expect(Page.GetSearchResult().GetByRole(AriaRole.Article)).ToHaveCountAsync(1);
+
+ await Step("And no news articles should be visible");
+
+ await Expect(Page.GetNieuwsSection()).ToBeHiddenAsync();
+
+ }
+
+ [TestMethod]
+ public async Task Scenario13()
+ {
+ await Step("Given there are at least 3 skills");
+
+ var skill1 = Guid.NewGuid().ToString();
+ var skill2 = Guid.NewGuid().ToString();
+ var skill3 = Guid.NewGuid().ToString();
+
+ await using var skillItem1 = await Page.CreateSkill(skill1);
+ await using var skillItem2 = await Page.CreateSkill(skill2);
+ await using var skillItem3 = await Page.CreateSkill(skill3);
+
+ await Step("And there is exactly one nieuwsbericht related to the first skill");
+
+ string uniqueTitle = Guid.NewGuid().ToString();
+ await using var nieuwsWithSkill1 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws, Skill = skill1 });
+
+
+ await Step("And there is exactly one werkinstructie related to the first skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var werkberichtWithSkill1 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie, Skill = skill1 });
+
+ await Step("And there is exactly one nieuwsbericht related to the second skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var nieuwsWithSkill2 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws, Skill = skill2 });
+
+ await Step("And there is exactly one werkinstructie related to the second skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var werkberichtWithSkill2 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie, Skill = skill2 });
+
+ await Step("And there is exactly one nieuwsbericht related to the third skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var nieuwsWithSkill3 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws, Skill = skill3 });
+
+ await Step("And there is exactly one werkinstructie related to the third skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var werkberichtWithSkill3 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie, Skill = skill3 });
+
+ await Step("And there is at least one nieuwsbericht without a relation to any skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var nieuwsWithSkill4 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws });
+
+ await Step("And there is at least one werkinstructie without a relation to any skill");
+
+ uniqueTitle = Guid.NewGuid().ToString();
+ await using var werkberichtWithSkill4 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And the user is on the HOME Page");
+
+ await Page.GotoAsync("/");
+
+ await Step("When the user selects the first skill from the filter options");
+
+ await Page.GetSkillsSummaryElement().ClickAsync();
+ await Page.GetSkillsFieldset().GetByRole(AriaRole.Checkbox, new() { Name = skill1 }).CheckAsync();
+
+
+ await Step("And the user selects the second skill from the filter options");
+
+ await Page.GetSkillsFieldset().GetByRole(AriaRole.Checkbox, new() { Name = skill2 }).CheckAsync();
+
+ await Step("Then only the two nieuwsberichten and werkinstructies related to the first and second skill are visible");
+
+ var nieuwsSection = Page.GetNieuwsSection();
+ var werkinstructiesSection = Page.GetWerkinstructiesSection();
+
+ await Expect(nieuwsSection.GetByRole(AriaRole.Article)).ToHaveCountAsync(2);
+ await Expect(nieuwsSection.GetByRole(AriaRole.Heading, new() { Name = nieuwsWithSkill1.Title })).ToBeVisibleAsync();
+ await Expect(nieuwsSection.GetByRole(AriaRole.Heading, new() { Name = nieuwsWithSkill2.Title })).ToBeVisibleAsync();
+ await Expect(nieuwsSection.GetByRole(AriaRole.Heading, new() { Name = nieuwsWithSkill3.Title })).ToBeHiddenAsync();
+
+ await Expect(werkinstructiesSection.GetByRole(AriaRole.Article)).ToHaveCountAsync(2);
+ await Expect(werkinstructiesSection.GetByRole(AriaRole.Heading, new() { Name = werkberichtWithSkill1.Title })).ToBeVisibleAsync();
+ await Expect(werkinstructiesSection.GetByRole(AriaRole.Heading, new() { Name = werkberichtWithSkill2.Title })).ToBeVisibleAsync();
+ await Expect(werkinstructiesSection.GetByRole(AriaRole.Heading, new() { Name = werkberichtWithSkill3.Title })).ToBeHiddenAsync();
+
+ }
+
+ [TestMethod]
+ public async Task Scenario14()
+ {
+ await Step("Given a unique text (uuid)");
+
+ var uniqueTitle = Guid.NewGuid().ToString();
+
+ await Step("Given there is exactly one nieuwsbericht with that text as the title");
+
+ await using var nieuwsbericht = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws });
+
+ await Step("And there is exactly one werkinstructie with that text as the title");
+
+ await using var werkinstructie = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And the user is on the HOME Page");
+
+ await Page.GotoAsync("/");
+
+ await Step("When the user selects 'Alle' from the filter dropdown");
+
+ await Page.GetWerkberichtTypeSelector().SelectOptionAsync("Alle");
+
+ await Step("And searches for the unique text");
+
+ await Page.GetNieuwsAndWerkinstructiesSearch().FillAsync(uniqueTitle);
+ await Page.GetNieuwsAndWerkinstructiesSearch().PressAsync("Enter");
+
+ await Step("Then exactly one nieuwsbericht and exactly one werkinstructie are visible");
+
+ await Expect(Page.GetSearchResultFilteredByType("Werkinstructie")).ToHaveCountAsync(1);
+ await Expect(Page.GetSearchResultFilteredByType("Nieuws")).ToHaveCountAsync(1);
+
+
+ }
+
+ [TestMethod]
+ public async Task Scenario15()
+ {
+ await Step("Given a unique text (uuid)");
+
+ var uniqueTitle = Guid.NewGuid().ToString();
+ var otherText = Guid.NewGuid().ToString();
+
+ await Step("Given there is exactly one nieuwsbericht with that text as the title");
+
+ await using var nieuws1 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Nieuws });
+
+ await Step("And there is exactly one werkinstructie with that text as the title");
+
+ await using var werkinstructie1 = await Page.CreateBericht(new() { Title = uniqueTitle, BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And there is at least one nieuwsbericht without that text");
+
+ await using var nieuws2 = await Page.CreateBericht(new() { Title = otherText, BerichtType = BerichtType.Nieuws });
+
+ await Step("And there is at least one werkinstructie without that text");
+
+ await using var werkinstructie2 = await Page.CreateBericht(new() { Title = otherText, BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And the user is on the HOME Page");
+
+ await Page.GotoAsync("/");
+
+ await Step("And has selected 'Alle' from the filter dropdown");
+
+ await Page.GetWerkberichtTypeSelector().SelectOptionAsync("Alle");
+
+ await Step("And has searched for the unique text");
+
+ await Page.GetNieuwsAndWerkinstructiesSearch().FillAsync(uniqueTitle);
+
+ await Step("When the user clicks on the close icon in the search bar");
+
+ await Page.GetNieuwsAndWerkinstructiesSearch().ClearAsync();
+
+ await Step("Then at least two werkinstructies should be visible");
+
+ Assert.IsTrue((await Page.GetWerkinstructiesSection().GetByRole(AriaRole.Article).CountAsync()) >= 2, "at least two werkinstructies should be visible");
+
+ await Step("And at least two nieuwsberichten should be visible");
+
+ Assert.IsTrue((await Page.GetNieuwsSection().GetByRole(AriaRole.Article).CountAsync()) >= 2, "at least two nieuwsberichten should be visible");
+
+
+ }
+ [TestMethod]
+ public void Scenario16()
+ {
+ Assert.Inconclusive($"This scenario seems to be a duplicate of {nameof(Scenario09)}");
+ }
+
+ [TestMethod]
+ public async Task Scenario17()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ await using var nieuws = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Nieuws });
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.GotoAsync("/");
+
+ await Step("Then the nieuwsbericht should be displayed in a list");
+
+ var nieuwsSection = Page.GetNieuwsSection();
+ await Expect(nieuwsSection.GetByRole(AriaRole.Heading, new() { Name = nieuws.Title })).ToBeVisibleAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario18()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ var nieuws = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Nieuws });
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+
+ await Step("When user clicks on the delete icon of the nieuwsbericht in the list");
+
+ var nieuwsRow = Page.GetBeheerRowByValue(nieuws.Title);
+
+ await Step("And confirms a pop-up window with the message ‘Weet u zeker dat u dit bericht wilt verwijderen?’");
+
+ var deleteButton = nieuwsRow.GetByTitle("Verwijder").First;
+
+ using (var _ = Page.AcceptAllDialogs())
+ {
+ await deleteButton.ClickAsync();
+ }
+
+ await Step("Then the nieuwsbericht is no longer in the list");
+
+ var deletedRow = Page.GetBeheerRowByValue(nieuws.Title);
+
+ await Expect(deletedRow).ToBeHiddenAsync();
+
+
+ }
+
+ [TestMethod]
+ public async Task Scenario19()
+ {
+ await Step("Given there is at least 1 werkinstructie");
+
+ var werkinstructie = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Werkinstructie });
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+
+ await Step("When user clicks on the delete icon of the werkinstructie in the list");
+
+ var werkinstructieRow = Page.GetBeheerRowByValue(werkinstructie.Title);
+
+ await Step("And confirms a pop-up window with the message ‘Weet u zeker dat u dit bericht wilt verwijderen?’");
+
+ var deleteButton = werkinstructieRow.GetByTitle("Verwijder").First;
+
+ using (var _ = Page.AcceptAllDialogs())
+ {
+ await deleteButton.ClickAsync();
+ }
+
+ await Step("Then the werkinstructie is no longer in the list");
+
+ await Expect(Page.GetBeheerRowByValue(werkinstructie.Title)).ToBeHiddenAsync();
+
+ }
+
+ [TestMethod]
+ public async Task Scenario20()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ await using var skill = await Page.CreateSkill(Guid.NewGuid().ToString());
+ await using var nieuw = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Nieuws, Skill=skill.Naam , Body= Guid.NewGuid().ToString()});
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+
+ await Step("When the user clicks on the arrow button of the nieuwsbericht");
+
+ await Page.GetBeheerRowByValue(nieuw.Title).GetByRole(AriaRole.Link).ClickAsync();
+
+ await Step("Then the Type, Titel, Inhoud, Publicatiedatum, Publicatie-einddatum and Skills of the nieuwsbericht are visible in a details screen");
+
+ await Expect(Page.Locator("#titel")).ToHaveValueAsync(nieuw.Title);
+ await Expect(Page.GetByText("Nieuws", new() { Exact = true })).ToBeCheckedAsync();
+ await Expect(Page.Locator("label:text('Inhoud') + div")).ToContainTextAsync(nieuw.Body);
+ await Expect(Page.Locator("#publicatieDatum")).ToHaveValueAsync(nieuw.PublicatieDatum.ToString("yyyy-MM-ddTHH:mm"));
+ await Expect(Page.GetByLabel("Publicatie-einddatum")).ToHaveValueAsync(nieuw.PublicatieEinddatum.ToString("yyyy-MM-ddTHH:mm"));
+ await Expect(Page.GetByRole(AriaRole.Checkbox, new() { Name = skill.Naam })).ToBeCheckedAsync();
+ }
+
+ [TestMethod]
+ public async Task Scenario21()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ await using var skill = await Page.CreateSkill(Guid.NewGuid().ToString());
+ var nieuw = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Nieuws, Skill = skill.Naam });
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+
+ await Step("And the user has clicked on the arrow button of the nieuwsbericht");
+
+ await Page.GetBeheerRowByValue(nieuw.Title).GetByRole(AriaRole.Link).ClickAsync();
+
+ await Step("And the news detail screen is displayed");
+
+ await Expect(Page.Locator("#titel")).ToHaveValueAsync(nieuw.Title);
+ await Expect(Page.GetByText("Nieuws", new() { Exact = true })).ToBeCheckedAsync();
+ await Expect(Page.GetByRole(AriaRole.Checkbox, new() { Name = skill.Naam })).ToBeCheckedAsync();
+
+ await Step("When the user updates the title section of news");
+
+ var updatedTitle = Guid.NewGuid().ToString();
+ await Page.GetByLabel("Titel").FillAsync(updatedTitle);
+
+ await Step("And clicks on the submit button");
+
+ var opslaanKnop = Page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
+ while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
+ {
+ await opslaanKnop.ClickAsync();
+ }
+
+ await Step("Then the updated news title is displayed in Berichten screen");
+
+
+ await Expect(Page.GetBeheerTableCell(1,1)).ToHaveTextAsync(updatedTitle);
+
+ await Step("And the “Gewijzigd op” field gets updated with the latest time");
+
+ await Expect(Page.GetBeheerTableCell(5, 1)).ToHaveTextAsync(DateTime.Now.ToString("dd-MM-yyyy, HH:mm"));
+ }
+
+ [TestMethod]
+ public async Task Scenario22()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ await using var skill = await Page.CreateSkill(Guid.NewGuid().ToString());
+ await using var nieuw = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Nieuws, Skill = skill.Naam });
+
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+
+ await Step("And the user has clicked on the arrow button of the nieuwsbericht");
+
+ await Page.GetBeheerRowByValue(nieuw.Title).GetByRole(AriaRole.Link).ClickAsync();
+
+ await Step("And the news detail screen is displayed");
+
+ await Expect(Page.Locator("#titel")).ToHaveValueAsync(nieuw.Title);
+ await Expect(Page.GetByText("Nieuws", new() { Exact = true })).ToBeCheckedAsync();
+ await Expect(Page.GetByRole(AriaRole.Checkbox, new() { Name = skill.Naam })).ToBeCheckedAsync();
+
+ await Step("When the user updates the Publicatiedatum section of the nieuwsbericht to a future date");
+
+ var updatedPublicatieDatum = nieuw.PublicatieDatum.AddDays(30);
+
+ await Page.GetByLabel("Publicatiedatum").FillAsync(updatedPublicatieDatum.ToString("yyyy-MM-ddTHH:mm"));
+
+ await Step("And clicks on the submit button");
+ var opslaanKnop = Page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
+ while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
+ {
+ await opslaanKnop.ClickAsync();
+ }
+ await Step("Then the nieuwsbericht with the updated Publicatiedatum is displayed in the Berichten screen");
+
+ await Expect(Page.GetBeheerTableCell(3, 1)).ToHaveTextAsync(updatedPublicatieDatum.ToString("dd-MM-yyyy, HH:mm"));
+
+ }
+
+ [TestMethod]
+ public async Task Scenario23()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ await using var skill = await Page.CreateSkill(Guid.NewGuid().ToString());
+ await using var nieuws = await Page.CreateBericht(new() { Title = Guid.NewGuid().ToString(), BerichtType = BerichtType.Nieuws, Skill = skill.Naam });
+
+ await Step("And the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Page.NavigateToNieuwsWerkinstructiesBeheer();
+
+ await Step("And the user has clicked on the arrow button of the nieuwsbericht");
+
+ await Page.GetBeheerRowByValue(nieuw.Title).GetByRole(AriaRole.Link).ClickAsync();
+
+ await Step("And the news detail screen is displayed");
+
+ await Expect(Page.Locator("#titel")).ToHaveValueAsync(nieuw.Title);
+ await Expect(Page.GetByText("Nieuws", new() { Exact = true })).ToBeCheckedAsync();
+ await Expect(Page.GetByRole(AriaRole.Checkbox, new() { Name = skill.Naam })).ToBeCheckedAsync();
+
+
+ await Step("When the user checks the ‘belangrijk’ checkbox");
+
+ await Page.GetByRole(AriaRole.Checkbox, new() { Name = "Belangrijk" }).CheckAsync();
+
+
+ await Step("And clicks on the submit button");
+
+ var opslaanKnop = Page.GetByRole(AriaRole.Button, new() { Name = "Opslaan" });
+ while (await opslaanKnop.IsVisibleAsync() && await opslaanKnop.IsEnabledAsync())
+ {
+ await opslaanKnop.ClickAsync();
+ }
+
+ await Step("And navigates to the home screen of the KISS environment");
+
+ await Page.GotoAsync("/");
+
+ await Step("And navigates to the page containing the nieuwsbericht selected earlier");
+ await Page.GetNieuwsAndWerkinstructiesSearch().FillAsync(nieuw.Title);
+ await Page.GetNieuwsAndWerkinstructiesSearch().PressAsync("Enter");
+
+ await Step("Then the nieuwsbericht should be displayed with the ‘belangrijk’ flag");
+
+ await Expect(Page.GetSearchResultFilteredByType("Nieuws")).ToHaveCountAsync(1);
+ await Expect(Page.GetSearchResultFilteredByType("Nieuws").GetByText("Belangrijk")).ToBeVisibleAsync();
+
+ }
+
+ [TestMethod]
+ public async Task Scenario24()
+ {
+ await Step("Given the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Step("When the user clicks on the “Toevoegen” button");
+
+ await Step("And selects ‘Nieuws’ as ‘Type’");
+
+ await Step("And fills in the ‘Titel’ and ‘Inhoud’ fields");
+
+ await Step("And clicks on the submit button");
+
+ await Step("Then the nieuwsbericht is displayed in Berichten");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario25()
+ {
+ await Step("Given the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Step("When the user clicks on the “Toevoegen” button");
+
+ await Step("And selects ‘Nieuws’ as ‘Type’");
+
+ await Step("And fills in the ‘Titel’ and ‘Inhoud’ fields");
+
+ await Step("And clicks on the submit button");
+
+ await Step("And navigates to the page containing the nieuwsbericht created earlier ");
+
+ await Step("Then the nieuwsbericht should be displayed");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario26()
+ {
+ await Step("Given the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Step("When the user clicks on the “Toevoegen” button");
+
+ await Step("And selects ‘Werkinstructie’ as ‘Type’");
+
+ await Step("And fills in the ‘Titel’ and ‘Inhoud’ fields");
+
+ await Step("And clicks on the submit button");
+
+ await Step("Then the werkinstructie is displayed in Berichten");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario27()
+ {
+ await Step("Given the user is on the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Step("When the user clicks on the “Toevoegen” button");
+
+ await Step("And selects Werkinstructieas ‘Type’");
+
+ await Step("And fills in the ‘Titel’ and ‘Inhoud’ fields");
+
+ await Step("And clicks on the submit button");
+
+ await Step("And navigates to the page containing the werkinstructie created earlier ");
+
+ await Step("Then the werkinstructie should be displayed");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario28()
+ {
+ await Step("Given there is at least 1 nieuwsbericht");
+
+ await Step("When the user navigates to the Nieuws and werkinstructiesscreen available under Beheer");
+
+ await Step("Then there is a table titled ‘Berichten’ with rows named as “Titel”, “Type”,”publicatiedatum”, “Aangemaakt op” and “ Gewijzigd op”");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public void Scenario29()
+ {
+ Assert.Inconclusive("This scenario in the document is still unclear");
+ }
+
+ [TestMethod]
+ public async Task Scenario30()
+ {
+ await Step("Given a nieuwsbericht for with a publicatiedatum in the future");
+
+ await Step("When the user navigates to the HOME Page");
+
+ await Step("And browses through all pages of the Nieuws section");
+
+ await Step("Then the nieuwsbericht should not be visible");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario31()
+ {
+ await Step("Given a nieuwsbericht for a publicatiedatum in the past");
+
+ await Step("When the user navigates to the HOME PageAnd the user browses through all pages of the Nieuws section");
+
+ await Step("Then the nieuwsbericht should be visible");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario32()
+ {
+ await Step("Given a nieuwsbericht for a publicatie-einddatum in the past");
+
+ await Step("When the user navigates to the HOME Page");
+
+ await Step("And browses through all pages of the Nieuws section");
+
+ await Step("Then the nieuwsbericht should not be visible");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario33()
+ {
+ await Step("Given a nieuwsbericht for a publicatie-einddatum in the future");
+
+ await Step("When the user navigates to the HOME Page");
+
+ await Step("And browses through all pages of the Nieuws section");
+
+ await Step("Then the nieuwsbericht should be visible");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario34()
+ {
+ await Step("Given a nieuwsbericht with multiple skills");
+
+ await Step("When the user navigates to the HOME Page");
+
+ await Step("And browses through all pages of the Nieuws section");
+
+ await Step("Then the nieuwsbericht should be displayed with the corresponding skills as labels");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+
+ [TestMethod]
+ public async Task Scenario35()
+ {
+ await Step("Given a werkinstructie with multiple skills");
+
+ await Step("When the user navigates to the HOME Page");
+
+ await Step("And browses through all pages of the Nieuws section");
+
+ await Step("Then the werkinstructie should be displayed with the corresponding skills as labels");
+
+ Assert.Inconclusive("Not implemented yet");
+ }
+}
diff --git a/Kiss.Bff.EndToEndTest/README.md b/Kiss.Bff.EndToEndTest/README.md
new file mode 100644
index 00000000..ed01dae5
--- /dev/null
+++ b/Kiss.Bff.EndToEndTest/README.md
@@ -0,0 +1,16 @@
+# End to end tests
+These tests are scheduled to run on Github Actions. [An html report](https://klantinteractie-servicesysteem.github.io/KISS-frontend/) is generated on Github Pages.
+
+## Run/debug the tests locally
+1. In Visual Studio, right click the `Kiss.Bff.EndToEndTest` project and select `Manage user secrets`
+1. Fill in the following values:
+```jsonc
+{
+ "TestSettings": {
+ "TEST_BASE_URL": "", // a valid base url for an environment where an instance of kiss is running
+ "TEST_USERNAME": "", // a valid username to login to Azure Entra Id
+ "TEST_PASSWORD": "", // a valid password to login to Azure Entra Id
+ "TEST_TOTP_SECRET": "" // a secret to generate 2 Factor Authentication codes for Azure Entra Id
+ }
+}
+```
\ No newline at end of file