关于 pw-init
pw-init 是一项用于在现有项目中搭建 Playwright 端到端测试框架的技能。它先收集环境与认证需求,再按单 Chromium 浏览器约定生成配置、文件和脚本。
主要功能
- 01引导配置环境与角色
- 02仅使用 Chromium 的 Playwright 配置
- 03按角色划分项目与认证状态
- 04按环境加载 dotenv 文件
- 05生成冒烟测试与测试脚本
适用场景
- 01在项目中启用端到端测试
- 02配置多环境测试
- 03添加认证及访客测试角色
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bondar-artem/ playwright-scripting-skills --skill pw-init安装后在 Claude Code 中输入/pw-init确认已加载。
详细介绍
从头开始在当前项目中初始化 Playwright E2E 框架。请按顺序执行以下步骤。
即使有人要求自主完成,也绝不能跳过本技能中的 AskUserQuestion 步骤。
必须遵循的约定
生成的框架遵循以下结构:
tests/
auth.setup.ts # Auth state persistence (only if roles requested)
<role>/ # One subfolder per auth role (e.g. guest, admin)
smoke.spec.ts # Generated sample smoke test
playwright-utils/
.auth/ # storageState files — gitignored
fixtures/
index.ts # Extended test + expect re-export (skeleton)
helpers/ # Stateless utilities
pages/ # Page objects (empty — created on demand)
types/
env.d.ts # process.env typing
.env.test.<env> # Per-environment vars — gitignored
playwright.config.ts # Single Chromium browser, one project per role
主要约定:
- 单一浏览器(Desktop Chrome)。不配置 Firefox/WebKit 项目。
- 环境文件命名为
.env.test.<env>(例如.env.test.local、.env.test.qa),通过dotenv根据TEST_ENV加载。默认值为local。 - 在
playwright.config.ts中按角色配置项目,每个项目都有自己的testDir: ./tests/<role>;对于已认证角色,还需配置storageState和dependencies: ['auth-setup']。 - 存储状态位于
playwright-utils/.auth/<role>.json(不是playwright/.auth/)。
1. 收集需求
使用 AskUserQuestion 和自由对话收集输入。按以下顺序提问:
1.1 环境
使用 AskUserQuestion,让问题在视觉上突出显示;但多数情况下,答案会通过“Other”以自由文本形式给出。按以下方式配置问题:
- header:
Environments - question:
How many test environments do you need, and what should they be called? Provide a baseURL for each. Example: local: http://localhost:3000, qa: https://qa.example.com - multiSelect:
false - options(预设涵盖常见情况;系统会自动附加“Other”,供用户输入自定义列表):
Just local—Single env, BASE_URL=http://localhost:3000local + qa—Two envs; I'll ask for the qa baseURL nextlocal + qa + production—Three envs; I'll ask for qa and production baseURLs next
如果用户选择了需要提供其他 baseURL(qa/production)的预设,请通过普通对话继续询问各个 URL。如果用户选择“Other”,请解析其自由文本列表。
列表中的第一个环境将成为默认环境(未设置 TEST_ENV 时使用)。
1.2 认证角色
使用 AskUserQuestion。按以下方式配置:
- header:
Auth roles - question:
What auth roles do you need? Each authenticated role gets an entry in auth.setup.ts plus its own project with storageState. "guest" is unauthenticated — no setup needed for it. - multiSelect:
false - options(预设涵盖常见情况;系统会自动附加“Other”,供用户输入自定义列表):
guest only—Unauthenticated tests only; skip auth.setup.ts and the auth-setup projectguest + user—One unauthenticated project plus one authenticated roleuser + admin—Two authenticated roles, no guest projectguest + user + admin—One unauthenticated project plus two authenticated roles
如果用户选择“Other”,请解析其自由文本列表。如果最终列表中只有 guest,则跳过生成 auth.setup.ts 和 auth-setup 项目。
1.3 登录流程详情(仅适用于存在已认证角色的情况)
使用 AskUserQuestion。配置:
- header:
Login flow - question:
How should I figure out the login flow for auth.setup.ts? I need: link text to the login page from /, form field labels for email and password, and the URL each role lands on after login. - multiSelect:
false - options:
Explore the source code—I'll search the codebase for the login page, form fields, and post-login URL, then write the setupGenerate placeholders—I'll use generic <LOGIN_LINK_TEXT>/<EMAIL_LABEL>/<PASSWORD_LABEL>/<POST_LOGIN_PATH> placeholders with a // TODO marker; the user fills them in laterI'll provide the details—User types the link text, field labels, and post-login URL via "Other"
如果用户选择 Explore the source code:搜索登录页面(查看 src/app/login、app/login、src/pages/login、名称匹配 Login* 的组件,或由“Log In”/“Sign In”链接引用的路由)。确定电子邮件/密码输入框的标签以及登录后的重定向目标。生成 auth.setup.ts 时使用这些准确值。如果搜索结果不可靠或没有结果,则改用 Generate placeholders 路径。
如果用户选择 Generate placeholders:使用占位值,并在每个 setup 块上方添加一条 // TODO: confirm selectors 注释。
如果用户选择 I'll provide the details(或在“Other”中输入答案):将其输入解析为 (a) 链接文本、(b) 电子邮件标签、(c) 密码标签、(d) 登录后的路径。
此步骤不要阻塞流程——选择一条路径并继续。
1.4 可选附加项
使用 AskUserQuestion 分别询问每项(单独提问,每项两个选项——是/否):
- CI webServer 块 — “Should I include a
webServerconfig inplaywright.config.tsto auto-start your dev server in CI?” 如果回答是,则询问启动命令(例如npm run dev)以及服务监听的 URL。 - 复制 Claude 规则 — “Should I copy
playwright-architecture.mdandplaywright-scripting.mdinto.claude/rules/so future AI work follows the conventions?” 仅回答是/否——不要询问源路径。规范源文件是用户级安装器技能:~/.claude/skills/init-playwright-architecture/SKILL.md和~/.claude/skills/init-playwright-scripting/SKILL.md。规则内容嵌入在和标记之间。如果这些文件不存在,请明确告知用户并跳过——不要编造内容。
2. 运行 Playwright 安装器
使用 create-playwright 标志以非交互方式运行安装器。这样会跳过向导提示,使整个步骤能够自动运行:
npm init playwright@latest -- --quiet --browser=chromium --install-deps
标志:
--quiet— 跳过向导,使用默认值--browser=chromium— 仅安装 Chromium(符合单浏览器约定)--install-deps— 自动安装浏览器和系统依赖- TypeScript、
tests/文件夹以及“无 GitHub Actions 工作流”是静默模式的默认值——无需标志
如果安装失败或卡住,请改为让用户在终端中交互式运行命令。
3. 清理默认内容
删除安装器创建的不符合我们约定的文件:
rm -r tests-examples 2>/dev/null
rm tests/example.spec.ts 2>/dev/null
4. 安装支持性依赖
让用户运行:
npm install -D dotenv
5. 生成 playwright.config.ts
覆盖默认配置。使用收集到的环境和角色。模板:
import { defineConfig, devices } from '@playwright/test'
import dotenv from 'dotenv'
const testEnv = process.env.TEST_ENV ?? '<DEFAULT_ENV>'
process.env.TEST_ENV = testEnv
dotenv.config({ path: `.env.test.${testEnv}`, quiet: true })
const isCI = !!process.env.CI
export default defineConfig({
testDir: './tests',
fullyParallel: false,
retries: isCI ? 2 : 0,
workers: isCI ? 1 : undefined,
reporter: isCI ? [['html', { open: 'never' }], ['github']] : [['html', { open: 'never' }]],
timeout: 60000,
expect: { timeout: 10000 },
use: {
baseURL: process.env.BASE_URL,
trace: 'on-first-retry'
},
projects: [
// Include only if any authenticated roles exist:
{
name: 'auth-setup',
testMatch: 'auth.setup.ts',
use: { ...devices['Desktop Chrome'] },
},
// Per-role projects — one entry per role.
// Unauthenticated roles (e.g. guest) omit storageState + dependencies:
{
name: '<role>',
testDir: './tests/<role>',
use: {
...devices['Desktop Chrome'],
storageState: 'playwright-utils/.auth/<role>.json', // omit for guest
},
dependencies: ['auth-setup'], // omit for guest
},
],
// Include only if user opted into webServer block:
// webServer: {
// command: '<USER_DEV_COMMAND>',
// url: '<USER_DEV_URL>',
// reuseExistingServer: !process.env.CI,
// timeout: 120_000,
// },
})
将 <DEFAULT_ENV> 替换为用户列出的第一个环境名称。为每个角色生成一个项目条目。
6. 更新 .gitignore
追加以下内容(如果文件不存在则创建):
# Playwright
playwright-utils/.auth/
test-results/
playwright-report/
playwright/.cache/
# Local env files (keep .env.test.example committed)
.env
.env.local
.env.test.*
!.env.test.example
7. 创建目录结构
mkdir -p playwright-utils/{fixtures,helpers,pages,types,.auth}
mkdir -p tests/<role> # one per role from step 1.2
8. 生成 tests/auth.setup.ts
如果没有需要身份验证的角色,则跳过。否则,根据步骤 1.3 中的登录流程详情,为每个需要身份验证的角色生成一个 setup(...) 代码块:
import { test as setup } from '@playwright/test'
const <role>File = 'playwright-utils/.auth/<role>.json'
setup('authenticate as <role>', async ({ page }) => {
await page.goto('/')
await page.getByRole('link', { name: '<LOGIN_LINK_TEXT>' }).click()
await page.getByRole('textbox', { name: '<EMAIL_LABEL>' }).fill(process.env.<ROLE>_EMAIL!)
await page.getByLabel('<PASSWORD_LABEL>').fill(process.env.<ROLE>_PASSWORD!)
await page.getByRole('button', { name: 'Login', exact: true }).click()
await page.waitForURL('**<POST_LOGIN_PATH>')
await page.context().storageState({ path: <role>File })
})
如果用户只提供了部分详情,则保留合理的占位内容,并在每个 setup 代码块上方添加一行 // TODO: confirm selectors 注释——用户运行时会完善选择器。(允许的注释:标记需要用户执行操作,不是旁白。)
9. 生成 playwright-utils/types/env.d.ts
export {}
declare global {
namespace NodeJS {
interface ProcessEnv {
TEST_ENV?: '<env1>' | '<env2>' | ...
BASE_URL?: string
CI?: string
// One pair per authenticated role:
<ROLE>_EMAIL?: string
<ROLE>_PASSWORD?: string
}
}
}
将 namespace NodeJS 声明包裹在 declare global { ... } 中。由于存在 export {},此文件是一个模块——在模块内部扩展全局 NodeJS.ProcessEnv 接口需要使用 declare global,否则 TypeScript 会将其视为局部声明,导致 process.env.<ROLE>_EMAIL 没有类型。
确认 tsconfig.json 包含此文件。Playwright 默认生成的 tsconfig.json 会匹配 **/*.ts,因此会自动包含该文件。
10. 生成 playwright-utils/fixtures/index.ts
用于重新导出扩展版 test 的骨架 — 以便将来接入页面对象:
import { test as base, expect } from '@playwright/test'
type Fixtures = {
// Add fixtures here as page objects and helpers are built.
}
export const test = base.extend<Fixtures>({})
export { expect }
11. 生成示例冒烟测试
为每个角色创建 tests/<role>/smoke.spec.ts。冒烟测试用于验证框架已正确配置——填写环境变量后,在全新安装中即可通过。
访客冒烟测试模板:
import { test, expect } from '@playwright/test'
test.describe('Guest smoke', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/')
})
test('Home page loads', async ({ page }) => {
await expect(page).toHaveURL('/')
})
})
需要身份验证的角色冒烟测试模板:
import { test, expect } from '@playwright/test'
test.describe('<Role> smoke', () => {
test('Authenticated session is active', async ({ page }) => {
await page.goto('/')
// TODO: replace with a real authenticated-only assertion
// (e.g. expect(page.getByRole('button', { name: '<user menu>' })).toBeVisible())
})
})
12. 更新 package.json 脚本
添加以下脚本(与现有 scripts 合并,不要覆盖):
{
"scripts": {
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui"
}
}
如果用户定义了多个环境,还要为每个环境添加一个别名(默认环境除外):
"test:e2e:<env>": "TEST_ENV=<env> playwright test"
13. 复制 Claude 规则(仅当用户选择加入时)
如果用户在步骤 1.4 中选择加入,则从用户级安装器技能中提取规则内容,并将其写入新项目的 .claude/rules/ 目录。不要询问用户路径——源文件位置固定。
对于每条规则(architecture 和 scripting):
- 来源:
~/.claude/skills/init-playwright-<name>/SKILL.md。如果文件不存在,请明确告知用户并跳过该规则——不要编造内容。 - 提取
和标记之间的内容(不包括标记)。删除开头和结尾的空行。 - 将提取的内容写入当前项目的
.claude/rules/playwright-<name>.md。
mkdir -p .claude/rules
# Architecture rule
awk '/^$/{flag=1; next} /^$/{flag=0} flag' \
~/.claude/skills/init-playwright-architecture/SKILL.md \
> .claude/rules/playwright-architecture.md
# Scripting rule
awk '/^$/{flag=1; next} /^$/{flag=0} flag' \
~/.claude/skills/init-playwright-scripting/SKILL.md \
> .claude/rules/playwright-scripting.md
如果新项目中已存在目标文件,覆盖前请询问用户选择 Overwrite / Skip。
14. 最终摘要和环境文件(最后一个手动步骤)
技能到此结束。不要暂停等待确认,不要验证文件,也不要运行冒烟测试。
为步骤 1.1 中的每个环境打印一个代码块(加入 gitignore),再为 .env.test.example 打印一个代码块(提交)。每个代码块都包含 BASE_URL=<env baseURL>,以及步骤 1.2 中每个需要身份验证的角色对应的一对空白 <ROLE>_EMAIL / <ROLE>_PASSWORD。.env.test.example 代码块使用第一个环境的 BASE_URL 作为占位值。
将代码块中的环境名和角色名替换为用户提供的实际名称。环境为 local + qa、角色为 user + admin 时的示例:
框架已就绪 — 最后一步,请创建以下环境文件。
.env.test.local(加入 gitignore):BASE_URL=http://localhost:3000 USER_EMAIL= USER_PASSWORD= ADMIN_EMAIL= ADMIN_PASSWORD=
.env.test.qa(加入 gitignore):BASE_URL=https://qa.example.com USER_EMAIL= USER_PASSWORD= ADMIN_EMAIL= ADMIN_PASSWORD=
.env.test.example(提交):BASE_URL=http://localhost:3000 USER_EMAIL= USER_PASSWORD= ADMIN_EMAIL= ADMIN_PASSWORD=