Playwright 测试配置(use)完全指南:Emulation、Network 与 Recording 选项的深度解析
导读
本文以 Playwright 测试运行器的核心配置块 use 为切入点,系统梳理如何在 playwright.config.ts 中统一声明浏览器上下文(BrowserContext)的仿真、网络与录制行为,并逐层讲解 baseURL、设备仿真、代理、TLS、trace/video 录制模式、显式上下文创建以及全局/项目/测试三级作用域的继承与覆盖机制。阅读完成后,你将掌握在单个文件中声明、按 project 细分、按 test.use() 精准覆盖的完整配置技巧,并能理解这些选项在 Playwright 源码中是如何被解析为浏览器上下文参数的。
use 配置块的本质:一组内建 fixture 选项
在 @playwright/test 的入口实现中,use 中的每一项配置都被实现为一个带 option: true 标记的 fixture。例如:
browserName在 packages/playwright/src/index.ts 中定义,默认读取defaultBrowserType即'chromium';viewport默认值为{ width: 1280, height: 720 };colorScheme默认'light'、locale默认'en-US';headless默认取launchOptions.headless ?? true,即默认无头运行。
因此,你写在 use: {} 里的每一项,本质上都是为这些 fixture 赋初值,再由运行器在你每个测试运行时装配到 browser、context、page 这些内建 fixture 之中。理解这一点,就能理解为什么“有的选项作用于浏览器实例、有的作用于上下文”,以及为什么它们可以按作用域层层覆盖。
基础选项:baseURL 与 storageState
最常见的两个顶层选项是页面导航基准地址与登录态注入:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Base URL to use in actions like `await page.goto('/')`.
baseURL: 'http://localhost:3000',
// Populates context with given storage state.
storageState: 'state.json',
},
});
| Option | Description |
|---|---|
baseURL |
配置上下文中所有页面使用的基准 URL,允许仅凭路径完成导航,例如 page.goto('/settings')。 |
storageState |
用给定的存储状态填充上下文,是快速实现登录态复用(authentication)的关键手段。 |
补充细节:
baseURL也接受环境变量PLAYWRIGHT_TEST_BASE_URL的注入(见 packages/playwright/src/index.ts),这一特性对 CI 中切换不同测试环境非常实用。storageState参数既可以传相对配置文件所在目录的文件路径,也可以直接传包含cookies、origins的对象字面量。- 关于基于 storageState 的完整登录态方案,可阅读 认证指南。
Emulation Options:从设备到时区的全链路仿真
Playwright 允许你仿真真实的移动端或平板设备,也可以针对所有测试或单个测试仿真 geolocation、locale、timezone,并通过 permissions 授予通知等权限、通过 colorScheme 切换配色主题。项目级设备矩阵可参考 test projects 指南 与 Emulation 指南。
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Emulates `'prefers-colors-scheme'` media feature.
colorScheme: 'dark',
// Context geolocation.
geolocation: { longitude: 12.492507, latitude: 41.889938 },
// Emulates the user locale.
locale: 'en-GB',
// Grants specified permissions to the browser context.
permissions: ['geolocation'],
// Emulates the user timezone.
timezoneId: 'Europe/Paris',
// Viewport used for all pages in the context.
viewport: { width: 1280, height: 720 },
},
});
| Option | Description |
|---|---|
colorScheme |
仿真 prefers-colors-scheme 媒体特性,支持 'light' 与 'dark',默认 'light'。 |
geolocation |
设置上下文的地理位置。 |
locale |
仿真的用户语言,例如 en-GB、de-DE 等,默认 'en-US'。 |
permissions |
授予上下文所有页面的一组权限。 |
timezoneId |
改变上下文的时区。 |
viewport |
上下文所有页面使用的视口尺寸,默认 { width: 1280, height: 720 }。 |
从源码看,这些配置最终会被逐一搬入 BrowserContextOptions:在 packages/playwright/src/index.ts 的 _combinedContextOptions fixture 中,colorScheme、geolocation、locale、timezoneId、viewport 等字段会被非空判断后写入上下文参数对象;随后在 runBeforeCreateBrowserContext 钩子里,只有在用户显式传入的参数不包含该 key 时,测试选项才会被合并进去——这保证了运行时显式传入的上下文选项优先于 use 中的声明。
值得注意的补充选项:
deviceScaleFactor(DPR,默认1)、hasTouch、isMobile、userAgent、serviceWorkers、reducedMotion、contrast、forcedColors同样可以放进use;这些上下文级选项在 packages/playwright/src/index.ts 中都有对应的默认值兜底。permissions常见取值包括'geolocation'、'notifications'、'camera'、'microphone'等浏览器权限名,配置后上下文中所有页面默认已获得授权。
Network Options:下载、请求头、认证、TLS 与代理
可用网络配置如下:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Whether to automatically download all the attachments.
acceptDownloads: false,
// An object containing additional HTTP headers to be sent with every request.
extraHTTPHeaders: {
'X-My-Header': 'value',
},
// Credentials for HTTP authentication.
httpCredentials: {
username: 'user',
password: 'pass',
},
// Whether to ignore HTTPS errors during navigation.
ignoreHTTPSErrors: true,
// Whether to emulate network being offline.
offline: true,
// Proxy settings used for all pages in the test.
proxy: {
server: 'http://myproxy.com:3128',
bypass: 'localhost',
},
},
});
| Option | Description |
|---|---|
acceptDownloads |
是否自动接受下载,默认 true。下载相关细节见 downloads 指南。 |
extraHTTPHeaders |
随每次请求发送的附加 HTTP 头对象,所有头值必须是字符串。 |
httpCredentials |
HTTP 认证凭据。 |
ignoreHTTPSErrors |
导航过程中是否忽略 HTTPS 错误,默认 false。 |
offline |
是否仿真网络离线,默认 false。 |
proxy |
测试中所有页面使用的代理设置。 |
补充说明:
acceptDownloads、extraHTTPHeaders、httpCredentials、ignoreHTTPSErrors、offline、proxy等选项在 packages/playwright/src/index.ts 中同样声明了各自的默认值(如acceptDownloads ?? true、offline ?? false),说明它们是“面向测试运行器的封装”,最终都会流入BrowserContextOptions。proxy中server为必填项,bypass是可选的分号分隔的主机列表,表示这些地址不走代理;配置为'*'表示全部绕过。- 除代理、认证外,Playwright 还支持
clientCertificates:为特定origin提供 TLS 客户端证书(certPath/keyPath、或pfxPath,可选passphrase),见 packages/playwright/types/test.d.ts。证书相关路径会以配置文件所在目录为基准做解析。
注:模拟网络请求时你其实无需做任何配置。只要为浏览器上下文注册自定义
Route即可完成对网络的 mock。完整的 mock 方案见 network mocking 指南。
Recording Options:截图、Trace 与视频
Playwright 可以自动捕获截图、录制视频以及生成 trace。默认三者均关闭,可通过在配置文件中设置 screenshot、video、trace 选项开启。trace、截图和视频文件都会输出到测试输出目录(通常是 test-results)。
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Capture screenshot after each test failure.
screenshot: 'only-on-failure',
// Record trace only when retrying a test for the first time.
trace: 'on-first-retry',
// Record video only when retrying a test for the first time.
video: 'on-first-retry'
},
});
| Option | Description |
|---|---|
screenshot |
捕获测试的截图,可选 'off'、'on'、'only-on-failure'。 |
trace |
Playwright 在测试运行期间产生 trace,之后可通过 Trace Viewer 回放详细的执行信息。可选 'off'、'on'、'retain-on-failure'、'on-first-retry' 等模式(完整列表见下文)。 |
video |
为测试录制视频,模式集合与 trace 一致。 |
Trace 模式速查
trace 选项支持多种模式,其差异体现在哪些运行会被录制以及测试结束后哪些录制结果会被保留。一次测试的首次运行称为 “first run”,由重试引起的后续运行称为 “retries”。
| Mode | Records a trace on | Keeps the trace when |
|---|---|---|
'off' |
never | — |
'on' |
every run | always |
'retain-on-failure' |
every run | that run failed |
'retain-on-first-failure' |
first run only | the first run failed |
'retain-on-failure-and-retries' |
every run | that run failed, or it is a retry |
'on-first-retry' |
first retry only | always |
'on-all-retries' |
every retry | always |
下表展示了在配置 retries: 2 的前提下,几个常见场景分别会保留哪些 trace:
| Mode | Passes on first run | Fails, then passes on retry | Fails on every run |
|---|---|---|---|
'off' |
— | — | — |
'on' |
first run | first run + retry | all three runs |
'retain-on-failure' |
— | first run | all three runs |
'retain-on-first-failure' |
— | first run | first run |
'retain-on-failure-and-retries' |
— | first run + retry | all three runs |
'on-first-retry' |
— | first retry | first retry |
'on-all-retries' |
— | first retry | both retries |
模式名的完整集合可从类型定义 packages/playwright/types/test.d.ts 中确认:'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' | 'retain-on-first-failure' | 'retain-on-failure-and-retries'。在 worker 端 trace 逻辑中可以看到这些模式的实际判定逻辑,例如 'on-first-retry' 要求 testInfo.retry === 1(即只在第一次重试时录制),'retain-on-failure' 在测试失败时保留录制。需要注意:
- 早期版本中的
'retry-with-trace'已标记为废弃,会被归一化为'on-first-retry'(见 packages/playwright/src/worker/testTracing.ts)。 trace还支持对象形态{ mode: 'on', snapshots: true, screenshots: true, sources: true },用于精细化控制是否录制 DOM/ARIA 快照、页面截图与源码映射。
视频模式速查
video 选项支持与 trace 完全相同的一组模式,录制与保留遵循同样的规则。
| Mode | Records a video on | Keeps the video when |
|---|---|---|
'off' |
never | — |
'on' |
every run | always |
'retain-on-failure' |
every run | that run failed |
'retain-on-first-failure' |
first run only | the first run failed |
'retain-on-failure-and-retries' |
every run | that run failed, or it is a retry |
'on-first-retry' |
first retry only | always |
'on-all-retries' |
every retry | always |
同样假设 retries: 2,各场景保留的视频如下:
| Mode | Passes on first run | Fails, then passes on retry | Fails on every run |
|---|---|---|---|
'off' |
— | — | — |
'on' |
first run | first run + retry | all three runs |
'retain-on-failure' |
— | first run | all three runs |
'retain-on-first-failure' |
— | first run | first run |
'retain-on-failure-and-retries' |
— | first run + retry | all three runs |
'on-first-retry' |
— | first retry | first retry |
'on-all-retries' |
— | first retry | both retries |
从实现上看,视频的“是否录制”与“是否保留”被拆成了两个独立函数 shouldCaptureVideo 与 shouldPreserveVideo(见 packages/playwright/src/index.ts):录制决策发生在上下文创建之前(例如 'on-first-retry' 需要 testInfo.retry === 1),而保留决策则发生在测试结束、拿到 testInfo.status 之后。保留的视频会以 test-{status}-{index}.webm 命名并保存到测试输出目录。对象形态的 video: { mode: 'retain-on-failure', size: { width, height } } 允许你进一步指定录制分辨率,'retry-with-video' 同样已被废弃并归一化为 'on-first-retry'。
截图模式与失败时行为
screenshot的类型在 packages/playwright/types/test.d.ts 中定义为'off' | 'on' | 'only-on-failure' | 'on-first-failure',支持on-first-failure(仅首次运行失败时截图)。- 截图同样支持对象形态,例如
screenshot: { mode: 'on', fullPage: true, omitBackground: true },可透传fullPage与omitBackground给page.screenshot()。 - 失败时测试错误上下文(
error-context)也会被收集,便于结合 trace 一起排障,见 ArtifactsRecorder 的实现。
其他选项:超时、浏览器选择与选择器约定
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Maximum time each action such as `click()` can take. Defaults to 0 (no limit).
actionTimeout: 0,
// Name of the browser that runs tests. For example `chromium`, `firefox`, `webkit`.
browserName: 'chromium',
// Toggles bypassing Content-Security-Policy.
bypassCSP: true,
// Channel to use, for example "chrome", "chrome-beta", "msedge", "msedge-beta".
channel: 'chrome',
// Run browser in headless mode.
headless: false,
// Change the default data-testid attribute.
testIdAttribute: 'pw-test-id',
},
});
| Option | Description |
|---|---|
actionTimeout |
每个 Playwright action(如 click())的超时毫秒数,默认 0(无限制)。超时机制的完整讲解见 test timeouts 指南。 |
browserName |
运行测试的浏览器名,默认 'chromium',可选 chromium、firefox 或 webkit。 |
bypassCSP |
是否绕过页面 Content-Security-Policy,当 CSP 包含生产域名、阻碍测试注入时很有用,默认 false。 |
channel |
使用的浏览器渠道(channel),例如 "chrome"、"chrome-beta"、"msedge"、"msedge-beta"。更多浏览器与渠道细节见 browsers 指南。 |
headless |
是否以无头模式运行浏览器(运行时不展示浏览器窗口),默认 true。 |
testIdAttribute |
改变 Playwright 定位器默认使用的 data-testid 属性,默认值即 data-testid。 |
源码补充:
- 传入非法的
browserName会直接抛出Unexpected browserName "xxx"错误,合法的三取值在 packages/playwright/src/index.ts 中校验。 actionTimeout与navigationTimeout会分别在上下文创建阶段被设置到playwright._defaultContextTimeout/_defaultContextNavigationTimeout,作为页面级默认超时(见 packages/playwright/src/index.ts)。testIdAttribute底层调用的是selectors.setTestIdAttribute(testIdAttribute)(见 packages/playwright/src/index.ts),即不仅影响getByTestId(),还同步影响page.locator('data-testid=...')这一类内置引擎。- 与此同级的还有
navigationTimeout、reuseContext、connectOptions、serviceWorkers等运行期选项;defaultBrowserType、screenshot、trace、video、launchOptions属于 worker 级配置,整个 worker 进程内共享。
更多浏览器与上下文选项:launchOptions / contextOptions / connectOptions
任何被 BrowserType.launch 接受的启动选项、被 Browser.newContext 接受的上下文选项、或被 BrowserType.connect 接受的连接选项,都可以分别放入 use 下的 launchOptions、contextOptions 或 connectOptions。
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
launchOptions: {
slowMo: 50,
},
},
});
这里 slowMo: 50 让每个操作之间人为停顿 50ms,适合演示与调试。不过,绝大多数常用项(如 headless、viewport)已经直接暴露在 use 顶层,正如上文的基础选项、仿真选项与网络选项所示,只有在使用非内置的“长尾”参数时才需要借助这三个分组。相应地:
launchOptions默认{}(worker 级);真实启动参数会在 packages/playwright/src/index.ts 中合并headless、channel、tracesDir后传给浏览器进程;connectOptions允许不本地启动浏览器而是连接一个已运行的远程端点,若设置了PLAYWRIGHT_TEST_BASE_URL类似的环境变量或PW_TEST_CONNECT_WS_ENDPOINT,连接信息会自动注入(见 packages/playwright/src/index.ts);contextOptions提供了把任意上下文参数“整体透传”的逃生通道,其内容与_combinedContextOptions展开出的具名字段会做浅合并。
显式创建上下文时的选项继承与优先级
在一个测试或 hook 运行期间,凡是经由测试运行器使用的 Playwright 实例创建的浏览器上下文,都会自动继承 use 段中的上下文选项。这包括:
- 使用内建
browserfixture 调用browser.newContext()创建的上下文; - 通过另行 launch 的浏览器创建的上下文;
- 使用
BrowserType.launchPersistentContext创建的持久化上下文; - 直接 import
playwright-core且解析到同一实例时创建的上下文。
并且,显式传入的上下文选项始终优先于 use 声明。背后的机制是 packages/playwright/src/index.ts 中 runBeforeCreateBrowserContext 的合并逻辑——它只为参数对象里“还没有的 key”补充默认值。
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
userAgent: 'some custom ua',
viewport: { width: 100, height: 100 },
},
});
下面这个测试可以验证 use 选项确实被应用到了新创建的上下文上:
test('should inherit use options on context when using built-in browser fixture', async ({
browser,
}) => {
const context = await browser.newContext();
const page = await context.newPage();
expect(await page.evaluate(() => navigator.userAgent)).toBe('some custom ua');
expect(await page.evaluate(() => window.innerWidth)).toBe(100);
await context.close();
});
Configuration Scopes:全局、项目、文件与单测的覆盖链
Playwright 允许你按全局、按项目、按测试文件、按 describe 块甚至按单个测试来逐级配置。以 locale 为例,可以先在全局 use 中设置默认值:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
locale: 'en-GB'
},
});
然后在某个项目内覆盖为德语(此处还借助了 devices['Desktop Chrome'] 预置的设备描述符):
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
locale: 'de-DE',
},
},
],
});
devices 描述符本质上就是一个展开的选项对象(可对照 deviceDescriptors.ts 查看),因此“合并项目专属仿真”与“展开某个设备定义”可以自然组合。
也可以对整个测试文件覆盖——用 test.use() 传入选项即可。例如让特定文件里的测试以法语运行:
import { test, expect } from '@playwright/test';
test.use({ locale: 'fr-FR' });
test('example', async ({ page }) => {
// ...
});
同样的写法也适用于 describe 块内,让块内测试使用法语:
import { test, expect } from '@playwright/test';
test.describe('french language block', () => {
test.use({ locale: 'fr-FR' });
test('example', async ({ page }) => {
// ...
});
});
优先级关系总结为:单个测试的 test.use() > 文件/describe 内的 test.use() > project 的 use > config 顶层 use。因为 use 选项本质是带作用域的 fixture option,该机制与 fixtures.ts 中实现的 fixture 覆盖链完全一致——内层声明会覆盖外层同名选项。
重置某个选项:回到 config 或彻底置空
如果文件级/describe 级 test.use() 已经把某个选项改掉,你仍可以在更内层把它“重置”回配置文件定义的值。考虑如下 config,它设置了 baseURL:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'https://playwright.dev',
},
});
随后在测试文件中先为整个文件配置新的 baseURL,再在某个 describe 块里退回到 config 定义的值:
import { test } from '@playwright/test';
// Configure baseURL for this file.
test.use({ baseURL: 'https://playwright.dev/docs/intro' });
test('check intro contents', async ({ page }) => {
// This test will use "https://playwright.dev/docs/intro" base url as defined above.
});
test.describe(() => {
// Reset the value to a config-defined one.
test.use({ baseURL: undefined });
test('can navigate to intro from the home page', async ({ page }) => {
// This test will use "https://playwright.dev" base url as defined in the config.
});
});
这里的关键技巧是:test.use({ baseURL: undefined }) 会把该文件级设置移除,从而回退到上一层(config 顶层)的值。如果你希望把值彻底清空为 undefined(即连 config 中的默认值也不使用),则需使用长格式的 fixture 语法:
import { test } from '@playwright/test';
// Completely unset baseURL for this file.
test.use({
baseURL: [async ({}, use) => use(undefined), { scope: 'test' }],
});
test('no base url', async ({ page }) => {
// This test will not have a base url.
});
这段长格式声明覆盖了整个测试文件的 baseURL fixture,使其始终产出 undefined,从而完全绕过 config 中的默认 baseURL。由此可以推导出更通用的规则:凡是形如 option: [async ({}, use) => use(value), { scope: 'test' }] 的长格式写法,都能在文件或 describe 粒度直接接管某个 fixture 选项的默认来源。
典型配置模板:把知识组合进一个真实项目
参考仓库中 examples/github-api 与 examples/todomvc 的写法,一个同时覆盖“仿真 + 网络 + 录制 + 多项目”的 use 段落通常长这样:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
retries: 2,
reporter: [['html', { open: 'never' }]],
use: {
baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
locale: 'en-GB',
timezoneId: 'Europe/Paris',
viewport: { width: 1280, height: 720 },
httpCredentials: { username: 'user', password: 'pass' },
launchOptions: { slowMo: 0 },
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
],
});
- 顶层的
retries: 2与use中的trace: 'on-first-retry'组合,可精确实现“只对第一次重试录 trace”——这与上文 trace 模式表中retries: 2的推演场景一一对应; - 把
baseURL交给环境变量,让 CI 与本地共用同一份配置; - 不同浏览器/设备用
projects表达,配合 docs/src/test-projects.md 可进一步做设备矩阵与并行分片。
小结
use 配置块是 Playwright 测试项目中承上启下的枢纽:向上它承接 config 顶层与 project 的定义,向下它把 BrowserType.launch / Browser.newContext / BrowserType.connect 三套 API 的参数统一收口。从 源码实现 可以看到,它依赖一套带 option: true 的 fixture 体系完成声明式默认值管理,又通过 _combinedContextOptions 与 runBeforeCreateBrowserContext 实现“显式优先、use 兜底”的上下文合并语义;录制类的 trace/video 选项则在 “shouldCapture”(何时录)与 “shouldPreserve”(录了留不留)两阶段分别决策。配合全局 → 项目 → 文件 → describe → 单测的覆盖链与“赋 undefined 回退 / 长格式彻底置空”两种重置手法,你可以在几乎不写额外代码的前提下,把整套浏览器行为声明得清晰、稳定且易于在多个项目与 CI 环境间复用。
延伸阅读
- 项目(projects)与设备矩阵配置
- 浏览器与渠道(channel)选择
- 超时体系与 actionTimeout
- 重试机制对录制模式的影响
- 仿真:设备、地理定位、时区与语言
- 网络:认证、代理与请求拦截
- 下载处理、截图、视频 与 Trace Viewer
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00