mcpField
E
e2e-test-conventions

e2e-test-conventions

github.com/agentmantis测试与质量12124 次安装29 周前更新
代码仓库

关于 e2e-test-conventions

面向编写、修改或审查浏览器端 E2E 测试的 Playwright 与 TypeScript 规范技能,覆盖目录组织、测试隔离、认证、导航、选择器及环境配置。

主要功能

  1. 01Playwright 与 TypeScript 规范
  2. 02浏览器与测试套件组织
  3. 03独立且适合并行的测试
  4. 04Page Object Model 复用指南
  5. 05选择器与导航规则
  6. 06环境及测试数据管理

适用场景

  1. 01统一 E2E 测试规范
  2. 02审查测试结构与可靠性
  3. 03编写可并行的独立测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/agentmantis/test-skills --skill e2e-test-conventions

安装后在 Claude Code 中输入/e2e-test-conventions确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
auth-setup.md
folder-structure.md
selector-priority.md

详细介绍

E2E 测试约定

这些约定适用于所有 Playwright E2E 测试代码。在生成、修改或审查测试时,请阅读并遵循这些约定。


技术栈

  • Playwright 用于浏览器自动化和运行测试
  • TypeScript 用于所有测试代码(不使用纯 JavaScript)
  • 与框架无关——根据项目使用的 UI 框架调整选择器和辅助工具

项目结构

e2e/ 目录采用以下布局:

e2e/
├── auth/                    # Authentication setup (runs before all tests)
│   └── auth.setup.ts        # Logs in and saves session state
├── fixtures/                # Custom Playwright fixtures
│   └── base.ts              # Extends Playwright's test with custom fixtures
├── helpers/                 # Shared utility functions (NOT page objects)
│   └── env-config.ts        # Environment resolution
├── poms/                    # Page Object Models (one file per page)
│   └── base.page.ts         # Abstract base class — all POMs extend this
├── test-data/               # External test data (JSON files)
├── tests/                   # Test specs organised by suite
│   ├── handover/            # Ticket-driven handover tests (temporary)
│   ├── regression/          # Full regression tests (permanent)
│   └── smoke/               # Quick critical-path checks
├── playwright.config.ts
├── tsconfig.json
└── .env.example             # Template for environment variables

规则:

  • 不得在此结构之外创建文件
  • 未经明确许可,不得移动现有文件

各目录的详细信息请参阅 references/folder-structure.md。


浏览器 × 测试套件配置

Playwright 配置使用 {browser}:{suite} 命名项目:

浏览器: chromium、firefox、webkit、mobile-chrome、mobile-safari

测试套件:

测试套件目录用途生命周期
regressiontests/regression/完整回归测试永久
handovertests/handover/由工单驱动的交接测试临时——升级或删除
smoketests/smoke/关键路径健全性检查永久

每个项目都依赖负责处理身份验证的 setup 项目。

运行测试
# From e2e/ directory
npx playwright test                                    # All browsers × all suites
npx playwright test --project="chromium:regression"    # Single project
npx playwright test --project="*:smoke"                # One suite, all browsers
npx playwright test --project="firefox:*"              # One browser, all suites

命名约定

类型模式示例
页面对象模型poms/ 中的 {feature}.page.tsdashboard.page.ts
回归测试规格文件tests/regression/ 中的 {feature}.spec.tsdashboard.spec.ts
Smoke 测试规格文件tests/smoke/ 中的 {feature}.spec.tsdashboard.spec.ts
交接测试规格文件tests/handover/ 中的 {TICKET}-{description}.spec.tsPROJ-123-bulk-delete.spec.ts
测试数据test-data/ 中的 {feature}.jsondashboard.json

POM、规格文件和测试数据文件中的 {feature} 名称必须一致。


测试独立性与并行运行

每项测试都必须完全独立
  • 每项测试都在隔离环境中运行,且顺序不限
  • 测试绝不能依赖之前测试创建的状态
  • 每项测试都通过 POM 的导航方法进入其页面
并行安全性

所有测试都会在多个工作进程中并行运行。为避免冲突:

  • 为所有测试数据值添加唯一后缀(时间戳 + 随机 ID)
  • 切勿在测试之间共享可变状态
  • 每项测试都创建自己的数据、验证数据并进行清理

身份验证

身份验证在 setup 项目(auth/auth.setup.ts)中执行一次,该项目会在所有测试项目之前运行。会话状态会保存到文件中,并通过 Playwright 的 storageState 配置复用。

切勿在规格文件、POM、beforeEach 或 beforeAll 中编写登录逻辑。身份验证已由其他流程处理。

如果应用程序将身份验证令牌存储在 IndexedDB 中(例如 Firebase Auth、Supabase、AWS Amplify 等),请使用 indexedDB 选项:

await page.context().storageState({ path: authFile, indexedDB: true });

完整模式请参阅 references/auth-setup.md。


导航

  • 始终使用 URL 直接导航(page.goto('/dashboard'))
  • 不要通过菜单或侧边栏点击导航——菜单状态和动画会导致测试不稳定
  • 导航后,断言 URL 正确,并且关键标题或元素可见

BasePage 与派生 POM 方法

BasePage 是存放适用于多个页面的可复用辅助方法的唯一位置。派生 POM 应仅关注特定页面的行为。

方法适合放在 BasePage 中的情况

满足以下条件时,将辅助方法移至 BasePage:

  • 可在多个 POM 之间复用——例如,关闭模态框、等待 Toast 通知或检查加载指示器
  • 与单个页面没有紧密耦合——无论当前处于哪个页面,工作方式都相同
  • 足够通用,可以被干净地继承——不依赖特定页面的选择器或假设
  • 如果留在功能专属的 POM 中,很可能会重复编写

BasePage 辅助方法示例:

  • waitForToast(message) — 等待并验证 Toast 通知
  • dismissModal() — 关闭任何已打开的模态对话框
  • waitForLoadingComplete() — 等待加载指示器消失
  • getTableRowCount() — 统计多个页面中都存在的数据表的行数
方法适合放在派生 POM 中的情况

满足以下条件时,将辅助方法保留在特定 POM 中:

  • 仅用于一个页面——例如,填写特定页面的表单
  • 依赖特定页面的结构——使用仅在该页面上存在的选择器
  • 预计不会在其他地方复用
这样做的重要性
  • 减少重复——共享逻辑集中在一处,而不是复制到多个 POM 中
  • 集中管理共享行为——更新通用辅助方法后,会自动应用于所有 POM
  • 让派生 POM 保持精简、专注——每个 POM 只包含该页面特有的内容
  • 提升可发现性——开发者知道可以在 BasePage 中查找共享工具
规则

如果发现自己要在第二个 POM 中编写相同的辅助方法,立即将其提升到 BasePage 中。不要让重复的辅助方法散落在各个功能 POM 中。


选择器和定位策略

按以下优先级顺序使用:

  1. getByRole() — 按钮、标题、对话框(最可靠)
  2. getByLabel() — 表单字段
  3. getByText() — 可见文本内容
  4. getByPlaceholder() — 输入框占位文本
  5. locator() 配合 CSS / filter() — 最后手段

提示:

  • 动态渲染的属性(工具提示、弹出层)在查询时可能尚未出现在 DOM 中——使用 filter() 匹配子内容
  • 图标按钮通常没有可见文本——按 aria-label 或子图标内容匹配
  • 优先使用基于角色和标签的选择器,而不是 CSS 类(这类选择器脆弱且依赖特定框架)

示例请参阅 references/selector-priority.md。


环境配置

每个环境在 e2e/ 目录中都有自己的 .env.{env} 文件:

文件环境
.env.local本地开发
.env.dev开发服务器
.env.test测试服务器
.env.uatUAT 服务器
.env.production生产环境

所有文件使用相同的变量名——只有值不同:

BASE_URL="https://your-app.example.com"
LOGIN_EMAIL="[email protected]"
LOGIN_PASSWORD="your-password"
AUTH_FILE="e2e/.auth/user.json"
选择当前环境

必须设置 TEST_ENV。如果未设置,env-config.ts 会立即抛出错误——测试运行不会启动。这样可以防止有人忘记设置变量时,意外对生产环境运行 E2E 测试。

TEST_ENV=dev npx playwright test          # loads .env then .env.dev
TEST_ENV=production npx playwright test    # loads .env then .env.production
npx playwright test                        # ❌ ERROR — TEST_ENV is not set
两层加载

helpers/env-config.ts 读取 TEST_ENV,并通过 dotenv 分两层加载环境变量:

  1. e2e/.env — 基础文件(可包含 TEST_ENV 和所有变量)
  2. e2e/.env.{env} — 可选的环境专属覆盖文件

两个文件都是可选的。 如果两个文件都不存在,进程将使用环境中已有的变量(例如由 CI 或容器注入的变量)。dotenv 不会覆盖已设置的变量,因此命令行导出和 CI 注入的值始终优先。

该模块导出辅助函数——getEnvConfig()、getBaseUrl()、getCredentials() 和 getAuthFilePath()——而非静态常量。每个进程只会加载一次;后续调用不执行任何操作。

规则
  • 必须设置 TEST_ENV — 缺少该变量时会抛出错误,确保 E2E 测试不会在不知情的情况下指向生产环境
  • 所有变量(BASE_URL、LOGIN_EMAIL、LOGIN_PASSWORD、AUTH_FILE)均为必填项 — 缺少任何变量都会抛出错误
  • 绝不要为必填环境变量使用硬编码的默认值;如果缺少变量,请抛出错误
  • .env.* 文件包含密钥,已被 Git 忽略
  • .env.example 是唯一提交的环境变量文件,用作模板

测试数据

  • 所有测试数据都存放在 e2e/test-data/{feature}.json
  • 绝不要在 spec 或 POM 文件中硬编码数据
  • 使用自定义 fixture 加载测试数据,并为其添加唯一后缀
  • 始终从自定义 fixture 导入 test,不要从 @playwright/test 导入

Spec 文件规则

  • 所有页面交互都必须通过 POM 进行 — 绝不要在 spec 中直接调用 page.getByRole()、page.locator() 等
  • 在 spec 中,允许使用 page 的情况仅有:将其传递给 POM 构造函数,或在 beforeAll 中创建 context
  • 使用 test.beforeAll 和手动创建的浏览器 context 调用 POM 的 setUp() 进行清理
  • 每个测试都通过 POM 导航方法独立导航

评论

支持 Markdown