Skip to content

Tamp Playwright

Scott Singleton edited this page May 15, 2026 · 2 revisions

Tamp.Playwright

Wrapper for Playwright 1.x — Microsoft's e2e browser test runner.

using Tamp.Playwright.V1;

Full reference: https://github.com/tamp-build/tamp-playwright.

Verbs

Playwright.Test(tool, s =>)            // the canonical CI verb
Playwright.Install(tool, s =>)         // install browsers
Playwright.InstallDeps(tool, s =>)     // OS-level deps only (Linux)
Playwright.Uninstall(tool, s =>)
Playwright.Codegen(tool, s =>)         // recorder UI
Playwright.ShowReport(tool, s =>)
Playwright.MergeReports(tool, s =>)    // stitch sharded blob reports
Playwright.ClearCache(tool, s =>)
Playwright.Open(tool, s =>)            // Inspector against a URL
Playwright.Raw(tool,)

The Test verb is flag-dense — covers browsers, projects, sharding (SetShard(1, 4)), reporters (repeatable), retries, traces (SetTrace("on-first-retry")), snapshot updates (SetUpdateSnapshots("changed")), UI mode, --forbid-only for CI gates, --pass-with-no-tests, --list, and positional file filters.

CI behaviour to know about

test --list still preflights browsers. Playwright 1.x's --list flag enumerates discovered tests without running them, but project setup still validates browser availability. Result: you can't run playwright test --list in CI without installing browsers first (~300MB per OS). The wrapper's own integration tests work around this by sticking to --help -v-style shape checks; production CI installs the browsers it needs.

Sharding stitches via merge-reports. Sharded runs each write a blob reporter output, and a separate merge-reports job stitches them into a single HTML report. The wrapper covers both.

Quick example — sharded CI run

[NuGetPackage("playwright", UseSystemPath = true)]
readonly Tool PlaywrightTool = null!;

[Parameter("Shard index (1-based)")]
readonly int Shard;

[Parameter("Total shards")]
readonly int TotalShards = 4;

Target InstallBrowsers => _ => _.Executes(() =>
    Playwright.Install(PlaywrightTool, s => s
        .AddBrowser("chromium")
        .SetWithDeps()
        .SetWorkingDirectory(RootDirectory / "frontend")));

Target E2E => _ => _
    .DependsOn(nameof(InstallBrowsers))
    .Executes(() =>
        Playwright.Test(PlaywrightTool, s => s
            .SetForbidOnly()
            .SetShard(Shard, TotalShards)
            .AddReporter("blob")
            .AddReporter("junit")
            .SetTrace("on-first-retry")
            .SetRetries(2)
            .SetWorkers(4)
            .SetWorkingDirectory(RootDirectory / "frontend")));

Target MergeShards => _ => _.Executes(() =>
    Playwright.MergeReports(PlaywrightTool, s => s
        .AddReporter("html")
        .AddReporter("junit")
        .SetReportFolder("blob-reports")
        .SetWorkingDirectory(RootDirectory / "frontend")));

See also

Settings authoring style

The example(s) above use the fluent Set*-chain shape. Every wrapper verb on this page also accepts a new XxxSettings { ... } object-init form. Both produce identical CommandPlans; the fluent shape stays canonical in docs and the tamp init template. See Build Script Authoring → Two authoring styles for the side-by-side comparison.

Clone this wiki locally