Add BrowserStack SDK + Playwright NUnit sample#1
Conversation
Customer-facing starting point for running NUnit + Microsoft.Playwright
.NET tests on BrowserStack via the BrowserStack .NET SDK
(BrowserStack.TestAdapter). Coexists with browserstack/csharp-playwright-browserstack
as the modern SDK-only variant; mirrors the shape of the xUnit + Reqnroll
sample at browserstack/xunit-reqnroll-playwright-browserstack but adapted
for NUnit.
Layout:
NunitPlaywrightBrowserstack.sln
NunitPlaywrightBrowserstack.Tests/
NunitPlaywrightBrowserstack.Tests.csproj (NUnit 4.3.2 + Playwright + BS.TestAdapter)
browserstack.yml (4 platforms x parallelsPerPlatform:2 = 8 sessions)
AssemblyInfo.cs (NUnit fixture-level parallelism)
PlaywrightFixtureBase.cs ([SetUp]/[TearDown]; SDK rewrites the launch)
BStackDemoCartTest.cs (bstackdemo add-to-cart)
BStackLocalSampleTest.cs (Local + bs-local.com:45454 harness)
.github/workflows/sanity-workflow.yml (windows-latest + macos-latest; both filters)
Source tag: nunit-playwright:sample-master:v1.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses the xunit-reqnroll PR #1 review feedback from @xxshubhamxx (structural parity with junit-browserstack/junit-5/browserstack.yml). Keeps the NUnit-specific 4 platforms x 2 fixtures = 8 sessions note underneath the generic Example 1/Example 2 worked-example text. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per the spirit of recent review feedback that all sample repos should look + work similarly, treat xunit-reqnroll-playwright-browserstack as the closest precedent for this sample (vs csharp-playwright-browserstack, the older reference). Refreshes inline comments to point at the right hooks/scenario in xunit-reqnroll. No behavioural changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review-comment alignment pass + cross-platform coverage updatePer a re-read of the xunit-reqnroll PR #1 review threads, treating that repo as the canonical reference for similarity. Review-comment alignment audit
Necessary deviations from junit-browserstack canonical yml — all warranted for .NET / Playwright correctness or user-chosen in brainstorm: Test-code pattern alignment (commit
|
| Dimension | Verified? | Evidence |
|---|---|---|
| BrowserStack platforms: Win11/Chrome, Win11/Edge, Win11/Firefox, OSX-Ventura/WebKit | ✅ 4/4 platforms × 2/2 fixtures = 8/8 sessions passed on the current branch head | Build 92f0a435… — dotnet test (no filter) against commit 97bef30 |
CI runner OS — windows-latest (sanity workflow) |
⏸️ blocked until merge | GitHub Actions only registers workflows that live on the default branch — sanity-workflow.yml is on browserstack-sdk only, invisible to workflow_dispatch API (HTTP 404). Same constraint xunit-reqnroll PR #1 hit and validated post-merge. |
CI runner OS — macos-latest (sanity workflow) |
⏸️ blocked until merge | same default-branch requirement |
Plan post-merge
Once merged, I'll dispatch the sanity workflow with the merge-commit SHA from both windows-latest and macos-latest runners and post the results back in a follow-up comment, matching xunit-reqnroll's verification flow.
CI verification on a fork (per @Baaryan's review feedback)To pre-validate the sanity workflow before merge, forked this repo to Jimesh-browserstack/nunit-playwright-browserstack, set the fork's default branch to Run results
BrowserStack-side coverage (run #2)Build
Conclusion
Fork remains live for re-dispatch on additional commits if reviewers want to re-verify later. |
- BStackLocalSampleTest.cs: drop xunit-reqnroll pointer; keep a one-line `browserstackLocal` + port-45454 prerequisite note. - AssemblyInfo.cs: collapse parallelism explainer to a single line about the SDK-spawned-process invariant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Align with nunit-browserstack (Selenium) sample conventions:
- browserstack.yml: parallelsPerPlatform 2 -> 1, browserstackLocal false -> true
- Tag fixtures with [Category("sample-test")] / [Category("sample-local-test")]
so `dotnet test --filter "Category=..."` scopes the run (matches
nunit-browserstack/SampleTest.cs and SampleLocalTest.cs)
- README: swap FullyQualifiedName filters for Category= filters; drop the
now-redundant "flip the toggle" step; update parallelism narrative to ppp=1
(4 platforms x 1 x 2 NUnit-parallel fixtures = still 8 concurrent sessions)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the README/yml changes from ed3541a: - Filter strings: FullyQualifiedName~BStack* -> Category=sample-test / sample-local-test - Drop the in-workflow sed that flipped browserstackLocal false -> true; the yml ships with browserstackLocal: true now - Refresh the top-of-file scenario summary to match Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Customer-facing starting point for running NUnit tests on BrowserStack via Playwright .NET and the BrowserStack .NET SDK. Coexists with
browserstack/csharp-playwright-browserstack(the legacy NUnit reference) as the modern, SDK-only variant; mirrors the layout ofbrowserstack/xunit-reqnroll-playwright-browserstackbut adapted for NUnit (no Reqnroll/BDD layer).Review round 2 — aligned with
nunit-browserstack(Selenium) conventions (ed3541a+cadbcfa)Follow-up changes after first-round review to match the established
browserstack/nunit-browserstackshape:browserstack.yml→parallelsPerPlatform: 1(was2);browserstackLocal: true(wasfalse). Other sample repos default toppp: 1; flipping Local on by default lets the local-host fixture run without a yml edit.[Category("sample-test")]/[Category("sample-local-test")], matchingnunit-browserstack/SampleTest.cs#L7andSampleLocalTest.cs..github/workflows/sanity-workflow.ymlfilters swapped fromFullyQualifiedName~…toCategory=sample-test/Category=sample-local-test; "flip the toggle" steps dropped from both the README and the workflow (now the default).What customers get
Plus
.github/workflows/sanity-workflow.yml(mirrors the xunit-reqnroll sanity workflow, but withmatrix.os = [windows-latest, macos-latest]and NUnitCategory=filters).One customer-facing entry point —
dotnet testfrom the project directory runs both fixtures across all four platforms in parallel on BrowserStack.Design notes
PlaywrightFixtureBase.cscallspw.Chromium.LaunchAsync()unconditionally; the SDK rewrites the launch (Harmony patches viaLib.Harmony) at runtime to route to the per-platform browser configured inbrowserstack.yml(chrome/playwright-webkit/playwright-firefox/edge). NoChromium.ConnectAsync(wss_url)plumbing in customer code.browserstackLocal: trueships on by default so bothCategory=sample-test(public bstackdemo) andCategory=sample-local-test(private host) run without a yml edit — customer only needs to stand up the local harness for the local fixture.parallelsPerPlatform: 1(yml) ×[assembly: Parallelizable(ParallelScope.Fixtures)](AssemblyInfo.cs) × 4 platforms × 2 fixtures produces 8 concurrent sessions perdotnet test— the headline parallelism story that differentiates this sample fromcsharp-playwright-browserstack.[Category]filtering matches thenunit-browserstack(Selenium) reference:dotnet test --filter "Category=sample-test"scopes to the cart fixture,Category=sample-local-testto the Local fixture, no filter runs all 8.Microsoft.Playwright(*) andBrowserStack.TestAdapter(0.*) to match the xunit-reqnroll/csharp-playwright pinning policy. NUnit pinned at4.3.2(current stable).Microsoft.Playwright.NUnitis required even though the fixtures don't usePageTest— the SDK's auto-generatedBrowserStackPatch.csreferencesMicrosoft.Playwright.NUnitwhenframework: nunitis set, so omitting the package fails the build with CS0234.<framework>-<library>-playwright:sample-master:v<N>→nunit-playwright:sample-master:v1.0.userName/accessKeyin the yml are passed literally to the wss CDP endpoint — env vars override only when the lines are absent. Both the yml comment and the README state this explicitly so customers don't get a confusing "Invalid username or password" error..gitignoreexcludesbin/,obj/,log/,.config/,.browserstack/,*.user,*.bak,.idea/,.vs/— same shape as xunit-reqnroll.Local verification (round 2 — current code)
Fresh end-to-end runs against BrowserStack on the current code (
ed3541a+cadbcfa:Category=filters, ppp=1, browserstackLocal=true by default). Creds in env vars, placeholder lines stripped from yml.dotnet test --filter "Category=sample-test"02e164650d…(build #21)dotnet test --filter "Category=sample-local-test"(python http.server harness on :45454; SDK auto-started Local tunnel via default-onbrowserstackLocal: true)22a853f38f…(build #23)bs-local.com:45454)dotnet test(no filter — full parallelism showcase)7e77413767…(build #25)Workflow verification (post-merge dispatch)
Run #26153748026 against merged
main(50a4e33) — both matrix jobs (windows-latest,macos-latest) ✓ green; bothRun sample tests (public bstackdemo)andRun local tests (BrowserStack Local + python http.server harness)steps exited 0. Windows job 4m13s; macos similar. (BS session URLs not visible from this PR account — the workflow uses org-level CI secrets that point to a separate BrowserStack account; success is inferred from the step exit codes, which would propagate any session failure as a non-zero exit.)Build verification:
dotnet buildclean with[Category]attribute resolving in both fixtures. Cleanup:browserstack.ymlrestored to shipping state (YOUR_USERNAME/YOUR_ACCESS_KEYplaceholders;browserstackLocal: truenow intentional); nobin/,obj/,.config/,.browserstack/, or.bakfiles staged.Test plan
dotnet test --filter "Category=sample-test"runs all 4 platforms in parallel — verified on round-2 commit,02e164650d…dotnet test --filter "Category=sample-local-test"with python http.server harness + default-on Local — verified on round-2 commit,22a853f38f…dotnet test(no filter) fans out to 8 concurrent sessions — verified on round-2 commit at ppp=1,7e77413767…NunitPlaywrightBrowserstack.Tests.BStackDemoCartTest.AddTheFirstItemToCart+…BStackLocalSampleTest.ReachPrivateHostViaBrowserStackLocal) flow to BrowserStack dashboard as session namesuserName/accessKeylines are absentbin/,obj/,log/,.config/,.browserstack/,*.bak) are committeddotnet buildclean on round-2 commit —[Category]attribute resolves at compile timeCategory=…) incadbcfa— both job steps run without an in-workflowsedtoggleworkflow_dispatchpost-merge — verified, run #26153748026 (both windows-latest + macos-latest matrix jobs green)nunit-playwright:sample-master:v1.0(please confirm with the ASI team if a different version/prefix is preferred)🤖 Generated with Claude Code