--- name: architecture description: POM 分层与 context 共享决策树。触发:架构、分层、POM、Page Object、基类设计、新增角色。 --- # 架构决策 — POM 分层与 context 共享模式 ## 适用场景 - 新增角色/端时决定是否引入新基类 - 判断某组用例要不要共享 page / context - 给新成员解释 POM 分层 --- ## POM 分层通用骨架 ``` ┌─────────────────────────────────────────────┐ │ tests/ 测试层 │ │ 按角色拆分文件:test__flow.py │ │ 每个测试类继承 Base(或 Role-Base) │ ├─────────────────────────────────────────────┤ │ pages/ 页面对象层 │ │ Base ← Login ← Landing ← Detail / ... │ │ 通用 Role 用前缀命名:RolePage │ ├─────────────────────────────────────────────┤ │ config/ 配置层 │ │ URL、Token、浏览器参数按环境切换 │ ├─────────────────────────────────────────────┤ │ conftest.py Fixture 层 │ │ browser → context → page → Role-specific base │ └─────────────────────────────────────────────┘ ``` **数据流向**:`config` → `conftest`(读取配置创建 fixture) → `pages`(接收 page 对象) → `tests`(组合页面对象执行断言) --- ## PageObject 骨架 ```python # 页面名称:<中文名> from core.base.base_page import BasePage class (BasePage): # 定位符常量(类顶部) = "" # P<0-5>: 说明 PAGE_IDENTIFIER = "" # 页面加载锚点 # 业务方法(前缀:click_ / fill_ / select_ / get_xxx_text / wait_for_ / is_xxx_visible) def click_(self): self.click(self.) # 页面加载验证(必须实现,放在最后) def is_page_loaded(self) -> bool: return self.is_visible(self.PAGE_IDENTIFIER) ``` --- ## context 共享模式决策树 ``` 一组用例是否满足以下 3 条? 1. 同一域名(不跨端) 2. 有统一前置(登录、角色切换…) 3. 有统一起点页面(可复位) │ ├─ 是(三条全满足) │ └→ class 级共享 context │ - 用 scope="class" 的 page fixture(实现见 browser-config skill) │ - 专用基类:class setup 完成前置;function-scope autouse 复位起点 │ - 用例末尾必须往返闭合(见 case-round-trip skill) │ └─ 否(任一不满足) └→ function 级独立 context - 每用例独立 browser.new_context() + new_page() - 每用例独立登录 ``` **注意事项:** - ❌ 禁止 session 级跨 class 共享 context(跨 class 职责边界不清) - ❌ 禁止同一 class 内跨域(会污染共享 context) - 详细规则见 [rules/playwright/browser-context.md](../../rules/playwright/browser-context.md) "浏览器上下文"段 --- ## 同 class 内跨用例 page 接力模式 同一 class 的多个用例之间接力同一页面状态(避免每个用例重新登录导航)的 实现要点、骨架与适用条件 → [references/page-relay-pattern.md](./references/page-relay-pattern.md) ## 新增 Role 的落地步骤 1. 决策:用上面的决策树判断新 Role 的用例是否可共享 context 2. PageObject:以 `RolePage` 命名、`role_` 文件名前缀,继承 `BasePage` 3. 基类(若采用 class 级共享):新建 `tests//_base_test.py::BaseTest` 继承 `BaseTest`,实现登录 + 切换 + 起点断言 4. 用例:`tests//test__flow.py::TestFlow` 继承新基类 5. 文档:在 [docs/architecture.md](../../docs/architecture.md) 表中追加一行 6. 目录:`pages/__init__.py` 追加新页面导出 --- ## 决策落地参考 本项目当前的落地情况(具体类名、fixture、起点页面)→ [docs/architecture.md](../../docs/architecture.md)。