Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
45 changes: 39 additions & 6 deletions .github/workflows/dotnetCi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,19 @@ jobs:
timeout-minutes: 30

env:
RunNumber: ${{ github.run_number }}.${{ github.run_attempt }}
VersionSuffix: ci.${{ github.run_number }}
SonarCloudProject: csf-dev_CSF.Extensions.WebDriver
SonarCloudUsername: craigfowler-github
SonarCloudUrl: https://sonarcloud.io
SonarCloudSecretKey: ${{ secrets.SONARCLOUDKEY }}
Configuration: Debug
Tfm: net8.0
DotnetVersion: 8.0.x
DISPLAY: :99
BranchName: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref_name }}
BranchParam: ${{ github.event_name == 'pull_request' && 'sonar.pullrequest.branch' || 'sonar.branch.name' }}
PullRequestParam: ${{ github.event_name == 'pull_request' && format('/d:sonar.pullrequest.key={0}', github.event.number) || '' }}

steps:
- name: Checkout
Expand All @@ -43,6 +52,10 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DotnetVersion }}
- name: Install SonarScanner
run: dotnet tool install --global dotnet-sonarscanner
- name: Install Coverlet console
run: dotnet tool install --global coverlet.console --version 8.0.1
- name: Install DocFX
run: dotnet tool install --global docfx
# See https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md
Expand All @@ -58,25 +71,45 @@ jobs:

# Build and test the solution

- name: Start SonarScanner
run: >
dotnet sonarscanner begin
/k:${{ env.SonarCloudProject }}
/v:GitHub_build_${{ env.RunNumber }}
/o:${{ env.SonarCloudUsername }}
/d:sonar.host.url=${{ env.SonarCloudUrl }}
/d:sonar.token=${{ env.SonarCloudSecretKey }}
/d:${{ env.BranchParam }}=${{ env.BranchName }} ${{ env.PullRequestParam }}
/s:$PWD/.sonarqube-analysisproperties.xml
- name: Build the solution
run: dotnet build -c ${{ env.Configuration }}
- name: Run .NET tests
run: dotnet build -c ${{ env.Configuration }} --no-incremental
- name: Run .NET tests with coverage
id: dotnet_tests
run: dotnet test
continue-on-error: true
shell: bash {0}
run: |
coverlet CSF.Extensions.WebDriver.Tests/bin/$Configuration/$Tfm/CSF.Extensions.WebDriver.Tests.dll --target "dotnet" --targetargs "test -c $Configuration --no-build --logger:nunit --test-adapter-path:." -f opencover -o "CSF.Extensions.WebDriver.Tests/TestResults/CSF.Extensions.WebDriver.Tests.opencover.xml"
exitCode=$?
if [ $exitCode -ne 0 ]
then
echo "One or more tests have failed; this build should eventually fail"
echo "failures=true" >> "$GITHUB_OUTPUT"
fi

# Post-test tasks (artifacts, overall status)

- name: Stop SonarScanner
run:
dotnet sonarscanner end /d:sonar.token=${{ env.SonarCloudSecretKey }}
- name: Gracefully stop Xvfb
run: killall Xvfb
continue-on-error: true
- name: Upload .NET test results artifacts
uses: actions/upload-artifact@v4
with:
name: NUnit test results
path: Tests/*.Tests/**/TestResults.xml
path: '**/TestResults/*.xml'
- name: Fail the build if any test failures
if: steps.dotnet_tests.outcome == 'failure'
if: steps.dotnet_tests.outputs.failures == 'failure'
run: |
echo "Failing the build due to test failures"
exit 1
Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/publishDocsWebsite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Update docs website

on:
push:
branches: [ "master" ]

jobs:

# This job builds the documentation website
# and the commits that to the master branch,
# which will result in replacing the currently published site

build_and_commit:
name: Build & commit docs website
runs-on: ubuntu-slim

env:
DotnetVersion: 8.0.x

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Add .NET global tools location to PATH
run: echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH"
- name: Install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DotnetVersion }}
- name: Install DocFX
run: dotnet tool install --global docfx
- name: Remove old docs
run: rm -rf docs/*
- name: Build new docs
working-directory: CSF.Extensions.WebDriver.Docs
run: docfx docfx.json
- name: Add & Commit
uses: EndBug/add-and-commit@v9.1.4
with:
add: -A docs/
default_author: github_actor
committer_name: Github Actions Workflow (bot)
committer_email: github-actions-workflow@bots.noreply.github.com
fetch: true
message: Publish updated documentation website
push: origin master


2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ bin/
obj/
*.userprefs
*.csproj.user
TestResult.xml
**/TestResults/**
*.log
*.orig
*.nupkg
Expand Down
13 changes: 13 additions & 0 deletions .sonarqube-analysisproperties.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<SonarQubeAnalysisProperties xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sonarsource.com/msbuild/integration/2015/1">
<Property Name="sonar.coverage.exclusions">CSF.Extensions.WebDriver.Tests\**\*,**\*Exception.cs</Property>
<Property Name="sonar.exclusions">docs\**\*</Property>
<Property Name="sonar.cpd.exclusions">CSF.Extensions.WebDriver.Tests\**\*</Property>
<Property Name="sonar.cs.nunit.reportsPaths">**\TestResults.xml</Property>
<Property Name="sonar.cs.opencover.reportsPaths">**\TestResults\*.opencover.xml</Property>
<Property Name="sonar.scanner.scanAll">false</Property>
<Property Name="sonar.test.inclusions">CSF.Extensions.WebDriver.Tests\**\*</Property>
<Property Name="sonar.scanner.skipJreProvisioning">true</Property>
</SonarQubeAnalysisProperties>
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="AutoFixture" Version="4.18.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="NunitXml.TestLogger" Version="8.0.0" />
<PackageReference Include="coverlet.collector" Version="8.0.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.18.1" />
<PackageReference Include="AutoFixture.NUnit3" Version="4.18.1" />
<PackageReference Include="Moq" Version="4.20.70" />
Expand Down
25 changes: 25 additions & 0 deletions CSF.Extensions.WebDriver.Tests/ConfigurationFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.Extensions.Configuration;

namespace CSF.Extensions.WebDriver;

public static class ConfigurationFactory
{
/// <summary>
/// Helper method to create an <see cref="IConfiguration"/> from a specified JSON string.
/// </summary>
/// <param name="jsonConfig">A JSON string which will be used as the basis for the returned config.</param>
/// <returns>A task exposing a configuration object, created from the JSON string.</returns>
public static async Task<IConfiguration> GetConfigurationAsync(string jsonConfig)
{
var builder = new ConfigurationBuilder();

var stream = new MemoryStream ();
using var writer = new StreamWriter(stream, leaveOpen: true);
await writer.WriteAsync(jsonConfig);
await writer.FlushAsync();
stream.Position = 0;

builder.AddJsonStream(stream);
return builder.Build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Microsoft.Extensions.Configuration;
using OpenQA.Selenium.Chrome;

namespace CSF.Extensions.WebDriver.Factories;

[TestFixture, Parallelizable]
public class DriverTypeProviderTests
{
[Test, AutoMoqData]
public void TryGetDriverTypeShouldReturnTrueForAKnownType([StandardTypes] DriverTypeProvider sut,
WebDriverCreationOptions options,
IConfigurationSection config)
{
options.DriverType = nameof(ChromeDriver);
Assert.That(sut.TryGetDriverType(options, config, out _), Is.True);
}

[Test, AutoMoqData]
public void TryGetDriverTypeShouldReturnFalseForAnUnknownType([StandardTypes] DriverTypeProvider sut,
WebDriverCreationOptions options,
IConfigurationSection config)
{
options.DriverType = "Elephant";
options.DriverFactoryType = null;
Assert.That(sut.TryGetDriverType(options, config, out _), Is.False);
}

[Test, AutoMoqData]
public void TryGetDriverTypeShouldReturnFalseIfDriverTypeIsNullAndDriverFactoryIsToo([StandardTypes] DriverTypeProvider sut,
WebDriverCreationOptions options,
IConfigurationSection config)
{
options.DriverType = null;
options.DriverFactoryType = null;
Assert.That(sut.TryGetDriverType(options, config, out _), Is.False);
}

[Test, AutoMoqData]
public void TryGetDriverTypeShouldReturnTrueForAnUnknownTypeIfDriverFactoryIsNotNull([StandardTypes] DriverTypeProvider sut,
WebDriverCreationOptions options,
IConfigurationSection config,
string factoryType)
{
options.DriverType = "Elephant";
options.DriverFactoryType = factoryType;
Assert.That(sut.TryGetDriverType(options, config, out _), Is.True);
}

[Test, AutoMoqData]
public void TryGetDriverTypeShouldReturnTrueIfDriverTypeIsNullIfDriverFactoryIsNotNull([StandardTypes] DriverTypeProvider sut,
WebDriverCreationOptions options,
IConfigurationSection config,
string factoryType)
{
options.DriverType = null;
options.DriverFactoryType = factoryType;
Assert.That(sut.TryGetDriverType(options, config, out _), Is.True);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Microsoft.Extensions.Configuration;
using NUnit.Framework.Internal;
using OpenQA.Selenium;

namespace CSF.Extensions.WebDriver.Factories;

[TestFixture, Parallelizable]
public class LogLevelDriverOptionsFactoryDecoratorTests
{
[Test, AutoMoqData]
public void CreateOptionsShouldSetLogLevelIfSpecifiedInConfig([Frozen] ICreatesDriverOptions wrapped,
LogLevelDriverOptionsFactoryDecorator sut,
Type optionsType,
IConfigurationSection config)
{
var options = new InspectableDriverOptions();
Mock.Get(wrapped).Setup(x => x.CreateOptions(optionsType, config)).Returns(options);
Mock.Get(config)
.Setup(x => x.GetSection(nameof(WebDriverCreationOptions.BrowserLogLevel)))
.Returns(Mock.Of<IConfigurationSection>(x => x.Value == LogLevel.Severe.ToString()));

sut.CreateOptions(optionsType, config);

Assert.That(options.GetLoggingPrefs()[LogType.Browser], Is.EqualTo("SEVERE"));
}

[Test, AutoMoqData]
public void CreateOptionsShouldNotSetLogLevelIfOmittedInConfig([Frozen] ICreatesDriverOptions wrapped,
LogLevelDriverOptionsFactoryDecorator sut,
Type optionsType,
IConfigurationSection config)
{
var options = new InspectableDriverOptions();
Mock.Get(wrapped).Setup(x => x.CreateOptions(optionsType, config)).Returns(options);
Mock.Get(config)
.Setup(x => x.GetSection(nameof(WebDriverCreationOptions.BrowserLogLevel)))
.Returns(Mock.Of<IConfigurationSection>(x => x.Value == null));

sut.CreateOptions(optionsType, config);

Assert.That(options.GetLoggingPrefs(), Is.Null);
}

[Test, AutoMoqData]
public void CreateOptionsShouldNotSetLogLevelIfConfigIsInvalid([Frozen] ICreatesDriverOptions wrapped,
LogLevelDriverOptionsFactoryDecorator sut,
Type optionsType,
IConfigurationSection config)
{
var options = new InspectableDriverOptions();
Mock.Get(wrapped).Setup(x => x.CreateOptions(optionsType, config)).Returns(options);
Mock.Get(config)
.Setup(x => x.GetSection(nameof(WebDriverCreationOptions.BrowserLogLevel)))
.Returns(Mock.Of<IConfigurationSection>(x => x.Value == "invalid level"));

sut.CreateOptions(optionsType, config);

Assert.That(options.GetLoggingPrefs(), Is.Null);
}

class InspectableDriverOptions : DriverOptions
{
public Dictionary<string, object> GetLoggingPrefs() => GenerateLoggingPreferencesDictionary();

public override ICapabilities ToCapabilities() => throw new NotImplementedException();
}
}
Loading
Loading