PlaywrightCI/CD浏览器缓存Skill playwright-ci-caching

本技能详细介绍如何在CI/CD流水线(如GitHub Actions和Azure DevOps)中高效缓存Playwright浏览器二进制文件,以显著减少构建时间。通过提取Playwright版本作为缓存键,实现自动缓存失效,并提供跨操作系统的路径配置、辅助脚本和故障排除指南。适用于需要优化Playwright端到端测试构建性能的开发团队。关键词:Playwright缓存,CI/CD优化,构建加速,GitHub Actions,Azure DevOps,浏览器二进制文件,自动化测试,DevOps工具链。

测试 0 次安装 0 次浏览 更新于 2/26/2026

name: playwright-ci-caching description: 在CI/CD流水线(GitHub Actions、Azure DevOps)中缓存Playwright浏览器二进制文件,避免每次构建时1-2分钟的下载开销。 invocable: false

在CI/CD中缓存Playwright浏览器

何时使用此技能

在以下情况下使用此技能:

  • 为带有Playwright端到端测试的项目设置CI/CD
  • 由于浏览器下载(约400MB,1-2分钟)导致构建时间缓慢
  • 希望在Playwright版本更改时自动使缓存失效
  • 使用GitHub Actions或Azure DevOps流水线

问题描述

默认情况下,每次CI运行都必须下载Playwright浏览器(约400MB)。这会导致:

  • 每次构建增加1-2分钟
  • 浪费带宽
  • 可能因临时网络问题而失败
  • 减慢PR反馈循环

核心模式

  1. 提取Playwright版本:从 Directory.Packages.props(CPM)中提取,用作缓存键
  2. 缓存浏览器二进制文件:使用适合平台的路径
  3. 条件安装:仅在缓存未命中时下载
  4. 自动缓存失效:键包含版本,因此包升级会使缓存失效

按操作系统的缓存路径

操作系统 路径
Linux ~/.cache/ms-playwright
macOS ~/Library/Caches/ms-playwright
Windows %USERPROFILE%\AppData\Local\ms-playwright

GitHub Actions

- name: 获取Playwright版本
  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: 缓存Playwright浏览器
  id: playwright-cache
  uses: actions/cache@v4
  with:
    path: ~/.cache/ms-playwright
    key: ${{ runner.os }}-playwright-${{ env.PlaywrightVersion }}

- name: 安装Playwright浏览器
  if: steps.playwright-cache.outputs.cache-hit != 'true'
  shell: pwsh
  run: ./build/playwright.ps1 install --with-deps

多操作系统GitHub Actions

对于在多个操作系统上运行的工作流:

- name: 缓存Playwright浏览器
  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 }}

Azure DevOps

- task: PowerShell@2
  displayName: '获取Playwright版本'
  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: '缓存Playwright浏览器'
  inputs:
    key: 'playwright | "$(Agent.OS)" | $(PlaywrightVersion)'
    path: '$(HOME)/.cache/ms-playwright'
    cacheHitVar: 'PlaywrightCacheHit'

- task: PowerShell@2
  displayName: '安装Playwright浏览器'
  condition: ne(variables['PlaywrightCacheHit'], 'true')
  inputs:
    filePath: 'build/playwright.ps1'
    arguments: 'install --with-deps'

辅助脚本:playwright.ps1

创建一个 build/playwright.ps1 脚本,用于发现并运行Playwright CLI。这抽象了Playwright CLI的位置,该位置因项目结构而异。

# build/playwright.ps1
# 发现Microsoft.Playwright.dll并运行捆绑的Playwright CLI

param(
    [Parameter(ValueFromRemainingArguments = $true)]
    [string[]]$Arguments
)

# 查找Playwright DLL(在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。请先运行'dotnet build'。"
    exit 1
}

$playwrightDir = $playwrightDll.DirectoryName

# 查找playwright CLI(路径因操作系统和节点版本而异)
$playwrightCmd = Get-ChildItem -Path "$playwrightDir/.playwright/node" -Recurse -Filter "playwright.cmd" -ErrorAction SilentlyContinue |
    Select-Object -First 1

if (-not $playwrightCmd) {
    # 尝试Unix可执行文件
    $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 "在$playwrightDir/.playwright/node中未找到Playwright CLI"
    exit 1
}

Write-Host "使用Playwright CLI: $($playwrightCmd.FullName)"
& $playwrightCmd.FullName @Arguments

用法:

# 安装浏览器
./build/playwright.ps1 install --with-deps

# 安装特定浏览器
./build/playwright.ps1 install chromium

# 显示已安装的浏览器
./build/playwright.ps1 install --dry-run

先决条件

此模式假设:

  1. 中央包管理(CPM) 使用 Directory.Packages.props

    <Project>
      <ItemGroup>
        <PackageVersion Include="Microsoft.Playwright" Version="1.40.0" />
      </ItemGroup>
    </Project>
    
  2. 项目已构建:在运行 playwright.ps1 之前(以便DLL存在)

  3. PowerShell可用:在CI代理上(GitHub Actions和Azure DevOps上预安装)

为什么基于版本的缓存键很重要

在缓存键中使用Playwright版本可确保:

  • 自动失效:当您升级Playwright时
  • 没有过时的浏览器二进制文件:与SDK版本不匹配
  • 无需手动清除缓存:版本升级后

如果您硬编码缓存键(例如 playwright-browsers-v1),则每次升级Playwright时都需要手动更新它,否则会出现难以理解的版本不匹配错误。

故障排除

缓存未被使用

  1. 验证版本提取步骤是否输出了正确的版本
  2. 检查缓存路径是否与您的操作系统匹配
  3. 确保 Directory.Packages.props 存在并包含Playwright包

缓存命中后出现“未找到浏览器”

缓存的浏览器与Playwright SDK版本不匹配。这发生在以下情况:

  • 缓存键不包含版本
  • 版本提取静默失败

修复:确保Playwright版本在缓存键中。

playwright.ps1 找不到DLL

在运行脚本之前运行 dotnet builddotnet restore。Playwright DLL仅在NuGet还原后存在。

参考

此模式已在生产项目中经过实战测试:

相关技能

  • dotnet-skills:playwright-blazor - 为Blazor应用程序编写Playwright测试
  • dotnet-skills:project-structure - 中央包管理设置