# openspec-superpowers-opencode 测试文档 ## 设计原则 ### 分层架构 ``` docs/ TESTING.md ← 测试计划(稳定) test-records/ ← 测试执行记录(每轮一次) YYYY-MM-DD.md ``` | 文件 | 内容 | 变更频率 | |------|------|---------| | `TESTING.md` | 测什么、怎么测、如何验证 | 低(功能变化时) | | `test-records/*.md` | 执行结果、实测日志、✅/❌ 记录 | 高(每次测试) | ### 预期值从代码源提取 TESTING.md 中不硬编码以下内容: - **commit message** — 引用 `bin/cli.js` 中 `git commit -m "..."` 的值 - **具体文件路径**(如旧版 manifest 路径)— 仅描述「应存在/不应存在」 - **git hash** — 永远不硬编码 测试时通过 grep / git 等命令从代码中提取预期值,保证文档不因代码变更而过时。 ### 时效性保证 测试执行前运行以下脚本验证覆盖完整性: ```powershell pwsh -NoProfile scripts\check-test-coverage.ps1 ``` 脚本功能: - 校验所有 CLI 子命令(`init`、`reset`、`dry-run`、`ensure-worktree`)在 TESTING.md 中都有对应 Phase - 检测 TESTING.md 中是否包含已知的过期引用(旧文件名、旧 hash 等) exit code 0 方可开始测试。 ### 执行规定 - **禁止在本项目工作目录中测试。** `init` 不带目录参数时默认使用当前目录。所有测试必须在独立临时目录执行。 - 每个 `bash` 调用是独立进程,变量不共享。建议将测试目录路径写入环境变量持久化: ```powershell $env:OPS_TEST_DIR = "$env:TEMP\ops-test-$(Get-Date -Format 'yyyyMMdd-HHmmss')" ``` - 执行 init 前确保 `` 已替换为包实际路径。 - Windows 上如果 `openspec` 命令不可用,通过 `npm install -g openspec` 安装。 - 如果 `git config core.autocrlf` 导致 CRLF warning,使用 `git -c core.autocrlf=false -c core.safecrlf=false` 前缀。 --- ## 前置条件 | 依赖 | 最低版本 | 验证命令(Windows / Linux) | |------|---------|---------------------------| | Node.js | >= 16 | `node --version` | | openspec CLI | 1.3+ | `openspec --version` | | opencode CLI | 1.15+ | `opencode --version` | | git | 任意 | `git --version` | | Superpowers 插件 | 最新 | `opencode /skills` 能看到 skill 列表 | --- ## 图例 | 符号/标记 | 含义 | |----------|------| | 📝 | 测试步骤 | | 🔍 | 验证步骤 | | ✅ | 通过 | | ❌ | 失败 | --- ## Phase 1 — init 测试 ### 1.1 创建临时目录 **Windows (PowerShell):** ```powershell $testDir = "$env:TEMP\ops-test-$(Get-Date -Format 'yyyyMMdd-HHmmss')" New-Item -ItemType Directory -Path $testDir -Force | Out-Null $testDir ``` **Linux (bash):** ```bash testDir=$(mktemp -d /tmp/ops-test-XXXXXX) echo "$testDir" ``` **📝 预期结果**:输出临时目录路径。 --- ### 1.2 执行 init **Windows:** ```powershell $pkgRoot = "" node "$pkgRoot\bin\cli.js" init "$testDir" ``` **Linux:** ```bash pkgRoot="" node "$pkgRoot/bin/cli.js" init "$testDir" ``` > `` 替换为 `openspec-superpowers-opencode` 包的实际路径。 **📝 预期结果**: - 输出包含 `About to commit:` + 文件清单(git diff --cached --name-status) - 输出包含 `🎉 初始化完成` - exit code 为 0 --- ### 1.3 验证 git 提交历史 **Windows / Linux:** ```bash cd "$testDir" git log --oneline ``` **🔍 预期结果**: - 一条 commit - commit message 匹配 `bin/cli.js` 中 `git commit -m "..."` 的值 --- ### 1.4 Git dirty 检查(已有 Git 仓库,有未提交文件时 init 应阻挡) **Windows:** ```powershell $dirtyDir = "$env:TEMP\ops-dirty-$(Get-Date -Format 'yyyyMMdd-HHmmss')" git init "$dirtyDir" Set-Content -Path "$dirtyDir\dirty.txt" -Value 'uncommitted' -Encoding utf8 $pkgRoot = "" node "$pkgRoot\bin\cli.js" init "$dirtyDir" ``` **Linux:** ```bash dirtyDir=$(mktemp -d /tmp/ops-dirty-XXXXXX) git init "$dirtyDir" echo 'uncommitted' > "$dirtyDir/dirty.txt" pkgRoot="" node "$pkgRoot/bin/cli.js" init "$dirtyDir" ``` **📝 预期结果**: - 输出包含 `Working directory has uncommitted changes`(英文)或 `工作目录有未提交的变更`(中文) - exit code 为 1 - 不部署任何文件(.opencode/、openspec/、AGENTS.md 等均不存在) 清理: ```bash Remove-Item -Recurse -Force "$dirtyDir" ``` --- ### 1.5 验证逻辑单元测试 > 测试 `test/setup-verify.test.js`,覆盖 setup.ps1 验证子步骤(step 8)中三个辅助函数的解析逻辑,共 **15 个单元测试**。 #### 1.5.1 `parseTemplateOutput()` — 模板输出解析 解析 `openspec templates --json` 的对象格式输出(`{ artifactName: { path, source } }`),统计 `source === 'project'` 的模板数。 | 测试 | 输入 | 预期 | |------|------|------| | 成功解析 8+ 个 project 源模板 | 10 个模板(8 project + 2 builtin) | `ok=true`, `count=8` | | 不足 8 个 project 源模板时报错 | 3 个 project 源模板 | `ok=false`, `count=3` | | 无效 JSON 时报错 | `'not json'` | `ok=false`, `count=0` | | 空数组返回 count=0 | `'[]'` | `ok=false`, `count=0` | #### 1.5.2 `changeListed()` — 变更列表解析 解析 `openspec list --json` 的变更列表,在数组中查找指定变更名。支持 `{changes: [...]}` 对象格式、裸数组格式、以及 JSON 解析失败的字符串回退。 | 测试 | 输入 | 预期 | |------|------|------| | 在 changes 数组中找到变更 | `{changes:[{name:"verify-deploy"}]}` | `true` | | 多个变更中找到目标 | 含 3 个变更的数组 | `true` | | 变更不存在时返回 false | 单变更数组,目标不同 | `false` | | 空 changes 列表返回 false | `{changes:[]}` | `false` | | 直接数组格式也能处理 | `['verify-deploy','feature-a']` | `true` | | 无效 JSON 回退字符串匹配 | `'verify-deploy'` | `true`(匹配) | | 字符串回退不匹配 | `'no-match'` | `false` | #### 1.5.3 `parseStatusOutput()` — 状态输出解析 解析 `openspec status --change` 的输出,统计以 `[` 开头的 artifact 行。 | 测试 | 输入 | 预期 | |------|------|------| | 统计 [ 开头的 artifact 行 | 8 artifact 行 + 其他文本 | `ok=true`, `count=8` | | artifact 不足时报错 | 2 行 artifact | `ok=false`, `count=2` | | 空输出 count=0 | `''` | `ok=false`, `count=0` | #### 1.5.4 运行 ```bash node --test test/setup-verify.test.js ``` 筛选仅运行单元测试: ```bash node --test --test-name-pattern="验证逻辑" test/setup-verify.test.js ``` **🔍 预期结果**:15 个单元测试全部通过 ✓。 --- ### 1.6 openspec CLI 集成测试 > 与 1.5 同文件 `test/setup-verify.test.js`,在临时目录中实际调用 openspec CLI,共 **3 个集成测试**。 > > **前置条件**:`openspec` CLI 已安装且可用。 > > **自动跳过**:如果 `openspec --version` 不可用,整个 describe 块跳过(`skip`)。 **📝 流程**: 1. `before()` 创建临时目录,复制 `template/` 中的 `openspec/` 和 `.opencode/` 结构 2. 切换到临时目录(模拟 init 后的项目环境) 3. 每个测试分别在临时目录中执行 openspec CLI 命令 4. `after()` 切换回原目录并递归删除临时目录 | 测试 | 执行命令 | 验证点 | |------|---------|--------| | `openspec templates --json` 返回 8+ 个 project 源 | `openspec templates --json --schema superpowers-bridge-opencode` | `parseTemplateOutput(out).ok === true` | | `openspec new change + list` 创建并列出变更 | `openspec new change test-verify-integration` → `openspec list --json` | `changeListed(listOut, 'test-verify-integration') === true` | | `openspec status --change` 返回 8+ 个 artifact | `openspec new change test-verify-artifacts` → `openspec status --change test-verify-artifacts` | `parseStatusOutput(statusOut).ok === true` | **运行全部测试(含集成测试):** ```bash node --test test/setup-verify.test.js ``` **筛选仅运行集成测试:** ```bash node --test --test-name-pattern="openspec" test/setup-verify.test.js ``` **🔍 预期结果**: - openspec CLI 可用时:3 个集成测试全部通过 ✓(+ 15 个单元测试 = 共 18 个 ✓) - openspec CLI 不可用时:集成测试跳过(显示 `# skip`),单元测试 15 个 ✓ --- ## Phase 2 — 项目结构验证 ### 2.1 验证根文件列表 **Windows / Linux:** ```bash cd "$testDir" ls -la ``` **🔍 预期文件**: | 文件/目录 | 说明 | |-----------|------| | `.opencode/` | 含 opencode.json、commands/、skills/ | | `.opencode/opencode.json` | | | `.opencode/install-manifest.json` | 安装清单 | | `openspec/` | | | `AGENTS.md` | | | `.gitignore` | | | `.gitattributes` | | | `.editorconfig` | EditorConfig 规则 | 以下文件不应存在于根目录: - `LICENSE`(不再部署) - `opencode.json`(移入 `.opencode/` 内) - `skills.lock.json`(仅包内校验) --- ### 2.2 验证 OPSX 命令 **Windows / Linux:** ```bash ls .opencode/commands/ ``` **🔍 预期结果**:12 个 opsx-* 文件: `opsx-apply.md`, `opsx-archive.md`, `opsx-bulk-archive.md`, `opsx-continue.md`, `opsx-explore.md`, `opsx-ff.md`, `opsx-finish.md`, `opsx-new.md`, `opsx-onboard.md`, `opsx-propose.md`, `opsx-sync.md`, `opsx-verify.md` --- ### 2.3 验证 Skill 文件 **Windows / Linux:** ```bash ls .opencode/skills/ ``` **🔍 预期结果**:11 个 openspec-* 目录,每个包含非空 `SKILD.md`。 **Windows:** ```powershell Get-ChildItem -Recurse .opencode/skills/*/SKILL.md | ForEach-Object { $len = (Get-Content $_.FullName -Raw).Length if ($len -lt 100) { Write-Warning "$($_.Name): EMPTY ($len chars)" } else { Write-Host "$($_.Name): $len chars" } } ``` **Linux:** ```bash for f in .opencode/skills/*/SKILL.md; do len=$(wc -c < "$f") if [ "$len" -lt 100 ]; then echo "WARNING: $f EMPTY ($len chars)"; else echo "$f: $len chars"; fi done ``` --- ### 2.4 验证 schema 模板 **Windows / Linux:** ```bash ls openspec/schemas/superpowers-bridge-opencode/ ls openspec/schemas/superpowers-bridge-opencode/templates/ ``` **🔍 预期结果**: - `schema.yaml` 存在 - `templates/` 包含 9 个模板文件:`brainstorm.md`, `design.md`, `plan.md`, `proposal.md`, `retrospective.md`, `spec.md`, `tasks.md`, `verify.md` + `adopters/CLAUDE.md.fragment.md` --- ### 2.5 验证 opencode.json 权限格式与入审规则 **Windows / Linux:** ```bash cat .opencode/opencode.json ``` **🔍 预期结果**: 1. **格式**: - 简单权限(`read`/`glob`/`grep`/`webfetch`/`question`/`skill`/`task`)值为 `"allow"` 字符串 - 带路径控制的权限(`edit`)使用对象格式 `{".worktrees/**": "allow", ...}` - `bash` 同理使用对象格式 `{"*": "allow", ...}` 2. **入审规则(Deny-by-Default)**: - `edit` 中不存在 `"openspec/**": "allow"`(不允许整个 openspec/) - `edit` 中存在 `"openspec/schemas/**": "deny"`(基础设施,禁止 AI 修改) - `edit` 中存在 `"openspec/config.yaml": "deny"`(基础设施,禁止 AI 修改) - `edit` 中存在 `"openspec/changes/**": "allow"`(用户内容,允许 AI 修改) - `edit` 中存在 `"openspec/specs/**": "allow"`(用户内容,允许 AI 修改) **Windows:** ```powershell $ocJson = Get-Content .opencode/opencode.json -Raw | ConvertFrom-Json $edit = $ocJson.permission.edit # 验证基础设施 deny if ($edit.'openspec/schemas/**' -eq 'deny') { Write-Host '✅ schemas/** deny' } else { Write-Host '❌ schemas/** not deny' } if ($edit.'openspec/config.yaml' -eq 'deny') { Write-Host '✅ config.yaml deny' } else { Write-Host '❌ config.yaml not deny' } # 验证不存在 blanket allow if ($edit.'openspec/**') { Write-Host '❌ openspec/** allow still exists' } else { Write-Host '✅ openspec/** blanket removed' } ``` **Linux:** ```bash # 验证基础设施 deny grep -q '"openspec/schemas/\*\*": "deny"' .opencode/opencode.json && echo "✅ schemas deny" || echo "❌ schemas not deny" grep -q '"openspec/config.yaml": "deny"' .opencode/opencode.json && echo "✅ config.yaml deny" || echo "❌ config.yaml not deny" # 验证不存在 blanket allow grep -q '"openspec/\*\*": "allow"' .opencode/opencode.json && echo "❌ openspec/** still exists" || echo "✅ openspec/** blanket removed" ``` --- ### 2.6 验证 Superpowers 路径替换 **Windows / Linux:** ```bash grep -n "SUPERPOWERS_BASE_PATH" AGENTS.md grep -n "SUPERPOWERS_BASE_PATH" openspec/schemas/superpowers-bridge-opencode/schema.yaml ``` **🔍 预期结果**:两条命令均无输出(`{{SUPERPOWERS_BASE_PATH}}` 已被替换为实际路径)。 验证实际路径已注入: **Windows:** ```powershell Select-String -Path AGENTS.md -Pattern "superpowers" -SimpleMatch ``` **Linux:** ```bash grep "superpowers" AGENTS.md | head -3 ``` **🔍 预期结果**:AGENTS.md 包含类似 `C:\Users\<用户名>\.cache\opencode\...`(Windows)或 `/root/.cache/opencode/...`(Linux)的实际路径。 --- ### 2.7 验证安装清单 **Windows / Linux:** ```bash cat .opencode/install-manifest.json ``` **🔍 预期结果**: - `files` 数组长度 ≥ 25 - `language` 为 `"en"`(默认,`--lang` 指定其他语言时对应变化) - `installedAt` 不为空 - `overwriteDecisions` 根据需要存在或不存在 --- ### 2.8 验证 git 工作树干净 **Windows / Linux:** ```bash cd "$testDir" && git status --short ``` **🔍 预期结果**:无输出(工作树干净)。 --- ### 2.9 验证 .gitignore 粒度 > 验证部署后基础设施文件被 gitignore,但用户内容目录可被 git 追踪。 **Windows / Linux:** ```bash cd "$testDir" ``` **🔍 验证基础设施已被排除:** ```bash # openspec/schemas/ 应在 .gitignore 中 grep -q "openspec/schemas/" .gitignore && echo "✅ schemas/ gitignored" || echo "❌ schemas/ not gitignored" # openspec/config.yaml 应在 .gitignore 中 grep -q "openspec/config.yaml" .gitignore && echo "✅ config.yaml gitignored" || echo "❌ config.yaml not gitignored" ``` **🔍 验证用户内容未被排除:** ```bash # openspec/changes/ 不应在 .gitignore 中 grep -q "openspec/changes/" .gitignore && echo "❌ changes/ should NOT be gitignored" || echo "✅ changes/ NOT gitignored" # openspec/specs/ 不应在 .gitignore 中 grep -q "openspec/specs/" .gitignore && echo "❌ specs/ should NOT be gitignored" || echo "✅ specs/ NOT gitignored" ``` **🔍 验证用户可在 changes/ 中提交文件:** ```bash mkdir -p openspec/changes/my-feature echo "test" > openspec/changes/my-feature/user-note.md git add openspec/changes/my-feature/user-note.md git status --short ``` **🔍 预期结果**: - 文件 `openspec/changes/my-feature/user-note.md` 被成功 staging(`A ...` 或 `?? ...` 转为 `A ...`) - 基础设施文件(schemas/、config.yaml)不会被意外 git add **清理:** ```bash git reset HEAD openspec/changes/my-feature/user-note.md rm -rf openspec/changes/my-feature ``` --- ## Phase 3 — openspec CLI 集成测试 ### 3.1 Schema 验证 **Windows / Linux:** ```bash cd "$testDir" openspec schema validate superpowers-bridge-opencode ``` **📝 预期结果**: ``` Note: Schema commands are experimental and may change. ✓ Schema 'superpowers-bridge-opencode' is valid ``` --- ### 3.2 列出可用 Schema **Windows / Linux:** ```bash openspec schemas ``` **🔍 预期结果**:列表包含 `superpowers-bridge-opencode (project)`。 --- ### 3.3 初始变更列表(空) **Windows / Linux:** ```bash openspec list --json ``` **🔍 预期结果**:`{"changes":[]}` --- ### 3.4 创建变更 **Windows / Linux:** ```bash openspec new change "test-change" ``` **📝 预期结果**: ``` ✔ Created change 'test-change' at openspec/changes/test-change/ (schema: superpowers-bridge-opencode) ``` --- ### 3.5 验证 Artifact 依赖链 **Windows / Linux:** ```bash openspec status --change "test-change" --json ``` **🔍 预期结果**:8 个 artifact 按以下依赖链排列: ``` brainstorm (ready) ├── design (blocked, depends: brainstorm) └── proposal (blocked, depends: brainstorm) └── specs (blocked, depends: proposal) └── tasks (blocked, depends: specs) └── plan (blocked, depends: tasks) └── verify (blocked, depends: plan) └── retrospective (blocked, depends: verify) ``` `applyRequires` 应为 `["plan"]`。 --- ### 3.6 Artifact 指令生成 **Windows / Linux:** ```bash openspec instructions brainstorm --change "test-change" ``` **🔍 预期结果**:输出包含以下字段: - `` - PRECHECK 指令(Read Superpowers skill 文件) - `` 块 - `