{"slug":"pdlc-e2e","title":"pdlc-e2e","summary":"端到端测试（生成或执行 E2E 用例）","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-23T18:54:23.134921Z","repo":{"url":"https://github.com/kanfu-panda/pdlc-skills","stars":15,"forks":2,"license":"MIT","updatedAt":"2026-09-23T15:59:31Z"},"bodyHtml":"<hr>\n<p>name: pdlc-e2e\ndescription: 端到端测试（生成或执行 E2E 用例）\nargument-hint: &lt;功能ID | 业务流程描述&gt;\nallowed-tools: Read, Write, Edit, Glob, Grep, Bash\nlayer: 2\nstage: e2e\nproduces:</p>\n<ul>\n<li>e2e/**/*.spec.ts\nrequires: []\nnext_step: pdlc-review\nterminal_state: e2e_done</li>\n</ul>\n<hr>\n<h1>端到端测试</h1>\n\n<p>⛔ <strong>IRON LAW · 不可违反的硬门禁</strong></p>\n<p>以下规则为<strong>不可协商</strong>的执行约束：</p>\n<ol>\n<li><strong>文件必须落盘</strong>：所有带编号（功能ID / 缺陷ID）的文档，必须作为实际文件写入磁盘，不可仅在对话中输出。</li>\n<li><strong>阶段必须落章</strong>：每个阶段完成后必须在状态机 <code>docs/.pdlc-state/&lt;feature-id&gt;.json</code> 追加 history，不可跳过。</li>\n<li><strong>测试必须存在</strong>：进入 <code>/pdlc-implement</code> 前，对应测试必须存在且处于红灯状态。违反则中止。</li>\n<li><strong>自检必须执行</strong>：段二自检为强制步骤，不得以\"已经很好了\"为由跳过。</li>\n<li><strong>防循环</strong>：段三修复为单次，不递归。无法自动修复的问题记录到报告，继续往下走。</li>\n<li><strong>状态必推进</strong>：成功执行某 phase 后 <code>current_stage</code> 必须变更。收尾时若发现 <code>current_stage</code> 未推进，视为失败并报错，<strong>不得静默返回</strong>（防止外层循环拿滞后的状态空转烧额度）。唯一例外：命中人工点主动 block 时，<code>current_stage</code> 保持不变但必须写 <code>last_phase_result.ok=false</code> + <code>blocked_reason</code>。</li>\n</ol>\n<p><strong>违反任一条 = 立即中止当前命令，输出违规详情，等待人工介入。</strong></p>\n\n<p>编写端到端（E2E）测试用例，验证完整的用户操作流程。</p>\n<h2>工作流程</h2>\n<ol>\n<li><strong>阅读需求文档</strong>: 阅读 <code>docs/01_requirements/user-stories/</code> 下的用户故事和验收标准</li>\n<li><strong>阅读 UI 设计</strong>: 阅读 <code>docs/02_design/ui-ux/</code> 下的 UI 设计文档</li>\n<li><strong>梳理测试场景</strong>: 按用户旅程梳理核心操作路径</li>\n<li><strong>编写测试计划</strong>: 在 <code>docs/04_testing/e2e-tests/</code> 下补充 E2E 测试用例</li>\n<li><strong>编写测试代码</strong>: 使用项目对应的 E2E 框架编写自动化测试</li>\n<li><strong>运行验证</strong>: 确保测试可通过</li>\n</ol>\n<h2>测试场景设计</h2>\n<ul>\n<li><strong>核心路径（P0）</strong>: 必须通过，如登录→主流程→结果验证</li>\n<li><strong>分支路径（P1）</strong>: 常见的备选操作路径</li>\n<li><strong>异常路径（P2）</strong>: 网络错误、超时、权限不足等异常场景</li>\n<li><strong>边界场景（P3）</strong>: 空数据、超长输入、并发操作</li>\n</ul>\n<h2>测试框架（根据前端技术栈）</h2>\n<ul>\n<li>React/Vue/Next.js: Playwright 或 Cypress</li>\n<li>微信小程序: miniprogram-automator</li>\n<li>API 层: 直接用 HTTP 请求库</li>\n</ul>\n<h2>要求</h2>\n\n<p>\uD83C\uDF10 <strong>Output language for generated artifacts</strong></p>\n<p>All generated artifacts (PRDs, design docs, code comments, review reports,\ntest plans, deployment manuals, changelog entries, etc.) follow this policy:</p>\n<ol>\n<li><p><strong>Default — match the conversation language exactly</strong>:</p>\n<ul>\n<li>用户用中文与 Claude 对话 → 产中文文档、中文代码注释、中文报告</li>\n<li>User talks to Claude in English → produce English artifacts</li>\n<li>User talks in another language → produce artifacts in that language</li>\n<li><strong>Never silently default to a fixed language regardless of the user's input.</strong></li>\n</ul>\n</li>\n<li><p><strong>Explicit override always wins</strong>: when the user specifies a language for\nan artifact (e.g. \"write the PRD in English\", \"用英文写 API 设计文档\",\n\"output the deploy doc in Japanese\"), use that language for that artifact,\nregardless of conversation language.</p>\n</li>\n<li><p><strong>Mixed-language requirements</strong>: if the user wants some artifacts in one\nlanguage and others in a different language (common: Chinese PRD + English\nAPI docs for partners), honour each per-artifact instruction.</p>\n</li>\n<li><p><strong>Uncertain</strong>: if you cannot reliably detect the conversation language,\nask once before producing the first artifact.</p>\n</li>\n</ol>\n<p>This policy applies to <strong>content</strong> (prose, comments, headings). It does\n<strong>not</strong> override technical conventions like English variable names, English\ngit commit subjects, or English error codes when the project's conventions\nrequire them.</p>\n\n<ul>\n<li>测试用例命名格式: <code>应该_当&lt;条件&gt;时_&lt;预期行为&gt;</code></li>\n<li>测试数据独立，不依赖其他测试的执行结果</li>\n<li>每个测试结束后清理数据</li>\n</ul>\n<p>测试目标: $ARGUMENTS</p>\n\n<blockquote>\n<p><strong>本命令的状态机取值</strong>：阶段短名 <code>e2e</code>（写进 <code>history[].stage</code> 与 <code>last_phase_result.stage</code>）；下一跳 <code>pdlc-review</code>（写进 <code>next_step</code>，交接时提示）。</p>\n</blockquote>\n\n\n<h2>状态机更新（段四必须执行）</h2>\n<p>本命令完成主产出后，必须更新状态机文件 <code>docs/.pdlc-state/&lt;feature-id&gt;.json</code>。</p>\n<h3>文件格式</h3>\n<pre><code>{\n  \"feature_id\": \"&lt;F/B ID&gt;\",\n  \"feature_name\": \"&lt;kebab-case&gt;\",\n  \"created_at\": \"&lt;首次创建时间 ISO 8601&gt;\",\n  \"current_stage\": \"&lt;当前阶段名&gt;\",\n  \"run_mode\": \"interactive | autonomous\",\n  \"history\": [\n    {\n      \"stage\": \"&lt;阶段名&gt;\",\n      \"done_at\": \"&lt;ISO 8601&gt;\",\n      \"produced\": [\"&lt;相对路径 1&gt;\", \"&lt;相对路径 2&gt;\"],\n      \"self_audit\": { \"passed\": &lt;N&gt;, \"failed\": &lt;N&gt;, \"manual\": &lt;N&gt; },\n      \"auto_decisions\": [\n        { \"point\": \"&lt;autonomous 下自动前进的确认点&gt;\", \"chose\": \"&lt;所选默认&gt;\", \"at\": \"&lt;ISO 8601&gt;\" }\n      ]\n    }\n  ],\n  \"last_phase_result\": {\n    \"stage\": \"&lt;本次阶段名&gt;\",\n    \"ok\": true,\n    \"advanced_to\": \"&lt;推进到的下一阶段 | null&gt;\",\n    \"checks\": {},\n    \"self_audit\": { \"failed\": 0 },\n    \"blocked_reason\": null,\n    \"run_mode\": \"interactive | autonomous\",\n    \"at\": \"&lt;ISO 8601&gt;\"\n  },\n  \"relations\": {\n    \"extends\": [],\n    \"depends_on\": [],\n    \"supersedes\": [],\n    \"resolves\": [],\n    \"conflicts_with\": [],\n    \"relates_to\": [],\n    \"_updated_at\": \"&lt;ISO 8601 | 省略&gt;\"\n  },\n  \"next_step\": \"&lt;下一跳命令名，如 pdlc-design；若流程结束则为 null&gt;\"\n}\n</code></pre>\n<blockquote>\n<p>⛔ 示例里的 <code>\"checks\": {}</code> 是「本阶段没有命令可跑」的样子，<strong>不是键名示范</strong>——键名与取值见下方 §1。</p>\n</blockquote>\n<blockquote>\n<p><strong><code>relations</code> 块（RFC#6，Phase 1 可选，Phase 2 推荐）</strong>：6 个 key 对应 6 种关系类型，各为 ID 数组，存<strong>出边</strong>。其中 <code>conflicts_with</code> / <code>relates_to</code> 是对称类型，两端都要写；其余四种有向，只写在源 feature 上。拿不准时用 <code>/pdlc-relate set</code> 写入，它会按规则校验。旧状态文件无此块时视为全空，向后兼容。入边由 <code>/pdlc-relate rebuild</code> 派生到 <code>_relations.json</code>，不在此块手维护。</p>\n</blockquote>\n<blockquote>\n<p>⛔ <strong>写状态机的四条硬约束</strong>——读侧（<code>/pdlc-status</code>、<code>/pdlc-retro</code>、<code>/pdlc-relate</code>）会逐条体检，\n违反的每一处都会出现在它们输出的最前面：</p>\n<ol>\n<li><strong>实例里不写 <code>terminal_state</code></strong>。skill frontmatter 的 <code>terminal_state:</code> 是「这个命令走完后应到达的终态名」，\n不是状态字段。判终态只看 <code>current_stage</code> 是否以 <code>_done</code> 结尾。</li>\n<li><strong><code>history[].stage</code> 写本命令的阶段短名</strong>（见本命令正文里「本命令的状态机取值」）——<code>pdlc-implement</code> 写 <code>impl</code>，\n不写 <code>implement</code> / <code>implementation</code>；<code>pdlc-prd</code> 写 <code>requirements</code>，不写 <code>prd</code>。</li>\n<li><strong>时间戳必须带时刻</strong>：<code>created_at</code> / <code>done_at</code> / <code>at</code> 一律写完整 ISO 8601（如 <code>2026-07-28T10:40:00+08:00</code>）。\n只写日期，同一天内的阶段耗时就全部算成 0——读侧只能记「不可测」。</li>\n<li><strong><code>next_step</code> 只写命令名或 <code>null</code></strong>，不附说明文字（如「pdlc-ship（等评审通过）」）。\n要说明原因，阻塞时写进 <code>last_phase_result.blocked_reason</code>。</li>\n</ol>\n</blockquote>\n<blockquote>\n<p>⛔ <strong><code>_done</code> 的含义是「已发布」，只由 <code>/pdlc-ship</code>（写 <code>ship_done</code>）与 <code>/pdlc-deploy</code>（写 <code>deploy_done</code>）写入。</strong>\n其它命令的 <code>current_stage</code> 一律写本命令的阶段短名，走完整条链路的编排命令（<code>/pdlc-feature</code>）也一样——\n它收尾时 <code>current_stage</code> 是最后一个阶段的短名，<code>next_step</code> 是 <code>pdlc-ship</code>。</p>\n<ul>\n<li>「评审通过、等待发布」就是 <code>current_stage</code> 为 <code>review</code>（或 <code>e2e</code> 等）且 <code>next_step</code> 为 <code>pdlc-ship</code>。\n循环相关文档里说的 <code>review_done</code> 指的就是这个状态，<strong>不是</strong>要写进 <code>current_stage</code> 的值。</li>\n<li>为什么：读侧判「已抵达终态」只看 <code>current_stage</code> 是否以 <code>_done</code> 结尾。评审通过就写 <code>_done</code>，\n<code>/pdlc-ship</code> 就分不清哪些功能已经发布过，发布说明会重复或漏收。</li>\n<li>旧版本写入的 <code>feature_done</code> / <code>fix_done</code> / <code>review_done</code> 分不清是否已发布，<code>/pdlc-ship</code> 会列出来请人确认。</li>\n</ul>\n</blockquote>\n<h3>更新流程</h3>\n<ol>\n<li><strong>文件不存在</strong> → 创建文件，写入初始结构（<code>history</code> 为含当前阶段的数组）</li>\n<li><strong>文件存在</strong> → 读取 JSON，追加当前阶段到 <code>history</code>，更新 <code>current_stage</code> 和 <code>next_step</code></li>\n<li><strong>写回文件</strong>：用 <code>jq</code> 或等效工具保持格式化</li>\n</ol>\n<p>⚠️ 若更新失败（文件损坏/权限问题），必须中止命令并在最终报告中报错。状态机不可跳过。</p>\n<h3><code>last_phase_result</code>（机器可读阶段结果，每个 phase 收尾必写）</h3>\n<p>顶层 <code>last_phase_result</code> 是循环判停的<strong>唯一真源</strong>，外层只需 <code>jq '.last_phase_result.ok'</code> 即可决定 继续 / 停止 / 交还人类。规则：</p>\n<ol>\n<li><p><strong><code>checks</code> 必须客观、真跑得来</strong>：只放<strong>真跑命令的退出码</strong>结果（命令取自 <code>docs/00_standards/test-commands.yml</code>，见 <code>test-commands-template.yml</code>），<strong>绝不用模型自评、绝不填占位</strong>。有测试的阶段用 <code>tests_pass</code> / <code>coverage_pass</code> / <code>lint_clean</code>（退出码 0 → <code>true</code>，非 0 → <code>false</code>）；stage 语义不同用对应键（如 tdd 段 <code>{ \"red_verified\": true }</code> 表示红灯已验证）。</p>\n<blockquote>\n<p>⛔ <strong>键名与类型都是契约的一部分</strong>：键名只能是 <code>tests_pass</code> / <code>coverage_pass</code> /\n<code>lint_clean</code> / <code>e2e_pass</code>（tdd 段 <code>red_verified</code>），值只能是<strong>布尔</strong>。\n最常见的两种错法：① 照抄 <code>test-commands.yml</code> 的 <code>unit</code> / <code>coverage</code> / <code>lint</code> / <code>e2e</code>\n——那是<strong>命令表</strong>的字段名，不是状态机的（跑 <code>unit</code> 得到的结论写进 <code>tests_pass</code>）；\n② 写成 <code>\"4 passed, 1 failed\"</code> 这类字符串摘要。两种都会让 <code>jq '.checks.tests_pass'</code>\n读回 <code>null</code>，消费方（发布闸门、质量报告、自主循环）只看到「无法判定」——\n<strong>你诚实跑出来的结果等于没写</strong>。三态怎么分见本命令正文里「跑 check 命令：退出码的三态语义」一节；正文里没有这一节的命令不跑 check 命令，<code>checks</code> 写 <code>{}</code>。</p>\n<p>⚠️ <strong>没有检查命令可跑的阶段（如 requirements/design 只产文档，或项目无 <code>test-commands.yml</code>）→ <code>checks: {}</code> 留空。绝不因为「本阶段成功」就把 <code>tests_pass</code>/<code>lint_clean</code> 等填 <code>true</code>——那是虚报，会污染跨工具共用的状态机、误导自主循环判停。</strong> 上面 schema 示例里 <code>checks</code> 之所以是空的，正是这个原因——<strong>空是\"没跑\"的意思，不是键名的示范</strong>。</p>\n</blockquote>\n</li>\n<li><p><strong><code>self_audit</code> 单列</strong>：只放自检未通过数，<strong>仅供参考，不作循环判停依据</strong>。</p>\n</li>\n<li><p><strong><code>ok</code> 的定义</strong>：本阶段全部 <code>checks</code> 通过且未命中 <code>blocked_reason</code> → <code>true</code>；否则 <code>false</code>。</p>\n</li>\n<li><p><strong>命名空间</strong>：<code>advanced_to</code> = <strong>下一阶段的短名</strong>，<strong>不是命令名、也不是本阶段的 <code>current_stage</code></strong>。三者关系：<code>stage</code>=本阶段短名、<code>current_stage</code>=本阶段完成后的当前短名、<code>advanced_to</code>=下一阶段短名、<code>next_step</code>=下一跳命令名。</p>\n<p>⛔ <strong>短名不是「命令名去掉 <code>pdlc-</code> 前缀」</strong>——<code>pdlc-implement</code> 的短名是 <strong><code>impl</code></strong>，不是 <code>implement</code>。别推导，查下表：</p>\n</li>\n</ol>\n\n<table>\n<thead>\n<tr>\n<th><code>next_step</code>（下一跳命令名）</th>\n<th><code>advanced_to</code>（下一阶段短名）</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>pdlc-tdd</code></td>\n<td><code>tdd</code></td>\n</tr>\n<tr>\n<td><code>pdlc-implement</code></td>\n<td><code>impl</code></td>\n</tr>\n<tr>\n<td><code>pdlc-review</code></td>\n<td><code>review</code></td>\n</tr>\n<tr>\n<td><code>pdlc-design</code></td>\n<td><code>design</code></td>\n</tr>\n<tr>\n<td><code>pdlc-ship</code></td>\n<td><code>ship</code></td>\n</tr>\n<tr>\n<td><code>pdlc-deploy</code></td>\n<td><code>deploy</code></td>\n</tr>\n</tbody>\n</table>\n\n<p><code>next_step</code> 为 <code>null</code>（终态或无后续）时 <code>advanced_to</code> 也是 <code>null</code>。</p>\n<blockquote>\n<p>\uD83D\uDCCC <strong>本表是唯一真源，且是被断言钉住的</strong>：每行的短名必须等于该 skill 自己 frontmatter\n里声明的 <code>stage:</code>，且任何 skill 的非 <code>null</code> <code>next_step</code> 都必须在表里有行——两个方向\n都由 <code>tests/frontmatter-check.sh</code> 检查，所以表不会和实现各自漂移。</p>\n<p>写错短名的后果与键名写错同类：消费方按契约名匹配，认不出就当没这个阶段。</p>\n</blockquote>\n<ol start=\"5\">\n<li><strong>推进一致</strong>：<code>ok=true</code> 时本阶段必须真的推进了 <code>current_stage</code>（与第 6 条 IRON LAW 呼应）；到达终态或无后续时 <code>advanced_to=null</code>。<code>ok=false</code>（含 blocked）时 <code>current_stage</code> 不变、<code>advanced_to=null</code>、<code>blocked_reason</code> 写明原因。</li>\n<li><strong><code>run_mode</code></strong>：镜像本次调用是否带 <code>--autonomous</code>（带了写 <code>autonomous</code>，没带写 <code>interactive</code>）。</li>\n</ol>\n\n\n<h2>段四：交接（Handoff）</h2>\n<p>命令完成后必须输出以下格式的最终消息：</p>\n<pre><code>✅ &lt;阶段名&gt; 完成：&lt;主要产出物路径&gt;\n\uD83D\uDCCA 自检：&lt;通过数&gt;/&lt;总数&gt; 通过（若有未通过，附要点）\n\uD83D\uDCE6 状态快照：docs/.pdlc-state/&lt;feature-id&gt;.json\n\uD83D\uDC49 下一步：/pdlc-&lt;next_step&gt;\n   （如果有分叉）或 /pdlc-&lt;alt&gt;（条件：&lt;选择依据&gt;）\n</code></pre>\n<p><strong>规则：</strong></p>\n<ul>\n<li>主流程命令（写状态机的命令；下一跳见正文里「本命令的状态机取值」）必须显式输出\"下一步\"，不可省略</li>\n<li>工具型命令（Layer 3）可以没有 <code>next_step</code>，此时输出 <code>\uD83D\uDC49 下一步：（本次流程结束，无后续）</code></li>\n<li>分叉场景必须说明<strong>选择条件</strong>，例如\"若需补充测试用例 → <code>/pdlc-tdd</code>；若测试已齐 → <code>/pdlc-review</code>\"</li>\n</ul>\n\n","files":[{"path":"SKILL.md","sizeBytes":14185,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-23T18:54:41.469444Z","sha256":"3D6463AFCF796901D04C1A54AF66B1E555F0BBB0E2AAB49FC731DDC1711BBF60","sizeBytes":7129},"review":null,"source":{"repositoryUrl":"https://github.com/kanfu-panda/pdlc-skills","path":"skills/pdlc-e2e","license":"MIT","commit":"3cd2f02ab45cb1cd48962e0f298ae4dad9fb442f","subtreeSha":"BA2BAF7DF1B363E75108E4EF9C5C70D903127AC3C4DBE3982ADB5E20CC51C40E","lastSyncedAt":"2026-09-23T18:54:21.123477Z"},"reviewedAt":"2026-09-23T18:55:30.009241Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/kanfu-panda/pdlc-skills/tree/main/skills/pdlc-e2e"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kanfu-panda-pdlc-skills@llmmart"},{"target":"git","command":"git clone https://github.com/kanfu-panda/pdlc-skills.git"}]}