README.md
Like this project? View sample code from the last ten years of T.J. Maher's automation development work at TJMaher.com | Programming Projects and his articles about software testing at TJMaher.com | Media. And be sure to check out his LinkedIn Profile!
It's a head-to-head matchup! Cursor AI versus VS Code + GitHub CoPilot (See the Login-C-Sharp repo ) to create automated test frameworks using MS Playwright + C#. Who creates the best tests? The best GitHub Actions Workflow? The best README docs? And can it be created only using prompts?
Let the battle begin!
End-to-end tests for https://the-internet.herokuapp.com/login using Playwright for .NET, C#, and NUnit, with Allure reporting and a GitHub Actions workflow (Test & Report) that can run smoke, regression, or page-specific suites and publish reports to GitHub Pages.
Cursor is an AI-powered code editor and coding agent that lets you describe changes or features in natural language and have the editor plan, edit, and test code for you. It builds on a VS Code–style editing experience but adds deep AI integration: agents that can explore your codebase, modify files, run tests, and iterate until changes are correct.
-
Product evolution & releases
- Cursor grew rapidly throughout 2023, shipping key features like full-codebase context and GPT‑4–powered completions (see the Cursor changelog and blog, e.g. “Our problems” (2023)).
- Cursor 2.0 and the Composer model (their in‑house coding model and multi‑agent interface) were announced on October 29, 2025, described in “Introducing Cursor 2.0 and Composer”.[1]
-
What makes Cursor different
- Agentic coding: you can ask Cursor to implement changes end‑to‑end; it plans steps, edits multiple files, and runs commands.
- Codebase context: Cursor indexes your repository so the agent can reference relevant files and history when answering questions or making edits.
- Multi-agent workflows (Cursor 2.0+): run multiple agents in parallel on different tasks or branches while Cursor manages conflicts.[1]
-
Official documentation
- Main docs: docs.cursor.com[2] (also accessible via
https://cursor.com/docs[2]). - The docs cover:
- Getting started, installation, and quickstart guides.[2]
- Agent modes, planning, review, terminal & browser tools.[2]
- Context (
@mentions, Rules, Skills, Subagents, Semantic Search).[2] - Configuration (shortcuts, themes, ignore files, integrations, parallel agents).[2]
- Main docs: docs.cursor.com[2] (also accessible via
In this repository, Cursor was used as the AI agent to:
- Scaffold the .NET + Playwright test project.
- Design and implement page objects, tests, and configuration.
- Create the GitHub Actions workflow and this README.
-
Prerequisites
- Install .NET SDK 8 or later (this project targets
net8.0):- Download from .NET downloads.
- Ensure PowerShell is available (Windows 11 ships with it by default).
- (Optional) Install Git from git-scm.com.
- Install .NET SDK 8 or later (this project targets
-
Clone & restore
git clone https://github.com/<your-org-or-user>/cursor-creates-playwright-c-sharp.git
cd cursor-creates-playwright-c-sharp
dotnet restore Tests.csproj- Build & install Playwright browsers
dotnet build Tests.csproj
pwsh bin/Release/net8.0/playwright.ps1 install --with-deps- Prerequisites
- Install Homebrew (if not already): see brew.sh.
- Install .NET SDK:
brew install dotnet-sdk- (Optional) Install Git:
brew install git- Clone & restore
git clone https://github.com/<your-org-or-user>/cursor-creates-playwright-c-sharp.git
cd cursor-creates-playwright-c-sharp
dotnet restore Tests.csproj- Build & install Playwright browsers
dotnet build Tests.csproj
pwsh bin/Release/net8.0/playwright.ps1 install --with-depsOn macOS, if
pwshis not installed, install PowerShell via Homebrew (brew install powershell) or usedotnet tool install --global Microsoft.Playwright.CLIand thenplaywright install.
High-level structure from the repository root:
cursor-creates-playwright-c-sharp/
Tests.csproj # .NET test project
e2e/
BaseTest.cs # Base NUnit/PageTest class
Credentials.cs # (Legacy stub) credentials wrapper
LoginPageTests.cs # Login page test suite
SecureAreaTests.cs # Secure area test suite
TestConfig.cs # JSON-backed configuration loader
TestData.cs # (Legacy stub) static test data wrapper
testdata.json # Externalized test data (URL, copy, credentials)
pages/
BasePage.cs # Shared Playwright page base class
LoginPage.cs # Login page object
SecureAreaPage.cs # Secure area page object
.github/
workflows/
playwright-tests.yml # "Test & Report" GitHub Actions workflow
bin/ # Build outputs (generated)
obj/ # MSBuild intermediates (generated)
From the repo root:
- Restore & build
dotnet restore Tests.csproj
dotnet build Tests.csproj- Install Playwright browsers (first time or after browser updates):
pwsh bin/Release/net8.0/playwright.ps1 install --with-deps- Run all tests
dotnet test Tests.csproj- Run only smoke tests
dotnet test Tests.csproj --filter "TestCategory=smoke"- Run only LoginPage or SecureArea tests
dotnet test Tests.csproj --filter "FullyQualifiedName~LoginPageTests"
dotnet test Tests.csproj --filter "FullyQualifiedName~SecureAreaTests"The tests use TestConfig.Current which reads from e2e/testdata.json, so you can change URLs, credentials, and expected UI text without recompiling.
- What it is: A free, open-source, cross-platform developer platform for building apps (web, desktop, mobile, cloud, etc.).
- Key release: .NET Core 1.0 (the first cross‑platform .NET) was released on June 27, 2016, announced on the official .NET Blog: “Announcing .NET Core 1.0”.
- Docs: .NET documentation.
- What it is: A modern, object‑oriented programming language for .NET, designed by Microsoft; widely used for application and test automation development.
- Docs: C# documentation.
- What it is: A unit testing framework for all .NET languages, originally ported from JUnit.
- Key release: NUnit 3.0 (major rewrite) released November 15, 2015; see the NUnit releases and NUnit.org.
- Docs: NUnit documentation.
- What it is: A modern browser automation / E2E testing framework supporting Chromium, Firefox, and WebKit with a unified API, including a .NET binding.
- Key release: Playwright was officially announced on January 31, 2020, as a cross‑browser automation library for modern web apps (InfoQ summary).
- Docs:
- General: playwright.dev
- .NET: Playwright for .NET docs.
- What it is: A framework‑agnostic test reporting tool that turns raw test results into an interactive HTML dashboard with timelines, history, and rich attachments.
- Current line: Allure 2 is the mature, widely used line; for example, Allure 2.36.0 was released on December 10 (see allure2 releases).
- Docs: Allure Report documentation and framework integrations.
- Mature and widely adopted in the .NET ecosystem, with strong tooling support (IDE integration, runners, analyzers).
- Attribute‑driven model (
[Test],[SetUp],[Category("smoke")]) makes tests declarative and easy to organize. - Rich assertion library (e.g.,
Assert.That(..., Is.EqualTo(...)),Does.StartWith(...)), helpful for readable tests. - First‑class support in .NET test tooling via
Microsoft.NET.Test.SdkandNUnit3TestAdapter, making it straightforward to run in CI (including GitHub Actions).
For this project, NUnit provides:
- Simple category‑based filtering for smoke vs regression suites.
- Seamless integration with Playwright for .NET via the
Microsoft.Playwright.NUnitpackage.
Other popular .NET testing frameworks include:
- xUnit.net
- Convention‑based tests and strong focus on best practices.
- Widely used in the .NET open‑source ecosystem.
- Docs: xunit.net.
- MSTest / MSTest v2
- Microsoft’s own test framework.
- Deep integration with Visual Studio and Azure DevOps.
- Docs: MSTest documentation.
- FluentAssertions (assertion library, often used with NUnit/xUnit/MSTest)
- Provides expressive, fluent assertion syntax.
- Docs: FluentAssertions docs.
NUnit was chosen primarily for its familiarity, rich assertions, and very strong integration with existing .NET test runners and tools.
GitHub Actions is GitHub’s built‑in CI/CD platform that runs workflows defined in YAML files inside your repo.
-
Key history
- GitHub Actions CI/CD support was announced in public beta on August 8, 2019:
“GitHub Actions now supports CI/CD”. - GitHub Actions reached general availability on November 13, 2019:
“GitHub Actions is generally available”.
- GitHub Actions CI/CD support was announced in public beta on August 8, 2019:
-
Docs
- Overview: GitHub Actions documentation.
- Workflow syntax: Workflow syntax for GitHub Actions.
- Automatically:
- On pushes or pull requests, if configured under
on: push/on: pull_request.
- On pushes or pull requests, if configured under
- Manually (
workflow_dispatch, which this project uses):- Go to the repo’s Actions tab.
- Select the “Test & Report” workflow.
- Click “Run workflow”, choose the
testSuiteinput (smoke,regression,LoginPage,SecureArea), then start the run.
- Initial framework setup
- User requested: Playwright + C# automation for
https://the-internet.herokuapp.com/login, with:- Tests in
e2e, page objects ine2e/pages, sharedBasePage. - Credentials taken from the site.
- Tests for headings, body text, and invalid login messages.
- Smoke tests tagged
smoke, plus separateLoginPageandSecureAreascenarios.
- Tests in
- User requested: Playwright + C# automation for
- Project restructuring
- User requested moving
e2e,bin,obj, and project file to the repository root and removing the originalE2ETestsfolder.
- User requested moving
- Configuration and test data refactor
- User asked to move strings, credentials, and URLs out of tests and into shared configuration / resource files.
- CI & reporting
- User requested a GitHub Actions workflow (
playwright-tests.yml) and Allure report generation + GitHub Pages publishing.
- User requested a GitHub Actions workflow (
Representative commands Cursor invoked (via automated shell) while constructing the project:
- Project creation and dependencies:
dotnet new nunit -n E2ETests
dotnet add E2ETests/E2ETests.csproj package Microsoft.Playwright.NUnit
dotnet build E2ETests/E2ETests.csproj- Restructuring to root:
dotnet build Tests.csproj
Remove-Item -LiteralPath "d:\src\cursor-creates-playwright-c-sharp\E2ETests" -Recurse -Force- Test runs during development:
dotnet test Tests.csproj
dotnet test Tests.csproj --filter "TestCategory=smoke"Cursor also used file‑system operations (via the IDE’s tools) to add, update, and delete C# files, the JSON config, and the GitHub Actions workflow YAML.
At the workflow level (see .github/workflows/playwright-tests.yml), Cursor:
-
Prepared for Allure results
- Assumed test execution would produce
allure-resultsdirectories (via an Allure adapter added to the test project). - For each browser job (Chromium, Firefox, WebKit), added an “Upload Allure results” step:
- Uses
actions/upload-artifact@v4to upload any**/allure-resultsfolders, named:allure-results-chromiumallure-results-firefoxallure-results-webkit
- Uses
- Assumed test execution would produce
-
Generated the aggregated report
- Added a
reportjob that depends on all browser jobs. - Downloads all Allure artifacts into
./allure-resultswithactions/download-artifact@v4. - Uses
simple-elf/allure-report-action@v1.7to generate a combined HTML report into./allure-report.
- Added a
-
Published to GitHub Pages
- Configures GitHub Pages with
actions/configure-pages@v4. - Uploads
./allure-reportas the Pages artifact usingactions/upload-pages-artifact@v3. - Deploys the artifact via
actions/deploy-pages@v4, publishing the report under the repository’s GitHub Pages URL (e.g.,https://tjmaher.github.io/cursor-creates-playwright-c-sharp/).
- Configures GitHub Pages with
Note: You still need to add an Allure adapter to the NUnit project (e.g., via NuGet) and configure it to output
allure-resultsfor the workflow’s reporting steps to have content.
Commands used inside .github/workflows/playwright-tests.yml:
-
dotnet restore Tests.csproj- Restores NuGet packages for the test project.
- Docs: Restore packages.
-
dotnet build Tests.csproj --configuration Release --no-restore- Builds the test project in Release configuration without restoring packages again.
- Docs: Build command.
-
pwsh bin/Release/net8.0/playwright.ps1 install --with-deps- Runs the Playwright CLI script generated by the .NET SDK to install required browsers and OS dependencies.
- Docs: Playwright CLI.
-
dotnet test Tests.csproj --configuration Release- Runs all tests in Release configuration.
- Docs: Test command.
-
dotnet test ... --filter "<expression>"- Runs only tests matching a filter:
TestCategory=smoke– smoke tests.FullyQualifiedName~LoginPageTests– tests inLoginPageTests.FullyQualifiedName~SecureAreaTests– tests inSecureAreaTests.
- Docs: Filter option.
- Runs only tests matching a filter:
-
Bash conditionals in workflow step:
if [ "$TEST_SUITE" = "smoke" ]; then
FILTER='TestCategory=smoke'
elif [ "$TEST_SUITE" = "LoginPage" ]; then
FILTER='FullyQualifiedName~LoginPageTests'
...
fiUsed to translate the workflow_dispatch input into a dotnet test --filter expression.
The playwright-tests.yml workflow uses these key actions:
-
actions/checkout@v4- Checks out the repository code into the runner.
- Docs: https://github.com/actions/checkout.
-
actions/setup-dotnet@v4- Installs and configures .NET SDK versions on the runner.
- Docs: https://github.com/actions/setup-dotnet.
-
actions/upload-artifact@v4- Uploads build/test artifacts (here,
allure-results-*) for later jobs to use or for download. - Docs: https://github.com/actions/upload-artifact.
- Uploads build/test artifacts (here,
-
actions/download-artifact@v4- Downloads previously uploaded artifacts into the current job (used to aggregate Allure results).
- Docs: https://github.com/actions/download-artifact.
-
simple-elf/allure-report-action@v1.7- Generates an Allure HTML report from collected
allure-resultsfolders. - Marketplace: https://github.com/marketplace/actions/allure-report-action.
- Generates an Allure HTML report from collected
-
actions/configure-pages@v4- Sets up the GitHub Pages deployment environment for the workflow.
- Docs: https://github.com/actions/configure-pages.
-
actions/upload-pages-artifact@v3- Packages the generated site (here, the Allure HTML report in
./allure-report) as an artifact for Pages. - Docs: https://github.com/actions/upload-pages-artifact.
- Packages the generated site (here, the Allure HTML report in
-
actions/deploy-pages@v4- Deploys the uploaded Pages artifact to GitHub Pages.
- Docs: https://github.com/actions/deploy-pages.
Together, these actions create a CI pipeline that:
- Restores and builds the .NET Playwright test project.
- Runs tests across Chromium, Firefox, and WebKit.
- Collects Allure test results.
- Generates and publishes an interactive test report to GitHub Pages.
The obj folder is where MSBuild and the .NET SDK keep intermediate build artifacts. You normally don’t commit it to source control, but it’s helpful to know what lives there:
-
.NETCoreApp,Version=v10.0.AssemblyAttributes.cs- Auto-generated file that adds the
[TargetFramework]attribute to the compiled assembly based onTargetFrameworkinTests.csproj.
- Auto-generated file that adds the
-
Tests.AssemblyInfo.cs/Tests.AssemblyInfoInputs.cache- Generated assembly-level metadata: title, version, configuration, etc.
- The
.cachefile tracks inputs so MSBuild knows when it needs to regenerate.
-
Tests.assets.cacheandproject.assets.json(one level up)- Represent resolved NuGet dependencies and their transitive closure.
- Used by MSBuild to know which assemblies to reference when compiling.
-
Tests.csproj.AssemblyReference.cache/Tests.csproj.CoreCompileInputs.cache- Caches of references and compile-time inputs so incremental builds can skip work if nothing changed.
-
Tests.GeneratedMSBuildEditorConfig.editorconfig- Auto-generated
EditorConfigthat encodes compilation and analyzer settings derived from the project and SDK.
- Auto-generated
-
Tests.GlobalUsings.g.cs- Contains global
usingdirectives generated due toImplicitUsings=enableinTests.csproj, so you don’t have to manually import common namespaces.
- Contains global
-
Tests.dll,Tests.pdb,Tests.genruntimeconfig.cache,Tests.csproj.FileListAbsolute.txt,Tests.csproj.Up2DateTests.dllandTests.pdbare the compiled test assembly and debug symbols for the Debug configuration.genruntimeconfigandUp2Datehelp the build know when a rebuild is necessary.FileListAbsolute.txttracks which files were output by the build.
-
ref/Tests.dllandrefint/Tests.dll- Reference assemblies used for compile-time binding (they contain public API surface only, not full implementation) to support faster and more deterministic builds.
In short, obj/ is MSBuild’s working directory; you almost never touch files here directly, but they explain how the project is compiled and why incremental builds are fast.
Tests.csproj is the project file that tells the .NET SDK how to build and run the test suite:
-
Target and language
TargetFrameworkis set tonet8.0, so the project compiles against .NET 10.LangVersionislatest, enabling the newest C# language features supported by the installed SDK.ImplicitUsingsisenable, so common namespaces are added automatically (and emitted intoTests.GlobalUsings.g.cs).Nullableisenable, turning on nullable reference type analysis for safer APIs.IsPackableisfalse, because this project is intended as a test project, not a NuGet package.
-
Test and tooling packages
Microsoft.NET.Test.Sdk– the test host that integrates withdotnet test.NUnit,NUnit3TestAdapter,NUnit.Analyzers– the NUnit framework, Visual Studio /dotnet testadapter, and static analysis rules.Microsoft.Playwright.NUnit– Playwright’s NUnit integration, providingPageTestand Playwright setup/teardown.coverlet.collector– enables code coverage collection when running tests withdotnet test --collect:"XPlat Code Coverage".
-
Usings and shared references
- A
Usingitem addsNUnit.Frameworkas a global using, so every test file can use NUnit attributes like[Test],[SetUp], and assertions without addingusing NUnit.Framework;to each file.
- A
-
Content copied to output
e2e\testdata.jsonis included asNonewithCopyToOutputDirectory="PreserveNewest", ensuring the JSON config is available besideTests.dllat runtime.TestConfigthen loads this file from the output directory so tests and page objects always read the latest configuration.
Together, Tests.csproj defines what to build and which libraries to use, while obj/ shows how the SDK and MSBuild orchestrate the build under the hood.
Where obj/ holds intermediate build artifacts, the bin/ folder contains the final, runnable outputs for each configuration (Debug / Release) and target framework (net8.0 in this project).
For example, under bin/Debug/net80.0 you’ll find:
-
Tests.dllandTests.pdbTests.dllis the compiled test assembly thatdotnet testexecutes.Tests.pdbcontains debug symbols to enable meaningful stack traces and step-through debugging in your IDE.
-
Tests.runtimeconfig.jsonandTests.deps.jsonTests.runtimeconfig.jsontells the .NET host which runtime to load (e.g.,.NET 10) and any runtime-specific options.Tests.deps.jsondescribes all runtime dependencies (NuGet packages, assembly versions, dependency graph) for your tests and is used by the .NET host to resolve assemblies at run time.
-
Playwright and test framework assemblies
Microsoft.Playwright.dll,Microsoft.Playwright.NUnit.dll,Microsoft.Playwright.TestAdapter.dll– the Playwright engine, NUnit integration, and test adapter used when running tests.nunit.framework.dll,nunit.framework.legacy.dll,NUnit3.TestAdapter.dll,nunit.engine*.dll,testcentric.engine.metadata.dll– NUnit’s core framework and test engine components.Microsoft.NET.Test.Sdk–related assemblies such as:Microsoft.TestPlatform.*.dll,Microsoft.VisualStudio.TestPlatform.*.dll,testhost.dll,testhost.exe– the infrastructure that hosts and runs your tests when you invokedotnet test.
- Supporting libraries like
Microsoft.ApplicationInsights.dll,Microsoft.Bcl.AsyncInterfaces.dll, andNewtonsoft.Json.dll.
-
Localized resource assemblies
- Subfolders like
cs/,de/,fr/,ja/,ko/,zh-Hans/, etc. contain satellite resource assemblies (e.g.,*.resources.dll) for localized messages from the test platform and tooling.
- Subfolders like
-
Playwright support files
-
.playwright/– Playwright-managed assets (browsers, drivers, helper scripts) needed to run tests across Chromium, Firefox, and WebKit. -
playwright.ps1– PowerShell script entry point to the Playwright CLI for this project; used in CI and local setup to install browsers:pwsh bin/Release/net8.0/playwright.ps1 install --with-deps
-
-
Copied configuration / data
e2e/testdata.json– the JSON config copied from thee2e/folder (as configured inTests.csproj), soTestConfigcan read it at runtime from beside the compiled assembly.
In summary:
obj/= “how MSBuild thinks” (intermediate compilation metadata and caches).bin/= “what you actually run” (the compiled test assembly, dependencies, runtime configs, and Playwright tooling used bydotnet testand GitHub Actions).
This file is a PowerShell script generated by the Playwright .NET tooling when you build the project. It acts as the entry point for Playwright CLI commands specific to your test project. The script is used to install the required browsers and OS dependencies for Playwright tests, both locally and in CI environments (such as GitHub Actions).
For example, running:
pwsh bin/Release/net8.0/playwright.ps1 install --with-depsinstalls all supported browsers and any required dependencies, ensuring your Playwright tests can run successfully. This script is automatically created in the appropriate output directory (e.g., bin/Release/net8.0/) when you build the project targeting .NET 8.0.
For more details, see:
- Official .NET output directories documentation: How .NET organizes build outputs (Microsoft Docs)
- Playwright for .NET CLI documentation: Playwright CLI for .NET
- About target frameworks: Target frameworks in .NET (Microsoft Docs)