Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ obj
/WebAPI/LearningHub.Nhs.Database/LearningHub.Nhs.Database.jfm
/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Database/LearningHub.Nhs.Migration.Staging.Database.dbmdl
/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Database/LearningHub.Nhs.Migration.Staging.Database.jfm
/LearningHub.Nhs.WebUI.AutomatedUiTests/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// <copyright file="AccessibilityTestsBase.cs" company="HEE.nhs.uk">
// Copyright (c) HEE.nhs.uk.
// </copyright>

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;

/// <summary>
/// Accessibility Tests Base.
/// </summary>
[Collection("Selenium test collection")]
public class AccessibilityTestsBase
{
/// <summary>
/// Gets the base URL for the tests.
/// </summary>
#pragma warning disable SA1401 // Fields should be private
internal readonly string BaseUrl;
#pragma warning restore SA1401 // Fields should be private

/// <summary>
/// Gets the WebDriver used for the tests.
/// </summary>
#pragma warning disable SA1401 // Fields should be private
internal readonly IWebDriver Driver;
#pragma warning restore SA1401 // Fields should be private

/// <summary>
/// Initializes a new instance of the <see cref="AccessibilityTestsBase"/> class.
/// </summary>
/// <param name="fixture">fixture.</param>
public AccessibilityTestsBase(AccessibilityTestsFixture fixture)
{
this.BaseUrl = fixture.BaseUrl;
this.Driver = fixture.Driver;
}

/// <summary>
/// Analyze Page Heading And Accessibility.
/// </summary>
/// <param name="pageTitle">Page Title.</param>
public void AnalyzePageHeadingAndAccessibility(string pageTitle)
{
this.ValidatePageHeading(pageTitle);

// then
var axeResult = new AxeBuilder(this.Driver).Analyze();
axeResult.Violations.Should().BeEmpty();
}

/// <summary>
/// ValidatePageHeading.
/// </summary>
/// <param name="pageTitle">Page Title.</param>
public void ValidatePageHeading(string pageTitle)
{
var h1Element = this.Driver.FindElement(By.TagName("h1"));
h1Element.Text.Should().BeEquivalentTo(pageTitle);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// <copyright file="BasicAccessibilityTests.cs" company="HEE.nhs.uk">
// Copyright (c) HEE.nhs.uk.
// </copyright>

namespace LearningHub.Nhs.WebUI.AutomatedUiTests.AccessibilityTests
{
using LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures;
using Xunit;

/// <summary>
/// BasicAccessibilityTests.
/// </summary>
public class BasicAccessibilityTests : AccessibilityTestsBase, IClassFixture<AccessibilityTestsFixture>
{
/// <summary>
/// Initializes a new instance of the <see cref="BasicAccessibilityTests"/> class.
/// BasicAccessibilityTests.
/// </summary>
/// <param name="fixture">fixture.</param>
public BasicAccessibilityTests(AccessibilityTestsFixture fixture)
: base(fixture)
{
}

[Theory]
[InlineData("/Home/Index", "A platform for learning and sharing resources")]

#pragma warning disable SA1600 // Elements should be documented
public void PageHasNoAccessibilityErrors(string url, string pageTitle)
#pragma warning restore SA1600 // Elements should be documented
{
// when
this.Driver.Navigate().GoToUrl(this.BaseUrl + url);

// then
this.AnalyzePageHeadingAndAccessibility(pageTitle);

this.Driver.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// <copyright file="MyAccountAccessibiltyTests.cs" company="HEE.nhs.uk">
// Copyright (c) HEE.nhs.uk.
// </copyright>

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;

/// <summary>
/// MyAccountAccessibiltyTests.
/// </summary>
public class MyAccountAccessibiltyTests : AccessibilityTestsBase,
IClassFixture<AuthenticatedAccessibilityTestsFixture>
{
/// <summary>
/// Initializes a new instance of the <see cref="MyAccountAccessibiltyTests"/> class.
/// MyAccountAccessibiltyTests.
/// </summary>
/// <param name="fixture">fixture.</param>
public MyAccountAccessibiltyTests(AuthenticatedAccessibilityTestsFixture fixture)
: base(fixture)
{
}

/// <summary>
/// MyAccount Page Has Accessibility Errors.
/// </summary>
[Fact]
public void MyAccountPageHasAccessibilityErrors()
{
// given
const string myaccountsUrl = "/myaccount";

// when
this.Driver.Navigate().GoToUrl(this.BaseUrl + myaccountsUrl);
var result = new AxeBuilder(this.Driver).Analyze();

// then
CheckAccessibilityResult(result);

// Dispose driver
this.Driver.LogOutUser(this.BaseUrl);
}

private static void CheckAccessibilityResult(AxeResult result)
{
// Expect axe violation
result.Violations.Should().HaveCount(5);

var violation = result.Violations[0];

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");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<IsPackable>false</IsPackable>

<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<None Remove="appsettings.Development.json" />
<None Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.13" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Selenium.Axe" Version="4.0.16" />
<PackageReference Include="Selenium.Support" Version="4.17.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.17.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="121.0.6167.18400" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\LearningHub.Nhs.WebUI\LearningHub.Nhs.WebUI.csproj" />
</ItemGroup>

</Project>
46 changes: 46 additions & 0 deletions LearningHub.Nhs.WebUI.AutomatedUiTests/SeleniumServerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// <copyright file="SeleniumServerFactory.cs" company="HEE.nhs.uk">
// Copyright (c) HEE.nhs.uk.
// </copyright>

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;

/// <summary>
/// SeleniumServerFactory.
/// </summary>
public class SeleniumServerFactory
{
/// <summary>
/// Root Uri.
/// </summary>
#pragma warning disable SA1401 // Fields should be private
public string RootUri;

/// <summary>
/// Initializes a new instance of the <see cref="SeleniumServerFactory"/> class.
/// </summary>
public SeleniumServerFactory()
{
IConfiguration configuration = ConfigurationHelper.GetConfiguration();
this.RootUri = configuration["LearningHubWebUiUrl"];
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// <copyright file="AccessibilityTestsFixture.cs" company="HEE.nhs.uk">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove copyright and suppress warning (globally)

// Copyright (c) HEE.nhs.uk.
// </copyright>

namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures
{
using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers;
using OpenQA.Selenium;

/// <summary>
/// Represents a fixture for accessibility tests.
/// </summary>
public class AccessibilityTestsFixture
{
/// <summary>
/// Gets the base URL for the tests.
/// </summary>
#pragma warning disable SA1401 // Fields should be private
internal readonly string BaseUrl;
#pragma warning restore SA1401 // Fields should be private

/// <summary>
/// Gets the WebDriver used for the tests.
/// </summary>
#pragma warning disable SA1401 // Fields should be private
internal readonly IWebDriver Driver;
#pragma warning restore SA1401 // Fields should be private

private readonly SeleniumServerFactory factory;

/// <summary>
/// Initializes a new instance of the <see cref="AccessibilityTestsFixture"/> class.
/// </summary>
public AccessibilityTestsFixture()
{
this.factory = new SeleniumServerFactory();
this.BaseUrl = this.factory.RootUri;
this.Driver = DriverHelper.CreateHeadlessChromeDriver();
}

/// <summary>
/// Dispose.
/// </summary>
public void Dispose()
{
this.Driver.Quit();
this.Driver.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <copyright file="AuthenticatedAccessibilityTestsFixture.cs" company="HEE.nhs.uk">
// Copyright (c) HEE.nhs.uk.
// </copyright>

namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestFixtures
{
using LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers;
using Microsoft.Extensions.Configuration;

/// <summary>
/// AuthenticatedAccessibilityTestsFixture.
/// </summary>
/// <typeparam name="TStartup">TStartup.</typeparam>
public class AuthenticatedAccessibilityTestsFixture : AccessibilityTestsFixture
{
/// <summary>
/// Initializes a new instance of the <see cref="AuthenticatedAccessibilityTestsFixture"/> class.
/// </summary>
public AuthenticatedAccessibilityTestsFixture()
{
IConfiguration configuration = ConfigurationHelper.GetConfiguration();
string adminUsername = configuration["AdminUser:Username"];
string adminPassword = configuration["AdminUser:Password"];
this.Driver.LogUserInAsAdmin(this.BaseUrl, adminUsername, adminPassword);
}

/// <summary>
/// Dispose.
/// </summary>
public new void Dispose()
{
this.Driver.LogOutUser(this.BaseUrl);
base.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// <copyright file="ConfigurationHelper.cs" company="HEE.nhs.uk">
// Copyright (c) HEE.nhs.uk.
// </copyright>

namespace LearningHub.Nhs.WebUI.AutomatedUiTests.TestHelpers
{
using Microsoft.Extensions.Configuration;

/// <summary>
/// ConfigurationHelper.
/// </summary>
public static class ConfigurationHelper
{
/// <summary>
/// GetConfiguration.
/// </summary>
/// <returns>IConfiguration.</returns>
public static IConfiguration GetConfiguration()
{
return new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.Development.json")
.Build();
}
}
}
Loading