Skip to content
Closed
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
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Build output
bin/
obj/

# .NET
*.user
*.suo
.vs/

# Reqnroll / SpecFlow generated files
*.feature.cs

# Playwright
**/bin/**/playwright.ps1
.playwright/

# BrowserStack
log/
local.log
.browserstack/

# Environment
.env

# OS
.DS_Store
65 changes: 63 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,63 @@
# nunit-csharp-reqnroll-playwright-browserstack
Sample repo for customers
# Reqnroll + NUnit + Playwright with BrowserStack

Sample repository demonstrating how to run C# Reqnroll (NUnit runner) + Playwright tests on
BrowserStack Automate using the [BrowserStack C# SDK](https://www.browserstack.com/docs/automate/selenium/sdk-overview).

## Prerequisites

- [.NET SDK](https://dotnet.microsoft.com/download) 6.0 or higher (8.0 recommended)
- A [BrowserStack account](https://www.browserstack.com/users/sign_up) (username + access key)
- Git

## Setup

1. Clone this repository and switch to the project directory:

```bash
git clone https://github.com/browserstack/nunit-csharp-reqnroll-playwright-browserstack.git
cd nunit-csharp-reqnroll-playwright-browserstack/Reqnroll-Playwright-BrowserStack
```

2. Restore the BrowserStack SDK tool and project dependencies:

```bash
dotnet tool restore
dotnet restore
```

3. Set your BrowserStack credentials as environment variables:

```bash
export BROWSERSTACK_USERNAME="YOUR_USERNAME"
export BROWSERSTACK_ACCESS_KEY="YOUR_ACCESS_KEY"
```

Alternatively, edit `browserstack.yml` and set the `userName` and `accessKey` values directly.

## Run Sample Test

Runs the BStack Demo "add to cart" scenario against the platforms configured in `browserstack.yml`:

```bash
dotnet test
```

To run only the sample (non-local) scenario, filter by its tag:

```bash
dotnet test --filter "TestCategory=sample-test"
```

## Run Local Test

Runs the BrowserStack Local scenario (`browserstackLocal: true` is already enabled in `browserstack.yml`):

```bash
dotnet test --filter "TestCategory=sample-local-test"
```

## Notes

- View your test results on the [BrowserStack Automate dashboard](https://automate.browserstack.com/).
- The framework is detected as `nunit` because Reqnroll runs on the NUnit test runner.
- Test Observability is enabled by default (`testObservability: true` in `browserstack.yml`).
22 changes: 22 additions & 0 deletions Reqnroll-Playwright-BrowserStack.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reqnroll-Playwright-BrowserStack", "Reqnroll-Playwright-BrowserStack\Reqnroll-Playwright-BrowserStack.csproj", "{C3215C4E-FED4-47A9-9808-7B561D6A9F0B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C3215C4E-FED4-47A9-9808-7B561D6A9F0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3215C4E-FED4-47A9-9808-7B561D6A9F0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3215C4E-FED4-47A9-9808-7B561D6A9F0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3215C4E-FED4-47A9-9808-7B561D6A9F0B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
12 changes: 12 additions & 0 deletions Reqnroll-Playwright-BrowserStack/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"browserstack-sdk": {
"version": "0.0.0",
"commands": [
"browserstack-sdk"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@sample-local-test
Feature: BStack Local
Scenario: Open BrowserStack Local
Given I navigate to the local website
Then the page title should be "BrowserStack Local"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@sample-test
Feature: BStack Sample
Scenario: Can add product to cart
Given I navigate to the StackDemo website
When I add the first product to the cart
And the cart pane is opened
Then the product in the cart matches the product on the page
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<RootNamespace>ReqnrollPlaywrightBrowserStack</RootNamespace>
<AssemblyName>ReqnrollPlaywrightBrowserStack</AssemblyName>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BrowserStack.TestAdapter" Version="0.*" />
<PackageReference Include="BrowserStackLocal" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Microsoft.Playwright" Version="1.40.0" />
<PackageReference Include="Microsoft.Playwright.NUnit" Version="1.40.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="Reqnroll.NUnit" Version="2.0.3" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Threading.Tasks;
using Microsoft.Playwright;
using Reqnroll;

namespace ReqnrollPlaywrightBrowserStack
{
// Manages the Playwright browser/page lifecycle for each scenario.
// The BrowserStack SDK intercepts the Playwright connection and routes it
// to the BrowserStack cloud using the platforms defined in browserstack.yml.
[Binding]
public class PlaywrightHooks
{
private readonly ScenarioContext _scenarioContext;

private IPlaywright? _playwright;
private IBrowser? _browser;
private IBrowserContext? _context;
private IPage? _page;

public PlaywrightHooks(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}

[BeforeScenario]
public async Task InitializeAsync()
{
_playwright = await Playwright.CreateAsync();
_browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = true
});
_context = await _browser.NewContextAsync();
_page = await _context.NewPageAsync();

// Expose the page to the step definitions via the scenario container.
_scenarioContext.ScenarioContainer.RegisterInstanceAs<IPage>(_page);
}

[AfterScenario]
public async Task TearDownAsync()
{
if (_page != null)
{
await _page.CloseAsync();
}
if (_context != null)
{
await _context.CloseAsync();
}
if (_browser != null)
{
await _browser.CloseAsync();
}
_playwright?.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Microsoft.Playwright;
using NUnit.Framework;
using Reqnroll;

namespace ReqnrollPlaywrightBrowserStack
{
[Binding]
public class SampleLocalTestSteps
{
private readonly IPage _page;

public SampleLocalTestSteps(ScenarioContext scenarioContext)
{
_page = scenarioContext.ScenarioContainer.Resolve<IPage>();
}

[Given(@"I navigate to the local website")]
public async Task GivenINavigateToTheLocalWebsite()
{
await _page.GotoAsync("http://bs-local.com:45454");
}

[Then(@"the page title should be ""(.*)""")]
public async Task ThenThePageTitleShouldBe(string expectedTitle)
{
string title = await _page.TitleAsync();
Assert.That(title, Is.EqualTo(expectedTitle));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Threading.Tasks;
using Microsoft.Playwright;
using NUnit.Framework;
using Reqnroll;

namespace ReqnrollPlaywrightBrowserStack
{
[Binding]
public class SampleTestSteps
{
private readonly IPage _page;
private string? _productOnPageText;

public SampleTestSteps(ScenarioContext scenarioContext)
{
_page = scenarioContext.ScenarioContainer.Resolve<IPage>();
}

[Given(@"I navigate to the StackDemo website")]
public async Task GivenINavigateToTheStackDemoWebsite()
{
await _page.GotoAsync("https://bstackdemo.com/");
}

[When(@"I add the first product to the cart")]
public async Task WhenIAddTheFirstProductToTheCart()
{
_productOnPageText = await _page.Locator("//*[@id=\"1\"]/p").InnerTextAsync();
await _page.Locator("//*[@id=\"1\"]/div[4]").ClickAsync();
}

[When(@"the cart pane is opened")]
public async Task WhenTheCartPaneIsOpened()
{
await _page.Locator(".float-cart__content").WaitForAsync();
}

[Then(@"the product in the cart matches the product on the page")]
public async Task ThenTheProductInTheCartMatchesTheProductOnThePage()
{
string productInCartText = await _page
.Locator("//*[@id=\"__next\"]/div/div/div[2]/div[2]/div[2]/div/div[3]/p[1]")
.InnerTextAsync();
Assert.That(productInCartText, Is.EqualTo(_productOnPageText));
}
}
}
26 changes: 26 additions & 0 deletions Reqnroll-Playwright-BrowserStack/browserstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
userName: YOUR_USERNAME
accessKey: YOUR_ACCESS_KEY
projectName: BrowserStack Samples
buildName: browserstack build
buildIdentifier: '#${BUILD_NUMBER}'
framework: nunit
platforms:
- os: OS X
osVersion: Big Sur
browserName: Chrome
browserVersion: latest
- os: Windows
osVersion: 10
browserName: Edge
browserVersion: latest
- deviceName: Samsung Galaxy S22 Ultra
browserName: chrome
osVersion: 12.0
parallelsPerPlatform: 1
browserstackAutomation: true
browserstackLocal: true
source: nunit-csharp-reqnroll-playwright-browserstack:sample-sdk:v1.0
testObservability: true
debug: false
networkLogs: false
consoleLogs: errors
Loading