From dotnet-skills
Optimize CI/CD pipelines by caching Playwright browser binaries and dependencies to speed up test execution. Use when setting up Playwright in CI/CD pipelines, reducing build times by caching browser binaries, or configuring GitHub Actions or Azure DevOps for Playwright tests.
npx claudepluginhub wshaddix/dotnet-skillsThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Use this skill when:
Playwright browsers (~400MB) must be downloaded on every CI run by default. This:
Directory.Packages.props (CPM) to use as cache key| OS | Path |
|---|---|
| Linux | ~/.cache/ms-playwright |
| macOS | ~/Library/Caches/ms-playwright |
| Windows | %USERPROFILE%\AppData\Local\ms-playwright |
- name: Get Playwright Version
shell: pwsh
run: |
$propsPath = "Directory.Packages.props"
[xml]$props = Get-Content $propsPath
$version = $props.Project.ItemGroup.PackageVersion |
Where-Object { $_.Include -eq "Microsoft.Playwright" } |
Select-Object -ExpandProperty Version
echo "PlaywrightVersion=$version" >> $env:GITHUB_ENV
- name: Cache Playwright Browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}
- name: Install Playwright Browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
shell: pwsh
run: ./build/playwright.ps1 install --with-deps
For workflows that run on multiple operating systems:
- name: Cache Playwright Browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
~/Library/Caches/ms-playwright
~/AppData/Local/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}
- task: PowerShell@2
displayName: 'Get Playwright Version'
inputs:
targetType: 'inline'
script: |
[xml]$props = Get-Content "Directory.Packages.props"
$version = $props.Project.ItemGroup.PackageVersion |
Where-Object { $_.Include -eq "Microsoft.Playwright" } |
Select-Object -ExpandProperty Version
Write-Host "##vso[task.setvariable variable=PlaywrightVersion]$version"
- task: Cache@2
displayName: 'Cache Playwright Browsers'
inputs:
key: 'playwright | "$(Agent.OS)" | $(PlaywrightVersion)'
path: '$(HOME)/.cache/ms-playwright'
cacheHitVar: 'PlaywrightCacheHit'
- task: PowerShell@2
displayName: 'Install Playwright Browsers'
condition: ne(variables['PlaywrightCacheHit'], 'true')
inputs:
filePath: 'build/playwright.ps1'
arguments: 'install --with-deps'
Create a build/playwright.ps1 script that discovers and runs the Playwright CLI. This abstracts away the Playwright CLI location which varies by project structure.
# build/playwright.ps1
# Discovers Microsoft.Playwright.dll and runs the bundled Playwright CLI
param(
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Arguments
)
# Find the Playwright DLL (after dotnet build/restore)
$playwrightDll = Get-ChildItem -Path . -Recurse -Filter "Microsoft.Playwright.dll" -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $playwrightDll) {
Write-Error "Microsoft.Playwright.dll not found. Run 'dotnet build' first."
exit 1
}
$playwrightDir = $playwrightDll.DirectoryName
# Find the playwright CLI (path varies by OS and node version)
$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright.cmd" -ErrorAction SilentlyContinue |
Select-Object -First 1
if (-not $playwrightCmd) {
# Try Unix executable
$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright" -ErrorAction SilentlyContinue |
Where-Object { $_.Name -eq "playwright" } |
Select-Object -First 1
}
if (-not $playwrightCmd) {
Write-Error "Playwright CLI not found in $playwrightDir/.playwright/node"
exit 1
}
Write-Host "Using Playwright CLI: $($playwrightCmd.FullName)"
& $playwrightCmd.FullName @Arguments
Usage:
# Install browsers
./build/playwright.ps1 install --with-deps
# Install specific browser
./build/playwright.ps1 install chromium
# Show installed browsers
./build/playwright.ps1 install --dry-run
This pattern assumes:
Central Package Management (CPM) with Directory.Packages.props:
<Project>
<ItemGroup>
<PackageVersion Include="Microsoft.Playwright" Version="1.40.0" />
</ItemGroup>
</Project>
Project has been built before running playwright.ps1 (so DLLs exist)
PowerShell available on CI agents (pre-installed on GitHub Actions and Azure DevOps)
Using the Playwright version in the cache key ensures:
If you hardcode the cache key (e.g., playwright-browsers-v1), you'll need to manually bump it every time you upgrade Playwright, or you'll get cryptic version mismatch errors.
Directory.Packages.props exists and has the Playwright packageThe cached browsers don't match the Playwright SDK version. This happens when:
Fix: Ensure the Playwright version is in the cache key.
Run dotnet build or dotnet restore before running the script. The Playwright DLL only exists after NuGet restore.
This pattern is battle-tested in production projects:
dotnet-skills:playwright-blazor - Writing Playwright tests for Blazor applicationsdotnet-skills:project-structure - Central Package Management setup