Stub Gen Selenium Tests
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Selenium.WebDriver" Version="4.12.0" />
|
||||||
|
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="118.0.5901.4300" />
|
||||||
|
<PackageReference Include="Selenium.Support" Version="4.12.0" />
|
||||||
|
<PackageReference Include="NUnit" Version="3.13.4" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using OpenQA.Selenium.Chrome;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Driver;
|
||||||
|
|
||||||
|
public static class DriverFactory
|
||||||
|
{
|
||||||
|
public static IWebDriver CreateChromeDriver()
|
||||||
|
{
|
||||||
|
var options = new ChromeOptions();
|
||||||
|
var headless = Environment.GetEnvironmentVariable("HEADLESS");
|
||||||
|
if (!string.IsNullOrEmpty(headless) && (headless == "1" || headless.Equals("true", StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
options.AddArgument("--headless=new");
|
||||||
|
}
|
||||||
|
|
||||||
|
options.AddArgument("--disable-gpu");
|
||||||
|
options.AddArgument("--no-sandbox");
|
||||||
|
options.AddArgument("--disable-dev-shm-usage");
|
||||||
|
|
||||||
|
var service = ChromeDriverService.CreateDefaultService();
|
||||||
|
service.HideCommandPromptWindow = true;
|
||||||
|
|
||||||
|
return new ChromeDriver(service, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using OpenQA.Selenium;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Pages;
|
||||||
|
|
||||||
|
public class CounterPage
|
||||||
|
{
|
||||||
|
private readonly IWebDriver _driver;
|
||||||
|
public CounterPage(IWebDriver driver) => _driver = driver;
|
||||||
|
|
||||||
|
public bool IsAt()
|
||||||
|
{
|
||||||
|
var url = _driver.Url ?? string.Empty;
|
||||||
|
return url.Contains("counter", System.StringComparison.OrdinalIgnoreCase) || _driver.PageSource.Contains("Counter");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using OpenQA.Selenium;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Pages;
|
||||||
|
|
||||||
|
public class HomePage
|
||||||
|
{
|
||||||
|
private readonly IWebDriver _driver;
|
||||||
|
public HomePage(IWebDriver driver) => _driver = driver;
|
||||||
|
|
||||||
|
public bool IsAt()
|
||||||
|
{
|
||||||
|
var url = _driver.Url ?? string.Empty;
|
||||||
|
return url.EndsWith("/") || url.Contains("/index", System.StringComparison.OrdinalIgnoreCase) || _driver.PageSource.Contains("Home");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Pages;
|
||||||
|
|
||||||
|
public class NavMenuPage
|
||||||
|
{
|
||||||
|
private readonly IWebDriver _driver;
|
||||||
|
|
||||||
|
public NavMenuPage(IWebDriver driver)
|
||||||
|
{
|
||||||
|
_driver = driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClickLinkByText(string linkText)
|
||||||
|
{
|
||||||
|
var link = _driver.FindElements(By.CssSelector("a[href]"))
|
||||||
|
.FirstOrDefault(e => !string.IsNullOrWhiteSpace(e.Text) && e.Text.Trim().Equals(linkText, System.StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (link == null)
|
||||||
|
{
|
||||||
|
throw new NoSuchElementException($"Link with text '{linkText}' not found in the page.");
|
||||||
|
}
|
||||||
|
|
||||||
|
link.Click();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using OpenQA.Selenium;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Pages;
|
||||||
|
|
||||||
|
public class WeatherPage
|
||||||
|
{
|
||||||
|
private readonly IWebDriver _driver;
|
||||||
|
public WeatherPage(IWebDriver driver) => _driver = driver;
|
||||||
|
|
||||||
|
public bool IsAt()
|
||||||
|
{
|
||||||
|
var url = _driver.Url ?? string.Empty;
|
||||||
|
return url.Contains("weather", System.StringComparison.OrdinalIgnoreCase) || _driver.PageSource.Contains("Weather");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# AOW4 Selenium Tests
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- .NET 10 SDK
|
||||||
|
- Google Chrome installed (compatible with ChromeDriver package)
|
||||||
|
- The AOW4 web app running locally (by default at `http://localhost:5000`) or set `BASE_URL` env var.
|
||||||
|
|
||||||
|
Run tests:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# optional: run headless
|
||||||
|
$env:HEADLESS = "1"
|
||||||
|
# optional: point to running app
|
||||||
|
$env:BASE_URL = "http://localhost:5000"
|
||||||
|
dotnet test AOW4.SeleniumTests\AOW4.SeleniumTests.csproj
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Navigation tests use the UI nav links — ensure the app is running before executing tests.
|
||||||
|
- Broken links scanner sends HTTP HEAD requests and falls back to GET if needed.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using AOW4.SeleniumTests.Driver;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Tests;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public abstract class BaseTest
|
||||||
|
{
|
||||||
|
protected IWebDriver Driver = null!;
|
||||||
|
protected string BaseUrl => System.Environment.GetEnvironmentVariable("BASE_URL") ?? "http://localhost:5000";
|
||||||
|
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public void GlobalSetup()
|
||||||
|
{
|
||||||
|
Driver = DriverFactory.CreateChromeDriver();
|
||||||
|
Driver.Manage().Window.Maximize();
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeTearDown]
|
||||||
|
public void GlobalTeardown()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Driver.Quit();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void GoHome()
|
||||||
|
{
|
||||||
|
Driver.Navigate().GoToUrl(BaseUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Tests;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class BrokenLinksTest : BaseTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void ScanAndReportBrokenLinks()
|
||||||
|
{
|
||||||
|
GoHome();
|
||||||
|
|
||||||
|
var anchors = Driver.FindElements(By.CssSelector("a[href]"))
|
||||||
|
.Select(a => a.GetAttribute("href") ?? string.Empty)
|
||||||
|
.Where(h => !string.IsNullOrWhiteSpace(h))
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var failures = new List<string>();
|
||||||
|
using var client = new HttpClient();
|
||||||
|
|
||||||
|
foreach (var raw in anchors)
|
||||||
|
{
|
||||||
|
if (raw.StartsWith("javascript:", System.StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
if (raw.StartsWith("mailto:", System.StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
System.Uri uri;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
uri = new System.Uri(raw, System.UriKind.RelativeOrAbsolute);
|
||||||
|
if (!uri.IsAbsoluteUri)
|
||||||
|
{
|
||||||
|
uri = new System.Uri(new System.Uri(BaseUrl), raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
failures.Add($"Invalid URI: {raw}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var req = new HttpRequestMessage(HttpMethod.Head, uri);
|
||||||
|
var resp = client.Send(req);
|
||||||
|
if (!resp.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
// try GET as fallback
|
||||||
|
using var greq = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||||
|
var gresp = client.Send(greq);
|
||||||
|
if (!gresp.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
failures.Add($"{(int)gresp.StatusCode} {uri}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
failures.Add($"Error checking {uri}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failures.Any())
|
||||||
|
{
|
||||||
|
Assert.Fail("Broken links found:\n" + string.Join("\n", failures));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using AOW4.SeleniumTests.Pages;
|
||||||
|
|
||||||
|
namespace AOW4.SeleniumTests.Tests;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class NavigationTests : BaseTest
|
||||||
|
{
|
||||||
|
[TestCase("Home", "/")]
|
||||||
|
[TestCase("Counter", "/counter")]
|
||||||
|
[TestCase("Weather", "/weather")]
|
||||||
|
public void ClickNavLink_NavigatesToPage(string linkText, string expectedPath)
|
||||||
|
{
|
||||||
|
GoHome();
|
||||||
|
|
||||||
|
var nav = new NavMenuPage(Driver);
|
||||||
|
nav.ClickLinkByText(linkText);
|
||||||
|
|
||||||
|
// small wait for navigation
|
||||||
|
System.Threading.Thread.Sleep(700);
|
||||||
|
|
||||||
|
Assert.IsTrue(Driver.Url.Contains(expectedPath, System.StringComparison.OrdinalIgnoreCase) || Driver.PageSource.Contains(linkText),
|
||||||
|
$"Expected to be on route containing '{expectedPath}' after clicking '{linkText}', but was '{Driver.Url}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<Solution>
|
<Solution>
|
||||||
<Project Path="AOW4.Client/AOW4.Client.csproj" />
|
<Project Path="AOW4.Client/AOW4.Client.csproj" />
|
||||||
|
<Project Path="AOW4.SeleniumTests/AOW4.SeleniumTests.csproj" />
|
||||||
<Project Path="AOW4/AOW4.csproj" />
|
<Project Path="AOW4/AOW4.csproj" />
|
||||||
</Solution>
|
</Solution>
|
||||||
|
|||||||
Reference in New Issue
Block a user