# 商城入驻协议 — 测试用例

> **依据：** 《商城入驻协议功能需求.md》v1.0、《商城入驻协议技术方案.md》v1.0  
> **范围：** 平台单页配置 GET/PUT；C 端 `GET /api/merchant/entry/agreement`（及可选 `GET /status`）；Facade 勾选校验；业务规则 **AP1～AP10**  
> **排除：** 协议历史版本、勾选存证、强制阅读时长、PDF、多语言；C 端入驻主体字段落库（另册，仅测协议环节与预留提交校验）  
> **环境：** RuoYi v3.9.2；平台 `/agri/merchantEntryAgreement`；C 端 `/api/merchant/entry`；平台 Token；UI 为平台管理端 + C 端用户商城（Playwright · Chromium）

---

## 用例编号说明

| 前缀 | 类型 | 工具 |
|------|------|------|
| MEA-UT-xxx | 单元测试 | JUnit 5 + Mockito（Service / AgreementContentSupport / Facade） |
| MEA-API-xxx | 接口测试 | Apifox / REST Assured / MockMvc |
| MEA-UI-xxx | 界面测试 | Playwright（`chromium`，模拟 Chrome） |

---

## 一、单元测试

### MEA-UT-001 协议标题为空拒绝保存

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 保存校验 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit + Mockito |
| **测试目的** | 验证 §5.2、AP5 标题必填 |
| **前置条件** | — |
| **测试步骤** | 调用 `saveConfig(dto)`，`agreementTitle` 为空或纯空格 |
| **预期结果** | 抛 `ServiceException`；msg「请输入协议标题」 |

### MEA-UT-002 启用时正文为空拒绝

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 保存校验 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP5 |
| **前置条件** | — |
| **测试步骤** | `enableFlag=1`，`content=null` 或 `""` |
| **预期结果** | 失败；msg「启用状态下请填写协议内容」 |

### MEA-UT-003 启用时仅空白 HTML 标签拒绝

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | AgreementContentSupport |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 §5.2 空标签 |
| **前置条件** | — |
| **测试步骤** | ① `isBlankHtml("<p></p><br/>")` 为 true ② `saveConfig` 同上 content |
| **预期结果** | ① true ② 失败；msg「协议内容不能为空」 |

### MEA-UT-004 禁用时正文可空保存成功

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 保存校验 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 §5.1 条件必填 |
| **前置条件** | 合法标题 |
| **测试步骤** | `enableFlag=0`，`content` 为空 |
| **预期结果** | 保存成功；库中 `enable_flag=0` |

### MEA-UT-005 enable_flag 非法值拒绝

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 字段校验 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证仅 0/1 |
| **前置条件** | — |
| **测试步骤** | `enableFlag=2` 或空 |
| **预期结果** | 失败；msg「是否启用参数无效」或等价 |

### MEA-UT-006 协议标题超长拒绝

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 字段长度 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 ≤128 |
| **前置条件** | — |
| **测试步骤** | `agreementTitle` 长度 129 |
| **预期结果** | 校验失败 |

### MEA-UT-007 版本号超长拒绝

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 字段长度 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 ≤32 |
| **前置条件** | — |
| **测试步骤** | `versionLabel` 长度 33 |
| **预期结果** | 校验失败 |

### MEA-UT-008 无库记录 getConfig 返回默认空壳

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | getConfig |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit + Mockito |
| **测试目的** | 验证 §4.2 首次、技术方案 §3.2 |
| **前置条件** | Mapper 返回 null |
| **测试步骤** | `getConfig()` |
| **预期结果** | `configId=1`；标题/内容空；`enableFlag=0` |

### MEA-UT-009 首次保存 insert config_id=1

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 单例写入 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit + Mockito |
| **测试目的** | 验证 AP1、单例 insert |
| **前置条件** | 表无 `config_id=1` |
| **测试步骤** | `saveConfig` 合法 dto |
| **预期结果** | 调用 `insert` 且 `config_id=1`；**不** 产生第二行 |

### MEA-UT-010 再次保存 update 不新增行

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 单例更新 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP1 |
| **前置条件** | 已有 `config_id=1` |
| **测试步骤** | 修改标题后 `saveConfig` |
| **预期结果** | 仅 `update`；表仍 **1** 行 |

### MEA-UT-011 isEnabled 启用且正文有效为 true

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | isEnabled |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 C 端开放判定 |
| **前置条件** | `enable_flag=1`，`content=<p>正文</p>` |
| **测试步骤** | `isEnabled()` |
| **预期结果** | 返回 `true` |

### MEA-UT-012 isEnabled 启用但正文无效为 false

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | isEnabled |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 §6.3 配置异常 |
| **前置条件** | `enable_flag=1`，`content` 仅 `<p></p>` |
| **测试步骤** | `isEnabled()`、`getForApp()` |
| **预期结果** | `false`；`getForApp` 的 `enabled=false` |

### MEA-UT-013 getForApp 禁用时无正文

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | getForApp |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP4 |
| **前置条件** | `enable_flag=0`，库中有历史 HTML |
| **测试步骤** | `getForApp()` |
| **预期结果** | `enabled=false`；`message` 含「商家入驻暂未开放」；**无** `content` 字段 |

### MEA-UT-014 checkboxLabel 含版本号

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | checkboxLabel |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证技术方案 §4.1 |
| **前置条件** | 启用；标题「农资商城商家入驻协议」；`versionLabel=v1.0` |
| **测试步骤** | `getForApp()` |
| **预期结果** | `checkboxLabel`=`我已阅读并同意《农资商城商家入驻协议》（v1.0）` |

### MEA-UT-015 checkboxLabel 无版本号

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | checkboxLabel |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 §2 版本可选 |
| **前置条件** | 启用；`versionLabel` 空 |
| **测试步骤** | `getForApp()` |
| **预期结果** | `checkboxLabel`=`我已阅读并同意《{标题}》`（无括号版本） |

### MEA-UT-016 assertAccepted 未勾选抛异常

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | Facade |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP3 |
| **前置条件** | `isEnabled()`=true |
| **测试步骤** | `assertAccepted(false)` |
| **预期结果** | `ServiceException`；msg 含「请先阅读并同意商家入驻协议」 |

### MEA-UT-017 assertAccepted 已勾选且开放通过

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | Facade |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP3 正向 |
| **前置条件** | `isEnabled()`=true |
| **测试步骤** | `assertAccepted(true)` |
| **预期结果** | 无异常 |

### MEA-UT-018 assertAccepted 入驻未开放时拒绝

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | Facade |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP4 + 提交前置 |
| **前置条件** | `isEnabled()`=false |
| **测试步骤** | `assertAccepted(true)` |
| **预期结果** | 失败；提示入驻未开放或等价（与实现一致） |

### MEA-UT-019 保存后 getForApp 立即读新正文

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 即时生效 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证 AP9 |
| **前置条件** | 已启用 |
| **测试步骤** | `saveConfig` 修改 `content` 为「新条款」→ 同实例 `getForApp()` |
| **预期结果** | `content` 含「新条款」 |

### MEA-UT-020 saveConfig 不调用商户 Mapper

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 状态不级联 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit + Mockito |
| **测试目的** | 验证 AP10 |
| **前置条件** | 注入 `BizMerchantMapper`（若存在）为 Mock |
| **测试步骤** | `saveConfig` 任意合法变更 |
| **预期结果** | **零次** 调用商户/店铺/商品相关 Mapper |

### MEA-UT-021 isBlankHtml 有效正文为 false

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | AgreementContentSupport |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证富文本非空判定 |
| **前置条件** | — |
| **测试步骤** | `isBlankHtml("<p>入驻条款第一条</p>")` |
| **预期结果** | 返回 `false` |

### MEA-UT-022 正文超应用上限拒绝（若实现）

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 内容长度 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit |
| **测试目的** | 验证技术方案 512KB 上限 |
| **前置条件** | 已实现长度校验 |
| **测试步骤** | `content` 长度 >512KB |
| **预期结果** | 保存失败；msg 含超出上限 |
| **备注** | 未实现长度校验时标为 **阻塞/跳过** |

---

## 二、接口测试

### MEA-API-001 平台获取配置成功

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | GET /agri/merchantEntryAgreement |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox / MockMvc |
| **测试目的** | 验证 §4 查看主流程 |
| **前置条件** | Token；`agri:merchantEntryAgreement:query`；库有 config_id=1 |
| **测试步骤** | `GET /agri/merchantEntryAgreement` |
| **预期结果** | `code=200`；`data` 含 `agreementTitle`、`versionLabel`、`content`、`enableFlag`、`updateTime` |

### MEA-API-002 无 Token 访问平台接口 401

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 鉴权 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP2 |
| **前置条件** | 不带 Authorization |
| **测试步骤** | `GET /agri/merchantEntryAgreement` |
| **预期结果** | `401` 或未授权 |

### MEA-API-003 无 query 权限 403

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 权限 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP2 |
| **前置条件** | 用户无 `agri:merchantEntryAgreement:query` |
| **测试步骤** | `GET /agri/merchantEntryAgreement` |
| **预期结果** | `403` |

### MEA-API-004 保存启用配置成功

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | PUT /agri/merchantEntryAgreement |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §5.3 主流程 |
| **前置条件** | `agri:merchantEntryAgreement:edit` |
| **测试步骤** | `PUT` Body：`agreementTitle`、`versionLabel`、`content=<p>正文</p>`、`enableFlag=1` |
| **预期结果** | `code=200`；再次 GET 字段一致；`updateBy` 为当前用户 |

### MEA-API-005 保存标题为空失败

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | PUT 校验 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §5.2 |
| **前置条件** | edit 权限 |
| **测试步骤** | `PUT`，`agreementTitle=""` |
| **预期结果** | 失败；msg「请输入协议标题」 |

### MEA-API-006 启用无正文失败

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | PUT 校验 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP5 |
| **前置条件** | edit 权限 |
| **测试步骤** | `PUT`，`enableFlag=1`，`content` 缺省或空 |
| **预期结果** | 失败；msg「启用状态下请填写协议内容」或「协议内容不能为空」 |

### MEA-API-007 禁用无正文保存成功

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | PUT 校验 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §5.1 |
| **前置条件** | edit 权限 |
| **测试步骤** | `PUT`，`enableFlag=0`，`content` 空，标题合法 |
| **预期结果** | `code=200` |

### MEA-API-008 无 edit 权限 PUT 403

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 权限 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP2 |
| **前置条件** | 仅 query 权限 |
| **测试步骤** | `PUT /agri/merchantEntryAgreement` |
| **预期结果** | `403` |

### MEA-API-009 保存后 C 端立即读到新内容

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | AP9 即时生效 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证无单独发布 |
| **前置条件** | 已启用 |
| **测试步骤** | ① `PUT` 修改 `content` 为「条款V2」 ② 无 Token `GET /api/merchant/entry/agreement` |
| **预期结果** | ② `data.content` 含「条款V2」 |

### MEA-API-010 C 端获取协议无需登录

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | GET /api/merchant/entry/agreement |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 Anonymous |
| **前置条件** | 配置已启用且正文有效 |
| **测试步骤** | 不带 Token 请求 |
| **预期结果** | `code=200` |

### MEA-API-011 C 端启用响应结构

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | C 端协议 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §6.1 |
| **前置条件** | `enable_flag=1`；有标题、版本、正文 |
| **测试步骤** | `GET /api/merchant/entry/agreement` |
| **预期结果** | `data.enabled=true`；含 `agreementTitle`、`versionLabel`、`content`、`checkboxLabel` |

### MEA-API-012 C 端禁用响应

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | C 端协议 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP4、§2.1 |
| **前置条件** | `enable_flag=0` |
| **测试步骤** | `GET /api/merchant/entry/agreement` |
| **预期结果** | `data.enabled=false`；`message` 含「商家入驻暂未开放」；**无** `content` |

### MEA-API-013 启用但库中正文为空 C 端视同未开放

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 异常配置 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox + SQL |
| **测试目的** | 验证 §6.3 |
| **前置条件** | 手工将 `enable_flag=1` 且 `content` 置空（绕过校验的脏数据） |
| **测试步骤** | `GET /api/merchant/entry/agreement` |
| **预期结果** | `enabled=false`；不可依赖正文展示 |

### MEA-API-014 可选 status 接口 entryOpen

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | GET /api/merchant/entry/status |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证技术方案 §4.3 |
| **前置条件** | 已实现 status 接口 |
| **测试步骤** | 启用/禁用各测一次 |
| **预期结果** | `entryOpen` 与 `isEnabled()` 一致 |
| **备注** | 未实现时 **跳过** |

### MEA-API-015 预留入驻提交未勾选失败

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | POST /api/merchant/entry |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP3、§4.4 |
| **前置条件** | 入驻已开放；接口已实现 |
| **测试步骤** | `POST`，`agreementAccepted=false` 或缺省 |
| **预期结果** | 失败；msg「请先阅读并同意商家入驻协议」 |
| **备注** | 接口未上线时 **跳过** |

### MEA-API-016 预留入驻提交未开放失败

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | POST /api/merchant/entry |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP4 |
| **前置条件** | `enable_flag=0`；接口已实现 |
| **测试步骤** | `POST`，`agreementAccepted=true` |
| **预期结果** | 失败；入驻未开放类提示 |
| **备注** | 未实现时 **跳过** |

### MEA-API-017 平台代录入商户不要求协议字段

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 × 商户管理 |
| **测试项** | POST /agri/merchant |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 AP8、§8.1 |
| **前置条件** | `agri:merchant:add`；合法商户 Body（无 `agreementAccepted`） |
| **测试步骤** | `POST /agri/merchant` |
| **预期结果** | 可按商户模块规则成功或业务校验失败；**不因** 未勾选入驻协议失败 |

### MEA-API-018 修改协议不改动已有商户认证状态

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 × 商户管理 |
| **测试项** | 状态不级联 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox + SQL |
| **测试目的** | 验证 AP6、AP10 |
| **前置条件** | 存在商户 M，`auth_status` 已知 |
| **测试步骤** | `PUT` 改协议标题与正文 → 查询商户 M |
| **预期结果** | M 的 `auth_status` 等 **不变** |

### MEA-API-019 关闭启用后已有商户不变

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | §2.1 禁用 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证仅拦新申请 |
| **前置条件** | 已有正常商户；配置由启用改为禁用 |
| **测试步骤** | ① `PUT enableFlag=0` ② 查商户列表/详情 |
| **预期结果** | 已有商户仍存在且状态不变；C 端 `agreement` 为未开放 |

### MEA-API-020 不提供删除接口

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 接口存在性 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证单例无删 |
| **前置条件** | — |
| **测试步骤** | `DELETE /agri/merchantEntryAgreement` 或 `/{id}` |
| **预期结果** | `404` 或 `405` |

---

## 三、界面测试（Playwright）

> **通用前置：** 平台：`{PLATFORM_URL}`，管理员账号；菜单「农资管理 → 内容管理 → 商城入驻协议」。C 端：`{MALL_URL}` 用户商城。  
> **工具：** `npx playwright test --project=chromium`；`page.goto` 使用上述 URL。

### MEA-UI-001 进入入驻协议配置页

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 配置页加载 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright (Chrome) |
| **测试目的** | 验证 §3、§4 |
| **前置条件** | 有 `agri:merchantEntryAgreement:query` |
| **测试步骤** | 登录平台 → 侧栏进入「商城入驻协议」 |
| **预期结果** | 单页表单：协议标题、版本号、是否启用、富文本区；展示最后更新人/时间（若有） |

### MEA-UI-002 首次空数据引导展示

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 首次配置 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §4.2 |
| **前置条件** | 库无有效内容或全新环境 |
| **测试步骤** | 进入配置页 |
| **预期结果** | 标题/内容可为空；启用默认「否」或占位说明；可编辑保存 |

### MEA-UI-003 保存启用协议完整流程

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 编辑保存 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §5.3 主流程 |
| **前置条件** | 有 `edit` 权限 |
| **测试步骤** | 填标题、版本、富文本正文 → 启用=是 → 保存 |
| **预期结果** | Toast「保存成功」；刷新后字段回显；`updateTime` 更新 |

### MEA-UI-004 启用开关旁说明文案

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 页面说明 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §7 |
| **前置条件** | 在配置页 |
| **测试步骤** | 查看「是否启用」表单项附近文案 |
| **预期结果** | 含「关闭后 C 端将无法提交新的商家入驻申请」或等价说明 |

### MEA-UI-005 启用无正文前端校验

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 保存校验 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §5.2、§7 双重校验 |
| **前置条件** | 有 edit 权限 |
| **测试步骤** | 启用=是，富文本留空 → 点保存 |
| **预期结果** | 表单项标红或 Toast；**不** 关闭页；与后端 msg 一致 |

### MEA-UI-006 禁用无正文可保存

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 保存校验 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §5.1 |
| **前置条件** | 标题已填 |
| **测试步骤** | 启用=否，正文空 → 保存 |
| **预期结果** | 保存成功 |

### MEA-UI-007 富文本预览与编辑区

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 富文本 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §5.4、§7 |
| **前置条件** | 已有正文 |
| **测试步骤** | 输入加粗、列表 → 点预览（若有） |
| **预期结果** | 预览区展示与编辑一致；链接/列表可渲染 |

### MEA-UI-008 无 query 权限不可见菜单

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 权限 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 AP2 |
| **前置条件** | 角色无 `agri:merchantEntryAgreement:query` |
| **测试步骤** | 登录 → 展开「内容管理」 |
| **预期结果** | **无**「商城入驻协议」菜单项 |

### MEA-UI-009 无 edit 权限保存按钮不可用

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 权限 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 AP2 |
| **前置条件** | 仅 query 权限 |
| **测试步骤** | 进入配置页 |
| **预期结果** | 表单只读或「保存」隐藏/禁用 |

### MEA-UI-010 平台关闭启用后 C 端入驻不可用

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 启用联动 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 AP4、§2.1 |
| **前置条件** | 原已启用 |
| **测试步骤** | 平台启用改否并保存 → 打开 C 端「商家入驻」页 |
| **预期结果** | 提示「商家入驻暂未开放」或入口不可见；**无** 协议正文区 |

### MEA-UI-011 C 端启用时展示协议与勾选框

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | C 端展示 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §6.1 |
| **前置条件** | 平台已启用且正文非空 |
| **测试步骤** | 进入 C 端商家入驻页 |
| **预期结果** | 可见协议标题、版本（若有）、可滚动正文；勾选框文案与 `checkboxLabel` 一致 |

### MEA-UI-012 C 端未勾选提交被阻断

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 勾选校验 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 AP3、§6.1 |
| **前置条件** | 入驻页已开放；入驻表单可提交（或仅测提交按钮） |
| **测试步骤** | 填写必填入驻字段（若有）→ **不勾选** 协议 → 点提交 |
| **预期结果** | Toast/提示「请先阅读并同意商家入驻协议」；**不** 提交成功 |

### MEA-UI-013 C 端勾选后可进入提交流程

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 勾选校验 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 AP3 正向 |
| **前置条件** | 入驻开放；其余入驻字段合法 |
| **测试步骤** | 勾选协议 → 提交 |
| **预期结果** | 不因协议拦截；进入下一成功/待审核提示（以入驻页实现为准） |
| **备注** | 入驻表单未上线时仅断言勾选后提交按钮可点且无协议类错误 |

### MEA-UI-014 再次进入须重新勾选

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 勾选记忆 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §6.1 不记忆 |
| **前置条件** | 上次已勾选并离开页面 |
| **测试步骤** | 重新进入商家入驻页 |
| **预期结果** | 勾选框为 **未选中** 状态 |

### MEA-UI-015 平台修改正文后 C 端展示更新

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 即时生效 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 AP9 |
| **前置条件** | C 端已打开展示某段正文 |
| **测试步骤** | 平台改正文为含唯一关键字「MEA_UI_15」→ 保存 → C 端刷新入驻页 |
| **预期结果** | C 端正文出现「MEA_UI_15」 |

### MEA-UI-016 平台商户新增页无入驻协议勾选

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 × 商户管理 |
| **测试项** | AP8 边界 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §8.1 |
| **前置条件** | 有商户新增权限 |
| **测试步骤** | 平台进入「商户管理」→ 新增商户弹窗/页 |
| **预期结果** | **无**「商家入驻协议」勾选框；可正常填写主体字段 |

### MEA-UI-017 访客未登录可见入驻协议正文

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | 未登录访问 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §6.3 若产品允许未登录申请 |
| **前置条件** | 产品允许未登录入驻；配置已启用 |
| **测试步骤** | 无痕窗口打开 C 端商家入驻 |
| **预期结果** | 协议正文与勾选框可见（与登录态一致） |
| **备注** | 产品要求须登录时改为登录后可见，并更新预期 |

### MEA-UI-018 与服务协议页面路径分离

| 要素 | 内容 |
|------|------|
| **测试模块** | 商城入驻协议 |
| **测试项** | AP7 边界 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §2.2 |
| **前置条件** | 会员注册页与商家入驻页均可访问 |
| **测试步骤** | 分别打开注册页、商家入驻页 |
| **预期结果** | 注册页展示/勾选 **服务协议**；入驻页展示 **入驻协议**；文案与标题互不混用 |

---

## 四、用例与业务规则对照

| 规则 | 覆盖用例 |
|------|----------|
| AP1 单条配置 | MEA-UT-009/010，MEA-API-020 |
| AP2 仅平台可编辑 | MEA-API-002/003/008，MEA-UI-008/009 |
| AP3 C 端须勾选 | MEA-UT-016/017，MEA-API-015，MEA-UI-012/013 |
| AP4 未启用不可申请 | MEA-UT-013/018，MEA-API-012/016，MEA-UI-010 |
| AP5 启用正文必填 | MEA-UT-002/003，MEA-API-006，MEA-UI-005 |
| AP6 不追溯 | MEA-API-018（数据不变） |
| AP7 与服务协议独立 | MEA-UI-018 |
| AP8 平台代录入不勾选 | MEA-API-017，MEA-UI-016 |
| AP9 保存即时生效 | MEA-UT-019，MEA-API-009，MEA-UI-015 |
| AP10 不级联 | MEA-UT-020，MEA-API-018/019 |

---

## 五、统计与执行说明

| 类型 | 数量 | 说明 |
|------|------|------|
| 单元测试 | 22 | 含 1 条可选长度校验 |
| 接口测试 | 20 | 含 3 条依赖未上线接口可跳过 |
| 界面测试 | 18 | Playwright Chromium |
| **合计** | **60** | |

**执行顺序建议：** 先执行 `sql/biz_merchant_entry_agreement.sql` → 单元测试 → 接口测试 → UI（需前后端与 C 端页面就绪）。

**Playwright 示例片段（供自动化落地参考）：**

```javascript
// tests/mea-ui-012.spec.js
test('未勾选不可提交', async ({ page }) => {
  await page.goto(process.env.MALL_URL + '/merchant/entry');
  await page.getByRole('button', { name: '提交申请' }).click();
  await expect(page.getByText('请先阅读并同意商家入驻协议')).toBeVisible();
});
```

---

*文档版本：v1.0 · 关联《商城入驻协议功能需求.md》v1.0、《商城入驻协议技术方案.md》v1.0*
