@zmice/zc 0.2.4 → 0.2.6
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.
- package/README.md +89 -9
- package/dist/cli/__tests__/platform.test.js +169 -2
- package/dist/cli/__tests__/platform.test.js.map +1 -1
- package/dist/cli/__tests__/surface.test.js +52 -0
- package/dist/cli/__tests__/surface.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.d.ts +2 -0
- package/dist/cli/__tests__/team.test.d.ts.map +1 -0
- package/dist/cli/__tests__/team.test.js +29 -0
- package/dist/cli/__tests__/team.test.js.map +1 -0
- package/dist/cli/__tests__/upstream.test.js +4 -0
- package/dist/cli/__tests__/upstream.test.js.map +1 -1
- package/dist/cli/platform.d.ts +11 -3
- package/dist/cli/platform.d.ts.map +1 -1
- package/dist/cli/platform.js +186 -49
- package/dist/cli/platform.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +114 -4
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/upstream.d.ts +1 -0
- package/dist/cli/upstream.d.ts.map +1 -1
- package/dist/cli/upstream.js +84 -5
- package/dist/cli/upstream.js.map +1 -1
- package/dist/node_modules/@zmice/platform-core/dist/index.d.ts +37 -3
- package/dist/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
- package/dist/node_modules/@zmice/platform-core/dist/index.js +68 -0
- package/dist/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
- package/dist/node_modules/@zmice/platform-core/dist/index.test.js +44 -1
- package/dist/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
- package/dist/runtime/__tests__/worktree-manager.test.js +63 -1
- package/dist/runtime/__tests__/worktree-manager.test.js.map +1 -1
- package/dist/runtime/worktree-manager.d.ts +26 -1
- package/dist/runtime/worktree-manager.d.ts.map +1 -1
- package/dist/runtime/worktree-manager.js +126 -12
- package/dist/runtime/worktree-manager.js.map +1 -1
- package/dist/team/__tests__/orchestrator.test.js +40 -0
- package/dist/team/__tests__/orchestrator.test.js.map +1 -1
- package/dist/team/__tests__/planner.test.d.ts +2 -0
- package/dist/team/__tests__/planner.test.d.ts.map +1 -0
- package/dist/team/__tests__/planner.test.js +43 -0
- package/dist/team/__tests__/planner.test.js.map +1 -0
- package/dist/team/__tests__/task-queue.test.js +18 -0
- package/dist/team/__tests__/task-queue.test.js.map +1 -1
- package/dist/team/orchestrator.d.ts +2 -1
- package/dist/team/orchestrator.d.ts.map +1 -1
- package/dist/team/orchestrator.js +29 -10
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/planner.d.ts +27 -0
- package/dist/team/planner.d.ts.map +1 -0
- package/dist/team/planner.js +120 -0
- package/dist/team/planner.js.map +1 -0
- package/dist/team/task-queue.d.ts +3 -0
- package/dist/team/task-queue.d.ts.map +1 -1
- package/dist/team/task-queue.js +11 -2
- package/dist/team/task-queue.js.map +1 -1
- package/dist/utils/qwen-extension-cli.d.ts.map +1 -1
- package/dist/utils/qwen-extension-cli.js +23 -0
- package/dist/utils/qwen-extension-cli.js.map +1 -1
- package/dist/utils/qwen-extension-cli.test.js +40 -0
- package/dist/utils/qwen-extension-cli.test.js.map +1 -1
- package/package.json +3 -3
- package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts +37 -3
- package/vendor/node_modules/@zmice/platform-core/dist/index.d.ts.map +1 -1
- package/vendor/node_modules/@zmice/platform-core/dist/index.js +68 -0
- package/vendor/node_modules/@zmice/platform-core/dist/index.js.map +1 -1
- package/vendor/node_modules/@zmice/platform-core/dist/index.test.js +44 -1
- package/vendor/node_modules/@zmice/platform-core/dist/index.test.js.map +1 -1
- package/vendor/packages/platform-claude/dist/index.d.ts.map +1 -1
- package/vendor/packages/platform-claude/dist/index.js +12 -70
- package/vendor/packages/platform-claude/dist/index.js.map +1 -1
- package/vendor/packages/platform-codex/dist/generate.d.ts +1 -1
- package/vendor/packages/platform-codex/dist/generate.d.ts.map +1 -1
- package/vendor/packages/platform-codex/dist/generate.js +1 -1
- package/vendor/packages/platform-codex/dist/generate.js.map +1 -1
- package/vendor/packages/platform-codex/dist/index.d.ts +16 -1
- package/vendor/packages/platform-codex/dist/index.d.ts.map +1 -1
- package/vendor/packages/platform-codex/dist/index.js +268 -67
- package/vendor/packages/platform-codex/dist/index.js.map +1 -1
- package/vendor/packages/platform-codex/dist/index.test.js +102 -7
- package/vendor/packages/platform-codex/dist/index.test.js.map +1 -1
- package/vendor/packages/platform-opencode/dist/index.d.ts.map +1 -1
- package/vendor/packages/platform-opencode/dist/index.js +15 -81
- package/vendor/packages/platform-opencode/dist/index.js.map +1 -1
- package/vendor/packages/platform-qwen/dist/index.d.ts.map +1 -1
- package/vendor/packages/platform-qwen/dist/index.js +28 -84
- package/vendor/packages/platform-qwen/dist/index.js.map +1 -1
- package/vendor/packages/toolkit/src/content/agents/architect/body.md +8 -0
- package/vendor/packages/toolkit/src/content/agents/code-reviewer/body.md +10 -0
- package/vendor/packages/toolkit/src/content/agents/product-owner/body.md +8 -0
- package/vendor/packages/toolkit/src/content/commands/plan-review/body.md +3 -1
- package/vendor/packages/toolkit/src/content/commands/start/body.md +51 -2
- package/vendor/packages/toolkit/src/content/commands/start/meta.yaml +2 -2
- package/vendor/packages/toolkit/src/content/skills/branch-finish-and-cleanup/body.md +17 -0
- package/vendor/packages/toolkit/src/content/skills/browser-qa-testing/body.md +77 -520
- package/vendor/packages/toolkit/src/content/skills/ci-cd-and-automation/body.md +56 -387
- package/vendor/packages/toolkit/src/content/skills/code-review-and-quality/body.md +10 -0
- package/vendor/packages/toolkit/src/content/skills/code-simplification/body.md +55 -301
- package/vendor/packages/toolkit/src/content/skills/context-engineering/body.md +10 -0
- package/vendor/packages/toolkit/src/content/skills/continuous-learning/body.md +66 -331
- package/vendor/packages/toolkit/src/content/skills/multi-perspective-review/body.md +30 -1
- package/vendor/packages/toolkit/src/content/skills/parallel-agent-dispatch/body.md +79 -317
- package/vendor/packages/toolkit/src/content/skills/performance-optimization/body.md +60 -330
- package/vendor/packages/toolkit/src/content/skills/planning-and-task-breakdown/body.md +35 -0
- package/vendor/packages/toolkit/src/content/skills/sdd-tdd-workflow/body.md +66 -342
- package/vendor/packages/toolkit/src/content/skills/sprint-retrospective/body.md +66 -303
- package/vendor/packages/toolkit/src/content/skills/team-orchestration/body.md +81 -327
- package/vendor/packages/toolkit/src/content/skills/test-driven-development/body.md +50 -346
- package/vendor/packages/toolkit/src/content/skills/using-agent-skills/body.md +26 -2
- package/vendor/references/upstreams.yaml +5 -0
- package/dist/cli/setup.d.ts +0 -3
- package/dist/cli/setup.d.ts.map +0 -1
- package/dist/cli/setup.js +0 -41
- package/dist/cli/setup.js.map +0 -1
|
@@ -1,374 +1,78 @@
|
|
|
1
1
|
# 测试驱动开发
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 角色定位
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
先用测试定义期望行为,再写最小实现让测试通过。这个 skill 负责行为变更的证据闭环,不负责铺满测试理论或替代专项浏览器 QA。
|
|
6
6
|
|
|
7
7
|
## 何时使用
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- 任何可能破坏既有行为的改动
|
|
9
|
+
- 新增或修改可观察行为。
|
|
10
|
+
- 修复 bug,需要先复现再修复。
|
|
11
|
+
- 重构可能影响现有行为。
|
|
12
|
+
- 需要为边界条件、错误路径或兼容性补回归保护。
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
不适用:纯文档、纯静态内容、无行为影响的配置调整。浏览器体验改动需要再接 `browser-qa-testing`。
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
## 快速路径
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
1. 写清要证明的行为或 bug 症状。
|
|
19
|
+
2. 选择最小测试层级:unit / integration / E2E。
|
|
20
|
+
3. **RED**:先写一个会失败的测试,确认失败原因匹配目标。
|
|
21
|
+
4. **GREEN**:写最小实现,只让当前测试通过。
|
|
22
|
+
5. **REFACTOR**:在测试保持绿色的前提下简化实现。
|
|
23
|
+
6. 跑相关回归测试,确认没有破坏邻近行为。
|
|
24
|
+
7. 记录测试证据和仍未覆盖的风险。
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
RED GREEN REFACTOR
|
|
23
|
-
Write a test Write minimal code Clean up the
|
|
24
|
-
that fails ──→ to make it pass ──→ implementation ──→ (repeat)
|
|
25
|
-
│ │ │
|
|
26
|
-
▼ ▼ ▼
|
|
27
|
-
Test FAILS Test PASSES Tests still PASS
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 第 1 步:RED - 写一个会失败的测试
|
|
31
|
-
|
|
32
|
-
先写测试。它必须失败。一个一开始就通过的测试什么都证明不了。
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// RED: This test fails because createTask doesn't exist yet
|
|
36
|
-
describe('TaskService', () => {
|
|
37
|
-
it('creates a task with title and default status', async () => {
|
|
38
|
-
const task = await taskService.createTask({ title: 'Buy groceries' });
|
|
39
|
-
|
|
40
|
-
expect(task.id).toBeDefined();
|
|
41
|
-
expect(task.title).toBe('Buy groceries');
|
|
42
|
-
expect(task.status).toBe('pending');
|
|
43
|
-
expect(task.createdAt).toBeInstanceOf(Date);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### 第 2 步:GREEN - 让它通过
|
|
49
|
-
|
|
50
|
-
写最少量的代码让测试通过,不要过度设计:
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
// GREEN: Minimal implementation
|
|
54
|
-
export async function createTask(input: { title: string }): Promise<Task> {
|
|
55
|
-
const task = {
|
|
56
|
-
id: generateId(),
|
|
57
|
-
title: input.title,
|
|
58
|
-
status: 'pending' as const,
|
|
59
|
-
createdAt: new Date(),
|
|
60
|
-
};
|
|
61
|
-
await db.tasks.insert(task);
|
|
62
|
-
return task;
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### 第 3 步:REFACTOR - 清理实现
|
|
67
|
-
|
|
68
|
-
测试变绿后,在不改变行为的前提下改进代码:
|
|
69
|
-
|
|
70
|
-
- 提取共享逻辑
|
|
71
|
-
- 改善命名
|
|
72
|
-
- 去除重复
|
|
73
|
-
- 如有必要再做优化
|
|
74
|
-
|
|
75
|
-
每次重构后都运行测试,确认没有回归。
|
|
76
|
-
|
|
77
|
-
## Bug 修复的 Prove-It 模式
|
|
78
|
-
|
|
79
|
-
面对 bug,不要先试着修复。先写一个能复现 bug 的测试。
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
Bug report arrives
|
|
83
|
-
│
|
|
84
|
-
▼
|
|
85
|
-
Write a test that demonstrates the bug
|
|
86
|
-
│
|
|
87
|
-
▼
|
|
88
|
-
Test FAILS (confirming the bug exists)
|
|
89
|
-
│
|
|
90
|
-
▼
|
|
91
|
-
Implement the fix
|
|
92
|
-
│
|
|
93
|
-
▼
|
|
94
|
-
Test PASSES (proving the fix works)
|
|
95
|
-
│
|
|
96
|
-
▼
|
|
97
|
-
Run full test suite (no regressions)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**示例:**
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// Bug: "Completing a task doesn't update the completedAt timestamp"
|
|
104
|
-
|
|
105
|
-
// Step 1: Write the reproduction test (it should FAIL)
|
|
106
|
-
it('sets completedAt when task is completed', async () => {
|
|
107
|
-
const task = await taskService.createTask({ title: 'Test' });
|
|
108
|
-
const completed = await taskService.completeTask(task.id);
|
|
109
|
-
|
|
110
|
-
expect(completed.status).toBe('completed');
|
|
111
|
-
expect(completed.completedAt).toBeInstanceOf(Date); // This fails → bug confirmed
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Step 2: Fix the bug
|
|
115
|
-
export async function completeTask(id: string): Promise<Task> {
|
|
116
|
-
return db.tasks.update(id, {
|
|
117
|
-
status: 'completed',
|
|
118
|
-
completedAt: new Date(), // This was missing
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Step 3: Test passes → bug fixed, regression guarded
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## 测试金字塔
|
|
126
|
-
|
|
127
|
-
按金字塔分配测试投入:小而快的测试应该占大多数,更高层的测试逐渐减少。
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
╱╲
|
|
131
|
-
╱ ╲ E2E Tests (~5%)
|
|
132
|
-
╱ ╲ Full user flows, real browser
|
|
133
|
-
╱──────╲
|
|
134
|
-
╱ ╲ Integration Tests (~15%)
|
|
135
|
-
╱ ╲ Component interactions, API boundaries
|
|
136
|
-
╱────────────╲
|
|
137
|
-
╱ ╲ Unit Tests (~80%)
|
|
138
|
-
╱ ╲ Pure logic, isolated, milliseconds each
|
|
139
|
-
╱──────────────────╲
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
**Beyonce Rule:** 如果你喜欢它,就应该给它配测试。基础设施改动、重构和迁移不负责替你发现 bug,测试才负责。如果代码被改坏了,而你没有对应测试,那是你的责任。
|
|
143
|
-
|
|
144
|
-
### 测试尺寸(资源模型)
|
|
145
|
-
|
|
146
|
-
除了金字塔层级,还可以按资源消耗分类:
|
|
147
|
-
|
|
148
|
-
| Size | Constraints | Speed | Example |
|
|
149
|
-
|------|------------|-------|------|
|
|
150
|
-
| **Small** | 单进程、无 I/O、无网络、无数据库 | 毫秒级 | 纯函数测试、数据转换 |
|
|
151
|
-
| **Medium** | 可多进程、仅本地、无外部服务 | 秒级 | 带测试库的 API 测试、组件测试 |
|
|
152
|
-
| **Large** | 可多机器、允许外部服务 | 分钟级 | E2E 测试、性能基准、预发集成 |
|
|
153
|
-
|
|
154
|
-
Small 测试应该占绝大多数。它们快、稳定、失败时也更容易调试。
|
|
155
|
-
|
|
156
|
-
### 决策指南
|
|
157
|
-
|
|
158
|
-
```
|
|
159
|
-
Is it pure logic with no side effects?
|
|
160
|
-
→ Unit test (small)
|
|
161
|
-
|
|
162
|
-
Does it cross a boundary (API, database, file system)?
|
|
163
|
-
→ Integration test (medium)
|
|
164
|
-
|
|
165
|
-
Is it a critical user flow that must work end-to-end?
|
|
166
|
-
→ E2E test (large) — limit these to critical paths
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## 写好测试
|
|
26
|
+
## Bug 修复 Prove-It 模式
|
|
170
27
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
断言操作的**结果**,而不是内部调用了哪些方法。验证方法调用顺序的测试在重构时很容易坏掉,即使行为没有变化。
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
// Good: Tests what the function does (state-based)
|
|
177
|
-
it('returns tasks sorted by creation date, newest first', async () => {
|
|
178
|
-
const tasks = await listTasks({ sortBy: 'createdAt', sortOrder: 'desc' });
|
|
179
|
-
expect(tasks[0].createdAt.getTime())
|
|
180
|
-
.toBeGreaterThan(tasks[1].createdAt.getTime());
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// Bad: Tests how the function works internally (interaction-based)
|
|
184
|
-
it('calls db.query with ORDER BY created_at DESC', async () => {
|
|
185
|
-
await listTasks({ sortBy: 'createdAt', sortOrder: 'desc' });
|
|
186
|
-
expect(db.query).toHaveBeenCalledWith(
|
|
187
|
-
expect.stringContaining('ORDER BY created_at DESC')
|
|
188
|
-
);
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### 测试中优先 DAMP,而不是 DRY
|
|
193
|
-
|
|
194
|
-
在生产代码里,DRY(Don't Repeat Yourself)通常是对的;但在测试里,**DAMP(Descriptive And Meaningful Phrases)** 更好。测试应该像规格一样可读,每个测试都应独立讲完整个故事,而不是让读者追着共享 helper 跑。
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
// DAMP: Each test is self-contained and readable
|
|
198
|
-
it('rejects tasks with empty titles', () => {
|
|
199
|
-
const input = { title: '', assignee: 'user-1' };
|
|
200
|
-
expect(() => createTask(input)).toThrow('Title is required');
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('trims whitespace from titles', () => {
|
|
204
|
-
const input = { title: ' Buy groceries ', assignee: 'user-1' };
|
|
205
|
-
const task = createTask(input);
|
|
206
|
-
expect(task.title).toBe('Buy groceries');
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Over-DRY: Shared setup obscures what each test actually verifies
|
|
210
|
-
// (Don't do this just to avoid repeating the input shape)
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
测试里的重复是可以接受的,只要它让每个测试都能独立理解。
|
|
214
|
-
|
|
215
|
-
### 优先使用真实实现,而不是 mock
|
|
216
|
-
|
|
217
|
-
优先使用最简单、足够用的测试替身。测试越接近真实代码,提供的信心越高。
|
|
218
|
-
|
|
219
|
-
```
|
|
220
|
-
Preference order (most to least preferred):
|
|
221
|
-
1. Real implementation → Highest confidence, catches real bugs
|
|
222
|
-
2. Fake → In-memory version of a dependency (e.g., fake DB)
|
|
223
|
-
3. Stub → Returns canned data, no behavior
|
|
224
|
-
4. Mock (interaction) → Verifies method calls — use sparingly
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
**只在以下情况下使用 mock:** 真实实现太慢、不可预测,或带有你无法控制的副作用(外部 API、邮件发送)。过度 mock 会让测试通过,而生产环境却坏掉。
|
|
228
|
-
|
|
229
|
-
### 使用 Arrange-Act-Assert 模式
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
it('marks overdue tasks when deadline has passed', () => {
|
|
233
|
-
// Arrange: Set up the test scenario
|
|
234
|
-
const task = createTask({
|
|
235
|
-
title: 'Test',
|
|
236
|
-
deadline: new Date('2025-01-01'),
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// Act: Perform the action being tested
|
|
240
|
-
const result = checkOverdue(task, new Date('2025-01-02'));
|
|
241
|
-
|
|
242
|
-
// Assert: Verify the outcome
|
|
243
|
-
expect(result.isOverdue).toBe(true);
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### 每个概念只保留一个断言
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
// Good: Each test verifies one behavior
|
|
251
|
-
it('rejects empty titles', () => { ... });
|
|
252
|
-
it('trims whitespace from titles', () => { ... });
|
|
253
|
-
it('enforces maximum title length', () => { ... });
|
|
254
|
-
|
|
255
|
-
// Bad: Everything in one test
|
|
256
|
-
it('validates titles correctly', () => {
|
|
257
|
-
expect(() => createTask({ title: '' })).toThrow();
|
|
258
|
-
expect(createTask({ title: ' hello ' }).title).toBe('hello');
|
|
259
|
-
expect(() => createTask({ title: 'a'.repeat(256) })).toThrow();
|
|
260
|
-
});
|
|
28
|
+
```text
|
|
29
|
+
Bug report -> Reproduction test fails -> Fix -> Reproduction test passes -> Regression suite passes
|
|
261
30
|
```
|
|
262
31
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
```typescript
|
|
266
|
-
// Good: Reads like a specification
|
|
267
|
-
describe('TaskService.completeTask', () => {
|
|
268
|
-
it('sets status to completed and records timestamp', ...);
|
|
269
|
-
it('throws NotFoundError for non-existent task', ...);
|
|
270
|
-
it('is idempotent — completing an already-completed task is a no-op', ...);
|
|
271
|
-
it('sends notification to task assignee', ...);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// Bad: Vague names
|
|
275
|
-
describe('TaskService', () => {
|
|
276
|
-
it('works', ...);
|
|
277
|
-
it('handles errors', ...);
|
|
278
|
-
it('test 3', ...);
|
|
279
|
-
});
|
|
280
|
-
```
|
|
32
|
+
如果无法先写复现测试,必须说明原因,并给出替代证据,例如最小命令、日志、浏览器 transcript 或人工可复查步骤。
|
|
281
33
|
|
|
282
|
-
##
|
|
34
|
+
## 测试层级选择
|
|
283
35
|
|
|
284
|
-
|
|
|
36
|
+
| 层级 | 何时选 | 代价 |
|
|
285
37
|
|---|---|---|
|
|
286
|
-
|
|
|
287
|
-
|
|
|
288
|
-
|
|
|
289
|
-
| 过度使用 snapshot | 大快照没人看,任何改动都容易坏 | 谨慎使用,并逐个审查变化 |
|
|
290
|
-
| 没有测试隔离 | 单独跑通过,合起来失败 | 每个测试都自己搭建和清理状态 |
|
|
291
|
-
| 什么都 mock | 测试通过但生产崩溃 | 优先真实实现 > fake > stub > mock;只有在边界处才使用 mock |
|
|
292
|
-
|
|
293
|
-
## 使用 DevTools 做浏览器测试
|
|
294
|
-
|
|
295
|
-
对于任何在浏览器里运行的东西,仅靠单元测试不够,还需要运行时验证。使用 Chrome DevTools MCP 让代理“看见”浏览器:DOM 检查、控制台日志、网络请求、性能轨迹和截图。
|
|
296
|
-
|
|
297
|
-
### DevTools 调试流程
|
|
298
|
-
|
|
299
|
-
```
|
|
300
|
-
1. REPRODUCE: Navigate to the page, trigger the bug, screenshot
|
|
301
|
-
2. INSPECT: Console errors? DOM structure? Computed styles? Network responses?
|
|
302
|
-
3. DIAGNOSE: Compare actual vs expected — is it HTML, CSS, JS, or data?
|
|
303
|
-
4. FIX: Implement the fix in source code
|
|
304
|
-
5. VERIFY: Reload, screenshot, confirm console is clean, run tests
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### 重点检查什么
|
|
38
|
+
| Unit | 纯逻辑、边界判断、数据转换 | 快,信心局部 |
|
|
39
|
+
| Integration | API、数据库、文件系统、模块边界 | 中等,能发现契约问题 |
|
|
40
|
+
| E2E / Browser | 用户关键路径、前端集成体验 | 慢,但最接近真实用户 |
|
|
308
41
|
|
|
309
|
-
|
|
310
|
-
|------|------|------|
|
|
311
|
-
| **Console** | Always | 生产级代码应当零错误、零警告 |
|
|
312
|
-
| **Network** | API issues | 状态码、payload 结构、耗时、CORS 错误 |
|
|
313
|
-
| **DOM** | UI bugs | 元素结构、属性、无障碍树 |
|
|
314
|
-
| **Styles** | Layout issues | 计算样式是否符合预期、优先级冲突 |
|
|
315
|
-
| **Performance** | Slow pages | LCP、CLS、INP、长任务(>50ms) |
|
|
316
|
-
| **Screenshots** | Visual changes | CSS 和布局改动的前后对比 |
|
|
42
|
+
默认从能证明目标的最低成本层级开始。不要为了形式写高层测试,也不要用过度 mock 让测试只证明实现细节。
|
|
317
43
|
|
|
318
|
-
|
|
44
|
+
## 测试质量门禁
|
|
319
45
|
|
|
320
|
-
|
|
46
|
+
- 测试名字描述行为,而不是实现细节。
|
|
47
|
+
- 断言结果状态,少断言内部调用顺序。
|
|
48
|
+
- 测试数据最小且可读,优先 DAMP 而不是过度 DRY。
|
|
49
|
+
- mock 只用于慢、不可控或有副作用的外部依赖。
|
|
50
|
+
- 每个测试失败时应指向一个清晰原因。
|
|
321
51
|
|
|
322
|
-
|
|
52
|
+
## 反模式
|
|
323
53
|
|
|
324
|
-
|
|
54
|
+
- 先写实现,再补一个永远会过的测试。
|
|
55
|
+
- 修改测试来迁就错误实现。
|
|
56
|
+
- 跳过失败测试继续加功能。
|
|
57
|
+
- 用快照覆盖大量不稳定 UI,导致 diff 不可审。
|
|
58
|
+
- 为了覆盖率写不验证业务行为的测试。
|
|
325
59
|
|
|
326
|
-
|
|
60
|
+
## 输出契约
|
|
327
61
|
|
|
62
|
+
```text
|
|
63
|
+
TDD evidence:
|
|
64
|
+
- Behavior:
|
|
65
|
+
- Test added/changed:
|
|
66
|
+
- Red result:
|
|
67
|
+
- Green result:
|
|
68
|
+
- Regression command:
|
|
69
|
+
- Remaining risk:
|
|
328
70
|
```
|
|
329
|
-
Main agent: "Spawn a subagent to write a test that reproduces this bug:
|
|
330
|
-
[bug description]. The test should fail with the current code."
|
|
331
71
|
|
|
332
|
-
|
|
72
|
+
推荐结论使用:
|
|
333
73
|
|
|
334
|
-
|
|
335
|
-
|
|
74
|
+
```text
|
|
75
|
+
Recommendation: <继续实现 / 修复测试 / 补更高层验证 / 进入 review> because <测试证据、风险和被放弃替代方案>。
|
|
336
76
|
```
|
|
337
77
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
## 另见
|
|
341
|
-
|
|
342
|
-
关于不同框架下更详细的测试模式、示例和反模式,请见 `references/testing-patterns.md`。
|
|
343
|
-
|
|
344
|
-
## 常见合理化说辞
|
|
345
|
-
|
|
346
|
-
| Rationalization | Reality |
|
|
347
|
-
|---|---|
|
|
348
|
-
| “我先把代码写出来,之后再补测试” | 你大概率不会。事后补的测试测的是实现,而不是行为。 |
|
|
349
|
-
| “这太简单了,不需要测试” | 简单代码也会变复杂。测试是在文档化预期行为。 |
|
|
350
|
-
| “测试会拖慢我” | 测试现在会拖慢你,但未来每次改代码都会帮你省时间。 |
|
|
351
|
-
| “我手动测过了” | 手工测试不会被保存。明天的改动可能把它弄坏,而你无从得知。 |
|
|
352
|
-
| “代码一看就懂” | 测试才是规格。它描述的是代码应该做什么,而不是它现在做了什么。 |
|
|
353
|
-
| “这只是原型” | 原型往往会演变成生产代码。从第一天就有测试,才能避免测试债危机。 |
|
|
354
|
-
|
|
355
|
-
## 红旗
|
|
356
|
-
|
|
357
|
-
- 写代码却没有对应测试
|
|
358
|
-
- 测试第一次运行就通过了(可能根本没测到你以为的内容)
|
|
359
|
-
- 说“所有测试通过”但实际上没有运行测试
|
|
360
|
-
- bug 修复没有复现测试
|
|
361
|
-
- 测试测试的是框架行为,而不是应用行为
|
|
362
|
-
- 测试名称没有描述预期行为
|
|
363
|
-
- 为了让测试套件通过而跳过测试
|
|
364
|
-
|
|
365
|
-
## 验证
|
|
366
|
-
|
|
367
|
-
完成任何实现后:
|
|
368
|
-
|
|
369
|
-
- [ ] 每个新行为都有对应测试
|
|
370
|
-
- [ ] 所有测试通过:`npm test`
|
|
371
|
-
- [ ] bug 修复包含一个在修复前会失败的复现测试
|
|
372
|
-
- [ ] 测试名称描述了被验证的行为
|
|
373
|
-
- [ ] 没有测试被跳过或禁用
|
|
374
|
-
- [ ] 覆盖率没有下降(如果有跟踪)
|
|
78
|
+
没有读过失败输出和通过输出,不要声明测试闭环成立。
|
|
@@ -31,6 +31,26 @@ Task arrives
|
|
|
31
31
|
└── Deploying/launching? ─────────→ shipping-and-launch
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Routing Metadata and Context Loading
|
|
35
|
+
|
|
36
|
+
Skill discovery depends on short metadata before the full skill is loaded. Treat each
|
|
37
|
+
skill description as an activation contract:
|
|
38
|
+
|
|
39
|
+
- It must say what capability the skill provides.
|
|
40
|
+
- It must say when to activate it.
|
|
41
|
+
- It should include exclusions when a nearby skill would be a better fit.
|
|
42
|
+
- It should not summarize the entire workflow; the agent should read the full skill
|
|
43
|
+
only after the skill is selected.
|
|
44
|
+
|
|
45
|
+
Prefer on-demand skill loading over always-on context. Persistent files such as
|
|
46
|
+
`AGENTS.md`, `GEMINI.md`, `CLAUDE.md`, or platform rules should contain stable project
|
|
47
|
+
conventions and canonical routing only. Do not load every skill into every session;
|
|
48
|
+
that wastes context and makes phase-specific rules compete with each other.
|
|
49
|
+
|
|
50
|
+
When a platform has native skill discovery, use its native directory or metadata model.
|
|
51
|
+
When it does not, use agent-driven routing through the project entry file. Do not imply
|
|
52
|
+
native plugin or slash-command behavior that the platform does not actually support.
|
|
53
|
+
|
|
34
54
|
## Core Operating Behaviors
|
|
35
55
|
|
|
36
56
|
These behaviors apply at all times, across all skills. They are non-negotiable.
|
|
@@ -121,9 +141,13 @@ These are the subtle errors that look like productivity but create problems:
|
|
|
121
141
|
|
|
122
142
|
2. **Skills are workflows, not suggestions.** Follow the steps in order. Don't skip verification steps.
|
|
123
143
|
|
|
124
|
-
3. **
|
|
144
|
+
3. **Load only the skills needed for the current phase.** If a task moves from planning to implementation, switch skills instead of carrying the entire planning context forward.
|
|
145
|
+
|
|
146
|
+
4. **Multiple skills can apply in sequence.** A feature implementation might involve `idea-refine` → `spec-driven-development` → `planning-and-task-breakdown` → `incremental-implementation` → `test-driven-development` → `code-review-and-quality` → `shipping-and-launch`.
|
|
147
|
+
|
|
148
|
+
5. **When in doubt, start with a spec.** If the task is non-trivial and there's no spec, begin with `spec-driven-development`.
|
|
125
149
|
|
|
126
|
-
|
|
150
|
+
6. **Ask only when it changes the route.** If the correct skill can be inferred from evidence, select it and state the assumption. Ask only for high-stakes ambiguity, conflicting goals, or missing context that would change the workflow.
|
|
127
151
|
|
|
128
152
|
## Lifecycle Sequence
|
|
129
153
|
|
|
@@ -12,6 +12,7 @@ upstreams:
|
|
|
12
12
|
kind: github-public-repo
|
|
13
13
|
status: active
|
|
14
14
|
owner: codex
|
|
15
|
+
source_url: https://github.com/addyosmani/agent-skills.git
|
|
15
16
|
source_paths:
|
|
16
17
|
- skills
|
|
17
18
|
- commands
|
|
@@ -27,6 +28,7 @@ upstreams:
|
|
|
27
28
|
kind: github-public-repo
|
|
28
29
|
status: active
|
|
29
30
|
owner: codex
|
|
31
|
+
source_url: https://github.com/obra/superpowers.git
|
|
30
32
|
source_paths:
|
|
31
33
|
- prompts
|
|
32
34
|
- instructions
|
|
@@ -43,6 +45,7 @@ upstreams:
|
|
|
43
45
|
kind: github-public-repo
|
|
44
46
|
status: active
|
|
45
47
|
owner: codex
|
|
48
|
+
source_url: https://github.com/affaan-m/everything-claude-code.git
|
|
46
49
|
source_paths:
|
|
47
50
|
- CLAUDE.md
|
|
48
51
|
- docs
|
|
@@ -59,6 +62,7 @@ upstreams:
|
|
|
59
62
|
kind: github-public-repo
|
|
60
63
|
status: active
|
|
61
64
|
owner: codex
|
|
65
|
+
source_url: https://github.com/garrytan/gstack.git
|
|
62
66
|
source_paths:
|
|
63
67
|
- prompts
|
|
64
68
|
- commands
|
|
@@ -75,6 +79,7 @@ upstreams:
|
|
|
75
79
|
kind: github-public-repo
|
|
76
80
|
status: active
|
|
77
81
|
owner: codex
|
|
82
|
+
source_url: https://github.com/multica-ai/andrej-karpathy-skills.git
|
|
78
83
|
source_paths:
|
|
79
84
|
- CLAUDE.md
|
|
80
85
|
- README.md
|
package/dist/cli/setup.d.ts
DELETED
package/dist/cli/setup.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2C3D"}
|
package/dist/cli/setup.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { discoverSkills, discoverCommands, discoverAgents, } from "../utils/skill-loader.js";
|
|
2
|
-
export function registerSetupCommand(program) {
|
|
3
|
-
program
|
|
4
|
-
.command("setup")
|
|
5
|
-
.description("扫描并验证 toolkit 资产")
|
|
6
|
-
.option("-r, --root <dir>", "项目根目录")
|
|
7
|
-
.action(async (opts) => {
|
|
8
|
-
console.log("\n🔍 正在扫描项目资产...\n");
|
|
9
|
-
const [skills, commands, agents] = await Promise.all([
|
|
10
|
-
discoverSkills(opts.root),
|
|
11
|
-
discoverCommands(opts.root),
|
|
12
|
-
discoverAgents(opts.root),
|
|
13
|
-
]);
|
|
14
|
-
// Skills
|
|
15
|
-
console.log(`📦 技能:${skills.length} 个`);
|
|
16
|
-
for (const s of skills) {
|
|
17
|
-
console.log(` ✅ ${s.name}`);
|
|
18
|
-
}
|
|
19
|
-
// Commands
|
|
20
|
-
console.log(`\n📋 命令:${commands.length} 个`);
|
|
21
|
-
for (const c of commands) {
|
|
22
|
-
console.log(` ✅ ${c.name}`);
|
|
23
|
-
}
|
|
24
|
-
// Agents
|
|
25
|
-
console.log(`\n🤖 代理:${agents.length} 个`);
|
|
26
|
-
for (const a of agents) {
|
|
27
|
-
console.log(` ✅ ${a.name}`);
|
|
28
|
-
}
|
|
29
|
-
// Summary
|
|
30
|
-
const total = skills.length + commands.length + agents.length;
|
|
31
|
-
console.log(`\n📊 总计:${total} 个资产`);
|
|
32
|
-
if (total === 0) {
|
|
33
|
-
console.log("\n⚠️ 未发现任何资产,请检查目录结构是否正确");
|
|
34
|
-
console.log(" 期望结构:packages/toolkit/src/content/<kind>/<name>/{meta.yaml,body.md,assets/}");
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
console.log("\n✅ 目录结构验证通过");
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=setup.js.map
|
package/dist/cli/setup.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,cAAc,GACf,MAAM,0BAA0B,CAAC;AAElC,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kBAAkB,CAAC;SAC/B,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,IAAuB,EAAE,EAAE;QACxC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAElC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACnD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;YACzB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;SAC1B,CAAC,CAAC;QAEH,SAAS;QACT,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;QAED,WAAW;QACX,OAAO,CAAC,GAAG,CAAC,WAAW,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;QAC5C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;QAED,SAAS;QACT,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;QAC1C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAChC,CAAC;QAED,UAAU;QACV,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC;QAEpC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|