@neyugn/agent-kits 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.
- package/LICENSE +21 -0
- package/README.md +514 -0
- package/README.vi.md +410 -0
- package/README.zh.md +410 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +422 -0
- package/kits/coder/ARCHITECTURE.md +289 -0
- package/kits/coder/agents/ai-engineer.md +344 -0
- package/kits/coder/agents/backend-specialist.md +270 -0
- package/kits/coder/agents/cloud-architect.md +363 -0
- package/kits/coder/agents/code-reviewer.md +284 -0
- package/kits/coder/agents/data-engineer.md +401 -0
- package/kits/coder/agents/database-specialist.md +251 -0
- package/kits/coder/agents/debugger.md +209 -0
- package/kits/coder/agents/devops-engineer.md +281 -0
- package/kits/coder/agents/documentation-writer.md +296 -0
- package/kits/coder/agents/frontend-specialist.md +298 -0
- package/kits/coder/agents/i18n-specialist.md +348 -0
- package/kits/coder/agents/integration-specialist.md +314 -0
- package/kits/coder/agents/mobile-developer.md +271 -0
- package/kits/coder/agents/multi-tenant-architect.md +281 -0
- package/kits/coder/agents/orchestrator.md +263 -0
- package/kits/coder/agents/performance-analyst.md +327 -0
- package/kits/coder/agents/project-planner.md +277 -0
- package/kits/coder/agents/queue-specialist.md +282 -0
- package/kits/coder/agents/realtime-specialist.md +267 -0
- package/kits/coder/agents/security-auditor.md +253 -0
- package/kits/coder/agents/test-engineer.md +315 -0
- package/kits/coder/agents/ux-researcher.md +388 -0
- package/kits/coder/rules/.cursorrules +287 -0
- package/kits/coder/rules/CLAUDE.md +287 -0
- package/kits/coder/rules/CODEX.md +287 -0
- package/kits/coder/rules/GEMINI.md +287 -0
- package/kits/coder/scripts/checklist.py +318 -0
- package/kits/coder/scripts/kit_status.py +292 -0
- package/kits/coder/scripts/skills_manager.py +243 -0
- package/kits/coder/scripts/verify_all.py +391 -0
- package/kits/coder/skills/accessibility-patterns/SKILL.md +372 -0
- package/kits/coder/skills/accessibility-patterns/scripts/a11y_checker.py +211 -0
- package/kits/coder/skills/ai-rag-patterns/SKILL.md +444 -0
- package/kits/coder/skills/api-patterns/SKILL.md +316 -0
- package/kits/coder/skills/api-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/api-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/api-patterns/scripts/api_validator.py +253 -0
- package/kits/coder/skills/api-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/auth-patterns/SKILL.md +267 -0
- package/kits/coder/skills/aws-patterns/SKILL.md +576 -0
- package/kits/coder/skills/brainstorming/SKILL.md +370 -0
- package/kits/coder/skills/brainstorming/assets/.gitkeep +1 -0
- package/kits/coder/skills/brainstorming/references/deep-dive.md +21 -0
- package/kits/coder/skills/brainstorming/scripts/validate.py +56 -0
- package/kits/coder/skills/clean-code/SKILL.md +240 -0
- package/kits/coder/skills/clean-code/assets/.gitkeep +1 -0
- package/kits/coder/skills/clean-code/references/deep-dive.md +21 -0
- package/kits/coder/skills/clean-code/scripts/lint_runner.py +186 -0
- package/kits/coder/skills/clean-code/scripts/validate.py +56 -0
- package/kits/coder/skills/database-design/SKILL.md +255 -0
- package/kits/coder/skills/database-design/assets/.gitkeep +1 -0
- package/kits/coder/skills/database-design/references/deep-dive.md +21 -0
- package/kits/coder/skills/database-design/scripts/schema_validator.py +272 -0
- package/kits/coder/skills/database-design/scripts/validate.py +56 -0
- package/kits/coder/skills/docker-patterns/SKILL.md +240 -0
- package/kits/coder/skills/documentation-templates/SKILL.md +441 -0
- package/kits/coder/skills/e2e-testing/SKILL.md +457 -0
- package/kits/coder/skills/flutter-patterns/SKILL.md +330 -0
- package/kits/coder/skills/frontend-design/SKILL.md +127 -0
- package/kits/coder/skills/github-actions/SKILL.md +349 -0
- package/kits/coder/skills/gitlab-ci-patterns/SKILL.md +466 -0
- package/kits/coder/skills/graphql-patterns/SKILL.md +558 -0
- package/kits/coder/skills/i18n-localization/SKILL.md +345 -0
- package/kits/coder/skills/i18n-localization/scripts/i18n_checker.py +267 -0
- package/kits/coder/skills/kubernetes-patterns/SKILL.md +357 -0
- package/kits/coder/skills/mermaid-diagrams/SKILL.md +351 -0
- package/kits/coder/skills/mobile-design/SKILL.md +305 -0
- package/kits/coder/skills/monitoring-observability/SKILL.md +458 -0
- package/kits/coder/skills/multi-tenancy/SKILL.md +317 -0
- package/kits/coder/skills/multi-tenancy/assets/.gitkeep +1 -0
- package/kits/coder/skills/multi-tenancy/references/deep-dive.md +21 -0
- package/kits/coder/skills/multi-tenancy/scripts/validate.py +56 -0
- package/kits/coder/skills/nodejs-best-practices/SKILL.md +220 -0
- package/kits/coder/skills/performance-profiling/SKILL.md +333 -0
- package/kits/coder/skills/performance-profiling/assets/.gitkeep +1 -0
- package/kits/coder/skills/performance-profiling/references/deep-dive.md +21 -0
- package/kits/coder/skills/performance-profiling/scripts/validate.py +56 -0
- package/kits/coder/skills/plan-writing/SKILL.md +360 -0
- package/kits/coder/skills/plan-writing/assets/.gitkeep +1 -0
- package/kits/coder/skills/plan-writing/references/deep-dive.md +21 -0
- package/kits/coder/skills/plan-writing/scripts/validate.py +56 -0
- package/kits/coder/skills/postgres-patterns/SKILL.md +361 -0
- package/kits/coder/skills/prompt-engineering/SKILL.md +277 -0
- package/kits/coder/skills/queue-patterns/SKILL.md +359 -0
- package/kits/coder/skills/queue-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/queue-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/queue-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/react-native-patterns/SKILL.md +393 -0
- package/kits/coder/skills/react-patterns/SKILL.md +319 -0
- package/kits/coder/skills/realtime-patterns/SKILL.md +506 -0
- package/kits/coder/skills/realtime-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/realtime-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/realtime-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/redis-patterns/SKILL.md +484 -0
- package/kits/coder/skills/security-fundamentals/SKILL.md +363 -0
- package/kits/coder/skills/security-fundamentals/assets/.gitkeep +1 -0
- package/kits/coder/skills/security-fundamentals/references/deep-dive.md +21 -0
- package/kits/coder/skills/security-fundamentals/scripts/security_scan.py +326 -0
- package/kits/coder/skills/security-fundamentals/scripts/validate.py +56 -0
- package/kits/coder/skills/seo-patterns/SKILL.md +262 -0
- package/kits/coder/skills/seo-patterns/scripts/seo_checker.py +211 -0
- package/kits/coder/skills/systematic-debugging/SKILL.md +478 -0
- package/kits/coder/skills/systematic-debugging/assets/.gitkeep +1 -0
- package/kits/coder/skills/systematic-debugging/references/deep-dive.md +21 -0
- package/kits/coder/skills/systematic-debugging/scripts/validate.py +56 -0
- package/kits/coder/skills/tailwind-patterns/SKILL.md +395 -0
- package/kits/coder/skills/terraform-patterns/SKILL.md +470 -0
- package/kits/coder/skills/testing-patterns/SKILL.md +285 -0
- package/kits/coder/skills/testing-patterns/assets/.gitkeep +1 -0
- package/kits/coder/skills/testing-patterns/references/deep-dive.md +21 -0
- package/kits/coder/skills/testing-patterns/scripts/test_runner.py +219 -0
- package/kits/coder/skills/testing-patterns/scripts/validate.py +56 -0
- package/kits/coder/skills/typescript-patterns/SKILL.md +417 -0
- package/kits/coder/skills/ui-ux-pro-max/SKILL.md +364 -0
- package/kits/coder/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/kits/coder/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/kits/coder/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/kits/coder/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/kits/coder/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/kits/coder/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/kits/coder/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/kits/coder/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/kits/coder/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/kits/coder/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/kits/coder/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/kits/coder/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/kits/coder/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/core.py +257 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/design_system.py +488 -0
- package/kits/coder/skills/ui-ux-pro-max/scripts/search.py +76 -0
- package/kits/coder/workflows/.gitkeep +20 -0
- package/kits/coder/workflows/create.md +152 -0
- package/kits/coder/workflows/debug.md +223 -0
- package/kits/coder/workflows/deploy.md +283 -0
- package/kits/coder/workflows/orchestrate.md +243 -0
- package/kits/coder/workflows/plan.md +134 -0
- package/kits/coder/workflows/test.md +237 -0
- package/kits/coder/workflows/ui-ux-pro-max.md +109 -0
- package/package.json +49 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-patterns
|
|
3
|
+
description: Testing patterns and principles. Unit, integration, mocking strategies. Use when writing tests, reviewing test coverage, or establishing testing conventions.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
|
+
version: 2.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Testing Patterns - Principles & Best Practices
|
|
9
|
+
|
|
10
|
+
> **Philosophy:** Tests are documentation. Write tests that explain behavior, not implementation.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Test Pyramid
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
/\ E2E (5-10%)
|
|
18
|
+
/ \ Critical user flows
|
|
19
|
+
/----\
|
|
20
|
+
/ \ Integration (20-30%)
|
|
21
|
+
/--------\ API, DB, services
|
|
22
|
+
/ \
|
|
23
|
+
/------------\ Unit (60-70%)
|
|
24
|
+
Functions, classes, logic
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Rule:** More tests at the base, fewer at the top. Fast, cheap, reliable tests first.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Test Type Selection
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
What are you testing?
|
|
35
|
+
ā
|
|
36
|
+
āā Pure function / business logic?
|
|
37
|
+
ā āā ā Unit test
|
|
38
|
+
ā
|
|
39
|
+
āā API endpoint / database query?
|
|
40
|
+
ā āā ā Integration test
|
|
41
|
+
ā
|
|
42
|
+
āā Critical user journey?
|
|
43
|
+
ā āā ā E2E test
|
|
44
|
+
ā
|
|
45
|
+
āā External service interaction?
|
|
46
|
+
ā āā ā Integration test with mocks
|
|
47
|
+
ā
|
|
48
|
+
āā UI component rendering?
|
|
49
|
+
āā ā Component test (unit-like)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## AAA Pattern (Arrange-Act-Assert)
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// ā
Clear AAA structure
|
|
58
|
+
describe("UserService", () => {
|
|
59
|
+
it("should return user by ID", async () => {
|
|
60
|
+
// Arrange
|
|
61
|
+
const userId = "123";
|
|
62
|
+
const expectedUser = { id: userId, name: "John" };
|
|
63
|
+
mockDb.users.findById.mockResolvedValue(expectedUser);
|
|
64
|
+
|
|
65
|
+
// Act
|
|
66
|
+
const result = await userService.getById(userId);
|
|
67
|
+
|
|
68
|
+
// Assert
|
|
69
|
+
expect(result).toEqual(expectedUser);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Unit Test Principles (FIRST)
|
|
77
|
+
|
|
78
|
+
| Principle | Meaning | Example |
|
|
79
|
+
| ------------------- | ------------------ | ------------------------ |
|
|
80
|
+
| **F**ast | < 100ms each | No I/O, no network |
|
|
81
|
+
| **I**solated | No dependencies | Mock external calls |
|
|
82
|
+
| **R**epeatable | Same result always | No random, no time |
|
|
83
|
+
| **S**elf-validating | Boolean pass/fail | No manual verification |
|
|
84
|
+
| **T**imely | Written with code | TDD or immediately after |
|
|
85
|
+
|
|
86
|
+
### What to Unit Test
|
|
87
|
+
|
|
88
|
+
| ā
Test | ā Don't Test |
|
|
89
|
+
| -------------- | ------------------------ |
|
|
90
|
+
| Business logic | Framework code |
|
|
91
|
+
| Edge cases | Third-party libraries |
|
|
92
|
+
| Error handling | Simple getters/setters |
|
|
93
|
+
| Calculations | Constructor-only classes |
|
|
94
|
+
| Validations | Private methods directly |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Integration Test Principles
|
|
99
|
+
|
|
100
|
+
### What to Integration Test
|
|
101
|
+
|
|
102
|
+
| Area | Focus | Example |
|
|
103
|
+
| ------------ | --------------------- | -------------------- |
|
|
104
|
+
| **API** | Request/Response | Correct status codes |
|
|
105
|
+
| **Database** | Queries, transactions | Data persistence |
|
|
106
|
+
| **Services** | Inter-service calls | Message passing |
|
|
107
|
+
| **Auth** | Token validation | Protected routes |
|
|
108
|
+
|
|
109
|
+
### Setup/Teardown Pattern
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
describe("UserAPI", () => {
|
|
113
|
+
beforeAll(async () => {
|
|
114
|
+
// Connect to test database
|
|
115
|
+
await db.connect();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
beforeEach(async () => {
|
|
119
|
+
// Reset state before each test
|
|
120
|
+
await db.clear();
|
|
121
|
+
await seedTestData();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
afterEach(async () => {
|
|
125
|
+
// Clean up test artifacts
|
|
126
|
+
await cleanupFiles();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
afterAll(async () => {
|
|
130
|
+
// Disconnect resources
|
|
131
|
+
await db.disconnect();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Mocking Strategy
|
|
139
|
+
|
|
140
|
+
### When to Mock
|
|
141
|
+
|
|
142
|
+
| ā
Mock | ā Don't Mock |
|
|
143
|
+
| ------------------------ | ------------------- |
|
|
144
|
+
| External APIs | Code under test |
|
|
145
|
+
| Database (in unit tests) | Simple dependencies |
|
|
146
|
+
| Time/Date | Pure functions |
|
|
147
|
+
| Network calls | In-memory stores |
|
|
148
|
+
| Third-party services | Internal modules |
|
|
149
|
+
|
|
150
|
+
### Mock Types
|
|
151
|
+
|
|
152
|
+
| Type | Purpose | Example |
|
|
153
|
+
| -------- | ---------------------------- | ---------------------------- |
|
|
154
|
+
| **Stub** | Return fixed values | `mockFn.mockReturnValue(42)` |
|
|
155
|
+
| **Spy** | Track calls without changing | `jest.spyOn(obj, 'method')` |
|
|
156
|
+
| **Mock** | Replace with expectations | `jest.fn()` |
|
|
157
|
+
| **Fake** | Simplified implementation | In-memory database |
|
|
158
|
+
|
|
159
|
+
### Mocking Decision Tree
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
Need to isolate from dependency?
|
|
163
|
+
āā Yes ā Is it external (API, DB)?
|
|
164
|
+
ā āā Yes ā Mock it
|
|
165
|
+
ā āā No ā Prefer real implementation
|
|
166
|
+
ā
|
|
167
|
+
āā No ā Use real dependency
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Test Data Strategies
|
|
173
|
+
|
|
174
|
+
| Strategy | Use Case | Example |
|
|
175
|
+
| ----------- | --------------------- | ----------------------------------------- |
|
|
176
|
+
| **Factory** | Generate varied data | `createUser({ name: 'John' })` |
|
|
177
|
+
| **Fixture** | Predefined datasets | JSON files |
|
|
178
|
+
| **Builder** | Fluent construction | `UserBuilder.default().withRole('admin')` |
|
|
179
|
+
| **Faker** | Random realistic data | `faker.person.fullName()` |
|
|
180
|
+
|
|
181
|
+
### Factory Pattern Example
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// factories/user.factory.ts
|
|
185
|
+
export const createUser = (overrides = {}) => ({
|
|
186
|
+
id: faker.string.uuid(),
|
|
187
|
+
name: faker.person.fullName(),
|
|
188
|
+
email: faker.internet.email(),
|
|
189
|
+
createdAt: new Date(),
|
|
190
|
+
...overrides,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Usage
|
|
194
|
+
const user = createUser({ role: "admin" });
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## TDD Workflow (Red-Green-Refactor)
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
āāāāāāāāāāā āāāāāāāāāāā āāāāāāāāāāāā
|
|
203
|
+
ā RED ā āāā ā GREEN ā āāā ā REFACTOR ā
|
|
204
|
+
ā Write ā ā Write ā ā Improve ā
|
|
205
|
+
ā failing ā ā minimal ā ā code ā
|
|
206
|
+
ā test ā ā code ā ā quality ā
|
|
207
|
+
āāāāāāāāāāā āāāāāāāāāāā āāāāāāāāāāāā
|
|
208
|
+
ā ā
|
|
209
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Test Naming Conventions
|
|
215
|
+
|
|
216
|
+
| Pattern | Example |
|
|
217
|
+
| --------------------------------- | ---------------------------------------- |
|
|
218
|
+
| **should_behavior** | `should returnErrorWhenUserNotFound` |
|
|
219
|
+
| **when_condition** | `whenUserIsNull_throwsError` |
|
|
220
|
+
| **given_when_then** | `givenValidInput_whenSubmit_thenSuccess` |
|
|
221
|
+
| **methodName_condition_expected** | `getUser_withInvalidId_returnsNull` |
|
|
222
|
+
|
|
223
|
+
**Rule:** Test names should describe behavior, not implementation.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Coverage Guidelines
|
|
228
|
+
|
|
229
|
+
| Level | Meaning |
|
|
230
|
+
| -------- | ----------------------------------- |
|
|
231
|
+
| **80%+** | Good coverage for most projects |
|
|
232
|
+
| **90%+** | High coverage, critical systems |
|
|
233
|
+
| **100%** | Often impractical, may waste effort |
|
|
234
|
+
|
|
235
|
+
### What to Cover
|
|
236
|
+
|
|
237
|
+
| Priority | Area |
|
|
238
|
+
| ---------- | ---------------------------- |
|
|
239
|
+
| **High** | Business logic, calculations |
|
|
240
|
+
| **Medium** | Error paths, edge cases |
|
|
241
|
+
| **Low** | Simple getters, boilerplate |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Anti-Patterns
|
|
246
|
+
|
|
247
|
+
| ā Don't | ā
Do |
|
|
248
|
+
| --------------------------- | -------------------------- |
|
|
249
|
+
| Test implementation details | Test behavior/outcomes |
|
|
250
|
+
| Duplicate test code | Use factories/helpers |
|
|
251
|
+
| Complex test setup | Simplify or split tests |
|
|
252
|
+
| Ignore flaky tests | Fix root cause immediately |
|
|
253
|
+
| Skip cleanup | Reset state every test |
|
|
254
|
+
| Test multiple things | One assertion per test |
|
|
255
|
+
| Hard-code test data | Use factories |
|
|
256
|
+
| Rely on test order | Make tests independent |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Testing Checklist
|
|
261
|
+
|
|
262
|
+
Before pushing code:
|
|
263
|
+
|
|
264
|
+
- [ ] All tests pass?
|
|
265
|
+
- [ ] Coverage meets threshold?
|
|
266
|
+
- [ ] Edge cases covered?
|
|
267
|
+
- [ ] Error paths tested?
|
|
268
|
+
- [ ] Tests are isolated?
|
|
269
|
+
- [ ] No flaky tests?
|
|
270
|
+
- [ ] Test names are descriptive?
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Related Skills
|
|
275
|
+
|
|
276
|
+
| Need | Skill |
|
|
277
|
+
| ------------------- | ----------------------- |
|
|
278
|
+
| Clean code | `clean-code` |
|
|
279
|
+
| API testing | `api-patterns` |
|
|
280
|
+
| E2E testing | `webapp-testing` |
|
|
281
|
+
| Performance testing | `performance-profiling` |
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
> **Remember:** If you can't understand what code does from its tests, rewrite the tests.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Assets directory - add templates, images, etc.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Reference Documentation for Testing Patterns
|
|
2
|
+
|
|
3
|
+
[TODO: Add detailed reference content here]
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
[Detailed explanation of concepts]
|
|
8
|
+
|
|
9
|
+
## Deep Dive Topics
|
|
10
|
+
|
|
11
|
+
### Topic 1
|
|
12
|
+
|
|
13
|
+
[Content]
|
|
14
|
+
|
|
15
|
+
### Topic 2
|
|
16
|
+
|
|
17
|
+
[Content]
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
[Real-world examples]
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test Runner - Unified test execution and coverage
|
|
4
|
+
==================================================
|
|
5
|
+
|
|
6
|
+
Auto-detects project type and runs appropriate test framework.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python .agent/skills/testing-patterns/scripts/test_runner.py <project_path>
|
|
10
|
+
python .agent/skills/testing-patterns/scripts/test_runner.py . --coverage
|
|
11
|
+
|
|
12
|
+
Supports:
|
|
13
|
+
- Node.js: npm test, jest, vitest
|
|
14
|
+
- Python: pytest, unittest
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
import json
|
|
20
|
+
import re
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
|
|
24
|
+
# Fix console encoding
|
|
25
|
+
try:
|
|
26
|
+
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
27
|
+
except:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def detect_test_framework(project_path: Path) -> dict:
|
|
32
|
+
"""Detect test framework and commands."""
|
|
33
|
+
result = {
|
|
34
|
+
"type": "unknown",
|
|
35
|
+
"framework": None,
|
|
36
|
+
"cmd": None,
|
|
37
|
+
"coverage_cmd": None
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Node.js project
|
|
41
|
+
package_json = project_path / "package.json"
|
|
42
|
+
if package_json.exists():
|
|
43
|
+
result["type"] = "node"
|
|
44
|
+
try:
|
|
45
|
+
pkg = json.loads(package_json.read_text(encoding='utf-8'))
|
|
46
|
+
scripts = pkg.get("scripts", {})
|
|
47
|
+
deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
|
|
48
|
+
|
|
49
|
+
if "test" in scripts:
|
|
50
|
+
result["framework"] = "npm test"
|
|
51
|
+
result["cmd"] = ["npm", "test"]
|
|
52
|
+
|
|
53
|
+
if "vitest" in deps:
|
|
54
|
+
result["framework"] = "vitest"
|
|
55
|
+
result["coverage_cmd"] = ["npx", "vitest", "run", "--coverage"]
|
|
56
|
+
elif "jest" in deps:
|
|
57
|
+
result["framework"] = "jest"
|
|
58
|
+
result["coverage_cmd"] = ["npx", "jest", "--coverage"]
|
|
59
|
+
elif "vitest" in deps:
|
|
60
|
+
result["framework"] = "vitest"
|
|
61
|
+
result["cmd"] = ["npx", "vitest", "run"]
|
|
62
|
+
result["coverage_cmd"] = ["npx", "vitest", "run", "--coverage"]
|
|
63
|
+
elif "jest" in deps:
|
|
64
|
+
result["framework"] = "jest"
|
|
65
|
+
result["cmd"] = ["npx", "jest"]
|
|
66
|
+
result["coverage_cmd"] = ["npx", "jest", "--coverage"]
|
|
67
|
+
|
|
68
|
+
except:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
# Python project
|
|
72
|
+
if (project_path / "pyproject.toml").exists() or (project_path / "requirements.txt").exists():
|
|
73
|
+
result["type"] = "python"
|
|
74
|
+
result["framework"] = "pytest"
|
|
75
|
+
result["cmd"] = ["python", "-m", "pytest", "-v"]
|
|
76
|
+
result["coverage_cmd"] = ["python", "-m", "pytest", "--cov", "--cov-report=term-missing"]
|
|
77
|
+
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def run_tests(cmd: list, cwd: Path) -> dict:
|
|
82
|
+
"""Run tests and return results."""
|
|
83
|
+
result = {
|
|
84
|
+
"passed": False,
|
|
85
|
+
"output": "",
|
|
86
|
+
"error": "",
|
|
87
|
+
"tests_run": 0,
|
|
88
|
+
"tests_passed": 0,
|
|
89
|
+
"tests_failed": 0
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
proc = subprocess.run(
|
|
94
|
+
cmd,
|
|
95
|
+
cwd=str(cwd),
|
|
96
|
+
capture_output=True,
|
|
97
|
+
text=True,
|
|
98
|
+
encoding='utf-8',
|
|
99
|
+
errors='replace',
|
|
100
|
+
timeout=300 # 5 min timeout
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
result["output"] = proc.stdout[:3000] if proc.stdout else ""
|
|
104
|
+
result["error"] = proc.stderr[:500] if proc.stderr else ""
|
|
105
|
+
result["passed"] = proc.returncode == 0
|
|
106
|
+
|
|
107
|
+
# Parse test counts
|
|
108
|
+
output = proc.stdout or ""
|
|
109
|
+
|
|
110
|
+
# Jest/Vitest pattern
|
|
111
|
+
if "passed" in output.lower() and "failed" in output.lower():
|
|
112
|
+
match = re.search(r'(\d+)\s+passed', output, re.IGNORECASE)
|
|
113
|
+
if match:
|
|
114
|
+
result["tests_passed"] = int(match.group(1))
|
|
115
|
+
match = re.search(r'(\d+)\s+failed', output, re.IGNORECASE)
|
|
116
|
+
if match:
|
|
117
|
+
result["tests_failed"] = int(match.group(1))
|
|
118
|
+
result["tests_run"] = result["tests_passed"] + result["tests_failed"]
|
|
119
|
+
|
|
120
|
+
# Pytest pattern
|
|
121
|
+
if "pytest" in str(cmd):
|
|
122
|
+
match = re.search(r'(\d+)\s+passed', output)
|
|
123
|
+
if match:
|
|
124
|
+
result["tests_passed"] = int(match.group(1))
|
|
125
|
+
match = re.search(r'(\d+)\s+failed', output)
|
|
126
|
+
if match:
|
|
127
|
+
result["tests_failed"] = int(match.group(1))
|
|
128
|
+
result["tests_run"] = result["tests_passed"] + result["tests_failed"]
|
|
129
|
+
|
|
130
|
+
except FileNotFoundError:
|
|
131
|
+
result["error"] = f"Command not found: {cmd[0]}"
|
|
132
|
+
except subprocess.TimeoutExpired:
|
|
133
|
+
result["error"] = "Timeout after 300s"
|
|
134
|
+
except Exception as e:
|
|
135
|
+
result["error"] = str(e)
|
|
136
|
+
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def main():
|
|
141
|
+
project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
|
|
142
|
+
with_coverage = "--coverage" in sys.argv
|
|
143
|
+
|
|
144
|
+
print(f"\n{'='*60}")
|
|
145
|
+
print(f"[AGT-KIT TEST RUNNER] Test Execution")
|
|
146
|
+
print(f"{'='*60}")
|
|
147
|
+
print(f"Project: {project_path}")
|
|
148
|
+
print(f"Coverage: {'enabled' if with_coverage else 'disabled'}")
|
|
149
|
+
print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
150
|
+
|
|
151
|
+
# Detect framework
|
|
152
|
+
test_info = detect_test_framework(project_path)
|
|
153
|
+
print(f"Type: {test_info['type']}")
|
|
154
|
+
print(f"Framework: {test_info['framework']}")
|
|
155
|
+
print("-"*60)
|
|
156
|
+
|
|
157
|
+
if not test_info["cmd"]:
|
|
158
|
+
print("No test framework found.")
|
|
159
|
+
output = {
|
|
160
|
+
"script": "test_runner",
|
|
161
|
+
"skill": "testing-patterns",
|
|
162
|
+
"project": str(project_path),
|
|
163
|
+
"type": test_info["type"],
|
|
164
|
+
"framework": None,
|
|
165
|
+
"passed": True,
|
|
166
|
+
"message": "No tests configured"
|
|
167
|
+
}
|
|
168
|
+
print(json.dumps(output, indent=2))
|
|
169
|
+
sys.exit(0)
|
|
170
|
+
|
|
171
|
+
# Run tests
|
|
172
|
+
cmd = test_info["coverage_cmd"] if with_coverage and test_info["coverage_cmd"] else test_info["cmd"]
|
|
173
|
+
print(f"Running: {' '.join(cmd)}")
|
|
174
|
+
print("-"*60)
|
|
175
|
+
|
|
176
|
+
result = run_tests(cmd, project_path)
|
|
177
|
+
|
|
178
|
+
# Print output
|
|
179
|
+
if result["output"]:
|
|
180
|
+
lines = result["output"].split("\n")
|
|
181
|
+
for line in lines[:30]:
|
|
182
|
+
print(line)
|
|
183
|
+
if len(lines) > 30:
|
|
184
|
+
print(f"... ({len(lines) - 30} more lines)")
|
|
185
|
+
|
|
186
|
+
# Summary
|
|
187
|
+
print("\n" + "="*60)
|
|
188
|
+
print("SUMMARY")
|
|
189
|
+
print("="*60)
|
|
190
|
+
|
|
191
|
+
if result["passed"]:
|
|
192
|
+
print("ā
All tests passed")
|
|
193
|
+
else:
|
|
194
|
+
print("ā Some tests failed")
|
|
195
|
+
if result["error"]:
|
|
196
|
+
print(f"Error: {result['error'][:200]}")
|
|
197
|
+
|
|
198
|
+
if result["tests_run"] > 0:
|
|
199
|
+
print(f"Tests: {result['tests_run']} total, {result['tests_passed']} passed, {result['tests_failed']} failed")
|
|
200
|
+
|
|
201
|
+
output = {
|
|
202
|
+
"script": "test_runner",
|
|
203
|
+
"skill": "testing-patterns",
|
|
204
|
+
"project": str(project_path),
|
|
205
|
+
"type": test_info["type"],
|
|
206
|
+
"framework": test_info["framework"],
|
|
207
|
+
"tests_run": result["tests_run"],
|
|
208
|
+
"tests_passed": result["tests_passed"],
|
|
209
|
+
"tests_failed": result["tests_failed"],
|
|
210
|
+
"passed": result["passed"]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
print("\n" + json.dumps(output, indent=2))
|
|
214
|
+
|
|
215
|
+
sys.exit(0 if result["passed"] else 1)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
if __name__ == "__main__":
|
|
219
|
+
main()
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example validator for testing-patterns
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python validate.py <project_path>
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate(project_path: str) -> dict:
|
|
14
|
+
"""Main validation logic"""
|
|
15
|
+
results = {
|
|
16
|
+
'errors': [],
|
|
17
|
+
'warnings': [],
|
|
18
|
+
'passed': []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# TODO: Add validation logic
|
|
22
|
+
results['passed'].append('Placeholder validation passed')
|
|
23
|
+
|
|
24
|
+
return results
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_results(results: dict):
|
|
28
|
+
"""Pretty print results"""
|
|
29
|
+
print("\nš Validation Results\n")
|
|
30
|
+
|
|
31
|
+
if results['errors']:
|
|
32
|
+
print(f"ā Errors ({len(results['errors'])})")
|
|
33
|
+
for error in results['errors']:
|
|
34
|
+
print(f" - {error}")
|
|
35
|
+
|
|
36
|
+
if results['warnings']:
|
|
37
|
+
print(f"\nā ļø Warnings ({len(results['warnings'])})")
|
|
38
|
+
for warning in results['warnings']:
|
|
39
|
+
print(f" - {warning}")
|
|
40
|
+
|
|
41
|
+
if results['passed']:
|
|
42
|
+
print(f"\nā
Passed ({len(results['passed'])})")
|
|
43
|
+
for passed in results['passed']:
|
|
44
|
+
print(f" - {passed}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
if len(sys.argv) < 2:
|
|
49
|
+
print("Usage: python validate.py <project_path>")
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
project_path = sys.argv[1]
|
|
53
|
+
results = validate(project_path)
|
|
54
|
+
print_results(results)
|
|
55
|
+
|
|
56
|
+
sys.exit(1 if results['errors'] else 0)
|