From 15f3283767b8cd25924b4956d96a6fe865e62a75 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 9 Jul 2024 15:39:51 +0100 Subject: [PATCH 01/31] structure and tests for specflow accessibility checks --- .../Features/AccessibilityTests.feature | 5 + .../Features/AccessibilityTests.feature.cs | 129 ++++++++++++++++++ .../Tests/Acceptance/Hooks/SpecFlowHooks.cs | 64 +++++++++ .../Acceptance/Steps/AccessibilitySteps.cs | 57 ++++++++ .../Dfe.Data.SearchPrototype.Web.Tests.csproj | 11 +- .../Integration/PageObjectModel/HomePage.cs | 3 + 6 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature new file mode 100644 index 0000000..adda656 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature @@ -0,0 +1,5 @@ +Feature: AccessibilityTests + +Scenario: Homepage accessibility + When the user views the homepage + Then the homepage is accessible diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs new file mode 100644 index 0000000..bef7be0 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs @@ -0,0 +1,129 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (https://www.specflow.org/). +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Features +{ + using TechTalk.SpecFlow; + using System; + using System.Linq; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public partial class AccessibilityTestsFeature : object, Xunit.IClassFixture, System.IDisposable + { + + private static TechTalk.SpecFlow.ITestRunner testRunner; + + private static string[] featureTags = ((string[])(null)); + + private Xunit.Abstractions.ITestOutputHelper _testOutputHelper; + +#line 1 "AccessibilityTests.feature" +#line hidden + + public AccessibilityTestsFeature(AccessibilityTestsFeature.FixtureData fixtureData, Dfe_Data_SearchPrototype_Web_Tests_XUnitAssemblyFixture assemblyFixture, Xunit.Abstractions.ITestOutputHelper testOutputHelper) + { + this._testOutputHelper = testOutputHelper; + this.TestInitialize(); + } + + public static void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Acceptance/Features", "AccessibilityTests", null, ProgrammingLanguage.CSharp, featureTags); + testRunner.OnFeatureStart(featureInfo); + } + + public static void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + public void TestInitialize() + { + } + + public void TestTearDown() + { + testRunner.OnScenarioEnd(); + } + + public void ScenarioInitialize(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioInitialize(scenarioInfo); + testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(_testOutputHelper); + } + + public void ScenarioStart() + { + testRunner.OnScenarioStart(); + } + + public void ScenarioCleanup() + { + testRunner.CollectScenarioErrors(); + } + + void System.IDisposable.Dispose() + { + this.TestTearDown(); + } + + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] + [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] + [Xunit.TraitAttribute("Description", "Homepage accessibility")] + public void HomepageAccessibility() + { + string[] tagsOfScenario = ((string[])(null)); + System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); +#line 3 +this.ScenarioInitialize(scenarioInfo); +#line hidden + if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) + { + testRunner.SkipScenario(); + } + else + { + this.ScenarioStart(); +#line 4 + testRunner.When("the user views the homepage", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 5 + testRunner.Then("the homepage is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + } + this.ScenarioCleanup(); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class FixtureData : System.IDisposable + { + + public FixtureData() + { + AccessibilityTestsFeature.FeatureSetup(); + } + + void System.IDisposable.Dispose() + { + AccessibilityTestsFeature.FeatureTearDown(); + } + } + } +} +#pragma warning restore +#endregion diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs new file mode 100644 index 0000000..51198ee --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs @@ -0,0 +1,64 @@ +using BoDi; +using OpenQA.Selenium.Chrome; +using OpenQA.Selenium; +using System.Diagnostics; +using TechTalk.SpecFlow; + +namespace UnitTestProject1 +{ + [Binding] + public class SpecFlowHooks + { + private readonly IObjectContainer _container; + public SpecFlowHooks(IObjectContainer container) + { + _container = container; + } + + [Before] + public void Before() + { + var process = new Process + { + StartInfo = + { + FileName = "dotnet", + Arguments = "run --urls=http://localhost:7001", + UseShellExecute = true, + WorkingDirectory = "C:\\Users\\aoakes1\\source\\repos\\DFE-Digital\\search-prototype\\dfe.data.SearchPrototype\\Web" + } + }; + process.Start(); + Thread.Sleep(1000); + } + + [BeforeScenario] + public void CreateWebDriver() + { + // Create and configure a concrete instance of IWebDriver + IWebDriver driver = new ChromeDriver(); + { + + }; + + // Make this instance available to all other step definitions + _container.RegisterInstanceAs(driver); + } + + [AfterScenario] + public void DestroyWebDriver() + { + IWebDriver driver = _container.Resolve(); + + driver.Close(); + driver.Dispose(); + } + + [After] + public void After() + { + var processes = Process.GetProcessesByName("WindowsTerminal"); + processes[0].CloseMainWindow(); + } + } +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs new file mode 100644 index 0000000..c02a37d --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -0,0 +1,57 @@ +using Deque.AxeCore.Selenium; +using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel; +using FluentAssertions; +using OpenQA.Selenium; +using TechTalk.SpecFlow; +using Xunit.Abstractions; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Steps +{ + [Binding] + public sealed class AccessibilitySteps + { + private readonly HomePage _homePage; + private readonly IWebDriver _driver; + private readonly ITestOutputHelper _logger; + private readonly ScenarioContext _scenarioContext; + + public AccessibilitySteps( + HomePage homePage, + IWebDriver driver, + ITestOutputHelper logger, + ScenarioContext scenarioContext + ) + { + _driver = driver; + _homePage = homePage; + _logger = logger; + _scenarioContext = scenarioContext; + } + + [StepDefinition(@"the user views the homepage")] + public void OpenHome() + { + _driver.Navigate().GoToUrl("http://localhost:7001/"); + _homePage.Heading.Criteria.Should().NotBeNull(); + } + + [StepDefinition(@"the (.*) is accessible")] + public void IsAccessible(string component) + { + // see https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#axe-core-tags + + var axeResult = new AxeBuilder(_driver) + .WithTags("wcag2a", "wcag2aa", "wcag21a", "wcag21aa") + .Analyze(); + + _logger.WriteLine($"Scan completed"); + + // Check that axe ran successfuly https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#error-result + axeResult.Violations.Should().BeEmpty(); + + var passCount = axeResult.Passes.Length; + passCount.Should().NotBe(0); + _logger.WriteLine($"Passed accessibility test count {passCount} for {component} at {axeResult.Url}"); + } + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index c713a44..93f1a1e 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -9,9 +9,14 @@ + + - + + + + @@ -19,5 +24,9 @@ + + + + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs index 2104448..a9bc31e 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs @@ -2,6 +2,7 @@ using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.PageComponents; using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.Setup; using Microsoft.AspNetCore.Mvc.Testing; +using OpenQA.Selenium; namespace DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel { @@ -13,6 +14,8 @@ public sealed class HomePage : DocumentObjectModelExtractor private const string PrivacyLink = "Privacy"; private const string MainHeadingClass = "govuk-header__link govuk-header__service-name"; + public By Heading => By.CssSelector("header div div:nth-of-type(2) a"); + public HomePage(WebApplicationFactory webApplicationFactory) : base(webApplicationFactory, PageName) { From 59f5f4e3628e268180392cffebdf79e01d777021 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 9 Jul 2024 16:51:54 +0100 Subject: [PATCH 02/31] running exe to launch web app --- .../Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs | 10 +++------- .../Web/Tests/Acceptance/Steps/AccessibilitySteps.cs | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs index 51198ee..a2aea3a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs @@ -22,14 +22,10 @@ public void Before() { StartInfo = { - FileName = "dotnet", - Arguments = "run --urls=http://localhost:7001", - UseShellExecute = true, - WorkingDirectory = "C:\\Users\\aoakes1\\source\\repos\\DFE-Digital\\search-prototype\\dfe.data.SearchPrototype\\Web" + FileName = "Dfe.Data.SearchPrototype.Web.exe", } }; process.Start(); - Thread.Sleep(1000); } [BeforeScenario] @@ -57,8 +53,8 @@ public void DestroyWebDriver() [After] public void After() { - var processes = Process.GetProcessesByName("WindowsTerminal"); - processes[0].CloseMainWindow(); + var processes = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); + processes[0].Kill(); } } } \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs index c02a37d..5a7da6f 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -31,7 +31,7 @@ ScenarioContext scenarioContext [StepDefinition(@"the user views the homepage")] public void OpenHome() { - _driver.Navigate().GoToUrl("http://localhost:7001/"); + _driver.Navigate().GoToUrl("http://localhost:5000/"); _homePage.Heading.Criteria.Should().NotBeNull(); } From 98198ea0a58a11944b1c648555293ac65f9ac0b5 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 10 Jul 2024 09:28:58 +0100 Subject: [PATCH 03/31] switched to run github workflow on windows-latest --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 23ab4e0..222a592 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v4 From 93764eaa2035037df19b9acd425c0f38ee474e23 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 10 Jul 2024 16:31:43 +0100 Subject: [PATCH 04/31] initial basic readme version added to acceptance tests --- .../Web/Tests/Acceptance/README.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md new file mode 100644 index 0000000..a1b4769 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md @@ -0,0 +1,27 @@ +# Performance Tables Web Tests + +[[_TOC_]] + +## Overview + +This test suite contains automated tests that check the functional and non-functional aspects of the search prototype application. + +## Test Levels + +- Functional + - Acceptance testing +- Non-functional + - Accessibility testing + +## Languages + +C# + +## Tools + +- [SpecFlow](https://specflow.org/) +- [Axe-core](https://github.com/dequelabs/axe-core/tree/develop) + +## Contribution + +Branches should be in the format `[contributor-initials]/test-[ticket-number]-[feature-description]`. From e6d8364bd480bfccad92d373031bd19041d28af4 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Mon, 15 Jul 2024 12:01:23 +0100 Subject: [PATCH 05/31] readme updated and privacy page accessibility test added --- .../Features/AccessibilityTests.feature | 8 +++-- .../Features/AccessibilityTests.feature.cs | 32 +++++++++++++++++-- .../Web/Tests/Acceptance/README.md | 3 +- .../Acceptance/Steps/AccessibilitySteps.cs | 13 ++++++-- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature index adda656..da7d187 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature @@ -1,5 +1,9 @@ Feature: AccessibilityTests Scenario: Homepage accessibility - When the user views the homepage - Then the homepage is accessible + When the user views the home page + Then the home page is accessible + +Scenario: Privacy page accessibility + When the user views the privacy page + Then the privacy page is accessible diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs index bef7be0..d4a9989 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs @@ -99,10 +99,38 @@ public void HomepageAccessibility() { this.ScenarioStart(); #line 4 - testRunner.When("the user views the homepage", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.When("the user views the home page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden #line 5 - testRunner.Then("the homepage is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("the home page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + } + this.ScenarioCleanup(); + } + + [Xunit.SkippableFactAttribute(DisplayName="Privacy page accessibility")] + [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] + [Xunit.TraitAttribute("Description", "Privacy page accessibility")] + public void PrivacyPageAccessibility() + { + string[] tagsOfScenario = ((string[])(null)); + System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Privacy page accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); +#line 7 +this.ScenarioInitialize(scenarioInfo); +#line hidden + if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) + { + testRunner.SkipScenario(); + } + else + { + this.ScenarioStart(); +#line 8 + testRunner.When("the user views the privacy page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 9 + testRunner.Then("the privacy page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden } this.ScenarioCleanup(); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md index a1b4769..7faad6e 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md @@ -1,6 +1,5 @@ -# Performance Tables Web Tests +# Search Prototype Acceptance & Accessbility Tests -[[_TOC_]] ## Overview diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs index 5a7da6f..3e8fca0 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -1,6 +1,7 @@ using Deque.AxeCore.Selenium; using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel; using FluentAssertions; +using Microsoft.AspNetCore.Mvc.RazorPages; using OpenQA.Selenium; using TechTalk.SpecFlow; using Xunit.Abstractions; @@ -14,6 +15,12 @@ public sealed class AccessibilitySteps private readonly IWebDriver _driver; private readonly ITestOutputHelper _logger; private readonly ScenarioContext _scenarioContext; + + private Dictionary _pageNameToUrlConverter = new Dictionary() + { + { "home", "/" }, + { "privacy", "/Home/Privacy" } + }; public AccessibilitySteps( HomePage homePage, @@ -28,10 +35,10 @@ ScenarioContext scenarioContext _scenarioContext = scenarioContext; } - [StepDefinition(@"the user views the homepage")] - public void OpenHome() + [StepDefinition(@"the user views the (home|privacy) page")] + public void OpenPage(string pageName) { - _driver.Navigate().GoToUrl("http://localhost:5000/"); + _driver.Navigate().GoToUrl($"http://localhost:5000{_pageNameToUrlConverter[pageName]}"); _homePage.Heading.Criteria.Should().NotBeNull(); } From 557a55da419ebb28d15ee15e17d74c9ed6bd194e Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 17 Jul 2024 09:40:00 +0100 Subject: [PATCH 06/31] integrated selenium context and factory code from sd suite moved page object dir out to root of project added appsettings test file --- .../Acceptance/Drivers/IWebDriverContext.cs | 15 ++ .../Acceptance/Drivers/IWebDriverFactory.cs | 8 ++ .../Acceptance/Drivers/WebDriverContext.cs | 130 ++++++++++++++++++ .../Acceptance/Drivers/WebDriverFactory.cs | 109 +++++++++++++++ .../Acceptance/Extensions/StringExtensions.cs | 19 +++ .../Features/AccessibilityTests.feature | 2 +- .../Tests/Acceptance/Hooks/SpecFlowHooks.cs | 44 +++--- .../Options/AccessibilityOptions.cs | 10 ++ .../Options/AccessibilityOptionsExtensions.cs | 20 +++ .../Tests/Acceptance/Options/OptionsHelper.cs | 19 +++ .../Acceptance/Options/WebDriverOptions.cs | 10 ++ .../Options/WebDriverSessionOptions.cs | 8 ++ .../Tests/Acceptance/Options/WebOptions.cs | 15 ++ .../Acceptance/Steps/AccessibilitySteps.cs | 40 ++++-- .../Dfe.Data.SearchPrototype.Web.Tests.csproj | 7 + .../Web/Tests/Integration/HomePageTests.cs | 2 +- .../PageObjectModel/HomePage.cs | 6 +- .../PageComponents/PageComponent.cs | 2 +- .../PageComponents/PageHeader.cs | 6 +- .../PageObjectModel/PrivacyPage.cs | 7 +- .../Setup/DocumentObjectModelExtractor.cs | 11 +- .../Setup/WebApplicationBootstrapper.cs | 2 +- .../Web/Tests/appsettings.test.json | 13 ++ 23 files changed, 452 insertions(+), 53 deletions(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverContext.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverFactory.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverContext.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverFactory.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Extensions/StringExtensions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptionsExtensions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/OptionsHelper.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverOptions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverSessionOptions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebOptions.cs rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => }/PageObjectModel/HomePage.cs (83%) rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => }/PageObjectModel/PageComponents/PageComponent.cs (88%) rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => }/PageObjectModel/PageComponents/PageHeader.cs (82%) rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => }/PageObjectModel/PrivacyPage.cs (81%) rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => }/PageObjectModel/Setup/DocumentObjectModelExtractor.cs (83%) rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => }/PageObjectModel/Setup/WebApplicationBootstrapper.cs (85%) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverContext.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverContext.cs new file mode 100644 index 0000000..df7d09b --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverContext.cs @@ -0,0 +1,15 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Support.UI; +using Xunit.Abstractions; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; + +public interface IWebDriverContext : IDisposable +{ + IWebDriver Driver { get; } + IWait Wait { get; } + void GoToUri(string path); + void GoToUri(string baseUri, string path); + void TakeScreenshot(ITestOutputHelper logger, string testName); +} + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverFactory.cs new file mode 100644 index 0000000..d352751 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverFactory.cs @@ -0,0 +1,8 @@ +using OpenQA.Selenium; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; + +public interface IWebDriverFactory +{ + Lazy CreateDriver(); +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverContext.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverContext.cs new file mode 100644 index 0000000..f3c3ed0 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverContext.cs @@ -0,0 +1,130 @@ +using OpenQA.Selenium.Support.UI; +using OpenQA.Selenium; +using System.Drawing; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; +using Microsoft.Extensions.Options; +using Xunit.Abstractions; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; + +public class WebDriverContext : IWebDriverContext +{ + private readonly WebDriverOptions _driverOptions; + private readonly Lazy _driver; + private readonly Lazy> _wait; + private readonly string _baseUri; + + public IWebDriver Driver => _driver.Value; + public IWait Wait => _wait.Value; + private Type[] IgnoredExceptions { get; } = new[] { typeof(StaleElementReferenceException) }; + + public WebDriverContext( + IWebDriverFactory factory, + IOptions options, + IOptions driverOptions + ) + { + _driver = factory?.CreateDriver() ?? throw new ArgumentNullException(nameof(factory)); + _baseUri = options.Value.GetWebUri() ?? throw new ArgumentNullException(nameof(options)); + _wait = new(() => InitializeWait(Driver, IgnoredExceptions)); + _driverOptions = driverOptions.Value; + } + + private IJavaScriptExecutor JsExecutor => Driver as IJavaScriptExecutor ?? throw new ArgumentNullException(nameof(IJavaScriptExecutor)); + + /// + /// Navigate to relative path + /// + /// + /// + public void GoToUri(string path) => GoToUri(_baseUri, path); + + /// + /// Navigate to a uri + /// + /// baseUri for site e.g https://google.co.uk + /// path from baseUri defaults to '/' e.g '/login' + /// + public void GoToUri(string baseUri, string path = "/") + { + _ = baseUri ?? throw new ArgumentNullException(nameof(baseUri)); + var absoluteUri = $"{baseUri.TrimEnd('/')}{path}"; + if (Uri.TryCreate(absoluteUri, UriKind.Absolute, out var uri)) + { + Driver.Navigate().GoToUrl(uri); + } + else + { + throw new ArgumentException(nameof(absoluteUri)); + } + } + + /// + /// Dispose of + /// + public void Dispose() + { + using (Driver) + { + Driver.Quit(); + } + } + + public void TakeScreenshot( + ITestOutputHelper logger, + string testName + ) + { + + // Allows alternative path + var baseScreenshotDirectory = + Path.IsPathFullyQualified(_driverOptions.ScreenshotsDirectory) ? + _driverOptions.ScreenshotsDirectory : + Path.Combine(Directory.GetCurrentDirectory(), _driverOptions.ScreenshotsDirectory); + + Directory.CreateDirectory(baseScreenshotDirectory); + + var outputPath = Path.Combine( + baseScreenshotDirectory, + testName + ".png" + ); + + // Maximise viewport + Driver.Manage().Window.Size = new Size( + width: GetBrowserWidth(), + height: GetBrowserHeight() + ); + + // Screenshot + (Driver as ITakesScreenshot)? + .GetScreenshot() + .SaveAsFile(outputPath); + + logger.WriteLine($"SCREENSHOT SAVED IN LOCATION: {outputPath}"); + } + + private static IWait InitializeWait(IWebDriver driver, Type[] ignoredExceptions) + { + var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20)); + wait.IgnoreExceptionTypes(ignoredExceptions); + return wait; + } + + private int GetBrowserWidth() => + // Math.max returns a 64 bit number requiring casting + (int)(long)JsExecutor.ExecuteScript( + @"return Math.max( + window.innerWidth, + document.body.scrollWidth, + document.documentElement.scrollWidth)" + ); + + private int GetBrowserHeight() => + // Math.max returns a 64 bit number requiring casting + (int)(long)JsExecutor.ExecuteScript( + @"return Math.max( + window.innerHeight, + document.body.scrollHeight, + document.documentElement.scrollHeight)" + ); +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverFactory.cs new file mode 100644 index 0000000..1131f7a --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverFactory.cs @@ -0,0 +1,109 @@ +using OpenQA.Selenium.Chrome; +using OpenQA.Selenium.Firefox; +using OpenQA.Selenium; +using Microsoft.Extensions.Options; +using System.Drawing; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; + + +public sealed class WebDriverFactory : IWebDriverFactory +{ + private static readonly IEnumerable DEFAULT_OPTIONS = new[] + { + "--incognito", + "--safebrowsing-disable-download-protection", + "--no-sandbox", + "--start-maximized", + "--start-fullscreen" + }; + + private static readonly Dictionary MOBILE_VIEWPORTS = new() + { + { "desktop", (1920, 1080) }, + { "iphone14", (390, 844) }, + { "iphone11", (414, 896) } + }; + + private static TimeSpan DEFAULT_PAGE_LOAD_TIMEOUT = TimeSpan.FromSeconds(30); + private readonly WebDriverOptions _webDriverOptions; + private readonly WebDriverSessionOptions _sessionOptions; + + public WebDriverFactory( + IOptions webDriverOptions, + WebDriverSessionOptions sessionOptions + ) + { + _webDriverOptions = webDriverOptions?.Value ?? throw new ArgumentNullException(nameof(webDriverOptions)); + _sessionOptions = sessionOptions ?? throw new ArgumentNullException(nameof(_sessionOptions)); + } + + public Lazy CreateDriver() + { + // viewports are expressed as cartesian coordinates (x,y) + var viewportDoesNotExist = !MOBILE_VIEWPORTS.TryGetValue(_sessionOptions.Device, out var viewport); + if (viewportDoesNotExist) + { + throw new ArgumentException($"device value {_sessionOptions.Device} has no mapped viewport"); + } + var (width, height) = viewport; + + return new Lazy(() => + { + _webDriverOptions.DriverBinaryDirectory ??= Directory.GetCurrentDirectory(); + IWebDriver driver = _sessionOptions switch + { + { DisableJs: true } or { Browser: "firefox" } => CreateFirefoxDriver(_webDriverOptions, _sessionOptions), + _ => CreateChromeDriver(_webDriverOptions) + }; + driver.Manage().Window.Size = new Size(width, height); + driver.Manage().Cookies.DeleteAllCookies(); + driver.Manage().Timeouts().PageLoad = DEFAULT_PAGE_LOAD_TIMEOUT; + return driver; + }); + } + + private static ChromeDriver CreateChromeDriver( + WebDriverOptions driverOptions + ) + { + ChromeOptions option = new(); + option.AddArguments(DEFAULT_OPTIONS); + + // chromium based browsers using new headless switch https://www.selenium.dev/blog/2023/headless-is-going-away/ + if (driverOptions.Headless) + { + option.AddArgument("--headless=new"); + } + option.AddUserProfilePreference("safebrowsing.enabled", true); + option.AddUserProfilePreference("download.prompt_for_download", false); + option.AddUserProfilePreference("disable-popup-blocking", "true"); + option.AddArgument("--window-size=1920,1080"); + return new ChromeDriver(driverOptions.DriverBinaryDirectory, option); + } + + private static FirefoxDriver CreateFirefoxDriver( + WebDriverOptions driverOptions, + WebDriverSessionOptions sessionOptions + ) + { + var options = new FirefoxOptions + { + // TODO load TLS cert into firefox options + AcceptInsecureCertificates = true, + EnableDevToolsProtocol = true, + }; + options.AddArguments(DEFAULT_OPTIONS); + if (driverOptions.Headless) + { + options.AddArgument("--headless"); + } + if (sessionOptions.DisableJs) + { + options.SetPreference("javascript.enabled", false); + } + return new(driverOptions.DriverBinaryDirectory, options); + } +} + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Extensions/StringExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Extensions/StringExtensions.cs new file mode 100644 index 0000000..8f5790c --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Extensions/StringExtensions.cs @@ -0,0 +1,19 @@ +using System.Text.RegularExpressions; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Extensions; + +public static class StringExtensions +{ + public static readonly Regex HtmlReplacer = new("<[^>]*>"); + public static string? ToLowerRemoveHyphens(this string? str) + => string.IsNullOrEmpty(str) ? str : str.Replace(' ', '-').ToLower(); + + public static string? ReplaceHTML(this string? str) + => string.IsNullOrEmpty(str) ? str : HtmlReplacer.Replace(str, string.Empty); + + public static string SanitiseToHTML(string input) + { + var ouput = input.Replace("\"", "\'"); + return ouput; + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature index da7d187..95032a6 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature @@ -6,4 +6,4 @@ Scenario: Homepage accessibility Scenario: Privacy page accessibility When the user views the privacy page - Then the privacy page is accessible + Then the privacy page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs index a2aea3a..91dad3f 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs @@ -1,18 +1,17 @@ using BoDi; -using OpenQA.Selenium.Chrome; -using OpenQA.Selenium; using System.Diagnostics; using TechTalk.SpecFlow; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; +using Microsoft.Extensions.Options; namespace UnitTestProject1 { [Binding] public class SpecFlowHooks { - private readonly IObjectContainer _container; - public SpecFlowHooks(IObjectContainer container) + public SpecFlowHooks( ) { - _container = container; } [Before] @@ -28,33 +27,36 @@ public void Before() process.Start(); } - [BeforeScenario] - public void CreateWebDriver() + [BeforeTestRun] + public static void BeforeTest(ObjectContainer container) { - // Create and configure a concrete instance of IWebDriver - IWebDriver driver = new ChromeDriver(); - { - }; + container.BaseContainer.RegisterInstanceAs(OptionsHelper.GetOptions(WebOptions.Key)); - // Make this instance available to all other step definitions - _container.RegisterInstanceAs(driver); + var driverOptions = OptionsHelper.GetOptions(WebDriverOptions.Key); + if (string.IsNullOrEmpty(driverOptions.Value.DriverBinaryDirectory)) + { + driverOptions.Value.DriverBinaryDirectory = Directory.GetCurrentDirectory(); + } + container.BaseContainer.RegisterInstanceAs>(driverOptions); + var accessibilityOptions = OptionsHelper.GetOptions(AccessibilityOptions.Key); + accessibilityOptions.Value.CreateArtifactOutputDirectory(); + container.BaseContainer.RegisterInstanceAs(accessibilityOptions); } - [AfterScenario] - public void DestroyWebDriver() + [BeforeScenario] + public void CreateWebDriver(IObjectContainer container) { - IWebDriver driver = _container.Resolve(); - - driver.Close(); - driver.Dispose(); + container.RegisterTypeAs(); + container.RegisterTypeAs(); } + [After] public void After() { - var processes = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); - processes[0].Kill(); + var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); + webProcesses[0].Kill(); } } } \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptions.cs new file mode 100644 index 0000000..a26e9f6 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptions.cs @@ -0,0 +1,10 @@ +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +public sealed class AccessibilityOptions +{ + public const string Key = "accessibility"; + public string ArtifactsOutputPath { get; set; } = string.Empty; + public string ReportOutputDirectory { get; set; } = "axe-reports"; + public string[] WcagTags { get; set; } = new[] { "wcag2a", "wcag2aa", "wcag21a", "wcag21aa" }; +} + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptionsExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptionsExtensions.cs new file mode 100644 index 0000000..ee24f74 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptionsExtensions.cs @@ -0,0 +1,20 @@ +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +internal static class AccessibilityOptionsExtensions +{ + internal static AccessibilityOptions CreateArtifactOutputDirectory( + this AccessibilityOptions options) + { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + var outputPath = Path.IsPathFullyQualified(options.ReportOutputDirectory) ? + options.ReportOutputDirectory : + Path.Combine(Directory.GetCurrentDirectory(), options.ReportOutputDirectory); + + Directory.CreateDirectory(outputPath); + options.ArtifactsOutputPath = outputPath; + return options; + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/OptionsHelper.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/OptionsHelper.cs new file mode 100644 index 0000000..314158a --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/OptionsHelper.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using static Microsoft.Extensions.Options.Options; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +public static class OptionsHelper +{ + private static readonly IConfiguration Configuration = + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.test.json", false) + .Build(); + + public static IOptions GetOptions(string key) where T : class + => Create(Configuration.GetRequiredSection(key) + .Get() + ?? throw new ArgumentException("Configuration section returned null object")); +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverOptions.cs new file mode 100644 index 0000000..c60d01c --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverOptions.cs @@ -0,0 +1,10 @@ +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +public sealed class WebDriverOptions +{ + public const string Key = "webDriver"; + public bool Headless { get; set; } + public string ScreenshotsDirectory { get; set; } = "screenshots"; + public string? DriverBinaryDirectory { get; set; } = null!; +} + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverSessionOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverSessionOptions.cs new file mode 100644 index 0000000..22d5205 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverSessionOptions.cs @@ -0,0 +1,8 @@ +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +public sealed class WebDriverSessionOptions +{ + public string Browser { get; set; } = "firefox"; + public string Device { get; set; } = "desktop"; + public bool DisableJs { get; set; } = false; +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebOptions.cs new file mode 100644 index 0000000..4dfe4de --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebOptions.cs @@ -0,0 +1,15 @@ +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; + +public sealed class WebOptions +{ + private const ushort DEFAULT_HTTPS_PORT = 443; + public const string Key = "web"; + public string Scheme { get; set; } = null!; + public string Domain { get; set; } = null!; + public ushort Port { get; set; } = DEFAULT_HTTPS_PORT; + public string? WebUri { private get; set; } = null; + + public string GetWebUri() => + !string.IsNullOrEmpty(WebUri) ? WebUri : + Port == DEFAULT_HTTPS_PORT ? $"{Scheme}://{Domain}" : $"{Scheme}://{Domain}:{Port}"; +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs index 3e8fca0..3140dc8 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -1,8 +1,10 @@ using Deque.AxeCore.Selenium; -using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Extensions; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; using FluentAssertions; -using Microsoft.AspNetCore.Mvc.RazorPages; -using OpenQA.Selenium; +using Microsoft.Extensions.Options; using TechTalk.SpecFlow; using Xunit.Abstractions; @@ -11,11 +13,12 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Steps [Binding] public sealed class AccessibilitySteps { + private readonly AccessibilityOptions _options; private readonly HomePage _homePage; - private readonly IWebDriver _driver; private readonly ITestOutputHelper _logger; - private readonly ScenarioContext _scenarioContext; - + private readonly IWebDriverContext _driverContext; + private readonly WebDriverSessionOptions _sessionOptions; + private Dictionary _pageNameToUrlConverter = new Dictionary() { { "home", "/" }, @@ -24,21 +27,23 @@ public sealed class AccessibilitySteps public AccessibilitySteps( HomePage homePage, - IWebDriver driver, + IOptions options, ITestOutputHelper logger, - ScenarioContext scenarioContext + IWebDriverContext driverContext, + WebDriverSessionOptions sessionOptions ) { - _driver = driver; - _homePage = homePage; + _driverContext = driverContext; + _homePage = homePage; _logger = logger; - _scenarioContext = scenarioContext; + _options = options.Value; + _sessionOptions = sessionOptions; } [StepDefinition(@"the user views the (home|privacy) page")] public void OpenPage(string pageName) { - _driver.Navigate().GoToUrl($"http://localhost:5000{_pageNameToUrlConverter[pageName]}"); + _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); _homePage.Heading.Criteria.Should().NotBeNull(); } @@ -47,11 +52,16 @@ public void IsAccessible(string component) { // see https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#axe-core-tags - var axeResult = new AxeBuilder(_driver) - .WithTags("wcag2a", "wcag2aa", "wcag21a", "wcag21aa") + var outputFile = Path.Combine( + _options.ArtifactsOutputPath, + $"{_sessionOptions.Device}-axe-result-{component.ToLowerRemoveHyphens()}.json" + ); + var axeResult = new AxeBuilder(_driverContext.Driver) + .WithTags(_options.WcagTags) + .WithOutputFile(outputFile) .Analyze(); - _logger.WriteLine($"Scan completed"); + _logger.WriteLine($"Scan completed output location {outputFile}"); // Check that axe ran successfuly https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#error-result axeResult.Violations.Should().BeEmpty(); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index 93f1a1e..9b72cbf 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -14,6 +14,7 @@ + @@ -28,5 +29,11 @@ + + + + PreserveNewest + + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/HomePageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/Integration/HomePageTests.cs index 772b599..6e7a139 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/HomePageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Integration/HomePageTests.cs @@ -1,5 +1,5 @@ using AngleSharp.Html.Dom; -using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; using Microsoft.AspNetCore.Mvc.Testing; using Xunit; diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs similarity index 83% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs index 7dbfd3e..f7b9c7a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/HomePage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs @@ -1,10 +1,10 @@ using AngleSharp.Html.Dom; -using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.PageComponents; -using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.Setup; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.PageComponents; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.Setup; using Microsoft.AspNetCore.Mvc.Testing; using OpenQA.Selenium; -namespace DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel { public sealed class HomePage : DocumentObjectModelExtractor { diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PageComponents/PageComponent.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/PageComponent.cs similarity index 88% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PageComponents/PageComponent.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/PageComponent.cs index 9f5885a..4de59b8 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PageComponents/PageComponent.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/PageComponent.cs @@ -1,6 +1,6 @@ using AngleSharp.Dom; -namespace Dfe.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.PageComponents +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.PageComponents { public abstract class PageComponent { diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PageComponents/PageHeader.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/PageHeader.cs similarity index 82% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PageComponents/PageHeader.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/PageHeader.cs index 0ba7ce5..5bc15e6 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PageComponents/PageHeader.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/PageHeader.cs @@ -1,15 +1,15 @@ using AngleSharp.Dom; using AngleSharp.Html.Dom; -using Dfe.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.PageComponents; -namespace DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.PageComponents +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.PageComponents { public sealed class PageHeader : PageComponent { private const string HeaderElementTag = "header"; private PageHeader(IDocument documentObjectModel) - : base(documentObjectModel, HeaderElementTag){ + : base(documentObjectModel, HeaderElementTag) + { } public string GetMainHeading(string headingClass) => diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PrivacyPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PrivacyPage.cs similarity index 81% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PrivacyPage.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PrivacyPage.cs index e473400..50e4646 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/PrivacyPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PrivacyPage.cs @@ -1,7 +1,7 @@ -using DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.Setup; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.Setup; using Microsoft.AspNetCore.Mvc.Testing; -namespace DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel { public sealed class PrivacyPage : DocumentObjectModelExtractor { @@ -9,7 +9,8 @@ public sealed class PrivacyPage : DocumentObjectModelExtractor private const string TitleElement = "h1"; public PrivacyPage(WebApplicationFactory webApplicationFactory, string pageName) : - base(webApplicationFactory, pageName){ + base(webApplicationFactory, pageName) + { } public string GetPrivacyPageTitle() diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/Setup/DocumentObjectModelExtractor.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/Setup/DocumentObjectModelExtractor.cs similarity index 83% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/Setup/DocumentObjectModelExtractor.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/Setup/DocumentObjectModelExtractor.cs index efead69..027edd9 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/Setup/DocumentObjectModelExtractor.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/Setup/DocumentObjectModelExtractor.cs @@ -2,7 +2,7 @@ using AngleSharp.Dom; using Microsoft.AspNetCore.Mvc.Testing; -namespace DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.Setup; +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.Setup; public abstract class DocumentObjectModelExtractor : WebApplicationBootstrapper { @@ -12,7 +12,8 @@ protected DocumentObjectModelExtractor( WebApplicationFactory webApplicationFactory, string? pageName) : base(webApplicationFactory) { - if (string.IsNullOrWhiteSpace(pageName)){ + if (string.IsNullOrWhiteSpace(pageName)) + { throw new ArgumentNullException(nameof(pageName)); } @@ -21,7 +22,8 @@ protected DocumentObjectModelExtractor( protected void SetPageObject(string pageName) { - Task.Run(async () => { + Task.Run(async () => + { HttpResponseMessage response = await HttpClient.GetAsync(pageName); string documentObjectModel = await response.Content.ReadAsStringAsync(); @@ -31,7 +33,8 @@ protected void SetPageObject(string pageName) }) .Wait(); - if (DocumentObjectModel == null){ + if (DocumentObjectModel == null) + { throw new InvalidOperationException( $"Unable to derive document object model for page {pageName}."); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/Setup/WebApplicationBootstrapper.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/Setup/WebApplicationBootstrapper.cs similarity index 85% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/Setup/WebApplicationBootstrapper.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/Setup/WebApplicationBootstrapper.cs index 645a9d9..9cdf236 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/PageObjectModel/Setup/WebApplicationBootstrapper.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/Setup/WebApplicationBootstrapper.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc.Testing; using Xunit; -namespace DfE.Data.SearchPrototype.Web.Tests.Integration.PageObjectModel.Setup; +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.Setup; public abstract class WebApplicationBootstrapper : IClassFixture> { diff --git a/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json b/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json new file mode 100644 index 0000000..476a5da --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json @@ -0,0 +1,13 @@ +{ + "web": { + "domain": "localhost", + "port": 5000, + "scheme": "http" + }, + "webDriver": { + "headless": true + }, + "accessibility": { + "ArtifactsOutputPath": "" + } +} From 88e47c6044d7dae32ef28e517d79ec1d66a9c509 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 17 Jul 2024 10:40:33 +0100 Subject: [PATCH 07/31] moved search compoenent into pageobject model dir --- .../PageComponents/SearchComponent.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/SearchComponent.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/SearchComponent.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/SearchComponent.cs new file mode 100644 index 0000000..4878589 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/PageComponents/SearchComponent.cs @@ -0,0 +1,42 @@ +using AngleSharp.Dom; +using AngleSharp.Html.Dom; + +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.PageComponents +{ + public sealed class SearchComponent : PageComponent + { + private const string SearchElementTag = "form"; + + private SearchComponent(IDocument documentObjectModel) + : base(documentObjectModel, SearchElementTag) + { + } + + public static SearchComponent Create(IDocument documentObjectModel) => new(documentObjectModel); + + public IHtmlInputElement GetTextInputBox(string tagName) => + PageElement == null ? + throw new InvalidOperationException( + "Unable to derive the search input box.") : + (IHtmlInputElement)PageElement + .GetElementsByTagName(tagName).Single(); // TODO try to get by the name + + public async Task ClickSubmitAsync() + { + var whatOnEarth = (IHtmlFormElement)PageElement; + whatOnEarth.SubmitAsync(); + + + //Task.Run(() => { + // ((IHtmlFormElement)PageElement!).SubmitAsync(); + //}).Wait(); + } + + public IHtmlButtonElement GetSubmitButton(string tagName) => + PageElement == null ? + throw new InvalidOperationException( + "Unable to derive the search submit button.") : + (IHtmlButtonElement)PageElement + .GetElementsByTagName(tagName).Single(); + } +} \ No newline at end of file From a8d0196faf96e3375b4a4caff46a266c04a0b08b Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 17 Jul 2024 14:46:15 +0100 Subject: [PATCH 08/31] acessibility exclude for hidden dev on search page --- .../Web/Tests/Acceptance/Steps/AccessibilitySteps.cs | 1 + Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs index 3140dc8..c597cda 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -59,6 +59,7 @@ public void IsAccessible(string component) var axeResult = new AxeBuilder(_driverContext.Driver) .WithTags(_options.WcagTags) .WithOutputFile(outputFile) + .Exclude(_homePage.SearchHiddenDiv.Criteria) .Analyze(); _logger.WriteLine($"Scan completed output location {outputFile}"); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs index 2e67802..b454904 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/HomePage.cs @@ -16,6 +16,7 @@ public sealed class HomePage : DocumentObjectModelExtractor private const string MainHeadingClass = "govuk-header__link govuk-header__service-name"; public By Heading => By.CssSelector("header div div:nth-of-type(2) a"); + public By SearchHiddenDiv => By.CssSelector("#searchKeyWord + div"); public HomePage(WebApplicationFactory webApplicationFactory) : base(webApplicationFactory, PageName) From 5927de567670162f70c332f646f1f6a7366760da Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 23 Jul 2024 13:49:55 +0100 Subject: [PATCH 09/31] added base page along with selenium helpers --- .../Acceptance/Drivers/WebDriverExtensions.cs | 47 +++++++++++++++++++ .../Acceptance/Steps/AccessibilitySteps.cs | 5 +- .../Dfe.Data.SearchPrototype.Web.Tests.csproj | 2 + .../Web/Tests/PageObjectModel/BasePage.cs | 13 +++++ .../Web/Tests/PageObjectModel/SearchPage.cs | 13 +++++ 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverExtensions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/BasePage.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverExtensions.cs new file mode 100644 index 0000000..a2f061f --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverExtensions.cs @@ -0,0 +1,47 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Support.UI; +using SeleniumExtras.WaitHelpers; +using Xunit; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; + +public static class WebDriverExtensions +{ + public static void ElementDoesNotExist(this IWebDriverContext context, Func locate) + { + context.Wait.Timeout = TimeSpan.FromSeconds(4); + Assert.ThrowsAny(locate); + } + + public static IWebElement UntilElementContainsText(this IWebElement element, IWebDriverContext context, string text) + { + _ = text ?? throw new ArgumentNullException(nameof(text)); + context.Wait.Message = $"Element did not contain text {text}"; + context.Wait.Until(t => element.Text.Contains(text)); + context.Wait.Message = string.Empty; + return element; + } + + public static IWebElement UntilElementTextIs(IWebElement element, IWait wait, string text) + { + _ = text ?? throw new ArgumentNullException(nameof(text)); + wait.Message = $"Element did not equal text {text}"; + wait.Until(t => element.Text.Contains(text)); + wait.Message = string.Empty; + return element; + } + + public static IWebElement UntilAriaExpandedIs(this IWait wait, bool isExpanded, By locator) + { + var element = wait.UntilElementExists(locator); + wait.Until(_ => element.GetAttribute("aria-expanded") == (isExpanded ? "true" : "false")); + return element; + } + public static IWebElement UntilElementExists(this IWait wait, By by) => wait.Until(ExpectedConditions.ElementExists(by)); + + public static IWebElement UntilElementIsVisible(this IWait wait, By by) => wait.Until(ExpectedConditions.ElementIsVisible(by)); + + public static IWebElement UntilElementIsClickable(this IWait wait, By by) => wait.Until(ExpectedConditions.ElementToBeClickable(by)); + public static IReadOnlyList UntilMultipleElementsExist(this IWait wait, By by) => wait.Until(ExpectedConditions.PresenceOfAllElementsLocatedBy(by)); + public static IReadOnlyList UntilMultipleElementsVisible(this IWait wait, By by) => wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(by)); +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs index c597cda..2989d66 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -17,6 +17,7 @@ public sealed class AccessibilitySteps private readonly HomePage _homePage; private readonly ITestOutputHelper _logger; private readonly IWebDriverContext _driverContext; + private readonly SearchPage _searchPage; private readonly WebDriverSessionOptions _sessionOptions; private Dictionary _pageNameToUrlConverter = new Dictionary() @@ -30,10 +31,12 @@ public AccessibilitySteps( IOptions options, ITestOutputHelper logger, IWebDriverContext driverContext, + SearchPage searchPage, WebDriverSessionOptions sessionOptions ) { _driverContext = driverContext; + _searchPage = searchPage; _homePage = homePage; _logger = logger; _options = options.Value; @@ -44,7 +47,7 @@ WebDriverSessionOptions sessionOptions public void OpenPage(string pageName) { _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); - _homePage.Heading.Criteria.Should().NotBeNull(); + _searchPage.Heading.Text.Should().Be("Search prototype"); } [StepDefinition(@"the (.*) is accessible")] diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index abcd241..1ba069d 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -11,9 +11,11 @@ + + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/BasePage.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/BasePage.cs new file mode 100644 index 0000000..2678f30 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/BasePage.cs @@ -0,0 +1,13 @@ +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; + +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; + +public abstract class BasePage +{ + internal IWebDriverContext DriverContext { get; } + + public BasePage(IWebDriverContext driverContext) + { + DriverContext = driverContext ?? throw new ArgumentNullException(nameof(driverContext)); + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs new file mode 100644 index 0000000..f6b2213 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs @@ -0,0 +1,13 @@ +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; +using OpenQA.Selenium; + +namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; + +public sealed class SearchPage : BasePage +{ + public SearchPage(IWebDriverContext driverContext) : base(driverContext) + { + } + + public IWebElement Heading => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); +} From 20dd1dc5b49cc3cf6107a46d1ca807ca9cd5eaa9 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 23 Jul 2024 15:15:02 +0100 Subject: [PATCH 10/31] added page integration test structure --- .../Acceptance/Steps/AccessibilitySteps.cs | 2 +- .../Web/Tests/Integration/SearchPageTests.cs | 31 ++++++++ .../Web/Tests/PageObjectModel/SearchPage.cs | 9 ++- .../Web/Tests/PageWebApplicationFactory.cs | 44 ++++++++++++ .../Web/Tests/Shared/Helpers/HtmlHelpers.cs | 72 +++++++++++++++++++ 5 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HtmlHelpers.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs index 2989d66..636938b 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs @@ -47,7 +47,7 @@ WebDriverSessionOptions sessionOptions public void OpenPage(string pageName) { _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); - _searchPage.Heading.Text.Should().Be("Search prototype"); + _searchPage.HeadingElement.Text.Should().Be("Search prototype"); } [StepDefinition(@"the (.*) is accessible")] diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs new file mode 100644 index 0000000..4e4713d --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs @@ -0,0 +1,31 @@ +using AngleSharp.Html.Dom; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.Helpers; +using FluentAssertions; +using Microsoft.AspNetCore.Mvc.Testing; +using Xunit; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Integration +{ + public class SearchPageTests : IClassFixture + { + private readonly HttpClient _client; + private readonly WebApplicationFactory _factory; + + public SearchPageTests(PageWebApplicationFactory factory) + { + _factory = factory; + } + + [Fact] + public async Task Search() + { + var response = await _factory.CreateClient().GetAsync("http://localhost:5000"); + + response.EnsureSuccessStatusCode(); + var document = await HtmlHelpers.GetDocumentAsync(response); + + document.GetElementText(SearchPage.Heading.Criteria).Should().Be("Search prototype"); + } + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs index f6b2213..57066da 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs @@ -1,4 +1,8 @@ using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.PageComponents; +using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.Setup; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.Testing; using OpenQA.Selenium; namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; @@ -6,8 +10,9 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; public sealed class SearchPage : BasePage { public SearchPage(IWebDriverContext driverContext) : base(driverContext) - { + { } - public IWebElement Heading => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); + public IWebElement HeadingElement => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); + public static By Heading => By.CssSelector("header div div:nth-of-type(2) a"); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs new file mode 100644 index 0000000..dffdb73 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs @@ -0,0 +1,44 @@ +using DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch.Options; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace Dfe.Data.SearchPrototype.Web.Tests; + +public sealed class PageWebApplicationFactory : WebApplicationFactory +{ + + public static readonly IConfiguration TestConfiguration = + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.test.json", false) + .Build(); + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + // TODO temp fix to read and set application settings from test appsettings.json, until devs generate appsettings with secrets in + if ( + string.IsNullOrEmpty(TestConfiguration["web:domain"]) || + string.IsNullOrEmpty(TestConfiguration["web:port"]) || + string.IsNullOrEmpty(TestConfiguration["web:scheme"])) + { + throw new ArgumentNullException("Missing test configuration: configure your user secrets file"); + }; + builder.ConfigureServices(t => + { + // remove any services that need overriding with test configuration + t.RemoveAll>(); + + //TODO comparisonTablePageTemplateService + + // register dependencies with test configuration + + t.AddOptions().Configure( + (options) => options.Credentials = TestConfiguration["azureSearchClientOptions:credentials"]); + + }); + } +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HtmlHelpers.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HtmlHelpers.cs new file mode 100644 index 0000000..2469948 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HtmlHelpers.cs @@ -0,0 +1,72 @@ +using AngleSharp; +using AngleSharp.Dom; +using AngleSharp.Html.Dom; +using AngleSharp.Io; +using System.Net.Http.Headers; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Shared.Helpers; + +public static class HtmlHelpers +{ + public static async Task GetDocumentAsync(this HttpResponseMessage response) + { + var content = await response.Content.ReadAsStringAsync(); + var config = Configuration.Default; + var document = await + BrowsingContext.New(config) + .OpenAsync(ResponseFactory, CancellationToken.None); + + return (IHtmlDocument)document; + void ResponseFactory(VirtualResponse htmlResponse) + { + htmlResponse + .Address(response.RequestMessage!.RequestUri) + .Status(response.StatusCode); + + MapHeaders(response.Headers); + MapHeaders(response.Content.Headers); + htmlResponse.Content(content); + void MapHeaders(HttpHeaders headers) + { + foreach (var header in headers) + { + foreach (var value in header.Value) + { + htmlResponse.Header(header.Key, value); + } + } + } + } + } + + public static IElement GetElement(this IParentNode document, string cssSelector) + { + if (string.IsNullOrEmpty(cssSelector)) + { + throw new ArgumentException("selector cannot be null or empty", nameof(cssSelector)); + } + return document.QuerySelector(cssSelector) ?? throw new ArgumentException($"Element not found with selector {cssSelector}"); + } + + public static IEnumerable GetMultipleElements(this IParentNode document, string cssSelector) + { + if (string.IsNullOrEmpty(cssSelector)) + { + throw new ArgumentException("selector cannot be null or empty", nameof(cssSelector)); + } + return document.QuerySelectorAll(cssSelector) ?? + throw new ArgumentNullException($"Multiple elements not found with selector {cssSelector}"); + } + + public static string GetElementText(this IParentNode document, string cssSelector) => document.GetElement(cssSelector).TextContent.Trim(); + + public static string? GetElementLinkValue(this IParentNode document, string cssSelector) => document.GetElement(cssSelector).GetAttribute("href"); + + public static IEnumerable GetMultipleElementText(this IParentNode document, string cssSelector) + => document.GetMultipleElements(cssSelector).Select(t => t.TextContent.Trim()); + + public static IEnumerable GetMultipleChildrenElementText(this IParentNode document, string cssSelector) + => document.GetMultipleElements(cssSelector) + .SelectMany(t => t.Children) + .Select(t => t.TextContent.Trim()); +} From 3aebe735119fe10e1805cbc38cb69a0051c88852 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 23 Jul 2024 16:16:22 +0100 Subject: [PATCH 11/31] structure changes --- .../Drivers/IWebDriverContext.cs | 0 .../Drivers/IWebDriverFactory.cs | 0 .../Drivers/WebDriverContext.cs | 0 .../Drivers/WebDriverExtensions.cs | 0 .../Drivers/WebDriverFactory.cs | 0 .../Extensions/StringExtensions.cs | 0 .../Features/AccessibilityTests.feature | 0 .../Features/AccessibilityTests.feature.cs | 4 ++-- .../{Acceptance => AcceptanceTests}/Hooks/SpecFlowHooks.cs | 0 .../Options/AccessibilityOptions.cs | 0 .../Options/AccessibilityOptionsExtensions.cs | 0 .../{Acceptance => AcceptanceTests}/Options/OptionsHelper.cs | 0 .../Options/WebDriverOptions.cs | 0 .../Options/WebDriverSessionOptions.cs | 0 .../{Acceptance => AcceptanceTests}/Options/WebOptions.cs | 0 .../Web/Tests/{Acceptance => AcceptanceTests}/README.md | 0 .../Steps/AccessibilitySteps.cs | 5 +---- .../Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj | 5 +---- .../{Integration => PageIntegrationTests}/SearchPageTests.cs | 2 -- .../Web/Tests/{PageObjectModel => Pages}/BasePage.cs | 0 .../Web/Tests/{PageObjectModel => Pages}/SearchPage.cs | 5 +---- Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json | 3 +++ 22 files changed, 8 insertions(+), 16 deletions(-) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Drivers/IWebDriverContext.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Drivers/IWebDriverFactory.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Drivers/WebDriverContext.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Drivers/WebDriverExtensions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Drivers/WebDriverFactory.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Extensions/StringExtensions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Features/AccessibilityTests.feature (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Features/AccessibilityTests.feature.cs (97%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Hooks/SpecFlowHooks.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Options/AccessibilityOptions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Options/AccessibilityOptionsExtensions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Options/OptionsHelper.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Options/WebDriverOptions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Options/WebDriverSessionOptions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Options/WebOptions.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/README.md (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{Acceptance => AcceptanceTests}/Steps/AccessibilitySteps.cs (94%) rename Dfe.Data.SearchPrototype/Web/Tests/{Integration => PageIntegrationTests}/SearchPageTests.cs (90%) rename Dfe.Data.SearchPrototype/Web/Tests/{PageObjectModel => Pages}/BasePage.cs (100%) rename Dfe.Data.SearchPrototype/Web/Tests/{PageObjectModel => Pages}/SearchPage.cs (69%) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverContext.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverContext.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverContext.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverContext.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverFactory.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/IWebDriverFactory.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverFactory.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverContext.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverContext.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverContext.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverContext.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverExtensions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverExtensions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverExtensions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Drivers/WebDriverFactory.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Extensions/StringExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Extensions/StringExtensions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Extensions/StringExtensions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Extensions/StringExtensions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs similarity index 97% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index d4a9989..184153d 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -10,7 +10,7 @@ // ------------------------------------------------------------------------------ #region Designer generated code #pragma warning disable -namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Features +namespace Dfe.Data.SearchPrototype.Web.Tests.AcceptanceTests.Features { using TechTalk.SpecFlow; using System; @@ -40,7 +40,7 @@ public AccessibilityTestsFeature(AccessibilityTestsFeature.FixtureData fixtureDa public static void FeatureSetup() { testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); - TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Acceptance/Features", "AccessibilityTests", null, ProgrammingLanguage.CSharp, featureTags); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "AcceptanceTests/Features", "AccessibilityTests", null, ProgrammingLanguage.CSharp, featureTags); testRunner.OnFeatureStart(featureInfo); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Hooks/SpecFlowHooks.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/AccessibilityOptions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/AccessibilityOptions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptionsExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/AccessibilityOptionsExtensions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/AccessibilityOptionsExtensions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/AccessibilityOptionsExtensions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/OptionsHelper.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/OptionsHelper.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/OptionsHelper.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/OptionsHelper.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverOptions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverOptions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverOptions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverSessionOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebDriverSessionOptions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebOptions.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Options/WebOptions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebOptions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/README.md rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs similarity index 94% rename from Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs rename to Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 636938b..73cf505 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Acceptance/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -14,7 +14,6 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Steps public sealed class AccessibilitySteps { private readonly AccessibilityOptions _options; - private readonly HomePage _homePage; private readonly ITestOutputHelper _logger; private readonly IWebDriverContext _driverContext; private readonly SearchPage _searchPage; @@ -27,7 +26,6 @@ public sealed class AccessibilitySteps }; public AccessibilitySteps( - HomePage homePage, IOptions options, ITestOutputHelper logger, IWebDriverContext driverContext, @@ -37,7 +35,6 @@ WebDriverSessionOptions sessionOptions { _driverContext = driverContext; _searchPage = searchPage; - _homePage = homePage; _logger = logger; _options = options.Value; _sessionOptions = sessionOptions; @@ -62,7 +59,7 @@ public void IsAccessible(string component) var axeResult = new AxeBuilder(_driverContext.Driver) .WithTags(_options.WcagTags) .WithOutputFile(outputFile) - .Exclude(_homePage.SearchHiddenDiv.Criteria) + .Exclude(_searchPage.SearchHiddenDiv.Criteria) .Analyze(); _logger.WriteLine($"Scan completed output location {outputFile}"); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index 1ba069d..052ca9e 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -15,6 +15,7 @@ + @@ -30,10 +31,6 @@ - - - - PreserveNewest diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs similarity index 90% rename from Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs rename to Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs index 4e4713d..2319aa3 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Integration/SearchPageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs @@ -9,7 +9,6 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.Integration { public class SearchPageTests : IClassFixture { - private readonly HttpClient _client; private readonly WebApplicationFactory _factory; public SearchPageTests(PageWebApplicationFactory factory) @@ -22,7 +21,6 @@ public async Task Search() { var response = await _factory.CreateClient().GetAsync("http://localhost:5000"); - response.EnsureSuccessStatusCode(); var document = await HtmlHelpers.GetDocumentAsync(response); document.GetElementText(SearchPage.Heading.Criteria).Should().Be("Search prototype"); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/BasePage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Pages/BasePage.cs similarity index 100% rename from Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/BasePage.cs rename to Dfe.Data.SearchPrototype/Web/Tests/Pages/BasePage.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs similarity index 69% rename from Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs rename to Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs index 57066da..6c55b95 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageObjectModel/SearchPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs @@ -1,8 +1,4 @@ using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; -using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.PageComponents; -using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel.Setup; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Mvc.Testing; using OpenQA.Selenium; namespace Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; @@ -15,4 +11,5 @@ public SearchPage(IWebDriverContext driverContext) : base(driverContext) public IWebElement HeadingElement => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); public static By Heading => By.CssSelector("header div div:nth-of-type(2) a"); + public By SearchHiddenDiv => By.CssSelector("#searchKeyWord + div"); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json b/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json index 476a5da..2c23fee 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json +++ b/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json @@ -9,5 +9,8 @@ }, "accessibility": { "ArtifactsOutputPath": "" + }, + "azureSearchClientOptions": { + "credentials": "" } } From 34acc48f93785144883a635e00257d4486695d6e Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Thu, 25 Jul 2024 14:27:37 +0100 Subject: [PATCH 12/31] added search form page integration test removed privacy page --- .../Features/AccessibilityTests.feature | 7 +- .../Features/AccessibilityTests.feature.cs | 39 ++-------- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 31 +++++--- .../Steps/AccessibilitySteps.cs | 2 +- .../PageIntegrationTests/SearchPageTests.cs | 47 +++++++++++- .../Web/Tests/PageWebApplicationFactory.cs | 2 - .../Web/Tests/Pages/SearchPage.cs | 4 + .../Shared/Helpers/HttpClientExtensions.cs | 75 +++++++++++++++++++ 8 files changed, 153 insertions(+), 54 deletions(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 95032a6..4b2fe74 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,9 +1,6 @@ Feature: AccessibilityTests +@ignore Scenario: Homepage accessibility When the user views the home page - Then the home page is accessible - -Scenario: Privacy page accessibility - When the user views the privacy page - Then the privacy page is accessible \ No newline at end of file + Then the home page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index 184153d..a1c4d6a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,15 +80,16 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility", Skip="Ignored")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Homepage accessibility")] public void HomepageAccessibility() { - string[] tagsOfScenario = ((string[])(null)); + string[] tagsOfScenario = new string[] { + "ignore"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 3 +#line 4 this.ScenarioInitialize(scenarioInfo); #line hidden if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) @@ -98,44 +99,16 @@ public void HomepageAccessibility() else { this.ScenarioStart(); -#line 4 +#line 5 testRunner.When("the user views the home page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden -#line 5 +#line 6 testRunner.Then("the home page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden } this.ScenarioCleanup(); } - [Xunit.SkippableFactAttribute(DisplayName="Privacy page accessibility")] - [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] - [Xunit.TraitAttribute("Description", "Privacy page accessibility")] - public void PrivacyPageAccessibility() - { - string[] tagsOfScenario = ((string[])(null)); - System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Privacy page accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 7 -this.ScenarioInitialize(scenarioInfo); -#line hidden - if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) - { - testRunner.SkipScenario(); - } - else - { - this.ScenarioStart(); -#line 8 - testRunner.When("the user views the privacy page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line hidden -#line 9 - testRunner.Then("the privacy page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line hidden - } - this.ScenarioCleanup(); - } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 91dad3f..11db905 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -4,27 +4,40 @@ using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; using Microsoft.Extensions.Options; +using OpenQA.Selenium.DevTools.V125.Animation; +using Microsoft.Extensions.Logging; +using Xunit.Abstractions; namespace UnitTestProject1 { [Binding] public class SpecFlowHooks { - public SpecFlowHooks( ) + private readonly ITestOutputHelper _logger; + + public SpecFlowHooks(ITestOutputHelper logger) { + _logger = logger; } [Before] public void Before() { - var process = new Process - { - StartInfo = - { - FileName = "Dfe.Data.SearchPrototype.Web.exe", - } - }; - process.Start(); + var workingDir = Directory.GetCurrentDirectory(); + _logger.WriteLine(workingDir); + + //var process = new Process + //{ + // StartInfo = + // { + // //FileName = "Dfe.Data.SearchPrototype.Web.exe", + // //WorkingDirectory = "\dfe.data.SearchPrototype\Web", + // //FileName = "dotnet", + // //Arguments = "run --urls=http://localhost:5000" + // } + //}; + //process.Start(); + ////Thread.Sleep(4000); } [BeforeTestRun] diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 73cf505..9ef12ec 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -40,7 +40,7 @@ WebDriverSessionOptions sessionOptions _sessionOptions = sessionOptions; } - [StepDefinition(@"the user views the (home|privacy) page")] + [StepDefinition(@"the user views the (home) page")] public void OpenPage(string pageName) { _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs index 2319aa3..863639b 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs @@ -1,29 +1,68 @@ -using AngleSharp.Html.Dom; +using AngleSharp.Dom; +using AngleSharp.Html.Dom; using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; using Dfe.Data.SearchPrototype.Web.Tests.Shared.Helpers; using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; using Xunit; +using Xunit.Abstractions; namespace Dfe.Data.SearchPrototype.Web.Tests.Integration { public class SearchPageTests : IClassFixture { + private const string uri = "http://localhost:5000"; + private readonly HttpClient _client; + private readonly ITestOutputHelper _logger; private readonly WebApplicationFactory _factory; - public SearchPageTests(PageWebApplicationFactory factory) + public SearchPageTests(PageWebApplicationFactory factory, ITestOutputHelper logger) { _factory = factory; + _client = factory.CreateClient(new WebApplicationFactoryClientOptions + { + AllowAutoRedirect = true + }); + _logger = logger; } [Fact] - public async Task Search() + public async Task Search_Title_IsDisplayed() { - var response = await _factory.CreateClient().GetAsync("http://localhost:5000"); + var response = await _factory.CreateClient().GetAsync(uri); var document = await HtmlHelpers.GetDocumentAsync(response); document.GetElementText(SearchPage.Heading.Criteria).Should().Be("Search prototype"); } + + [Fact] + public async Task Search_ByName_ReturnsResults() + { + var response = await _factory.CreateClient().GetAsync(uri); + var document = await HtmlHelpers.GetDocumentAsync(response); + + var formElement = document.QuerySelector(SearchPage.SearchForm.Criteria) ?? throw new Exception("Unable to find the sign in form"); + var formButton = document.QuerySelector(SearchPage.SearchButton.Criteria) ?? throw new Exception("Unable to find the submit button on search form"); + var searchTerm = "academy"; + + var formResponse = await _client.SendAsync( + formElement, + formButton, + new Dictionary + { + ["searchKeyWord"] = searchTerm + }); + + _logger.WriteLine("SendAsync client base address: " + _client.BaseAddress); + _logger.WriteLine("SendAsync request message: " + formResponse.RequestMessage.ToString()); + + var resultsPage = await HtmlHelpers.GetDocumentAsync(formResponse); + + _logger.WriteLine("Document: " + resultsPage.Body.OuterHtml); + + resultsPage.GetElementText(SearchPage.SearchResultsNumber.Criteria).Should().Contain("Results"); + resultsPage.GetMultipleElements(SearchPage.SearchResultLinks.Criteria).Count().Should().BeGreaterThan(1); + } } } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs index dffdb73..8e86d31 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs @@ -32,8 +32,6 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) // remove any services that need overriding with test configuration t.RemoveAll>(); - //TODO comparisonTablePageTemplateService - // register dependencies with test configuration t.AddOptions().Configure( diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs index 6c55b95..646cd95 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs @@ -12,4 +12,8 @@ public SearchPage(IWebDriverContext driverContext) : base(driverContext) public IWebElement HeadingElement => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); public static By Heading => By.CssSelector("header div div:nth-of-type(2) a"); public By SearchHiddenDiv => By.CssSelector("#searchKeyWord + div"); + public static By SearchForm => By.CssSelector("#main-content form"); + public static By SearchButton => By.CssSelector("#main-content form button"); + public static By SearchResultsNumber => By.CssSelector(".govuk-heading-m"); + public static By SearchResultLinks => By.CssSelector("ul li h4 a"); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs new file mode 100644 index 0000000..c9f37ab --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs @@ -0,0 +1,75 @@ +using AngleSharp.Html.Dom; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.Helpers; +using Xunit; + +namespace Dfe.Data.SearchPrototype.Web.Tests.Shared.Helpers +{ + public static class HttpClientExtensions + { + public static Task SendAsync( + this HttpClient client, + IHtmlFormElement form, + IHtmlElement submitButton) + { + return client.SendAsync(form, submitButton, new Dictionary()); + } + + public static Task SendAsync( + this HttpClient client, + IHtmlFormElement form, + IEnumerable> formValues) + { + var submitElement = Assert.Single(form.QuerySelectorAll("[type=submit]")); + var submitButton = Assert.IsAssignableFrom(submitElement); + + return client.SendAsync(form, submitButton, formValues); + } + + public static Task SendAsync( + this HttpClient client, + IHtmlFormElement form, + IHtmlElement submitButton, + IEnumerable> formValues) + { + foreach (var kvp in formValues) + { + switch (form[kvp.Key]) + { + case IHtmlInputElement input: + input.Value = kvp.Value; + if (bool.TryParse(kvp.Value, out var isChecked)) + { + input.IsChecked = isChecked; + } + + break; + case IHtmlSelectElement select: + select.Value = kvp.Value; + break; + default: + throw new Exception($"Unknown form element: '{kvp.Key}'"); + } + } + + var submit = form.GetSubmission(submitButton); + var target = (Uri)submit.Target; + if (submitButton.HasAttribute("formaction")) + { + var formaction = submitButton.GetAttribute("formaction"); + target = new Uri(formaction, UriKind.Relative); + } + var submision = new HttpRequestMessage(new HttpMethod(submit.Method.ToString()), target) + { + Content = new StreamContent(submit.Body) + }; + + foreach (var header in submit.Headers) + { + submision.Headers.TryAddWithoutValidation(header.Key, header.Value); + submision.Content.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + return client.SendAsync(submision); + } + } +} \ No newline at end of file From 0e4cf543836e4e848551b6fe5b58123d9923df25 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Thu, 25 Jul 2024 16:05:18 +0100 Subject: [PATCH 13/31] no results returned test added --- .../PageIntegrationTests/SearchPageTests.cs | 40 ++++++++++++++++--- .../Web/Tests/Pages/SearchPage.cs | 1 + 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs index 863639b..6055957 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs @@ -36,15 +36,16 @@ public async Task Search_Title_IsDisplayed() document.GetElementText(SearchPage.Heading.Criteria).Should().Be("Search prototype"); } - [Fact] - public async Task Search_ByName_ReturnsResults() + [Theory] + [InlineData("academy")] + [InlineData("school")] + public async Task Search_ByName_ReturnsResults(string searchTerm) { var response = await _factory.CreateClient().GetAsync(uri); var document = await HtmlHelpers.GetDocumentAsync(response); var formElement = document.QuerySelector(SearchPage.SearchForm.Criteria) ?? throw new Exception("Unable to find the sign in form"); var formButton = document.QuerySelector(SearchPage.SearchButton.Criteria) ?? throw new Exception("Unable to find the submit button on search form"); - var searchTerm = "academy"; var formResponse = await _client.SendAsync( formElement, @@ -55,14 +56,43 @@ public async Task Search_ByName_ReturnsResults() }); _logger.WriteLine("SendAsync client base address: " + _client.BaseAddress); - _logger.WriteLine("SendAsync request message: " + formResponse.RequestMessage.ToString()); + _logger.WriteLine("SendAsync request message: " + formResponse.RequestMessage!.ToString()); var resultsPage = await HtmlHelpers.GetDocumentAsync(formResponse); - _logger.WriteLine("Document: " + resultsPage.Body.OuterHtml); + _logger.WriteLine("Document: " + resultsPage.Body!.OuterHtml); resultsPage.GetElementText(SearchPage.SearchResultsNumber.Criteria).Should().Contain("Results"); resultsPage.GetMultipleElements(SearchPage.SearchResultLinks.Criteria).Count().Should().BeGreaterThan(1); } + + [Theory] + [InlineData("ant")] + [InlineData("boo")] + public async Task Search_ByName_NoMatch_ReturnsNoResults(string searchTerm) + { + var response = await _factory.CreateClient().GetAsync(uri); + var document = await HtmlHelpers.GetDocumentAsync(response); + + var formElement = document.QuerySelector(SearchPage.SearchForm.Criteria) ?? throw new Exception("Unable to find the sign in form"); + var formButton = document.QuerySelector(SearchPage.SearchButton.Criteria) ?? throw new Exception("Unable to find the submit button on search form"); + + var formResponse = await _client.SendAsync( + formElement, + formButton, + new Dictionary + { + ["searchKeyWord"] = searchTerm + }); + + _logger.WriteLine("SendAsync client base address: " + _client.BaseAddress); + _logger.WriteLine("SendAsync request message: " + formResponse.RequestMessage!.ToString()); + + var resultsPage = await HtmlHelpers.GetDocumentAsync(formResponse); + + _logger.WriteLine("Document: " + resultsPage.Body!.OuterHtml); + + resultsPage.GetElementText(SearchPage.SearchNoResultText.Criteria).Should().Be("Sorry no results found please amend your search criteria"); + } } } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs index 646cd95..28a13b1 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs @@ -16,4 +16,5 @@ public SearchPage(IWebDriverContext driverContext) : base(driverContext) public static By SearchButton => By.CssSelector("#main-content form button"); public static By SearchResultsNumber => By.CssSelector(".govuk-heading-m"); public static By SearchResultLinks => By.CssSelector("ul li h4 a"); + public static By SearchNoResultText => By.CssSelector("#main-content form + p"); } From 0f1ade78b4644e1b6ca4a59e0f692dff2ede44cd Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Mon, 29 Jul 2024 09:16:23 +0100 Subject: [PATCH 14/31] search establishment elements test added --- .../PageIntegrationTests/SearchPageTests.cs | 16 ++++++++++++++++ .../Web/Tests/Pages/SearchPage.cs | 3 +++ 2 files changed, 19 insertions(+) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs index 6055957..b62e381 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs @@ -36,6 +36,22 @@ public async Task Search_Title_IsDisplayed() document.GetElementText(SearchPage.Heading.Criteria).Should().Be("Search prototype"); } + [Fact] + public async Task Search_Establishment_IsDisplayed() + { + var response = await _factory.CreateClient().GetAsync(uri); + + var document = await HtmlHelpers.GetDocumentAsync(response); + + document.GetElementText(SearchPage.SearchHeading.Criteria).Should().Be("Search"); + + document.GetElementText(SearchPage.SearchSubHeading.Criteria).Should().Be("Search establishments and check their performance"); + + document.GetMultipleElements(SearchPage.SearchInput.Criteria).Count().Should().Be(1); + + document.GetMultipleElements(SearchPage.SearchButton.Criteria).Count().Should().Be(1); + } + [Theory] [InlineData("academy")] [InlineData("school")] diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs index 28a13b1..2d9674c 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs @@ -11,7 +11,10 @@ public SearchPage(IWebDriverContext driverContext) : base(driverContext) public IWebElement HeadingElement => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); public static By Heading => By.CssSelector("header div div:nth-of-type(2) a"); + public static By SearchHeading => By.CssSelector("h1 label"); + public static By SearchSubHeading => By.CssSelector("#searchKeyWord-hint"); public By SearchHiddenDiv => By.CssSelector("#searchKeyWord + div"); + public static By SearchInput => By.CssSelector("#searchKeyWord"); public static By SearchForm => By.CssSelector("#main-content form"); public static By SearchButton => By.CssSelector("#main-content form button"); public static By SearchResultsNumber => By.CssSelector(".govuk-heading-m"); From 3e1679c16a7b52c97dbee0da2262e0da5ec8b6e6 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Mon, 29 Jul 2024 11:37:04 +0100 Subject: [PATCH 15/31] dummy search service adator created and tests modified --- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 7 ++-- .../Dfe.Data.SearchPrototype.Web.Tests.csproj | 14 +++++++ .../PageIntegrationTests/SearchPageTests.cs | 36 +++++++++++++++--- .../DummySearchServiceAdapter.cs | 37 +++++++++++++++++++ .../DummySearchServiceAdapterOptions.cs | 7 ++++ .../Resources/Establishments.json | 17 +++++++++ .../Resources/JsonFileLoader.cs | 37 +++++++++++++++++++ .../Web/Tests/PageWebApplicationFactory.cs | 23 ++++++++++-- .../Web/Tests/appsettings.test.json | 3 ++ 9 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 11db905..435a05c 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -4,8 +4,6 @@ using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; using Microsoft.Extensions.Options; -using OpenQA.Selenium.DevTools.V125.Animation; -using Microsoft.Extensions.Logging; using Xunit.Abstractions; namespace UnitTestProject1 @@ -26,18 +24,19 @@ public void Before() var workingDir = Directory.GetCurrentDirectory(); _logger.WriteLine(workingDir); + //var process = new Process //{ // StartInfo = // { // //FileName = "Dfe.Data.SearchPrototype.Web.exe", - // //WorkingDirectory = "\dfe.data.SearchPrototype\Web", + // //WorkingDirectory = workingDir, // //FileName = "dotnet", // //Arguments = "run --urls=http://localhost:5000" // } //}; //process.Start(); - ////Thread.Sleep(4000); + //Thread.Sleep(4000); } [BeforeTestRun] diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index 052ca9e..70678af 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -5,6 +5,20 @@ enable enable + + + + + + + + + + + + PreserveNewest + + diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs index b62e381..393caa6 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs @@ -52,10 +52,8 @@ public async Task Search_Establishment_IsDisplayed() document.GetMultipleElements(SearchPage.SearchButton.Criteria).Count().Should().Be(1); } - [Theory] - [InlineData("academy")] - [InlineData("school")] - public async Task Search_ByName_ReturnsResults(string searchTerm) + [Fact] + public async Task Search_ByName_ReturnsSingleResult() { var response = await _factory.CreateClient().GetAsync(uri); var document = await HtmlHelpers.GetDocumentAsync(response); @@ -68,7 +66,35 @@ public async Task Search_ByName_ReturnsResults(string searchTerm) formButton, new Dictionary { - ["searchKeyWord"] = searchTerm + ["searchKeyWord"] = "School" + }); + + _logger.WriteLine("SendAsync client base address: " + _client.BaseAddress); + _logger.WriteLine("SendAsync request message: " + formResponse.RequestMessage!.ToString()); + + var resultsPage = await HtmlHelpers.GetDocumentAsync(formResponse); + + _logger.WriteLine("Document: " + resultsPage.Body!.OuterHtml); + + resultsPage.GetElementText(SearchPage.SearchResultsNumber.Criteria).Should().Contain("Result"); + resultsPage.GetMultipleElements(SearchPage.SearchResultLinks.Criteria).Count().Should().Be(1); + } + + [Fact] + public async Task Search_ByName_ReturnsMultipleResults() + { + var response = await _factory.CreateClient().GetAsync(uri); + var document = await HtmlHelpers.GetDocumentAsync(response); + + var formElement = document.QuerySelector(SearchPage.SearchForm.Criteria) ?? throw new Exception("Unable to find the sign in form"); + var formButton = document.QuerySelector(SearchPage.SearchButton.Criteria) ?? throw new Exception("Unable to find the submit button on search form"); + + var formResponse = await _client.SendAsync( + formElement, + formButton, + new Dictionary + { + ["searchKeyWord"] = "Academy" }); _logger.WriteLine("SendAsync client base address: " + _client.BaseAddress); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs new file mode 100644 index 0000000..f54012c --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs @@ -0,0 +1,37 @@ +using Dfe.Data.SearchPrototype.Search; +using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources; +using Newtonsoft.Json.Linq; + +namespace Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter +{ + public sealed class DummySearchServiceAdapter : ISearchServiceAdapter where TSearchResult : class + { + private readonly IJsonFileLoader _jsonFileLoader; + + public DummySearchServiceAdapter(IJsonFileLoader jsonFileLoader) + { + _jsonFileLoader = jsonFileLoader; + } + + public async Task SearchAsync(SearchContext searchContext) + { + string json = await _jsonFileLoader.LoadJsonFile(); + + JObject establishmentsObject = JObject.Parse(json); + + IEnumerable establishments = + from establishmentToken in establishmentsObject["establishments"] + where establishmentToken["name"]!.ToString().Contains(searchContext.SearchKeyword) + select new Establishment( + (string)establishmentToken["urn"]!, + (string)establishmentToken["name"]!); + + EstablishmentResults results = new(); + + establishments.ToList().ForEach(establishment => results.AddEstablishment(establishment)); + + return results; + + } + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs new file mode 100644 index 0000000..476a2cf --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs @@ -0,0 +1,7 @@ +namespace Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options +{ + public sealed class DummySearchServiceAdapterOptions + { + public string FileName { get; set; } + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json new file mode 100644 index 0000000..6409242 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json @@ -0,0 +1,17 @@ +{ + "establishments": [ + + { + "urn": "123456", + "name": "Goose Academy" + }, + { + "urn": "234567", + "name": "Horse Academy" + }, + { + "urn": "345678", + "name": "Duck School" + } + ] +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs new file mode 100644 index 0000000..73c54f1 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs @@ -0,0 +1,37 @@ +using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options; +using Microsoft.Extensions.Options; + +namespace Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources +{ + public sealed class JsonFileLoader : IJsonFileLoader + { + private readonly DummySearchServiceAdapterOptions _options; + + public JsonFileLoader(IOptions options) + { + _options = options.Value; + } + + public Task LoadJsonFile() => LoadJsonFile(_options.FileName); + + public async Task LoadJsonFile(string path) + { + string? rawJson = null; + + using (StreamReader sr = new StreamReader(path)) + { + rawJson = await sr.ReadToEndAsync(); + } + + return rawJson; + + } + } + + public interface IJsonFileLoader + { + Task LoadJsonFile(); + + Task LoadJsonFile(string path); + } +} diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs index 8e86d31..4962ce9 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs @@ -1,10 +1,16 @@ -using DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch.Options; +using Dfe.Data.SearchPrototype.Infrastructure; +using Dfe.Data.SearchPrototype.Search; +using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter; +using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options; +using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources; +using DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch.Options; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using Infrastructure = Dfe.Data.SearchPrototype.Infrastructure; namespace Dfe.Data.SearchPrototype.Web.Tests; @@ -27,14 +33,23 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) { throw new ArgumentNullException("Missing test configuration: configure your user secrets file"); }; - builder.ConfigureServices(t => + builder.ConfigureServices(services => { // remove any services that need overriding with test configuration - t.RemoveAll>(); + services.RemoveAll>(); + + services.RemoveAll(); // register dependencies with test configuration - t.AddOptions().Configure( + services.AddSingleton(); + + services.AddScoped(typeof(ISearchServiceAdapter), typeof(DummySearchServiceAdapter)); + + services.AddOptions().Configure( + (options) => options.FileName = TestConfiguration["dummySearchServiceAdapter:fileName"]); + + services.AddOptions().Configure( (options) => options.Credentials = TestConfiguration["azureSearchClientOptions:credentials"]); }); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json b/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json index 2c23fee..e463148 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json +++ b/Dfe.Data.SearchPrototype/Web/Tests/appsettings.test.json @@ -12,5 +12,8 @@ }, "azureSearchClientOptions": { "credentials": "" + }, + "dummySearchServiceAdapter": { + "fileName": "Establishments.json" } } From 0b670de99e452329611f13fec5205123f427622f Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Mon, 29 Jul 2024 14:19:33 +0100 Subject: [PATCH 16/31] dotnet run added back into specflow hooks --- .../Features/AccessibilityTests.feature | 1 - .../Features/AccessibilityTests.feature.cs | 5 +- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 69 ++++++++++++------- .../DummySearchServiceAdapterOptions.cs | 2 +- 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 4b2fe74..2a3f007 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,6 +1,5 @@ Feature: AccessibilityTests -@ignore Scenario: Homepage accessibility When the user views the home page Then the home page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index a1c4d6a..2b236ca 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,13 +80,12 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility", Skip="Ignored")] + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Homepage accessibility")] public void HomepageAccessibility() { - string[] tagsOfScenario = new string[] { - "ignore"}; + string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); #line 4 diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 435a05c..408d47f 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -5,6 +5,7 @@ using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; using Microsoft.Extensions.Options; using Xunit.Abstractions; +using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Extensions; namespace UnitTestProject1 { @@ -18,30 +19,23 @@ public SpecFlowHooks(ITestOutputHelper logger) _logger = logger; } - [Before] - public void Before() - { - var workingDir = Directory.GetCurrentDirectory(); - _logger.WriteLine(workingDir); - - - //var process = new Process - //{ - // StartInfo = - // { - // //FileName = "Dfe.Data.SearchPrototype.Web.exe", - // //WorkingDirectory = workingDir, - // //FileName = "dotnet", - // //Arguments = "run --urls=http://localhost:5000" - // } - //}; - //process.Start(); - //Thread.Sleep(4000); - } - [BeforeTestRun] public static void BeforeTest(ObjectContainer container) { + var newPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")); + + var process = new Process + { + StartInfo = + { + //FileName = "Dfe.Data.SearchPrototype.Web.exe", + WorkingDirectory = newPath, + FileName = "dotnet", + Arguments = "run --urls=http://localhost:5000" + } + }; + process.Start(); + Thread.Sleep(1000); container.BaseContainer.RegisterInstanceAs(OptionsHelper.GetOptions(WebOptions.Key)); @@ -63,12 +57,39 @@ public void CreateWebDriver(IObjectContainer container) container.RegisterTypeAs(); } - - [After] - public void After() + [AfterScenario] + public void After( + FeatureContext featureContext, + ScenarioContext scenarioContext, + ITestOutputHelper logger, + IOptions driverOptions, + WebDriverSessionOptions sessionOptions, + IWebDriverContext driverContext + ) + { + using (driverContext) + { + logger.WriteLine($"START {nameof(After)}"); + if (scenarioContext.ScenarioExecutionStatus == ScenarioExecutionStatus.TestError) + { + logger.WriteLine($"FAILURE DETECTED: {scenarioContext.TestError.Message}"); + logger.WriteLine($"FAILURE URL: {driverContext.Driver.Url}"); + logger.WriteLine($"FAILURE HTML: {driverContext.Driver.PageSource}"); + var featureName = featureContext.FeatureInfo.Title.ToLowerRemoveHyphens(); + var scenarioName = scenarioContext.ScenarioInfo.Title.ToLowerRemoveHyphens(); + var testName = $"{sessionOptions.Device}-{featureName}-{scenarioName}"; + driverContext.TakeScreenshot(logger, testName); + } + logger.WriteLine($"FINISH {nameof(After)}"); + } + } + + [AfterTestRun] + public static void After() { var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); webProcesses[0].Kill(); } + } } \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs index 476a2cf..82ca2b7 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs @@ -2,6 +2,6 @@ { public sealed class DummySearchServiceAdapterOptions { - public string FileName { get; set; } + public string? FileName { get; set; } } } From f85d82837b09b2a12b2ed8d66a99aff237208b4a Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Mon, 29 Jul 2024 14:40:03 +0100 Subject: [PATCH 17/31] temporary removal of accessibility test and app start through hooks --- .../Features/AccessibilityTests.feature | 1 + .../Features/AccessibilityTests.feature.cs | 5 +-- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 32 +++++++++---------- .../Dfe.Data.SearchPrototype.Web.Tests.csproj | 8 +++++ 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 2a3f007..4b2fe74 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,5 +1,6 @@ Feature: AccessibilityTests +@ignore Scenario: Homepage accessibility When the user views the home page Then the home page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index 2b236ca..a1c4d6a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,12 +80,13 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility", Skip="Ignored")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Homepage accessibility")] public void HomepageAccessibility() { - string[] tagsOfScenario = ((string[])(null)); + string[] tagsOfScenario = new string[] { + "ignore"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); #line 4 diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 408d47f..668652b 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -22,20 +22,20 @@ public SpecFlowHooks(ITestOutputHelper logger) [BeforeTestRun] public static void BeforeTest(ObjectContainer container) { - var newPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")); - - var process = new Process - { - StartInfo = - { - //FileName = "Dfe.Data.SearchPrototype.Web.exe", - WorkingDirectory = newPath, - FileName = "dotnet", - Arguments = "run --urls=http://localhost:5000" - } - }; - process.Start(); - Thread.Sleep(1000); + //var newPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")); + // + //var process = new Process + //{ + // StartInfo = + // { + // //FileName = "Dfe.Data.SearchPrototype.Web.exe", + // WorkingDirectory = newPath, + // FileName = "dotnet", + // Arguments = "run --urls=http://localhost:5000" + // } + //}; + //process.Start(); + //Thread.Sleep(1000); container.BaseContainer.RegisterInstanceAs(OptionsHelper.GetOptions(WebOptions.Key)); @@ -87,8 +87,8 @@ IWebDriverContext driverContext [AfterTestRun] public static void After() { - var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); - webProcesses[0].Kill(); + //var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); + //webProcesses[0].Kill(); } } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index 70678af..74cac9a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -51,4 +51,12 @@ + + + + + + + + From 210ba38fca5a04cd488f258874aebc585b524f39 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Mon, 29 Jul 2024 14:55:08 +0100 Subject: [PATCH 18/31] commented out after hook --- .../Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 435a05c..dffb1fa 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -67,8 +67,8 @@ public void CreateWebDriver(IObjectContainer container) [After] public void After() { - var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); - webProcesses[0].Kill(); + //var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); + //webProcesses[0].Kill(); } } } \ No newline at end of file From b392aed2d682359daabce4ed8dd1c74840700fc0 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 30 Jul 2024 10:14:52 +0100 Subject: [PATCH 19/31] experimentation of dotnet run for accessibility test in pipeline --- .../Features/AccessibilityTests.feature | 1 - .../Features/AccessibilityTests.feature.cs | 11 ++++----- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 24 +++++++++---------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 4b2fe74..2a3f007 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,6 +1,5 @@ Feature: AccessibilityTests -@ignore Scenario: Homepage accessibility When the user views the home page Then the home page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index a1c4d6a..fcb83bd 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,16 +80,15 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility", Skip="Ignored")] + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Homepage accessibility")] public void HomepageAccessibility() { - string[] tagsOfScenario = new string[] { - "ignore"}; + string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 4 +#line 3 this.ScenarioInitialize(scenarioInfo); #line hidden if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) @@ -99,10 +98,10 @@ public void HomepageAccessibility() else { this.ScenarioStart(); -#line 5 +#line 4 testRunner.When("the user views the home page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden -#line 6 +#line 5 testRunner.Then("the home page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index dffb1fa..6b697b4 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -25,18 +25,18 @@ public void Before() _logger.WriteLine(workingDir); - //var process = new Process - //{ - // StartInfo = - // { - // //FileName = "Dfe.Data.SearchPrototype.Web.exe", - // //WorkingDirectory = workingDir, - // //FileName = "dotnet", - // //Arguments = "run --urls=http://localhost:5000" - // } - //}; - //process.Start(); - //Thread.Sleep(4000); + var process = new Process + { + StartInfo = + { + //FileName = "Dfe.Data.SearchPrototype.Web.exe", + WorkingDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")), + FileName = "dotnet", + Arguments = "run --urls=http://localhost:5000" + } + }; + process.Start(); + Thread.Sleep(1000); } [BeforeTestRun] From 9a2892ee0c99102a3400d43aea0b0f1dc62829a2 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 30 Jul 2024 10:33:48 +0100 Subject: [PATCH 20/31] header link test added --- .../Web/Tests/PageIntegrationTests/SearchPageTests.cs | 10 ++++++++++ Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs | 1 + 2 files changed, 11 insertions(+) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs index 393caa6..38fb0ac 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchPageTests.cs @@ -36,6 +36,16 @@ public async Task Search_Title_IsDisplayed() document.GetElementText(SearchPage.Heading.Criteria).Should().Be("Search prototype"); } + [Fact] + public async Task Header_Link_IsDisplayed() + { + var response = await _factory.CreateClient().GetAsync(uri); + + var document = await HtmlHelpers.GetDocumentAsync(response); + + document.GetElementText(SearchPage.HomeLink.Criteria).Should().Be("Home"); + } + [Fact] public async Task Search_Establishment_IsDisplayed() { diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs index 2d9674c..b8b1ab0 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Pages/SearchPage.cs @@ -11,6 +11,7 @@ public SearchPage(IWebDriverContext driverContext) : base(driverContext) public IWebElement HeadingElement => DriverContext.Wait.UntilElementExists(By.CssSelector("header div div:nth-of-type(2) a")); public static By Heading => By.CssSelector("header div div:nth-of-type(2) a"); + public static By HomeLink => By.CssSelector("nav a"); public static By SearchHeading => By.CssSelector("h1 label"); public static By SearchSubHeading => By.CssSelector("#searchKeyWord-hint"); public By SearchHiddenDiv => By.CssSelector("#searchKeyWord + div"); From e99775429544b8fe2fb9a8158bda93bbafdc64a7 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 30 Jul 2024 10:39:31 +0100 Subject: [PATCH 21/31] ignored accessibility test and hook to start web --- .../Features/AccessibilityTests.feature | 1 + .../Features/AccessibilityTests.feature.cs | 11 ++++--- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 32 +++++++++---------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 2a3f007..4b2fe74 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,5 +1,6 @@ Feature: AccessibilityTests +@ignore Scenario: Homepage accessibility When the user views the home page Then the home page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index fcb83bd..a1c4d6a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,15 +80,16 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility", Skip="Ignored")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Homepage accessibility")] public void HomepageAccessibility() { - string[] tagsOfScenario = ((string[])(null)); + string[] tagsOfScenario = new string[] { + "ignore"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 3 +#line 4 this.ScenarioInitialize(scenarioInfo); #line hidden if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) @@ -98,10 +99,10 @@ public void HomepageAccessibility() else { this.ScenarioStart(); -#line 4 +#line 5 testRunner.When("the user views the home page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden -#line 5 +#line 6 testRunner.Then("the home page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 6b697b4..4c48183 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -21,22 +21,22 @@ public SpecFlowHooks(ITestOutputHelper logger) [Before] public void Before() { - var workingDir = Directory.GetCurrentDirectory(); - _logger.WriteLine(workingDir); - - - var process = new Process - { - StartInfo = - { - //FileName = "Dfe.Data.SearchPrototype.Web.exe", - WorkingDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")), - FileName = "dotnet", - Arguments = "run --urls=http://localhost:5000" - } - }; - process.Start(); - Thread.Sleep(1000); + //var workingDir = Directory.GetCurrentDirectory(); + //_logger.WriteLine(workingDir); + // + // + //var process = new Process + //{ + // StartInfo = + // { + // //FileName = "Dfe.Data.SearchPrototype.Web.exe", + // WorkingDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")), + // FileName = "dotnet", + // Arguments = "run --urls=http://localhost:5000" + // } + //}; + //process.Start(); + //Thread.Sleep(1000); } [BeforeTestRun] From 7dad5fcbb92855adcceea97ca372ba6fc4cb258b Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 30 Jul 2024 11:07:04 +0100 Subject: [PATCH 22/31] hooks and accessibility test back in --- .../Features/AccessibilityTests.feature | 1 - .../Features/AccessibilityTests.feature.cs | 11 +++---- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 32 +++++++++---------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 4b2fe74..2a3f007 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,6 +1,5 @@ Feature: AccessibilityTests -@ignore Scenario: Homepage accessibility When the user views the home page Then the home page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index a1c4d6a..fcb83bd 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,16 +80,15 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility", Skip="Ignored")] + [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Homepage accessibility")] public void HomepageAccessibility() { - string[] tagsOfScenario = new string[] { - "ignore"}; + string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 4 +#line 3 this.ScenarioInitialize(scenarioInfo); #line hidden if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) @@ -99,10 +98,10 @@ public void HomepageAccessibility() else { this.ScenarioStart(); -#line 5 +#line 4 testRunner.When("the user views the home page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden -#line 6 +#line 5 testRunner.Then("the home page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 4c48183..33250ab 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -21,22 +21,22 @@ public SpecFlowHooks(ITestOutputHelper logger) [Before] public void Before() { - //var workingDir = Directory.GetCurrentDirectory(); - //_logger.WriteLine(workingDir); - // - // - //var process = new Process - //{ - // StartInfo = - // { - // //FileName = "Dfe.Data.SearchPrototype.Web.exe", - // WorkingDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")), - // FileName = "dotnet", - // Arguments = "run --urls=http://localhost:5000" - // } - //}; - //process.Start(); - //Thread.Sleep(1000); + var workingDir = Directory.GetCurrentDirectory(); + _logger.WriteLine(workingDir); + + + var process = new Process + { + StartInfo = + { + //FileName = "Dfe.Data.SearchPrototype.Web.exe", + WorkingDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")), + FileName = "dotnet", + Arguments = "run --urls=http://localhost:5000" + } + }; + process.Start(); + Thread.Sleep(1000); } [BeforeTestRun] From f53a070e5d57176befe68a0bede4e3cdafff7e95 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Tue, 30 Jul 2024 14:46:12 +0100 Subject: [PATCH 23/31] added establishment address and type to dummy search after merging main --- .../DummySearchServiceAdapter.cs | 18 ++++++----- .../DummySearchServiceAdapterOptions.cs | 2 +- .../Resources/Establishments.json | 32 ++++++++++++++++--- .../Web/Tests/PageWebApplicationFactory.cs | 4 +-- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs index f54012c..c01be01 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs @@ -1,4 +1,4 @@ -using Dfe.Data.SearchPrototype.Search; +using Dfe.Data.SearchPrototype.SearchForEstablishments; using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources; using Newtonsoft.Json.Linq; @@ -24,14 +24,16 @@ from establishmentToken in establishmentsObject["establishments"] where establishmentToken["name"]!.ToString().Contains(searchContext.SearchKeyword) select new Establishment( (string)establishmentToken["urn"]!, - (string)establishmentToken["name"]!); - - EstablishmentResults results = new(); - - establishments.ToList().ForEach(establishment => results.AddEstablishment(establishment)); - - return results; + (string)establishmentToken["name"]!, + new Address( + (string)establishmentToken["address"]!["street"]!, + (string)establishmentToken["address"]!["locality"]!, + (string)establishmentToken["address"]!["address3"]!, + (string)establishmentToken["address"]!["town"]!, + (string)establishmentToken["address"]!["postcode"]!), + (string)establishmentToken["establishmentType"]!); + return new EstablishmentResults(establishments); } } } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs index 476a2cf..82ca2b7 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs @@ -2,6 +2,6 @@ { public sealed class DummySearchServiceAdapterOptions { - public string FileName { get; set; } + public string? FileName { get; set; } } } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json index 6409242..58ee502 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json @@ -3,15 +3,39 @@ { "urn": "123456", - "name": "Goose Academy" + "name": "Goose Academy", + "address": + { + "street": "Street One", + "locality": "locality", + "address3": "address3", + "town": "town", + "postcode": "postcode" + } }, { "urn": "234567", - "name": "Horse Academy" + "name": "Horse Academy", + "address": + { + "street": "Street One", + "locality": "locality", + "address3": "address3", + "town": "town", + "postcode": "postcode" + } }, - { + { "urn": "345678", - "name": "Duck School" + "name": "Duck School", + "address": + { + "street": "Street One", + "locality": "locality", + "address3": "address3", + "town": "town", + "postcode": "postcode" + } } ] } \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs index 4962ce9..3b7ace7 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs @@ -1,5 +1,4 @@ -using Dfe.Data.SearchPrototype.Infrastructure; -using Dfe.Data.SearchPrototype.Search; +using Dfe.Data.SearchPrototype.SearchForEstablishments; using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter; using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options; using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources; @@ -10,7 +9,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; -using Infrastructure = Dfe.Data.SearchPrototype.Infrastructure; namespace Dfe.Data.SearchPrototype.Web.Tests; From 476777f205644eed7bf7e7c82162d6201947ed5b Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 31 Jul 2024 08:43:57 +0100 Subject: [PATCH 24/31] web app factory fixture implemented --- .../Drivers/IWebDriverFactory.cs | 3 +- .../Drivers/WebDriverContext.cs | 31 ++++++---- .../Drivers/WebDriverFactory.cs | 62 +++++++++++-------- .../AcceptanceTests/Hooks/SpecFlowHooks.cs | 38 ------------ .../Steps/AccessibilitySteps.cs | 19 +++++- .../WebApplicationFactoryFixture.cs | 62 +++++++++++++++++++ .../Dfe.Data.SearchPrototype.Web.Tests.csproj | 8 +-- .../Resources/Establishments.json | 41 ------------ .../Web/Tests/PageWebApplicationFactory.cs | 6 +- .../DummySearchServiceAdapter.cs | 6 +- .../DummySearchServiceAdapterOptions.cs | 2 +- .../Resources/Establishments.json | 41 ++++++++++++ .../Resources/JsonFileLoader.cs | 4 +- 13 files changed, 190 insertions(+), 133 deletions(-) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs delete mode 100644 Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json rename Dfe.Data.SearchPrototype/Web/Tests/{PageIntegrationTests => Shared}/SearchServiceAdapter/DummySearchServiceAdapter.cs (86%) rename Dfe.Data.SearchPrototype/Web/Tests/{PageIntegrationTests => Shared}/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs (54%) create mode 100644 Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/Establishments.json rename Dfe.Data.SearchPrototype/Web/Tests/{PageIntegrationTests => Shared}/SearchServiceAdapter/Resources/JsonFileLoader.cs (81%) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverFactory.cs index d352751..805797c 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/IWebDriverFactory.cs @@ -4,5 +4,6 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; public interface IWebDriverFactory { - Lazy CreateDriver(); + // TODO: reimplement Lazy + IWebDriver CreateDriver(); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverContext.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverContext.cs index f3c3ed0..a86cc0d 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverContext.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverContext.cs @@ -10,13 +10,14 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; public class WebDriverContext : IWebDriverContext { private readonly WebDriverOptions _driverOptions; - private readonly Lazy _driver; + // TODO: reimplement Lazy + private readonly IWebDriver _driver; private readonly Lazy> _wait; private readonly string _baseUri; - public IWebDriver Driver => _driver.Value; + public IWebDriver Driver => _driver; public IWait Wait => _wait.Value; - private Type[] IgnoredExceptions { get; } = new[] { typeof(StaleElementReferenceException) }; + private Type[] IgnoredExceptions { get; } = [typeof(StaleElementReferenceException)]; public WebDriverContext( IWebDriverFactory factory, @@ -30,7 +31,9 @@ IOptions driverOptions _driverOptions = driverOptions.Value; } - private IJavaScriptExecutor JsExecutor => Driver as IJavaScriptExecutor ?? throw new ArgumentNullException(nameof(IJavaScriptExecutor)); + private IJavaScriptExecutor JsExecutor => + Driver as IJavaScriptExecutor ?? + throw new ArgumentNullException(nameof(IJavaScriptExecutor)); /// /// Navigate to relative path @@ -64,16 +67,22 @@ public void GoToUri(string baseUri, string path = "/") /// public void Dispose() { - using (Driver) + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) { - Driver.Quit(); + using (Driver) + { + Driver.Quit(); + } } } - public void TakeScreenshot( - ITestOutputHelper logger, - string testName - ) + public void TakeScreenshot(ITestOutputHelper logger, string testName) { // Allows alternative path @@ -127,4 +136,4 @@ private int GetBrowserHeight() => document.body.scrollHeight, document.documentElement.scrollHeight)" ); -} +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs index 1131f7a..acdf870 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs @@ -4,10 +4,9 @@ using Microsoft.Extensions.Options; using System.Drawing; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; - + namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; - - + public sealed class WebDriverFactory : IWebDriverFactory { private static readonly IEnumerable DEFAULT_OPTIONS = new[] @@ -18,18 +17,20 @@ public sealed class WebDriverFactory : IWebDriverFactory "--start-maximized", "--start-fullscreen" }; - + private static readonly Dictionary MOBILE_VIEWPORTS = new() { { "desktop", (1920, 1080) }, { "iphone14", (390, 844) }, { "iphone11", (414, 896) } }; - + private static TimeSpan DEFAULT_PAGE_LOAD_TIMEOUT = TimeSpan.FromSeconds(30); + private readonly WebDriverOptions _webDriverOptions; - private readonly WebDriverSessionOptions _sessionOptions; + private readonly WebDriverSessionOptions _sessionOptions; + public WebDriverFactory( IOptions webDriverOptions, WebDriverSessionOptions sessionOptions @@ -38,51 +39,57 @@ WebDriverSessionOptions sessionOptions _webDriverOptions = webDriverOptions?.Value ?? throw new ArgumentNullException(nameof(webDriverOptions)); _sessionOptions = sessionOptions ?? throw new ArgumentNullException(nameof(_sessionOptions)); } - - public Lazy CreateDriver() + + public IWebDriver CreateDriver() { // viewports are expressed as cartesian coordinates (x,y) var viewportDoesNotExist = !MOBILE_VIEWPORTS.TryGetValue(_sessionOptions.Device, out var viewport); + if (viewportDoesNotExist) { throw new ArgumentException($"device value {_sessionOptions.Device} has no mapped viewport"); } var (width, height) = viewport; - return new Lazy(() => - { - _webDriverOptions.DriverBinaryDirectory ??= Directory.GetCurrentDirectory(); - IWebDriver driver = _sessionOptions switch - { - { DisableJs: true } or { Browser: "firefox" } => CreateFirefoxDriver(_webDriverOptions, _sessionOptions), - _ => CreateChromeDriver(_webDriverOptions) - }; - driver.Manage().Window.Size = new Size(width, height); - driver.Manage().Cookies.DeleteAllCookies(); - driver.Manage().Timeouts().PageLoad = DEFAULT_PAGE_LOAD_TIMEOUT; - return driver; - }); - } + _webDriverOptions.DriverBinaryDirectory ??= Directory.GetCurrentDirectory(); + IWebDriver driver = CreateChromeDriver(_webDriverOptions); + + //IWebDriver driver = _sessionOptions switch + //{ + // { DisableJs: true } or { Browser: "firefox" } => CreateFirefoxDriver(_webDriverOptions, _sessionOptions), + // _ => CreateChromeDriver(_webDriverOptions) + //}; + + driver.Manage().Window.Size = new Size(width, height); + driver.Manage().Cookies.DeleteAllCookies(); + driver.Manage().Timeouts().PageLoad = DEFAULT_PAGE_LOAD_TIMEOUT; + return driver; + + } + private static ChromeDriver CreateChromeDriver( WebDriverOptions driverOptions ) { ChromeOptions option = new(); - option.AddArguments(DEFAULT_OPTIONS); + option.AddArguments(DEFAULT_OPTIONS); + // chromium based browsers using new headless switch https://www.selenium.dev/blog/2023/headless-is-going-away/ + if (driverOptions.Headless) { option.AddArgument("--headless=new"); } + option.AddUserProfilePreference("safebrowsing.enabled", true); option.AddUserProfilePreference("download.prompt_for_download", false); option.AddUserProfilePreference("disable-popup-blocking", "true"); option.AddArgument("--window-size=1920,1080"); return new ChromeDriver(driverOptions.DriverBinaryDirectory, option); } - + private static FirefoxDriver CreateFirefoxDriver( WebDriverOptions driverOptions, WebDriverSessionOptions sessionOptions @@ -94,16 +101,19 @@ WebDriverSessionOptions sessionOptions AcceptInsecureCertificates = true, EnableDevToolsProtocol = true, }; + options.AddArguments(DEFAULT_OPTIONS); + if (driverOptions.Headless) { options.AddArgument("--headless"); } + if (sessionOptions.DisableJs) { options.SetPreference("javascript.enabled", false); } + return new(driverOptions.DriverBinaryDirectory, options); } -} - +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs index 33250ab..2b68c4d 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Hooks/SpecFlowHooks.cs @@ -1,44 +1,14 @@ using BoDi; -using System.Diagnostics; using TechTalk.SpecFlow; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; using Microsoft.Extensions.Options; -using Xunit.Abstractions; namespace UnitTestProject1 { [Binding] public class SpecFlowHooks { - private readonly ITestOutputHelper _logger; - - public SpecFlowHooks(ITestOutputHelper logger) - { - _logger = logger; - } - - [Before] - public void Before() - { - var workingDir = Directory.GetCurrentDirectory(); - _logger.WriteLine(workingDir); - - - var process = new Process - { - StartInfo = - { - //FileName = "Dfe.Data.SearchPrototype.Web.exe", - WorkingDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\")), - FileName = "dotnet", - Arguments = "run --urls=http://localhost:5000" - } - }; - process.Start(); - Thread.Sleep(1000); - } - [BeforeTestRun] public static void BeforeTest(ObjectContainer container) { @@ -62,13 +32,5 @@ public void CreateWebDriver(IObjectContainer container) container.RegisterTypeAs(); container.RegisterTypeAs(); } - - - [After] - public void After() - { - //var webProcesses = Process.GetProcessesByName("Dfe.Data.SearchPrototype.Web"); - //webProcesses[0].Kill(); - } } } \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 9ef12ec..433b8f8 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -2,16 +2,19 @@ using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Drivers; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Extensions; using Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Options; +using Dfe.Data.SearchPrototype.Web.Tests.AcceptanceTests; using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; using FluentAssertions; using Microsoft.Extensions.Options; +using OpenQA.Selenium; using TechTalk.SpecFlow; +using Xunit; using Xunit.Abstractions; namespace Dfe.Data.SearchPrototype.Web.Tests.Acceptance.Steps { [Binding] - public sealed class AccessibilitySteps + public sealed class AccessibilitySteps : IClassFixture> { private readonly AccessibilityOptions _options; private readonly ITestOutputHelper _logger; @@ -19,6 +22,8 @@ public sealed class AccessibilitySteps private readonly SearchPage _searchPage; private readonly WebDriverSessionOptions _sessionOptions; + private readonly IWebDriver _webDriver; + private Dictionary _pageNameToUrlConverter = new Dictionary() { { "home", "/" }, @@ -26,6 +31,7 @@ public sealed class AccessibilitySteps }; public AccessibilitySteps( + WebApplicationFactoryFixture factory, IOptions options, ITestOutputHelper logger, IWebDriverContext driverContext, @@ -33,6 +39,8 @@ public AccessibilitySteps( WebDriverSessionOptions sessionOptions ) { + factory.CreateDefaultClient(); + _driverContext = driverContext; _searchPage = searchPage; _logger = logger; @@ -43,7 +51,12 @@ WebDriverSessionOptions sessionOptions [StepDefinition(@"the user views the (home) page")] public void OpenPage(string pageName) { - _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); + string url = $"http://localhost:5028/Home"; + + _driverContext.Driver.Navigate().GoToUrl(url); + + string pageSource = _driverContext.Driver.PageSource; // Just wanted to see the whole page view ;) + _searchPage.HeadingElement.Text.Should().Be("Search prototype"); } @@ -72,4 +85,4 @@ public void IsAccessible(string component) _logger.WriteLine($"Passed accessibility test count {passCount} for {component} at {axeResult.Url}"); } } -} +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs new file mode 100644 index 0000000..c91dc28 --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs @@ -0,0 +1,62 @@ +using Dfe.Data.SearchPrototype.SearchForEstablishments; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Options; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Resources; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Dfe.Data.SearchPrototype.Web.Tests.AcceptanceTests +{ + public sealed class WebApplicationFactoryFixture : WebApplicationFactory where TEntryPoint : class + { + public string HostUrl { get; set; } = "http://localhost:5028"; // Default. + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.UseUrls(HostUrl); + builder.ConfigureServices(services => ConfigureServices(services)); + } + + protected override IHost CreateHost(IHostBuilder builder) + { + IHost testHost = builder.Build(); + + builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel()); + + var host = builder.Build(); + host.Start(); + + return testHost; + } + + private void ConfigureServices(IServiceCollection services) + { + // Remove registration of the default ISearchServiceAdapter (i.e. CognitiveSearchServiceAdapter). + var searchServiceAdapterDescriptor = + services.SingleOrDefault( + serviceDescriptor => serviceDescriptor.ServiceType == + typeof(ISearchServiceAdapter)); + + services.Remove(searchServiceAdapterDescriptor!); + + // Register our dummy search service adapter. + services.AddSingleton(); + services.AddScoped( + typeof(ISearchServiceAdapter), + typeof(DummySearchServiceAdapter)); + + string fileName = + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.test.json", false) + .Build()["dummySearchServiceAdapter:fileName"]!; + + services.AddOptions() + .Configure((options) => + options.FileName = fileName); + } + } +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj index 70678af..f3a6a34 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj +++ b/Dfe.Data.SearchPrototype/Web/Tests/Dfe.Data.SearchPrototype.Web.Tests.csproj @@ -7,16 +7,16 @@ - + - + - - PreserveNewest + + Always diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json b/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json deleted file mode 100644 index 58ee502..0000000 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/Establishments.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "establishments": [ - - { - "urn": "123456", - "name": "Goose Academy", - "address": - { - "street": "Street One", - "locality": "locality", - "address3": "address3", - "town": "town", - "postcode": "postcode" - } - }, - { - "urn": "234567", - "name": "Horse Academy", - "address": - { - "street": "Street One", - "locality": "locality", - "address3": "address3", - "town": "town", - "postcode": "postcode" - } - }, - { - "urn": "345678", - "name": "Duck School", - "address": - { - "street": "Street One", - "locality": "locality", - "address3": "address3", - "town": "town", - "postcode": "postcode" - } - } - ] -} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs index 3b7ace7..10b909a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/PageWebApplicationFactory.cs @@ -1,7 +1,7 @@ using Dfe.Data.SearchPrototype.SearchForEstablishments; -using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter; -using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options; -using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Options; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Resources; using DfE.Data.ComponentLibrary.Infrastructure.CognitiveSearch.Options; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/DummySearchServiceAdapter.cs similarity index 86% rename from Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs rename to Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/DummySearchServiceAdapter.cs index c01be01..75b177e 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/DummySearchServiceAdapter.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/DummySearchServiceAdapter.cs @@ -1,8 +1,8 @@ using Dfe.Data.SearchPrototype.SearchForEstablishments; -using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Resources; using Newtonsoft.Json.Linq; -namespace Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter +namespace Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter { public sealed class DummySearchServiceAdapter : ISearchServiceAdapter where TSearchResult : class { @@ -23,7 +23,7 @@ public async Task SearchAsync(SearchContext searchContext) from establishmentToken in establishmentsObject["establishments"] where establishmentToken["name"]!.ToString().Contains(searchContext.SearchKeyword) select new Establishment( - (string)establishmentToken["urn"]!, + (string)establishmentToken["urn"]!, (string)establishmentToken["name"]!, new Address( (string)establishmentToken["address"]!["street"]!, diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs similarity index 54% rename from Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs rename to Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs index 82ca2b7..0f527a2 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Options/DummySearchServiceAdapterOptions.cs @@ -1,4 +1,4 @@ -namespace Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options +namespace Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Options { public sealed class DummySearchServiceAdapterOptions { diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/Establishments.json b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/Establishments.json new file mode 100644 index 0000000..bf4f62c --- /dev/null +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/Establishments.json @@ -0,0 +1,41 @@ +{ + "establishments": [ + + { + "urn": "123456", + "name": "Goose Academy", + "address": { + "street": "Goose Street", + "locality": "Goose Locality", + "address3": "Goose Address 3", + "town": "Goose Town", + "postcode": "GOO OSE" + }, + "establishmentType": "Academy" + }, + { + "urn": "234567", + "name": "Horse Academy", + "address": { + "street": "Horse Street", + "locality": "Horse Locality", + "address3": "Horse Address 3", + "town": "Horse Town", + "postcode": "HOR SEE" + }, + "establishmentType": "Academy" + }, + { + "urn": "345678", + "name": "Duck School", + "address": { + "street": "Duck Street", + "locality": "Duck Locality", + "address3": "Duck Address 3", + "town": "Duck Town", + "postcode": "DUU CKK" + }, + "establishmentType": "Community School" + } + ] +} \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs similarity index 81% rename from Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs rename to Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs index 73c54f1..3b9b642 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/PageIntegrationTests/SearchServiceAdapter/Resources/JsonFileLoader.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs @@ -1,7 +1,7 @@ -using Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Options; +using Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Options; using Microsoft.Extensions.Options; -namespace Dfe.Data.SearchPrototype.Web.Tests.PageIntegrationTests.SearchServiceAdapter.Resources +namespace Dfe.Data.SearchPrototype.Web.Tests.Shared.SearchServiceAdapter.Resources { public sealed class JsonFileLoader : IJsonFileLoader { From b92d6b8ca1ba3b0da26a29cda2b9ac1662ad4296 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 31 Jul 2024 08:58:02 +0100 Subject: [PATCH 25/31] set default url and updated home page step --- .../Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs | 6 +----- .../Tests/AcceptanceTests/WebApplicationFactoryFixture.cs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 433b8f8..57ad0cc 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -51,11 +51,7 @@ WebDriverSessionOptions sessionOptions [StepDefinition(@"the user views the (home) page")] public void OpenPage(string pageName) { - string url = $"http://localhost:5028/Home"; - - _driverContext.Driver.Navigate().GoToUrl(url); - - string pageSource = _driverContext.Driver.PageSource; // Just wanted to see the whole page view ;) + _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); _searchPage.HeadingElement.Text.Should().Be("Search prototype"); } diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs index c91dc28..94d8630 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/WebApplicationFactoryFixture.cs @@ -12,7 +12,7 @@ namespace Dfe.Data.SearchPrototype.Web.Tests.AcceptanceTests { public sealed class WebApplicationFactoryFixture : WebApplicationFactory where TEntryPoint : class { - public string HostUrl { get; set; } = "http://localhost:5028"; // Default. + public string HostUrl { get; set; } = "http://localhost:5000"; // Default. protected override void ConfigureWebHost(IWebHostBuilder builder) { From 645e7ba001e58e770aa7060e6b860311c0e6dbce Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 31 Jul 2024 09:13:51 +0100 Subject: [PATCH 26/31] search results page accessibility test added --- .../Features/AccessibilityTests.feature | 8 +++-- .../Features/AccessibilityTests.feature.cs | 36 ++++++++++++++++--- .../Steps/AccessibilitySteps.cs | 4 +-- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index 2a3f007..d29edff 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -1,5 +1,9 @@ Feature: AccessibilityTests -Scenario: Homepage accessibility +Scenario: Home page accessibility When the user views the home page - Then the home page is accessible \ No newline at end of file + Then the home page is accessible + +Scenario: Search results page accessibility + When the user views the search results page + Then the search results page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index fcb83bd..4c13af0 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -80,14 +80,14 @@ void System.IDisposable.Dispose() this.TestTearDown(); } - [Xunit.SkippableFactAttribute(DisplayName="Homepage accessibility")] + [Xunit.SkippableFactAttribute(DisplayName="Home page accessibility")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] - [Xunit.TraitAttribute("Description", "Homepage accessibility")] - public void HomepageAccessibility() + [Xunit.TraitAttribute("Description", "Home page accessibility")] + public void HomePageAccessibility() { string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Homepage accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Home page accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); #line 3 this.ScenarioInitialize(scenarioInfo); #line hidden @@ -108,6 +108,34 @@ public void HomepageAccessibility() this.ScenarioCleanup(); } + [Xunit.SkippableFactAttribute(DisplayName="Search results page accessibility")] + [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] + [Xunit.TraitAttribute("Description", "Search results page accessibility")] + public void SearchResultsPageAccessibility() + { + string[] tagsOfScenario = ((string[])(null)); + System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Search results page accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); +#line 7 +this.ScenarioInitialize(scenarioInfo); +#line hidden + if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) + { + testRunner.SkipScenario(); + } + else + { + this.ScenarioStart(); +#line 8 + testRunner.When("the user views the search results page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 9 + testRunner.Then("the search results page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + } + this.ScenarioCleanup(); + } + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 57ad0cc..267ca6a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -27,7 +27,7 @@ public sealed class AccessibilitySteps : IClassFixture _pageNameToUrlConverter = new Dictionary() { { "home", "/" }, - { "privacy", "/Home/Privacy" } + { "search results", "/?searchKeyWord=Academy" } }; public AccessibilitySteps( @@ -48,7 +48,7 @@ WebDriverSessionOptions sessionOptions _sessionOptions = sessionOptions; } - [StepDefinition(@"the user views the (home) page")] + [StepDefinition(@"the user views the (home|search results) page")] public void OpenPage(string pageName) { _driverContext.GoToUri($"{_pageNameToUrlConverter[pageName]}"); From d9331e80b1b1b5049870ec74aaa3eaf5a8e38c22 Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 31 Jul 2024 09:53:57 +0100 Subject: [PATCH 27/31] fixed accessibility failure - search results list --- .../Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs | 2 -- Dfe.Data.SearchPrototype/Web/Views/Home/Index.cshtml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 267ca6a..6eaedbb 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -22,8 +22,6 @@ public sealed class AccessibilitySteps : IClassFixture _pageNameToUrlConverter = new Dictionary() { { "home", "/" }, diff --git a/Dfe.Data.SearchPrototype/Web/Views/Home/Index.cshtml b/Dfe.Data.SearchPrototype/Web/Views/Home/Index.cshtml index f7fd0fa..10485f4 100644 --- a/Dfe.Data.SearchPrototype/Web/Views/Home/Index.cshtml +++ b/Dfe.Data.SearchPrototype/Web/Views/Home/Index.cshtml @@ -49,8 +49,8 @@
  • Type of establishment: @searchItem.EstablishmentType +
  • -
    } From e05b4b1c4a45f4c02fddf6420d5c3691c8c7f3fb Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 31 Jul 2024 10:28:42 +0100 Subject: [PATCH 28/31] ignore test until pr merged --- .../Features/AccessibilityTests.feature | 1 + .../Features/AccessibilityTests.feature.cs | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature index d29edff..209b0b6 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature @@ -4,6 +4,7 @@ Scenario: Home page accessibility When the user views the home page Then the home page is accessible +@ignore Scenario: Search results page accessibility When the user views the search results page Then the search results page is accessible \ No newline at end of file diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs index 4c13af0..5dc5198 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Features/AccessibilityTests.feature.cs @@ -108,15 +108,16 @@ public void HomePageAccessibility() this.ScenarioCleanup(); } - [Xunit.SkippableFactAttribute(DisplayName="Search results page accessibility")] + [Xunit.SkippableFactAttribute(DisplayName="Search results page accessibility", Skip="Ignored")] [Xunit.TraitAttribute("FeatureTitle", "AccessibilityTests")] [Xunit.TraitAttribute("Description", "Search results page accessibility")] public void SearchResultsPageAccessibility() { - string[] tagsOfScenario = ((string[])(null)); + string[] tagsOfScenario = new string[] { + "ignore"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Search results page accessibility", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 7 +#line 8 this.ScenarioInitialize(scenarioInfo); #line hidden if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) @@ -126,10 +127,10 @@ public void SearchResultsPageAccessibility() else { this.ScenarioStart(); -#line 8 +#line 9 testRunner.When("the user views the search results page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden -#line 9 +#line 10 testRunner.Then("the search results page is accessible", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden } From 0d552e4431e5ff55dd801ec42d4a9add53023db7 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 31 Jul 2024 10:38:55 +0100 Subject: [PATCH 29/31] final clean up --- .../AcceptanceTests/Drivers/WebDriverFactory.cs | 12 +++++------- .../AcceptanceTests/Steps/AccessibilitySteps.cs | 1 - .../Web/Tests/Shared/Helpers/HttpClientExtensions.cs | 4 ++-- .../SearchServiceAdapter/Resources/JsonFileLoader.cs | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs index acdf870..17eeb38 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Drivers/WebDriverFactory.cs @@ -53,13 +53,11 @@ public IWebDriver CreateDriver() _webDriverOptions.DriverBinaryDirectory ??= Directory.GetCurrentDirectory(); - IWebDriver driver = CreateChromeDriver(_webDriverOptions); - - //IWebDriver driver = _sessionOptions switch - //{ - // { DisableJs: true } or { Browser: "firefox" } => CreateFirefoxDriver(_webDriverOptions, _sessionOptions), - // _ => CreateChromeDriver(_webDriverOptions) - //}; + IWebDriver driver = _sessionOptions switch + { + { DisableJs: true } or { Browser: "firefox" } => CreateFirefoxDriver(_webDriverOptions, _sessionOptions), + _ => CreateChromeDriver(_webDriverOptions) + }; driver.Manage().Window.Size = new Size(width, height); driver.Manage().Cookies.DeleteAllCookies(); diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs index 6eaedbb..2c28934 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Steps/AccessibilitySteps.cs @@ -6,7 +6,6 @@ using Dfe.Data.SearchPrototype.Web.Tests.PageObjectModel; using FluentAssertions; using Microsoft.Extensions.Options; -using OpenQA.Selenium; using TechTalk.SpecFlow; using Xunit; using Xunit.Abstractions; diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs index c9f37ab..aff0060 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/Helpers/HttpClientExtensions.cs @@ -52,11 +52,11 @@ public static Task SendAsync( } var submit = form.GetSubmission(submitButton); - var target = (Uri)submit.Target; + var target = (Uri)submit!.Target; if (submitButton.HasAttribute("formaction")) { var formaction = submitButton.GetAttribute("formaction"); - target = new Uri(formaction, UriKind.Relative); + target = new Uri(formaction!, UriKind.Relative); } var submision = new HttpRequestMessage(new HttpMethod(submit.Method.ToString()), target) { diff --git a/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs index 3b9b642..f9b2948 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/Shared/SearchServiceAdapter/Resources/JsonFileLoader.cs @@ -12,7 +12,7 @@ public JsonFileLoader(IOptions options) _options = options.Value; } - public Task LoadJsonFile() => LoadJsonFile(_options.FileName); + public Task LoadJsonFile() => LoadJsonFile(_options.FileName!); public async Task LoadJsonFile(string path) { From 5fadba2ad28085ba9134f2eae2aa5675f591f123 Mon Sep 17 00:00:00 2001 From: Antony OAKES Date: Wed, 31 Jul 2024 11:28:20 +0100 Subject: [PATCH 30/31] chrome browser by default --- .../Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs index 22d5205..aea5965 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/Options/WebDriverSessionOptions.cs @@ -2,7 +2,7 @@ public sealed class WebDriverSessionOptions { - public string Browser { get; set; } = "firefox"; + public string Browser { get; set; } = "chrome"; public string Device { get; set; } = "desktop"; public bool DisableJs { get; set; } = false; } From f3a54f23623d9bbb18841e44113bde054ff1d28f Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 31 Jul 2024 12:05:25 +0100 Subject: [PATCH 31/31] add prerequisites to Readme for tests --- Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md index 7faad6e..be2463a 100644 --- a/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md +++ b/Dfe.Data.SearchPrototype/Web/Tests/AcceptanceTests/README.md @@ -5,6 +5,10 @@ This test suite contains automated tests that check the functional and non-functional aspects of the search prototype application. +## Prerequisites + +Currently only supports chrome browser, so ensure you have the chrome browser installed. + ## Test Levels - Functional