@angli/unit-test-tool 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/README.md +232 -0
  3. package/dist/src/cli/commands/analyze.js +20 -0
  4. package/dist/src/cli/commands/guard.js +26 -0
  5. package/dist/src/cli/commands/init.js +39 -0
  6. package/dist/src/cli/commands/run.js +72 -0
  7. package/dist/src/cli/commands/schedule.js +29 -0
  8. package/dist/src/cli/commands/start.js +102 -0
  9. package/dist/src/cli/commands/status.js +27 -0
  10. package/dist/src/cli/commands/verify.js +15 -0
  11. package/dist/src/cli/context/create-context.js +101 -0
  12. package/dist/src/cli/index.js +23 -0
  13. package/dist/src/cli/utils/scan-dir.js +6 -0
  14. package/dist/src/core/analyzers/coverage-analyzer.js +8 -0
  15. package/dist/src/core/analyzers/dependency-complexity-analyzer.js +19 -0
  16. package/dist/src/core/analyzers/existing-test-analyzer.js +66 -0
  17. package/dist/src/core/analyzers/failure-history-analyzer.js +9 -0
  18. package/dist/src/core/analyzers/file-classifier-analyzer.js +24 -0
  19. package/dist/src/core/analyzers/index.js +37 -0
  20. package/dist/src/core/analyzers/llm-semantic-analyzer.js +3 -0
  21. package/dist/src/core/analyzers/path-priority-analyzer.js +34 -0
  22. package/dist/src/core/coverage/read-coverage-summary.js +183 -0
  23. package/dist/src/core/executor/claude-cli-executor.js +91 -0
  24. package/dist/src/core/middleware/loop-detection.js +6 -0
  25. package/dist/src/core/middleware/pre-completion-checklist.js +27 -0
  26. package/dist/src/core/middleware/silent-success-post-check.js +13 -0
  27. package/dist/src/core/planner/rank-candidates.js +3 -0
  28. package/dist/src/core/planner/rule-planner.js +41 -0
  29. package/dist/src/core/planner/score-candidate.js +49 -0
  30. package/dist/src/core/prompts/case-library.js +35 -0
  31. package/dist/src/core/prompts/edit-boundary-prompt.js +24 -0
  32. package/dist/src/core/prompts/retry-prompt.js +18 -0
  33. package/dist/src/core/prompts/system-prompt.js +27 -0
  34. package/dist/src/core/prompts/task-prompt.js +22 -0
  35. package/dist/src/core/reporter/index.js +48 -0
  36. package/dist/src/core/state-machine/index.js +12 -0
  37. package/dist/src/core/storage/defaults.js +16 -0
  38. package/dist/src/core/storage/event-store.js +16 -0
  39. package/dist/src/core/storage/lifecycle-store.js +18 -0
  40. package/dist/src/core/storage/report-store.js +16 -0
  41. package/dist/src/core/storage/state-store.js +11 -0
  42. package/dist/src/core/strategies/classify-failure.js +14 -0
  43. package/dist/src/core/strategies/switch-mock-strategy.js +9 -0
  44. package/dist/src/core/tools/analyze-baseline.js +54 -0
  45. package/dist/src/core/tools/guard.js +68 -0
  46. package/dist/src/core/tools/run-loop.js +108 -0
  47. package/dist/src/core/tools/run-with-claude-cli.js +645 -0
  48. package/dist/src/core/tools/verify-all.js +75 -0
  49. package/dist/src/core/worktrees/is-git-repo.js +10 -0
  50. package/dist/src/types/index.js +1 -0
  51. package/dist/src/types/logger.js +1 -0
  52. package/dist/src/utils/clock.js +10 -0
  53. package/dist/src/utils/command-runner.js +18 -0
  54. package/dist/src/utils/commands.js +28 -0
  55. package/dist/src/utils/duration.js +22 -0
  56. package/dist/src/utils/fs.js +53 -0
  57. package/dist/src/utils/logger.js +10 -0
  58. package/dist/src/utils/paths.js +21 -0
  59. package/dist/src/utils/process-lifecycle.js +74 -0
  60. package/dist/src/utils/prompts.js +20 -0
  61. package/dist/tests/core/create-context.test.js +41 -0
  62. package/dist/tests/core/default-state.test.js +10 -0
  63. package/dist/tests/core/failure-classification.test.js +7 -0
  64. package/dist/tests/core/loop-detection.test.js +7 -0
  65. package/dist/tests/core/paths.test.js +11 -0
  66. package/dist/tests/core/prompt-builders.test.js +33 -0
  67. package/dist/tests/core/score-candidate.test.js +28 -0
  68. package/dist/tests/core/state-machine.test.js +12 -0
  69. package/dist/tests/integration/status-report.test.js +21 -0
  70. package/docs/architecture.md +20 -0
  71. package/docs/demo.sh +266 -0
  72. package/docs/skill-integration.md +15 -0
  73. package/docs/state-machine.md +15 -0
  74. package/package.json +31 -0
  75. package/src/cli/commands/analyze.ts +22 -0
  76. package/src/cli/commands/guard.ts +28 -0
  77. package/src/cli/commands/init.ts +41 -0
  78. package/src/cli/commands/run.ts +79 -0
  79. package/src/cli/commands/schedule.ts +32 -0
  80. package/src/cli/commands/start.ts +111 -0
  81. package/src/cli/commands/status.ts +30 -0
  82. package/src/cli/commands/verify.ts +17 -0
  83. package/src/cli/context/create-context.ts +142 -0
  84. package/src/cli/index.ts +27 -0
  85. package/src/cli/utils/scan-dir.ts +5 -0
  86. package/src/core/analyzers/coverage-analyzer.ts +10 -0
  87. package/src/core/analyzers/dependency-complexity-analyzer.ts +25 -0
  88. package/src/core/analyzers/existing-test-analyzer.ts +76 -0
  89. package/src/core/analyzers/failure-history-analyzer.ts +12 -0
  90. package/src/core/analyzers/file-classifier-analyzer.ts +25 -0
  91. package/src/core/analyzers/index.ts +51 -0
  92. package/src/core/analyzers/llm-semantic-analyzer.ts +6 -0
  93. package/src/core/analyzers/path-priority-analyzer.ts +41 -0
  94. package/src/core/coverage/read-coverage-summary.ts +224 -0
  95. package/src/core/executor/claude-cli-executor.ts +94 -0
  96. package/src/core/middleware/loop-detection.ts +8 -0
  97. package/src/core/middleware/pre-completion-checklist.ts +32 -0
  98. package/src/core/middleware/silent-success-post-check.ts +16 -0
  99. package/src/core/planner/rank-candidates.ts +5 -0
  100. package/src/core/planner/rule-planner.ts +65 -0
  101. package/src/core/planner/score-candidate.ts +60 -0
  102. package/src/core/prompts/case-library.ts +36 -0
  103. package/src/core/prompts/edit-boundary-prompt.ts +26 -0
  104. package/src/core/prompts/retry-prompt.ts +22 -0
  105. package/src/core/prompts/system-prompt.ts +32 -0
  106. package/src/core/prompts/task-prompt.ts +26 -0
  107. package/src/core/reporter/index.ts +56 -0
  108. package/src/core/state-machine/index.ts +14 -0
  109. package/src/core/storage/defaults.ts +18 -0
  110. package/src/core/storage/event-store.ts +18 -0
  111. package/src/core/storage/lifecycle-store.ts +20 -0
  112. package/src/core/storage/report-store.ts +19 -0
  113. package/src/core/storage/state-store.ts +18 -0
  114. package/src/core/strategies/classify-failure.ts +9 -0
  115. package/src/core/strategies/switch-mock-strategy.ts +12 -0
  116. package/src/core/tools/analyze-baseline.ts +61 -0
  117. package/src/core/tools/guard.ts +89 -0
  118. package/src/core/tools/run-loop.ts +142 -0
  119. package/src/core/tools/run-with-claude-cli.ts +926 -0
  120. package/src/core/tools/verify-all.ts +83 -0
  121. package/src/core/worktrees/is-git-repo.ts +10 -0
  122. package/src/types/index.ts +291 -0
  123. package/src/types/logger.ts +6 -0
  124. package/src/utils/clock.ts +10 -0
  125. package/src/utils/command-runner.ts +24 -0
  126. package/src/utils/commands.ts +42 -0
  127. package/src/utils/duration.ts +20 -0
  128. package/src/utils/fs.ts +50 -0
  129. package/src/utils/logger.ts +12 -0
  130. package/src/utils/paths.ts +24 -0
  131. package/src/utils/process-lifecycle.ts +92 -0
  132. package/src/utils/prompts.ts +22 -0
  133. package/tests/core/create-context.test.ts +45 -0
  134. package/tests/core/default-state.test.ts +11 -0
  135. package/tests/core/failure-classification.test.ts +8 -0
  136. package/tests/core/loop-detection.test.ts +8 -0
  137. package/tests/core/paths.test.ts +13 -0
  138. package/tests/core/prompt-builders.test.ts +38 -0
  139. package/tests/core/score-candidate.test.ts +30 -0
  140. package/tests/core/state-machine.test.ts +14 -0
  141. package/tests/fixtures/simple-project/.openclaw-testbot/logs/events.jsonl +10 -0
  142. package/tests/fixtures/simple-project/.openclaw-testbot/plan.json +75 -0
  143. package/tests/fixtures/simple-project/.openclaw-testbot/reports/coverage-summary.json +9 -0
  144. package/tests/fixtures/simple-project/.openclaw-testbot/reports/final-report.json +14 -0
  145. package/tests/fixtures/simple-project/.openclaw-testbot/state.json +18 -0
  146. package/tests/fixtures/simple-project/coverage-summary.json +1 -0
  147. package/tests/fixtures/simple-project/package.json +8 -0
  148. package/tests/fixtures/simple-project/src/add.js +3 -0
  149. package/tests/fixtures/simple-project/test-runner.js +18 -0
  150. package/tests/integration/status-report.test.ts +24 -0
  151. package/tsconfig.json +18 -0
@@ -0,0 +1,45 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
+ import path from 'node:path'
4
+ import os from 'node:os'
5
+ import { createContext } from '../../src/cli/context/create-context.js'
6
+
7
+ describe('createContext', () => {
8
+ it('passes promptOverrides into prompt builders', async () => {
9
+ const projectPath = mkdtempSync(path.join(os.tmpdir(), 'unit-test-tool-'))
10
+
11
+ try {
12
+ writeFileSync(path.join(projectPath, 'package.json'), JSON.stringify({ scripts: {} }))
13
+
14
+ const ctx = await createContext({
15
+ projectPath,
16
+ coverageTarget: 80,
17
+ configOverrides: {
18
+ promptOverrides: {
19
+ systemAppend: 'system override',
20
+ taskAppend: 'task override',
21
+ retryAppend: 'retry override'
22
+ }
23
+ }
24
+ })
25
+
26
+ const task = {
27
+ taskId: 't1',
28
+ targetFile: 'src/foo.ts',
29
+ testFiles: [],
30
+ score: 1,
31
+ reasons: [],
32
+ estimatedDifficulty: 'low' as const,
33
+ strategy: '补测试',
34
+ status: 'pending' as const,
35
+ attemptCount: 0
36
+ }
37
+
38
+ expect(ctx.prompts.buildSystemPrompt()).toContain('system override')
39
+ expect(ctx.prompts.buildTaskPrompt(task)).toContain('task override')
40
+ expect(ctx.prompts.buildRetryPrompt(task, 'failed')).toContain('retry override')
41
+ } finally {
42
+ rmSync(projectPath, { recursive: true, force: true })
43
+ }
44
+ })
45
+ })
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { defaultState } from '../../src/core/storage/defaults.js'
3
+
4
+ describe('defaultState', () => {
5
+ it('provides baseline state', () => {
6
+ const state = defaultState()
7
+ expect(state.phase).toBe('INIT')
8
+ expect(state.status).toBe('idle')
9
+ expect(state.totals.pending).toBe(0)
10
+ })
11
+ })
@@ -0,0 +1,8 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { classifyFailure } from '../../src/core/strategies/classify-failure.js'
3
+
4
+ describe('classifyFailure', () => {
5
+ it('classifies timeout messages', () => {
6
+ expect(classifyFailure('request timeout')).toBe('CLI_TIMEOUT')
7
+ })
8
+ })
@@ -0,0 +1,8 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { loopDetection } from '../../src/core/middleware/loop-detection.js'
3
+
4
+ describe('loopDetection', () => {
5
+ it('detects when threshold exceeded', () => {
6
+ expect(loopDetection({ attemptCount: 3 } as any, 2).loopDetected).toBe(true)
7
+ })
8
+ })
@@ -0,0 +1,13 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { buildPaths } from '../../src/utils/paths.js'
3
+
4
+ describe('buildPaths', () => {
5
+ it('builds runtime file paths', () => {
6
+ const paths = buildPaths('/tmp/demo-project')
7
+
8
+ expect(paths.runtimeDir).toBe('/tmp/demo-project/.unit_test_tool_workspace')
9
+ expect(paths.statePath).toBe('/tmp/demo-project/.unit_test_tool_workspace/state.json')
10
+ expect(paths.eventsPath).toBe('/tmp/demo-project/.unit_test_tool_workspace/logs/events.jsonl')
11
+ expect(paths.finalReportPath).toBe('/tmp/demo-project/.unit_test_tool_workspace/reports/final-report.json')
12
+ })
13
+ })
@@ -0,0 +1,38 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { buildPromptBuilders } from '../../src/utils/prompts.js'
3
+
4
+ describe('buildPromptBuilders', () => {
5
+ it('includes default strategy and case library in system prompt', () => {
6
+ const prompts = buildPromptBuilders()
7
+ const systemPrompt = prompts.buildSystemPrompt()
8
+
9
+ expect(systemPrompt).toContain('通用单测策略:')
10
+ expect(systemPrompt).toContain('典型案例约束:')
11
+ expect(systemPrompt).toContain('render/HOC 包装组件')
12
+ expect(systemPrompt).toContain('强依赖上下文组件')
13
+ })
14
+
15
+ it('appends project prompt overrides', () => {
16
+ const prompts = buildPromptBuilders({
17
+ systemAppend: 'system rule',
18
+ taskAppend: 'task rule',
19
+ retryAppend: 'retry rule'
20
+ })
21
+
22
+ const task = {
23
+ taskId: 't1',
24
+ targetFile: 'src/foo.ts',
25
+ testFiles: [],
26
+ score: 1,
27
+ reasons: [],
28
+ estimatedDifficulty: 'low' as const,
29
+ strategy: '补测试',
30
+ status: 'pending' as const,
31
+ attemptCount: 0
32
+ }
33
+
34
+ expect(prompts.buildSystemPrompt()).toContain('system rule')
35
+ expect(prompts.buildTaskPrompt(task)).toContain('task rule')
36
+ expect(prompts.buildRetryPrompt(task, 'boom')).toContain('retry rule')
37
+ })
38
+ })
@@ -0,0 +1,30 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { scoreCandidate } from '../../src/core/planner/score-candidate.js'
3
+
4
+ describe('scoreCandidate', () => {
5
+ it('scores priority and low complexity candidates higher', () => {
6
+ const result = scoreCandidate({
7
+ targetFile: 'src/a.ts',
8
+ coverage: { coverageGap: 20 },
9
+ pathPriority: { label: 'priority', score: 100 },
10
+ fileClassification: {},
11
+ dependencyComplexity: {
12
+ importCount: 1,
13
+ externalDependencyCount: 1,
14
+ complexityLevel: 'low'
15
+ },
16
+ existingTest: {
17
+ hasExistingTest: false,
18
+ testFilePaths: []
19
+ },
20
+ failureHistory: {
21
+ previousAttemptCount: 0,
22
+ loopDetected: false,
23
+ blockedBefore: false,
24
+ failurePenaltyScore: 0
25
+ }
26
+ })
27
+
28
+ expect(result.baseScore).toBeGreaterThan(100)
29
+ })
30
+ })
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { deriveStatusFromPhase } from '../../src/core/state-machine/index.js'
3
+
4
+ describe('deriveStatusFromPhase', () => {
5
+ it('maps blocked and done phases', () => {
6
+ expect(deriveStatusFromPhase('BLOCKED')).toBe('blocked')
7
+ expect(deriveStatusFromPhase('DONE')).toBe('done')
8
+ })
9
+
10
+ it('maps init to idle and active phases to running', () => {
11
+ expect(deriveStatusFromPhase('INIT')).toBe('idle')
12
+ expect(deriveStatusFromPhase('WRITING_TESTS')).toBe('running')
13
+ })
14
+ })
@@ -0,0 +1,10 @@
1
+ {"eventType":"baseline_analyzed","phase":"ANALYZE_BASELINE","message":"analyzed 1 source files","data":{"framework":"unknown","sourceFiles":1,"testFiles":0},"timestamp":"2026-03-31T17:38:43.768Z"}
2
+ {"eventType":"plan_generated","phase":"PLANNING","message":"generated plan with 1 tasks","data":{"totalTasks":1},"timestamp":"2026-03-31T17:38:43.771Z"}
3
+ {"eventType":"baseline_analyzed","phase":"ANALYZE_BASELINE","message":"analyzed 1 source files","data":{"framework":"unknown","sourceFiles":1,"testFiles":0},"timestamp":"2026-03-31T17:55:30.031Z"}
4
+ {"eventType":"baseline_analyzed","phase":"ANALYZE_BASELINE","message":"analyzed 1 source files","data":{"framework":"unknown","sourceFiles":1,"testFiles":0},"timestamp":"2026-03-31T17:57:20.718Z"}
5
+ {"eventType":"plan_generated","phase":"PLANNING","message":"generated plan with 1 tasks","data":{"totalTasks":1},"timestamp":"2026-03-31T17:57:20.721Z"}
6
+ {"eventType":"baseline_analyzed","phase":"ANALYZE_BASELINE","message":"analyzed 1 source files","data":{"framework":"unknown","sourceFiles":1,"testFiles":0},"timestamp":"2026-03-31T23:53:44.984Z"}
7
+ {"eventType":"baseline_analyzed","phase":"ANALYZE_BASELINE","message":"analyzed 1 source files","data":{"framework":"unknown","sourceFiles":1,"testFiles":0},"timestamp":"2026-03-31T23:53:45.007Z"}
8
+ {"eventType":"plan_generated","phase":"PLANNING","message":"generated plan with 1 tasks","data":{"totalTasks":1},"timestamp":"2026-03-31T23:53:45.010Z"}
9
+ {"eventType":"plan_generated","phase":"PLANNING","message":"generated plan with 1 tasks","data":{"totalTasks":1},"timestamp":"2026-03-31T23:56:30.257Z"}
10
+ {"eventType":"task_started","phase":"WRITING_TESTS","taskId":"t-0001","message":"task started","data":{"targetFile":"src/add.js","attemptCount":1},"timestamp":"2026-03-31T23:56:40.567Z"}
@@ -0,0 +1,75 @@
1
+ {
2
+ "planId": "plan-1775001390254",
3
+ "generatedAt": "2026-03-31T23:56:30.254Z",
4
+ "coverageBaseline": {
5
+ "lines": 0,
6
+ "rawSummary": "sourceFiles=1, testFiles=0"
7
+ },
8
+ "selectionStrategy": "rule-plus-llm",
9
+ "plannerMode": "rule-plus-llm",
10
+ "llmPlannerApplied": true,
11
+ "llmPlannerFallback": false,
12
+ "llmValidationWarnings": [],
13
+ "tasks": [
14
+ {
15
+ "taskId": "t-0001",
16
+ "targetFile": "src/add.js",
17
+ "testFiles": [],
18
+ "score": 12,
19
+ "reasons": [
20
+ "low-complexity"
21
+ ],
22
+ "estimatedDifficulty": "low",
23
+ "strategy": "pure-logic",
24
+ "status": "failed",
25
+ "attemptCount": 1,
26
+ "priorityGroup": "P1",
27
+ "businessReason": "低复杂度逻辑文件,优先完成以快速提升覆盖率。",
28
+ "riskTag": "low",
29
+ "llmAdjustment": 2,
30
+ "analyzerFacts": {
31
+ "targetFile": "src/add.js",
32
+ "coverage": {
33
+ "lineRate": 0,
34
+ "coverageGap": 0
35
+ },
36
+ "pathPriority": {
37
+ "label": "normal",
38
+ "score": 0
39
+ },
40
+ "existingTest": {
41
+ "hasExistingTest": false,
42
+ "testFilePaths": [],
43
+ "partialCoverageLikely": false
44
+ },
45
+ "fileClassification": {
46
+ "ruleCategory": "unknown",
47
+ "semanticCategory": "unknown",
48
+ "uiSignal": false,
49
+ "domSignal": false,
50
+ "frameworkSignal": false
51
+ },
52
+ "dependencyComplexity": {
53
+ "importCount": 0,
54
+ "externalDependencyCount": 0,
55
+ "complexityLevel": "low"
56
+ },
57
+ "failureHistory": {
58
+ "previousAttemptCount": 0,
59
+ "loopDetected": false,
60
+ "blockedBefore": false,
61
+ "failurePenaltyScore": 0
62
+ },
63
+ "analyzerWarnings": []
64
+ },
65
+ "lastTriedAt": "2026-03-31T23:56:40.565Z",
66
+ "failureCategory": "RUNTIME_ENV_ERROR",
67
+ "lastError": "npm error Missing script: \"lint\"\nnpm error\nnpm error Did you mean this?\nnpm error npm link # Symlink a package folder\nnpm error\nnpm error To see a list of scripts, run:\nnpm error npm run\nnpm error A complete log of this run can be found in: /Users/starlee/.npm/_logs/2026-03-31T23_57_15_899Z-debug-0.log"
68
+ }
69
+ ],
70
+ "groups": {
71
+ "P0": 0,
72
+ "P1": 1,
73
+ "P2": 0
74
+ }
75
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "framework": "unknown",
3
+ "sourceFileCount": 1,
4
+ "testFileCount": 0,
5
+ "coverageSnapshot": {
6
+ "lines": 0,
7
+ "rawSummary": "sourceFiles=1, testFiles=0"
8
+ }
9
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "generatedAt": "2026-03-31T23:53:44.985Z",
3
+ "totals": {
4
+ "pending": 1,
5
+ "running": 0,
6
+ "passed": 0,
7
+ "failed": 0,
8
+ "blocked": 0
9
+ },
10
+ "blockedTasks": [],
11
+ "failedTasks": [],
12
+ "coveragePassed": false,
13
+ "suggestedNextAction": "plan"
14
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "phase": "PLANNING",
3
+ "status": "running",
4
+ "totals": {
5
+ "pending": 1,
6
+ "running": 0,
7
+ "passed": 0,
8
+ "failed": 0,
9
+ "blocked": 0
10
+ },
11
+ "lastAction": "generate-plan",
12
+ "nextSuggestedAction": "run-once",
13
+ "updatedAt": "2026-03-31T23:56:30.256Z",
14
+ "coverageSnapshot": {
15
+ "lines": 0,
16
+ "rawSummary": "sourceFiles=1, testFiles=0"
17
+ }
18
+ }
@@ -0,0 +1 @@
1
+ {"total":{"lines":{"pct":100},"statements":{"pct":100},"functions":{"pct":100},"branches":{"pct":100}}}
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "simple-project",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "test": "node ./test-runner.js"
7
+ }
8
+ }
@@ -0,0 +1,3 @@
1
+ export function add(a, b) {
2
+ return a + b
3
+ }
@@ -0,0 +1,18 @@
1
+ import { writeFileSync } from 'node:fs'
2
+ import { add } from './src/add.js'
3
+
4
+ if (add(1, 2) !== 3) {
5
+ console.error('add failed')
6
+ process.exit(1)
7
+ }
8
+
9
+ writeFileSync('coverage-summary.json', JSON.stringify({
10
+ total: {
11
+ lines: { pct: 100 },
12
+ statements: { pct: 100 },
13
+ functions: { pct: 100 },
14
+ branches: { pct: 100 }
15
+ }
16
+ }))
17
+
18
+ console.log('ok')
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import path from 'node:path'
3
+ import { createContext } from '../../src/cli/context/create-context.js'
4
+ import { analyzeBaseline } from '../../src/core/tools/analyze-baseline.js'
5
+ import { buildFinalReport, reportStatus } from '../../src/core/reporter/index.js'
6
+
7
+ const fixture = path.resolve('tests/fixtures/simple-project')
8
+
9
+ describe('integration: status/report', () => {
10
+ it('builds status and report', async () => {
11
+ const ctx = await createContext({
12
+ projectPath: fixture,
13
+ coverageTarget: 80
14
+ })
15
+ await analyzeBaseline(ctx)
16
+ const status = await reportStatus(ctx)
17
+ expect(status.ok).toBe(true)
18
+
19
+ const report = await buildFinalReport(ctx)
20
+ await ctx.reportStore.saveFinalReport(report)
21
+ const loaded = await ctx.reportStore.loadFinalReport()
22
+ expect(loaded).toBeTruthy()
23
+ })
24
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "resolveJsonModule": true,
11
+ "outDir": "dist",
12
+ "rootDir": ".",
13
+ "types": ["node"],
14
+ "noEmitOnError": true
15
+ },
16
+ "include": ["src", "tests"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }