Files
Claude-Code-Workflow/.claude/skills/ccw-loop/phases/actions/action-validate-with-file.md
catlog22 0cc5101c0e feat: Add phases for document consolidation, assembly, and compliance refinement
- Introduced Phase 2.5: Consolidation Agent to summarize analysis outputs and generate design overviews.
- Added Phase 4: Document Assembly to create index-style documents linking chapter files.
- Implemented Phase 5: Compliance Review & Iterative Refinement for CPCC compliance checks and updates.
- Established CPCC Compliance Requirements document outlining mandatory sections and validation functions.
- Created a base template for analysis agents to ensure consistency and efficiency in execution.
2026-01-28 19:57:24 +08:00

7.3 KiB
Raw Blame History

Action: Validate With File

运行测试并验证实现,记录结果到 validation.md支持 Gemini 辅助分析测试覆盖率和质量。

Purpose

执行测试验证流程,包括:

  • 运行单元测试
  • 运行集成测试
  • 检查代码覆盖率
  • 生成验证报告
  • 分析失败原因

Preconditions

  • state.initialized === true
  • state.status === 'running'
  • state.develop.completed_count > 0 || state.debug.confirmed_hypothesis !== null

Session Setup

const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()

const sessionFolder = `.workflow/.loop/${state.session_id}`
const validateFolder = `${sessionFolder}/validate`
const validationPath = `${validateFolder}/validation.md`
const testResultsPath = `${validateFolder}/test-results.json`
const coveragePath = `${validateFolder}/coverage.json`

Execution

Step 1: 运行测试

console.log('\n运行测试...')

// 检测测试框架
const packageJson = JSON.parse(Read('package.json'))
const testScript = packageJson.scripts?.test || 'npm test'

// 运行测试并捕获输出
const testResult = await Bash({
  command: testScript,
  timeout: 300000  // 5分钟
})

// 解析测试输出
const testResults = parseTestOutput(testResult.stdout)

Step 2: 检查覆盖率

// 运行覆盖率检查
let coverageData = null

if (packageJson.scripts?.['test:coverage']) {
  const coverageResult = await Bash({
    command: 'npm run test:coverage',
    timeout: 300000
  })

  // 解析覆盖率报告
  coverageData = parseCoverageReport(coverageResult.stdout)

  Write(coveragePath, JSON.stringify(coverageData, null, 2))
}

Step 3: Gemini 辅助分析

ccw cli -p "
PURPOSE: Analyze test results and coverage
Success criteria: Identify quality issues and suggest improvements

TASK:
• Analyze test execution results
• Review code coverage metrics
• Identify missing test cases
• Suggest quality improvements
• Verify requirements coverage

MODE: analysis

CONTEXT:
@${testResultsPath}
@${coveragePath}
@${sessionFolder}/develop/progress.md

EXPECTED:
- Quality assessment report
- Failed tests analysis
- Coverage gaps identification
- Improvement recommendations
- Pass/Fail decision with rationale

CONSTRAINTS: Evidence-based quality assessment
" --tool gemini --mode analysis --rule analysis-review-code-quality

Step 4: 生成验证报告

const timestamp = getUtc8ISOString()
const iteration = (state.validate.test_results?.length || 0) + 1

const validationReport = `# Validation Report

**Session ID**: ${state.session_id}
**Task**: ${state.task_description}
**Validated**: ${timestamp}

---

## Iteration ${iteration} - Validation Run

### Test Execution Summary

| Metric | Value |
|--------|-------|
| Total Tests | ${testResults.total} |
| Passed | ${testResults.passed} |
| Failed | ${testResults.failed} |
| Skipped | ${testResults.skipped} |
| Duration | ${testResults.duration_ms}ms |
| **Pass Rate** | **${(testResults.passed / testResults.total * 100).toFixed(1)}%** |

### Coverage Report

${coverageData ? `
| File | Statements | Branches | Functions | Lines |
|------|------------|----------|-----------|-------|
${coverageData.files.map(f => `| ${f.path} | ${f.statements}% | ${f.branches}% | ${f.functions}% | ${f.lines}% |`).join('\n')}

**Overall Coverage**: ${coverageData.overall.statements}%
` : '_No coverage data available_'}

### Failed Tests

${testResults.failed > 0 ? `
${testResults.failures.map(f => `
#### ${f.test_name}

- **Suite**: ${f.suite}
- **Error**: ${f.error_message}
- **Stack**:
\`\`\`
${f.stack_trace}
\`\`\`
`).join('\n')}
` : '_All tests passed_'}

### Gemini Quality Analysis

${geminiAnalysis}

### Recommendations

${recommendations.map(r => `- ${r}`).join('\n')}

---

## Validation Decision

**Result**: ${testResults.passed === testResults.total ? '✅ PASS' : '❌ FAIL'}

**Rationale**: ${validationDecision}

${testResults.passed !== testResults.total ? `
### Next Actions

1. Review failed tests
2. Debug failures using action-debug-with-file
3. Fix issues and re-run validation
` : `
### Next Actions

1. Consider code review
2. Prepare for deployment
3. Update documentation
`}
`

// 写入验证报告
Write(validationPath, validationReport)

Step 5: 保存测试结果

const testResultsData = {
  iteration,
  timestamp,
  summary: {
    total: testResults.total,
    passed: testResults.passed,
    failed: testResults.failed,
    skipped: testResults.skipped,
    pass_rate: (testResults.passed / testResults.total * 100).toFixed(1),
    duration_ms: testResults.duration_ms
  },
  tests: testResults.tests,
  failures: testResults.failures,
  coverage: coverageData?.overall || null
}

Write(testResultsPath, JSON.stringify(testResultsData, null, 2))

State Updates

const validationPassed = testResults.failed === 0 && testResults.passed > 0

return {
  stateUpdates: {
    validate: {
      test_results: [...(state.validate.test_results || []), testResultsData],
      coverage: coverageData?.overall.statements || null,
      passed: validationPassed,
      failed_tests: testResults.failures.map(f => f.test_name),
      last_run_at: getUtc8ISOString()
    },
    last_action: 'action-validate-with-file'
  },
  continue: true,
  message: validationPassed
    ? `验证通过 ✅\n测试: ${testResults.passed}/${testResults.total}\n覆盖率: ${coverageData?.overall.statements || 'N/A'}%`
    : `验证失败 ❌\n失败: ${testResults.failed}/${testResults.total}\n建议进入调试模式`
}

Test Output Parsers

Jest/Vitest Parser

function parseJestOutput(stdout) {
  const testPattern = /Tests:\s+(\d+) passed.*?(\d+) failed.*?(\d+) total/
  const match = stdout.match(testPattern)

  return {
    total: parseInt(match[3]),
    passed: parseInt(match[1]),
    failed: parseInt(match[2]),
    // ... parse individual test results
  }
}

Pytest Parser

function parsePytestOutput(stdout) {
  const summaryPattern = /(\d+) passed.*?(\d+) failed.*?(\d+) error/
  // ... implementation
}

Error Handling

Error Type Recovery
Tests don't run 检查测试脚本配置,提示用户
All tests fail 建议进入 debug 模式
Coverage tool missing 跳过覆盖率检查,仅运行测试
Timeout 增加超时时间或拆分测试

Validation Report Template

参考 templates/validation-template.md

CLI Integration

质量分析

ccw cli -p "PURPOSE: Analyze test results and coverage...
TASK: • Review results • Identify gaps • Suggest improvements
MODE: analysis
CONTEXT: @test-results.json @coverage.json
EXPECTED: Quality assessment
" --tool gemini --mode analysis --rule analysis-review-code-quality

测试生成 (如覆盖率低)

ccw cli -p "PURPOSE: Generate missing test cases...
TASK: • Analyze uncovered code • Write tests
MODE: write
CONTEXT: @coverage.json @src/**/*
EXPECTED: Test code
" --tool gemini --mode write --rule development-generate-tests

Next Actions (Hints)

  • 验证通过: action-complete (完成循环)
  • 验证失败: action-debug-with-file (调试失败测试)
  • 覆盖率低: action-develop-with-file (添加测试)
  • 用户选择: action-menu (返回菜单)