Page Object 提取
当同一段流程出现在多个 spec 里时,只要这段流程的 UI 有变化,你就得逐个修改每个 spec。Hover 会把重复的流程抽取成一个共享的 Page Object,让这类改动变成改一个文件就搞定。
它生成什么
一个位于 pages/<Name>.ts 的 Page Object,外加一个 fixtures.ts 入口。各 spec 不再把步骤内联重复,而是使用这个 fixture 并调用对应方法:
import { test, expect } from './fixtures';
test('checkout after adding to cart', async ({ cartPage, page }) => {
await cartPage.addItemAndCheckout('Blue Widget', 2);
await expect(page.getByRole('heading', { name: /order confirmed/i })).toBeVisible();
});
__vibe_tests__/
├── pages/CartPage.ts # 被抽取出来的 Page Object
├── fixtures.ts # 以 fixture 形式暴露它
└── checkout.spec.ts # 使用 await cartPage.x() + 从 './fixtures' 导入
流程中会变化的数据值(商品名、数量)会变成方法参数。
什么时候触发
在 test_app 的 Phase 5,crystallize 完成之后,Hover 会用 detect_shared_flows 扫描你的 spec。如果某个非登录流程在多个 spec 中重复出现,agent 会征询你的意见是否要抽取。你同意后,extract_page_objects 会生成 Page Object 并把这些 spec 折叠到它上面。整个抽取过程是确定性的——没有 LLM 参与写代码。
登录被有意排除:它已经由 auth-as-fixture 处理,本来就不会在每个测试里重跑——参见 登录与凭据。
诚实地说说适用范围
它的价值随测试套件规模而放大。如果套件很小、各流程互不相同,那么正确的结果就是没什么可抽取的——根本没有共享的非登录流程可以复用。真正见效的是大型套件:多个 spec 在做各自的事情之前,都要先走一遍相同的非登录入口流程。
依然是纯 Playwright
Page Object 和 fixture 都是 Playwright 自带的原语。折叠后的 spec 在 CI 里用 npx playwright test 运行,回路中没有 agent,也没有 Hover 运行时。