diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/AccessibilityTestsBase.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/AccessibilityTestsBase.cs new file mode 100644 index 000000000..487b29b79 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/AccessibilityTestsBase.cs @@ -0,0 +1,60 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.Startup; + using OpenQA.Selenium; + using Selenium.Axe; + using Xunit; + + /// + /// Accessibility Tests Base. + /// + [Collection("Selenium test collection")] + public class AccessibilityTestsBase + { + /// + /// Gets the base URL for the tests. + /// + internal readonly string BaseUrl; + + /// + /// Gets the WebDriver used for the tests. + /// + internal readonly IWebDriver Driver; + + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public AccessibilityTestsBase(AccessibilityTestsFixture fixture) + { + this.BaseUrl = fixture.BaseUrl; + this.Driver = fixture.Driver; + } + + /// + /// Analyze Page Heading And Accessibility. + /// + /// Page Title. + public void AnalyzePageHeadingAndAccessibility(string pageTitle) + { + this.ValidatePageHeading(pageTitle); + + // then + // Exclude conditional radios, see: https://github.com/alphagov/govuk-frontend/issues/979#issuecomment-872300557 + var axeResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + axeResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + + /// + /// ValidatePageHeading. + /// + /// Page Title. + public void ValidatePageHeading(string pageTitle) + { + var h1Element = this.Driver.FindElement(By.TagName("h1")); + h1Element.Text.Should().BeEquivalentTo(pageTitle); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs new file mode 100644 index 000000000..09316a41c --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs @@ -0,0 +1,54 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using Selenium.Axe; + using Xunit; + + /// + /// BasicAccessibilityTests. + /// + public class BasicAccessibilityTests : AccessibilityTestsBase, IClassFixture + { + /// + /// Initializes a new instance of the class. + /// BasicAccessibilityTests. + /// + /// fixture. + public BasicAccessibilityTests(AccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// PageHasNoAccessibilityErrors. + /// + /// url to the page. + /// title of the page. + [Theory] + [InlineData("/forgotten-password", "Forgotten your username or password")] + [InlineData("/Login", "Access your Learning Hub account")] + [InlineData("/Home/Contactus", "Contact us")] + [InlineData("/Home/Aboutus", "About us")] + [InlineData("/Updates", "Service updates and releases")] + [InlineData("/Policies", "Our policies")] + [InlineData("/Home/Accessibility", "Accessibility Statement for the NHS England Learning Hub")] + [InlineData("/Home/NHSsites", "NHS sites")] + [InlineData("/policies/terms-and-conditions", "NHS England Learning Hub Terms and Conditions of Use (‘Terms’)")] + [InlineData("/policies/content-policy", "NHS England Learning Hub Content Policy")] + [InlineData("/policies/privacy-policy", "PRIVACY NOTICE")] + [InlineData("/policies/cookie-policy", "Cookie policy")] + [InlineData("/policies/acceptable-use-policy", "ACCEPTABLE USE POLICY")] + + public void PageHasNoAccessibilityErrors(string url, string pageTitle) + { + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + url); + + // then + this.AnalyzePageHeadingAndAccessibility(pageTitle); + + ////this.Driver.Dispose(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs new file mode 100644 index 000000000..92ab1811c --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs @@ -0,0 +1,47 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using Microsoft.Azure.Management.Media.Models; + using OpenQA.Selenium; + using Xunit; + + /// + /// BasicAuthenticatedAccessibilityTests. + /// + public class BasicAuthenticatedAccessibilityTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// BasicAuthenticatedAccessibilityTests. + /// + /// fixture. + public BasicAuthenticatedAccessibilityTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// Authenticated Page Has no Accessibility Errors. + /// + /// url. + /// pageTitle. + [Theory] + [InlineData("/myaccount", "My account details")] + [InlineData("/MyLearning", "My learning")] + [InlineData("/allcatalogue", "A-Z of catalogues")] + [InlineData("/allcataloguesearch?term=primary#searchTab", "Search results for primary")] + public void AuthenticatedPageHasNoAccessibilityErrors(string url, string pageTitle) + { + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + url); + + // then + this.AnalyzePageHeadingAndAccessibility(pageTitle); + + // Dispose driver + ////this.Driver.LogOutUser(this.BaseUrl); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BookmarksTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BookmarksTests.cs new file mode 100644 index 000000000..b0964de50 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/BookmarksTests.cs @@ -0,0 +1,100 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using Microsoft.AspNetCore.Components.Web; + using OpenQA.Selenium; + using Selenium.Axe; + using Xunit; + + /// + /// Bookmarks Tests. + /// + public class BookmarksTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public BookmarksTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// BookmarksPageHasNoAccessibilityErrors. + /// + [Fact] + public void BookmarksPageHasNoAccessibilityErrors() + { + // given + const string resourceUrl = "/Resource/17844/Item"; + const string resourceProdUrl = "/Resource/48180/Item"; + const string addBookmarkPageUrl = "/bookmark/resource?bookmarked=False&title=Understanding%20and%20managing%20conflict%20in%20children%27s%20healthcare&rri=16593&returnUrl=%2FResource%2F16593%2FItem"; + const string myBookmarksPage = "/bookmark"; + const string bookmarkname = "Primary care clinicians"; + IWebElement renameBookmarkElement = null; + IWebElement addBookmarkElement = null; + IWebElement moveBookmarkElement = null; + AxeResult addBookmarkPageResult = null; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + resourceProdUrl); + + var h1Element = this.Driver.FindElement(By.TagName("h1")); + if (h1Element.Text == "Unknown error" || h1Element.Text != bookmarkname) + { + this.Driver.Navigate().GoToUrl(this.BaseUrl + resourceUrl); + } + + try + { + addBookmarkElement = this.Driver.FindElement(By.XPath("//a[contains(text(),'Add to my bookmarks')]")); + if (addBookmarkElement.Displayed) + { + this.Driver.ClickLinkContainingText("Add to my bookmarks"); + this.ValidatePageHeading("Add bookmark"); + addBookmarkPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickButtonByText("Continue"); + } + } + catch (NoSuchElementException) + { + this.Driver.Navigate().GoToUrl(this.BaseUrl + addBookmarkPageUrl); + this.ValidatePageHeading("Add bookmark"); + addBookmarkPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Cancel"); + } + + this.Driver.Navigate().GoToUrl(this.BaseUrl + myBookmarksPage); + this.ValidatePageHeading("Bookmarked learning"); + var myBookmarksPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + this.Driver.ClickLinkContainingText("Add a folder"); + this.ValidatePageHeading("Add a folder"); + var addBookmarkFolderPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Cancel"); + + renameBookmarkElement = this.Driver.FindElement(By.XPath($"//tr[td//span[contains(text(), '{bookmarkname}')]]//td//div//form//span//button[contains(text(), 'Rename')]")); + renameBookmarkElement.Click(); + this.ValidatePageHeading("Rename bookmark"); + var renameBookmarkPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Cancel"); + + moveBookmarkElement = this.Driver.FindElement(By.XPath($"//tr[td//span[contains(text(), '{bookmarkname}')]]//td//div//form//span//button[contains(text(), 'Move')]")); + moveBookmarkElement.Click(); + this.ValidatePageHeading("Move your bookmark"); + var moveBookmarkPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Cancel"); + + // then + addBookmarkPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + myBookmarksPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + addBookmarkFolderPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + renameBookmarkPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + moveBookmarkPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/CatalogueFolderContentTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/CatalogueFolderContentTests.cs new file mode 100644 index 000000000..76b87944b --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/CatalogueFolderContentTests.cs @@ -0,0 +1,46 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using Selenium.Axe; + using Xunit; + + /// + /// Catalogue Folder Content Tests. + /// + public class CatalogueFolderContentTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public CatalogueFolderContentTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// DashboardPageHasNoAccessibilityErrors. + /// + [Fact] + public void CatalogueFolderContentPageHasNoAccessibilityErrors() + { + // given + const string catalogueUrl = "/catalogue/Neonatal-AHP"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + catalogueUrl); + this.ValidatePageHeading("Enhanced Modules for Allied Health Professionals Working in Neonatal Care"); + var cataloguePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + ////this.Driver.ClickLinkContainingText("Manage this catalogue"); + ////this.ValidatePageHeading("Catalogue Management"); + ////var catalogueManagementPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + // then + cataloguePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/CreateAccountTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/CreateAccountTests.cs new file mode 100644 index 000000000..da149920a --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/CreateAccountTests.cs @@ -0,0 +1,186 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using OpenQA.Selenium; + using OpenQA.Selenium.Support.UI; + using Selenium.Axe; + using Xunit; + + /// + /// CreateAccountTests. + /// + public class CreateAccountTests : AccessibilityTestsBase, IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public CreateAccountTests(AccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// CreateFullUserAccountPageHasNoAccessibilityErrors. + /// + [Fact] + public void CreateFullUserAccountPageHasNoAccessibilityErrors() + { + // given + const string createAccountUrl = "/Registration/CreateAccountRegInfo"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl); + this.Driver.ClickLinkContainingText("Create new account"); + this.ValidatePageHeading("What you need to set up an account"); + var accountPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.ClickButtonByText("Continue"); + this.Driver.FindElement(By.XPath("//button[normalize-space(text())='Continue']")).Click(); + + // Verify the heading on the new page + this.ValidatePageHeading("Create an account"); + var emailVerificationPageResult = new AxeBuilder(this.Driver).Analyze(); + + this.Driver.FillTextInput("Email", "testuser4@nhs.net"); + this.Driver.FillTextInput("ComfirmEmail", "testuser4@nhs.net"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Full User Account"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Enter your personal details"); + var personalDetailsPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.FillTextInput("FirstName", "test"); + this.Driver.FillTextInput("LastName", "user"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Search for your country"); + this.Driver.FillTextInput("FilterText", "England"); + this.Driver.SubmitForm(); + var countryPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("CountryId-0"); + this.Driver.ClickButtonByText("Continue"); + + this.ValidatePageHeading("Select your region"); + var regionPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("RegionId-0"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Search for your current role"); + this.Driver.FillTextInput("FilterText", "admin"); + this.Driver.SubmitForm(); + var rolePageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("CurrentRole-0"); + this.Driver.ClickButtonByText("Continue"); + + this.ValidatePageHeading("Select your grade"); + var gradePageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("GradeId-0"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Search for your primary specialty"); + var specialityPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("PrimarySpecialtyId-0"); + this.Driver.ClickButtonByText("Continue"); + + this.ValidatePageHeading("Enter your start date"); + var startDatePageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.FillTextInput("Day", "1"); + this.Driver.FillTextInput("Month", "1"); + this.Driver.FillTextInput("Year", "2022"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Search for your place of work"); + this.Driver.FillTextInput("FilterText", "london"); + this.Driver.SubmitForm(); + var placeOfWorkPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("LocationId-0"); + this.Driver.ClickButtonByText("Continue"); + + this.ValidatePageHeading("Check your details"); + var summaryPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.Navigate().GoToUrl(this.BaseUrl); + + // then + emailVerificationPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + personalDetailsPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + countryPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + regionPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + rolePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + gradePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + specialityPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + startDatePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + placeOfWorkPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + summaryPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + + /// + /// CreateGeneralUserAccountPageHasNoAccessibilityErrors. + /// + [Fact] + public void CreateGeneralUserAccountPageHasNoAccessibilityErrors() + { + // given + const string createAccountUrl = "/Registration/CreateAccountRegInfo"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl); + ////this.Driver.Navigate().GoToUrl(this.BaseUrl + createAccountUrl); + this.Driver.ClickLinkContainingText("Create new account"); + this.ValidatePageHeading("What you need to set up an account"); + var accountPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.ClickButtonByText("Continue"); + this.Driver.FindElement(By.XPath("//button[normalize-space(text())='Continue']")).Click(); + + // Verify the heading on the new page + this.ValidatePageHeading("Create an account"); + var emailVerificationPageResult = new AxeBuilder(this.Driver).Analyze(); + + this.Driver.FillTextInput("Email", "testuser4@gmail.com"); + this.Driver.FillTextInput("ComfirmEmail", "testuser4@gmail.com"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("General User Account"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Enter your personal details"); + var personalDetailsPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.FillTextInput("FirstName", "test"); + this.Driver.FillTextInput("LastName", "user"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Search for your country"); + this.Driver.FillTextInput("FilterText", "England"); + this.Driver.SubmitForm(); + var countryPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("CountryId-0"); + this.Driver.ClickButtonByText("Continue"); + + this.ValidatePageHeading("Select your region"); + var regionPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("RegionId-0"); + this.Driver.SubmitForm(); + + this.ValidatePageHeading("Search for your current role"); + this.Driver.FillTextInput("FilterText", "admin"); + this.Driver.SubmitForm(); + var rolePageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.SelectRadioOptionById("CurrentRole-0"); + this.Driver.ClickButtonByText("Continue"); + + this.ValidatePageHeading("Check your details"); + var summaryPageResult = new AxeBuilder(this.Driver).Analyze(); + this.Driver.Navigate().GoToUrl(this.BaseUrl); + + // then + emailVerificationPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + personalDetailsPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + countryPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + regionPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + rolePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + summaryPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/DashboardTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/DashboardTests.cs new file mode 100644 index 000000000..c89ae663f --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/DashboardTests.cs @@ -0,0 +1,46 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using Selenium.Axe; + using Xunit; + + /// + /// Post login dashboard tests. + /// + public class DashboardTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public DashboardTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// DashboardPageHasNoAccessibilityErrors. + /// + [Fact] + public void DashboardPageHasNoAccessibilityErrors() + { + // given + const string dashboardUrl = "/?myLearningDashboard=my-in-progress&resourceDashboard=popular-resources&catalogueDashboard=popular-catalogues"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + dashboardUrl); + var axeResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + // then + CheckAccessibilityResult(axeResult); + } + + private static void CheckAccessibilityResult(AxeResult result) + { + result.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/MyAccountAccessibiltyTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/MyAccountAccessibiltyTests.cs new file mode 100644 index 000000000..5a2e85d33 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/MyAccountAccessibiltyTests.cs @@ -0,0 +1,133 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using Selenium.Axe; + using Xunit; + + /// + /// MyAccountAccessibiltyTests. + /// + public class MyAccountAccessibiltyTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// MyAccountAccessibiltyTests. + /// + /// fixture. + public MyAccountAccessibiltyTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// MyAccount Page Has Accessibility Errors. + /// + [Fact] + public void MyAccountPageHasAccessibilityErrors() + { + // given + const string myaccountsUrl = "/myaccount"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + myaccountsUrl); + this.ValidatePageHeading("My account details"); + var myAccountPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + this.Driver.ClickLinkContainingText("first name"); + this.ValidatePageHeading("Update your first name"); + var firstNameChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + this.ValidatePageHeading("My account details"); + this.Driver.ClickLinkContainingText("last name"); + this.ValidatePageHeading("Update your last name"); + var lastNameChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("preferred name"); + this.ValidatePageHeading("Update your preferred name"); + var preferredNameChangeResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("country"); + this.ValidatePageHeading("Update your country"); + var countryChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("secondry email"); + this.ValidatePageHeading("Enter your new secondary email address"); + var emailChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("security question 1"); + this.ValidatePageHeading("Choose your first security question"); + var securityQuestChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("security question 2"); + this.ValidatePageHeading("Choose your second security question"); + var securityQuest2ChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("current role"); + this.ValidatePageHeading("Update current job role"); + var roleChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("grade"); + this.ValidatePageHeading("Update grade"); + var gradeChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("primary specialty"); + this.ValidatePageHeading("Update primary specialty"); + var primarySpecialityChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("start date"); + this.ValidatePageHeading("Update start date"); + var startDateChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + this.Driver.ClickLinkContainingText("place of work"); + this.ValidatePageHeading("Update place of work"); + var placeOfWorkChangePageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + this.Driver.ClickLinkContainingText("Go back"); + + // then + myAccountPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + firstNameChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + lastNameChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + preferredNameChangeResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + countryChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + ////regionChangePageResult.Violations.Should().BeEmpty(); + emailChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + securityQuestChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + securityQuest2ChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + roleChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + gradeChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + primarySpecialityChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + startDateChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + placeOfWorkChangePageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + ////CheckAccessibilityResult(result); + + // Dispose driver + ////this.Driver.LogOutUser(this.BaseUrl); + } + + private static void CheckAccessibilityResult(AxeResult result) + { + // Expect axe violation + result.Violations.Should().HaveCount(6); + + var violation = result.Violations[1]; + + violation.Id.Should().Be("landmark-contentinfo-is-top-level"); + violation.Nodes.Should().HaveCount(1); + violation.Nodes[0].Target.Should().HaveCount(1); + violation.Nodes[0].Target[0].Selector.Should().Be("footer > footer"); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/MyContributionsTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/MyContributionsTests.cs new file mode 100644 index 000000000..85c1bf38f --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/MyContributionsTests.cs @@ -0,0 +1,45 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using Selenium.Axe; + using Xunit; + + /// + /// Contributions Tests. + /// + public class MyContributionsTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public MyContributionsTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// MyContributionsPageHasNoAccessibilityErrors. + /// + [Fact] + public void MyContributionsPageHasNoAccessibilityErrors() + { + // given + const string myContributionUrl = "/my-contributions"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + myContributionUrl); + var axeResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + // then + CheckAccessibilityResult(axeResult); + } + + private static void CheckAccessibilityResult(AxeResult result) + { + result.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/ResourcePagesTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/ResourcePagesTests.cs new file mode 100644 index 000000000..551e294a9 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/ResourcePagesTests.cs @@ -0,0 +1,64 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using OpenQA.Selenium; + using Selenium.Axe; + using Xunit; + + /// + /// SearchResultsTests. + /// + public class ResourcePagesTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public ResourcePagesTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// ResourcePagesHasNoAccessibilityErrors. + /// + /// url. + /// pageTitle. + [Theory] + [MemberData(nameof(GetResourcePageTestData))] + public void ResourcePagesHasNoAccessibilityErrors(string url, string pageTitle) + { + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + url); + + // then + var h1Element = this.Driver.FindElement(By.TagName("h1")); + if (h1Element.Text == "Unknown error" || h1Element.Text != pageTitle) + { + return; + } + + this.AnalyzePageHeadingAndAccessibility(pageTitle); + } + + /// + /// GetResourcePageTestData. + /// + /// resource url. + internal static IEnumerable GetResourcePageTestData() + { + yield return new object[] { "/Resource/309/Item", "IE11 Image test" }; + yield return new object[] { "/Resource/91/Item", "Removal and disposal of Personal Protective Equipment (PPE)" }; + yield return new object[] { "/Resource/15458/Item", "Test PDF File 16Dec" }; + yield return new object[] { "/Resource/17014/Item", "How to develop your teaching skills | BMJ Careers" }; + yield return new object[] { "/Resource/17760/Item", "HTML" }; + yield return new object[] { "/Resource/21430/Item", "MHA/MCA Interface Case Study (document)" }; + yield return new object[] { "/Resource/52338/Item", "How to develop your teaching skills | BMJ Careers" }; + yield return new object[] { "/Resource/56274/Item", "Phlebitis (HTML)" }; + yield return new object[] { "/Resource/27527/Item", "Pain after spinal cord injury - articles" }; + yield return new object[] { "/Resource/31888/Item", "360 Image of AMU Bed Bay" }; + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/SearchResultsTests.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/SearchResultsTests.cs new file mode 100644 index 000000000..8c995f02c --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/AccessibilityTests/SearchResultsTests.cs @@ -0,0 +1,47 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures; + using Selenium.Axe; + using Xunit; + + /// + /// SearchResultsTests. + /// + public class SearchResultsTests : AccessibilityTestsBase, + IClassFixture + { + /// + /// Initializes a new instance of the class. + /// + /// fixture. + public SearchResultsTests(AuthenticatedAccessibilityTestsFixture fixture) + : base(fixture) + { + } + + /// + /// SearchResultPageHasNoAccessibilityErrors. + /// + [Fact] + public void SearchResultPageHasNoAccessibilityErrors() + { + // given + const string searchResultUrl = "/search/results?term=primary"; + const string catalogueSearchResultUrl = "/catalogues?term=primary"; + + // when + this.Driver.Navigate().GoToUrl(this.BaseUrl + searchResultUrl); + this.ValidatePageHeading("Search results for primary"); + var searchResultPageResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + this.Driver.Navigate().GoToUrl(this.BaseUrl + catalogueSearchResultUrl); + ////this.ValidatePageHeading("Search results for primary"); + var catalogueSearchResult = new AxeBuilder(this.Driver).Exclude("div.nhsuk-radios--conditional div.nhsuk-radios__item input.nhsuk-radios__input").Analyze(); + + // then + searchResultPageResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + catalogueSearchResult.Violations.Where(v => !v.Tags.Contains("best-practice")).Should().BeEmpty(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/GlobalSuppressions.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/GlobalSuppressions.cs new file mode 100644 index 000000000..01866c145 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/GlobalSuppressions.cs @@ -0,0 +1,13 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Allowed", Scope = "member", Target = "~F:LearningHub.Nhs.WebUI.AutomatedUiTests.SeleniumServerFactory.RootUri")] +[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Allowed", Scope = "member", Target = "~F:LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures.AccessibilityTestsFixture.Driver")] +[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Allowed", Scope = "member", Target = "~F:LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures.AccessibilityTestsFixture.BaseUrl")] +[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Allowed", Scope = "member", Target = "~F:LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests.AccessibilityTestsBase.BaseUrl")] +[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Allowed", Scope = "member", Target = "~F:LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests.AccessibilityTestsBase.Driver")] +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Regions allowed", Scope = "member", Target = "~M:LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests.BasicAccessibilityTests.PageHasNoAccessibilityErrors(System.String,System.String)")] diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj new file mode 100644 index 000000000..d6bf3cd0d --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj @@ -0,0 +1,37 @@ + + + + net8.0 + enable + enable + + false + + True + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/SeleniumServerFactory.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/SeleniumServerFactory.cs new file mode 100644 index 000000000..19edcdaef --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/SeleniumServerFactory.cs @@ -0,0 +1,41 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests +{ + using System; + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using LearningHub.Nhs.WebUI.Startup; + using Microsoft.AspNetCore; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.Hosting.Server.Features; + using Microsoft.AspNetCore.Mvc.Testing; + using Microsoft.AspNetCore.TestHost; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.Configuration.Json; + using Serilog; + + /// + /// SeleniumServerFactory. + /// + public class SeleniumServerFactory + { + /// + /// Root Uri. + /// + public string RootUri; + + /// + /// Initializes a new instance of the class. + /// + public SeleniumServerFactory() + { + IConfiguration configuration = ConfigurationHelper.GetConfiguration(); + this.RootUri = configuration["LearningHubWebUiUrl"]; + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/TestFixtures/AccessibilityTestsFixture.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestFixtures/AccessibilityTestsFixture.cs new file mode 100644 index 000000000..28eafbe22 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestFixtures/AccessibilityTestsFixture.cs @@ -0,0 +1,46 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures +{ + using FluentAssertions; + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using OpenQA.Selenium; + + /// + /// Represents a fixture for accessibility tests. + /// + public class AccessibilityTestsFixture + { + /// + /// Gets the base URL for the tests. + /// + internal readonly string BaseUrl; + + /// + /// Gets the WebDriver used for the tests. + /// + internal readonly IWebDriver Driver; + + private readonly SeleniumServerFactory factory; + + /// + /// Initializes a new instance of the class. + /// + public AccessibilityTestsFixture() + { + this.factory = new SeleniumServerFactory(); + this.BaseUrl = this.factory.RootUri; + this.Driver = DriverHelper.CreateHeadlessChromeDriver(); + AssertionOptions.FormattingOptions.MaxLines = 500; + AssertionOptions.FormattingOptions.MaxDepth = 10; + } + + /// + /// Dispose. + /// + public void Dispose() + { + this.Driver.Quit(); + this.Driver.Dispose(); + ////Thread.Sleep(3000); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/TestFixtures/AuthenticatedAccessibilityTestsFixture.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestFixtures/AuthenticatedAccessibilityTestsFixture.cs new file mode 100644 index 000000000..9f16bed3b --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestFixtures/AuthenticatedAccessibilityTestsFixture.cs @@ -0,0 +1,33 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures +{ + using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers; + using Microsoft.Extensions.Configuration; + + /// + /// AuthenticatedAccessibilityTestsFixture. + /// + /// TStartup. + public class AuthenticatedAccessibilityTestsFixture : AccessibilityTestsFixture + { + /// + /// Initializes a new instance of the class. + /// + public AuthenticatedAccessibilityTestsFixture() + { + IConfiguration configuration = ConfigurationHelper.GetConfiguration(); + string adminUsername = configuration["AdminUser:Username"]; + string adminPassword = configuration["AdminUser:Password"]; + this.Driver.LogUserInAsAdmin(this.BaseUrl, adminUsername, adminPassword); + } + + /// + /// Dispose. + /// + public new void Dispose() + { + this.Driver.LogOutUser(this.BaseUrl); + this.Driver.Quit(); + base.Dispose(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/ConfigurationHelper.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/ConfigurationHelper.cs new file mode 100644 index 000000000..660575162 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/ConfigurationHelper.cs @@ -0,0 +1,22 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers +{ + using Microsoft.Extensions.Configuration; + + /// + /// ConfigurationHelper. + /// + public static class ConfigurationHelper + { + /// + /// GetConfiguration. + /// + /// IConfiguration. + public static IConfiguration GetConfiguration() + { + return new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.Development.json") + .Build(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/DriverHelper.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/DriverHelper.cs new file mode 100644 index 000000000..ff60ad923 --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/DriverHelper.cs @@ -0,0 +1,109 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers +{ + using OpenQA.Selenium; + using OpenQA.Selenium.Chrome; + using OpenQA.Selenium.Support.UI; + + /// + /// Driver Helper. + /// + public static class DriverHelper + { + /// + /// Create Headless ChromeDriver. + /// + /// Chrome Driver. + public static ChromeDriver CreateHeadlessChromeDriver() + { + var chromeOptions = new ChromeOptions(); + + chromeOptions.AddArguments( + "--headless", + "no-sandbox"); + return new ChromeDriver(chromeOptions); + } + + /// + /// Fill Text Input. + /// + /// WebDriver. + /// inputId. + /// inputText. + public static void FillTextInput(this IWebDriver driver, string inputId, string inputText) + { + var answer = driver.FindElement(By.Id(inputId)); + answer.Clear(); + answer.SendKeys(inputText); + } + + /// + /// ClickButtonByText. + /// + /// WebDriver. + /// text. + public static void ClickButtonByText(this IWebDriver driver, string text) + { + var addButton = driver.FindElement(By.XPath($"//button[.='{text}']")); + addButton.Click(); + } + + /// + /// ClickLinkContainingText. + /// + /// WebDriver. + /// text. + public static void ClickLinkContainingText(this IWebDriver driver, string text) + { + var foundLink = driver.FindElement(By.XPath($"//a[contains(., '{text}')]")); + foundLink.Click(); + } + + /// + /// SelectDropdownItemValue. + /// + /// WebDriver. + /// dropdownId. + /// selectedValue. + public static void SelectDropdownItemValue(this IWebDriver driver, string dropdownId, string selectedValue) + { + var dropdown = new SelectElement(driver.FindElement(By.Id(dropdownId))); + dropdown.SelectByValue(selectedValue); + } + + /// + /// SetCheckboxState. + /// + /// WebDriver. + /// inputId. + /// checkState. + public static void SetCheckboxState(this IWebDriver driver, string inputId, bool checkState) + { + var answer = driver.FindElement(By.Id(inputId)); + if (answer.Selected != checkState) + { + answer.Click(); + } + } + + /// + /// Submit Form. + /// + /// WebDriver. + public static void SubmitForm(this IWebDriver driver) + { + var selectPromptForm = driver.FindElement(By.TagName("form")); + selectPromptForm.Submit(); + } + + /// + /// Select Radio Option By Id. + /// + /// WebDriver. + /// radio Id. + public static void SelectRadioOptionById(this IWebDriver driver, string radioId) + { + var radioInput = driver.FindElement(By.Id(radioId)); + radioInput.Click(); + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/LoginHelper.cs b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/LoginHelper.cs new file mode 100644 index 000000000..5b098b0be --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/TestHelpers/LoginHelper.cs @@ -0,0 +1,80 @@ +namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers +{ + using OpenQA.Selenium; + using OpenQA.Selenium.Support.UI; + + /// + /// LoginHelper. + /// + public static class LoginHelper + { + /// + /// Get LogUserInAsAdmin. + /// + /// WebDriver. + /// baseUrl. + /// adminName. + /// adminPassword. + public static void LogUserInAsAdmin(this IWebDriver driver, string baseUrl, string adminName, string adminPassword) + { + driver.Navigate().GoToUrl(baseUrl + "/Login"); + var username = driver.FindElement(By.Id("Username")); + username.SendKeys(adminName); + + var password = driver.FindElement(By.Id("Password")); + password.SendKeys(adminPassword); + + var submitButton = driver.FindElement(By.TagName("form")); + submitButton.Submit(); + } + + /// + /// LogOutUser. + /// + /// WebDriver. + /// baseUrl. + public static void LogOutUser(this IWebDriver driver, string baseUrl) + { + driver.Navigate().GoToUrl(baseUrl); + + try + { + // Maximum time to wait for the element in seconds + int maxWaitTimeInSeconds = 10; + + // Find the element using XPath + IWebElement logoutLink = null; + + for (int i = 0; i < maxWaitTimeInSeconds; i++) + { + try + { + logoutLink = driver.FindElement(By.CssSelector("a.nhsuk-account__login--link[href='/Home/Logout']")); + if (logoutLink.Displayed) + { + break; // Exit the loop if element is found and displayed + } + } + catch (NoSuchElementException) + { + // Element not found yet, wait for a second and try again + Thread.Sleep(1000); + } + } + + // Check if the element is found and displayed + if (logoutLink != null && logoutLink.Displayed) + { + // Perform an action on the element (e.g., click) + logoutLink.Click(); + } + } + finally + { + // Close the browser window + driver.Quit(); + driver.Dispose(); + } + } + } +} diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/appsettings.json b/LearningHub.Nhs.WebUI.AutomatedUiTests/appsettings.json new file mode 100644 index 000000000..223c0c93f --- /dev/null +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/appsettings.json @@ -0,0 +1,7 @@ +{ + "LearningHubWebUiUrl": "", + "AdminUser": { + "Username": "", + "Password": "" + } +} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.sln b/LearningHub.Nhs.WebUI.sln index 9cce69d55..5aea6885f 100644 --- a/LearningHub.Nhs.WebUI.sln +++ b/LearningHub.Nhs.WebUI.sln @@ -79,6 +79,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LearningHub.Nhs.ReportApi.S EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LearningHub.Nhs.ReportApi.Shared", "ReportAPI\LearningHub.Nhs.ReportApi.Shared\LearningHub.Nhs.ReportApi.Shared.csproj", "{6167F037-166C-4C5A-81BE-55618E77D4E8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.WebUI.AutomatedUiTests", "LearningHub.Nhs.WebUI.AutomatedUiTests\LearningHub.Nhs.WebUI.AutomatedUiTests.csproj", "{A84EC50B-2B01-4819-A2B1-BD867B7595CA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -335,6 +337,14 @@ Global {6167F037-166C-4C5A-81BE-55618E77D4E8}.Release|Any CPU.Build.0 = Release|Any CPU {6167F037-166C-4C5A-81BE-55618E77D4E8}.Release|x64.ActiveCfg = Release|Any CPU {6167F037-166C-4C5A-81BE-55618E77D4E8}.Release|x64.Build.0 = Release|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Debug|x64.Build.0 = Debug|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|Any CPU.Build.0 = Release|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|x64.ActiveCfg = Release|Any CPU + {A84EC50B-2B01-4819-A2B1-BD867B7595CA}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialty.cshtml b/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialty.cshtml index 0bc9979cf..fb35d21ad 100644 --- a/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialty.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialty.cshtml @@ -63,7 +63,7 @@
-
diff --git a/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialtySelection.cshtml b/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialtySelection.cshtml index 495df4081..393d5c76a 100644 --- a/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialtySelection.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Account/CreateAccountPrimarySpecialtySelection.cshtml @@ -145,7 +145,7 @@
-
diff --git a/LearningHub.Nhs.WebUI/Views/Bookmark/Move.cshtml b/LearningHub.Nhs.WebUI/Views/Bookmark/Move.cshtml index 462133de2..10677a0b6 100644 --- a/LearningHub.Nhs.WebUI/Views/Bookmark/Move.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Bookmark/Move.cshtml @@ -52,7 +52,7 @@ }
- +
@@ -72,6 +72,7 @@ required="@(Model.SelectedFolderId == 0)" />
+
@if (Model.Bookmark.ParentId.HasValue || (Model.Folders != null && Model.Folders.Any())) { diff --git a/LearningHub.Nhs.WebUI/Views/Bookmark/_BookmarkItem.cshtml b/LearningHub.Nhs.WebUI/Views/Bookmark/_BookmarkItem.cshtml index d3698d691..19d19e07a 100644 --- a/LearningHub.Nhs.WebUI/Views/Bookmark/_BookmarkItem.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Bookmark/_BookmarkItem.cshtml @@ -24,11 +24,11 @@ @Model.Bookmark.Title - + Type @GetResourceTypeName(Model.Bookmark.BookmarkTypeId, Model.Bookmark.ResourceTypeId) - + Organise diff --git a/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLastName.cshtml b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLastName.cshtml index 4b4167544..9212175be 100644 --- a/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLastName.cshtml +++ b/LearningHub.Nhs.WebUI/Views/MyAccount/ChangeLastName.cshtml @@ -18,7 +18,7 @@
Change last name
-

Update your last name

+

Update your last name

@if (Model.ShowSearch) { - + } @if (User.Identity.IsAuthenticated) { - +