@qazuor/claude-code-config 0.5.0 → 0.6.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/README.md +106 -41
- package/dist/bin.cjs +963 -84
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +963 -84
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +73 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +73 -56
- package/dist/index.js.map +1 -1
- package/package.json +23 -24
- package/templates/CLAUDE.md.template +60 -5
- package/templates/agents/README.md +58 -39
- package/templates/agents/_registry.json +43 -202
- package/templates/agents/engineering/{hono-engineer.md → api-engineer.md} +61 -70
- package/templates/agents/engineering/database-engineer.md +253 -0
- package/templates/agents/engineering/frontend-engineer.md +302 -0
- package/templates/hooks/on-notification.sh +0 -0
- package/templates/scripts/add-changelogs.sh +0 -0
- package/templates/scripts/generate-code-registry.ts +0 -0
- package/templates/scripts/health-check.sh +0 -0
- package/templates/scripts/sync-registry.sh +0 -0
- package/templates/scripts/telemetry-report.ts +0 -0
- package/templates/scripts/validate-docs.sh +0 -0
- package/templates/scripts/validate-registry.sh +0 -0
- package/templates/scripts/validate-structure.sh +0 -0
- package/templates/scripts/worktree-cleanup.sh +0 -0
- package/templates/scripts/worktree-create.sh +0 -0
- package/templates/skills/README.md +99 -90
- package/templates/skills/_registry.json +323 -16
- package/templates/skills/api-frameworks/express-patterns.md +411 -0
- package/templates/skills/api-frameworks/fastify-patterns.md +419 -0
- package/templates/skills/api-frameworks/hono-patterns.md +388 -0
- package/templates/skills/api-frameworks/nestjs-patterns.md +497 -0
- package/templates/skills/database/drizzle-patterns.md +449 -0
- package/templates/skills/database/mongoose-patterns.md +503 -0
- package/templates/skills/database/prisma-patterns.md +487 -0
- package/templates/skills/frontend-frameworks/astro-patterns.md +415 -0
- package/templates/skills/frontend-frameworks/nextjs-patterns.md +470 -0
- package/templates/skills/frontend-frameworks/react-patterns.md +516 -0
- package/templates/skills/frontend-frameworks/tanstack-start-patterns.md +469 -0
- package/templates/skills/patterns/atdd-methodology.md +364 -0
- package/templates/skills/patterns/bdd-methodology.md +281 -0
- package/templates/skills/patterns/clean-architecture.md +444 -0
- package/templates/skills/patterns/hexagonal-architecture.md +567 -0
- package/templates/skills/patterns/vertical-slice-architecture.md +502 -0
- package/templates/agents/engineering/astro-engineer.md +0 -293
- package/templates/agents/engineering/db-drizzle-engineer.md +0 -360
- package/templates/agents/engineering/express-engineer.md +0 -316
- package/templates/agents/engineering/fastify-engineer.md +0 -399
- package/templates/agents/engineering/mongoose-engineer.md +0 -473
- package/templates/agents/engineering/nestjs-engineer.md +0 -429
- package/templates/agents/engineering/nextjs-engineer.md +0 -451
- package/templates/agents/engineering/prisma-engineer.md +0 -432
- package/templates/agents/engineering/react-senior-dev.md +0 -394
- package/templates/agents/engineering/tanstack-start-engineer.md +0 -447
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atdd-methodology
|
|
3
|
+
category: patterns
|
|
4
|
+
description: Acceptance Test-Driven Development focusing on user acceptance criteria before implementation
|
|
5
|
+
usage: Use when acceptance criteria must be verified and stakeholder sign-off is required
|
|
6
|
+
input: User stories with acceptance criteria, business requirements
|
|
7
|
+
output: Automated acceptance tests, validated features meeting business requirements
|
|
8
|
+
config_required:
|
|
9
|
+
- TEST_FRAMEWORK: "Acceptance test framework (e.g., Playwright, Cypress, TestCafe)"
|
|
10
|
+
- ACCEPTANCE_DIR: "Directory for acceptance tests (e.g., tests/acceptance/)"
|
|
11
|
+
- BASE_URL: "Application base URL for testing"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# ATDD Methodology
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
Acceptance Test-Driven Development (ATDD) is a practice where the whole team collaboratively discusses acceptance criteria and creates acceptance tests before development begins, ensuring features meet business requirements.
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
| Setting | Description | Example |
|
|
23
|
+
|---------|-------------|---------|
|
|
24
|
+
| TEST_FRAMEWORK | E2E framework | `Playwright`, `Cypress`, `TestCafe` |
|
|
25
|
+
| ACCEPTANCE_DIR | Test location | `tests/acceptance/`, `e2e/` |
|
|
26
|
+
| BASE_URL | App URL | `http://localhost:3000` |
|
|
27
|
+
| REPORT_DIR | Reports output | `reports/acceptance/` |
|
|
28
|
+
|
|
29
|
+
## The ATDD Cycle
|
|
30
|
+
|
|
31
|
+
### Discuss → Distill → Develop → Demo
|
|
32
|
+
|
|
33
|
+
1. **Discuss**: Team discusses user story and acceptance criteria
|
|
34
|
+
2. **Distill**: Write concrete acceptance tests from criteria
|
|
35
|
+
3. **Develop**: Implement feature until tests pass
|
|
36
|
+
4. **Demo**: Demonstrate passing tests to stakeholders
|
|
37
|
+
|
|
38
|
+
## Workflow
|
|
39
|
+
|
|
40
|
+
### 1. Discuss - Define Acceptance Criteria
|
|
41
|
+
|
|
42
|
+
**Participants**: Product Owner, Developers, QA
|
|
43
|
+
|
|
44
|
+
**User Story Format:**
|
|
45
|
+
```
|
|
46
|
+
As a [role]
|
|
47
|
+
I want [feature]
|
|
48
|
+
So that [benefit]
|
|
49
|
+
|
|
50
|
+
Acceptance Criteria:
|
|
51
|
+
- [ ] Criterion 1
|
|
52
|
+
- [ ] Criterion 2
|
|
53
|
+
- [ ] Criterion 3
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Example:**
|
|
57
|
+
```markdown
|
|
58
|
+
## User Story: Password Reset
|
|
59
|
+
|
|
60
|
+
As a registered user
|
|
61
|
+
I want to reset my forgotten password
|
|
62
|
+
So that I can regain access to my account
|
|
63
|
+
|
|
64
|
+
### Acceptance Criteria:
|
|
65
|
+
- [ ] User can request password reset from login page
|
|
66
|
+
- [ ] System sends reset email within 5 minutes
|
|
67
|
+
- [ ] Reset link expires after 24 hours
|
|
68
|
+
- [ ] User can set new password with link
|
|
69
|
+
- [ ] Old password no longer works after reset
|
|
70
|
+
- [ ] User receives confirmation of password change
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Distill - Write Acceptance Tests
|
|
74
|
+
|
|
75
|
+
**Transform criteria into executable tests:**
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// tests/acceptance/password-reset.spec.ts
|
|
79
|
+
import { test, expect } from '@playwright/test';
|
|
80
|
+
import { MailboxHelper } from '../helpers/mailbox';
|
|
81
|
+
|
|
82
|
+
test.describe('Password Reset', () => {
|
|
83
|
+
test.describe('Request Reset', () => {
|
|
84
|
+
test('user can request password reset from login page', async ({ page }) => {
|
|
85
|
+
// Arrange
|
|
86
|
+
await page.goto('/login');
|
|
87
|
+
|
|
88
|
+
// Act
|
|
89
|
+
await page.click('text=Forgot password?');
|
|
90
|
+
await page.fill('[name="email"]', 'user@example.com');
|
|
91
|
+
await page.click('button:has-text("Send reset link")');
|
|
92
|
+
|
|
93
|
+
// Assert
|
|
94
|
+
await expect(page.locator('.success-message')).toContainText(
|
|
95
|
+
'Reset link sent'
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('system sends reset email within 5 minutes', async ({ page }) => {
|
|
100
|
+
const mailbox = new MailboxHelper();
|
|
101
|
+
const email = `test-${Date.now()}@example.com`;
|
|
102
|
+
|
|
103
|
+
// Create user and request reset
|
|
104
|
+
await createTestUser(email);
|
|
105
|
+
await page.goto('/forgot-password');
|
|
106
|
+
await page.fill('[name="email"]', email);
|
|
107
|
+
await page.click('button:has-text("Send reset link")');
|
|
108
|
+
|
|
109
|
+
// Wait for email (max 5 minutes = 300000ms)
|
|
110
|
+
const resetEmail = await mailbox.waitForEmail(email, {
|
|
111
|
+
subject: 'Password Reset',
|
|
112
|
+
timeout: 300000
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(resetEmail).toBeDefined();
|
|
116
|
+
expect(resetEmail.receivedAt).toBeLessThan(Date.now());
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test.describe('Reset Link', () => {
|
|
121
|
+
test('reset link expires after 24 hours', async ({ page }) => {
|
|
122
|
+
// Create expired reset token (25 hours old)
|
|
123
|
+
const expiredToken = await createResetToken({
|
|
124
|
+
email: 'user@example.com',
|
|
125
|
+
createdAt: new Date(Date.now() - 25 * 60 * 60 * 1000)
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await page.goto(`/reset-password?token=${expiredToken}`);
|
|
129
|
+
|
|
130
|
+
await expect(page.locator('.error-message')).toContainText(
|
|
131
|
+
'Reset link has expired'
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('user can set new password with valid link', async ({ page }) => {
|
|
136
|
+
const token = await createResetToken({ email: 'user@example.com' });
|
|
137
|
+
|
|
138
|
+
await page.goto(`/reset-password?token=${token}`);
|
|
139
|
+
await page.fill('[name="password"]', 'NewSecurePass123!');
|
|
140
|
+
await page.fill('[name="confirmPassword"]', 'NewSecurePass123!');
|
|
141
|
+
await page.click('button:has-text("Reset Password")');
|
|
142
|
+
|
|
143
|
+
await expect(page).toHaveURL('/login');
|
|
144
|
+
await expect(page.locator('.success-message')).toContainText(
|
|
145
|
+
'Password reset successful'
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test.describe('Post-Reset Behavior', () => {
|
|
151
|
+
test('old password no longer works after reset', async ({ page }) => {
|
|
152
|
+
// Reset password first
|
|
153
|
+
await resetUserPassword('user@example.com', 'NewPassword123!');
|
|
154
|
+
|
|
155
|
+
// Try login with old password
|
|
156
|
+
await page.goto('/login');
|
|
157
|
+
await page.fill('[name="email"]', 'user@example.com');
|
|
158
|
+
await page.fill('[name="password"]', 'OldPassword123!');
|
|
159
|
+
await page.click('button:has-text("Login")');
|
|
160
|
+
|
|
161
|
+
await expect(page.locator('.error-message')).toContainText(
|
|
162
|
+
'Invalid credentials'
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('user receives confirmation of password change', async ({ page }) => {
|
|
167
|
+
const mailbox = new MailboxHelper();
|
|
168
|
+
const email = 'user@example.com';
|
|
169
|
+
|
|
170
|
+
await resetUserPassword(email, 'NewPassword123!');
|
|
171
|
+
|
|
172
|
+
const confirmationEmail = await mailbox.waitForEmail(email, {
|
|
173
|
+
subject: 'Password Changed'
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(confirmationEmail).toBeDefined();
|
|
177
|
+
expect(confirmationEmail.body).toContain('password was changed');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 3. Develop - Implement Feature
|
|
184
|
+
|
|
185
|
+
**Run acceptance tests continuously:**
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Watch mode during development
|
|
189
|
+
npx playwright test --watch
|
|
190
|
+
|
|
191
|
+
# Run specific test file
|
|
192
|
+
npx playwright test tests/acceptance/password-reset.spec.ts
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Implementation Order:**
|
|
196
|
+
1. Run tests - all should fail (RED)
|
|
197
|
+
2. Implement first criterion
|
|
198
|
+
3. Run tests - first should pass
|
|
199
|
+
4. Implement next criterion
|
|
200
|
+
5. Repeat until all tests pass (GREEN)
|
|
201
|
+
|
|
202
|
+
### 4. Demo - Demonstrate to Stakeholders
|
|
203
|
+
|
|
204
|
+
**Demo Checklist:**
|
|
205
|
+
- [ ] Show all acceptance tests passing
|
|
206
|
+
- [ ] Walk through each criterion
|
|
207
|
+
- [ ] Demonstrate actual feature behavior
|
|
208
|
+
- [ ] Get stakeholder sign-off
|
|
209
|
+
- [ ] Document any feedback
|
|
210
|
+
|
|
211
|
+
## Test Structure
|
|
212
|
+
|
|
213
|
+
### Page Object Pattern
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// pages/LoginPage.ts
|
|
217
|
+
export class LoginPage {
|
|
218
|
+
constructor(private page: Page) {}
|
|
219
|
+
|
|
220
|
+
async goto() {
|
|
221
|
+
await this.page.goto('/login');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async login(email: string, password: string) {
|
|
225
|
+
await this.page.fill('[name="email"]', email);
|
|
226
|
+
await this.page.fill('[name="password"]', password);
|
|
227
|
+
await this.page.click('button:has-text("Login")');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async clickForgotPassword() {
|
|
231
|
+
await this.page.click('text=Forgot password?');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async getErrorMessage() {
|
|
235
|
+
return this.page.locator('.error-message').textContent();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Usage in tests
|
|
240
|
+
test('login with invalid credentials shows error', async ({ page }) => {
|
|
241
|
+
const loginPage = new LoginPage(page);
|
|
242
|
+
|
|
243
|
+
await loginPage.goto();
|
|
244
|
+
await loginPage.login('user@example.com', 'wrongpassword');
|
|
245
|
+
|
|
246
|
+
const error = await loginPage.getErrorMessage();
|
|
247
|
+
expect(error).toContain('Invalid credentials');
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Test Data Management
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// helpers/test-data.ts
|
|
255
|
+
export class TestDataManager {
|
|
256
|
+
private createdUsers: string[] = [];
|
|
257
|
+
private createdTokens: string[] = [];
|
|
258
|
+
|
|
259
|
+
async createUser(data: CreateUserData): Promise<User> {
|
|
260
|
+
const user = await db.users.create({ data });
|
|
261
|
+
this.createdUsers.push(user.id);
|
|
262
|
+
return user;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async createResetToken(email: string): Promise<string> {
|
|
266
|
+
const token = generateToken();
|
|
267
|
+
await db.resetTokens.create({
|
|
268
|
+
data: { email, token, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) }
|
|
269
|
+
});
|
|
270
|
+
this.createdTokens.push(token);
|
|
271
|
+
return token;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async cleanup() {
|
|
275
|
+
await db.resetTokens.deleteMany({
|
|
276
|
+
where: { token: { in: this.createdTokens } }
|
|
277
|
+
});
|
|
278
|
+
await db.users.deleteMany({
|
|
279
|
+
where: { id: { in: this.createdUsers } }
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Project Structure
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
project/
|
|
289
|
+
├── tests/
|
|
290
|
+
│ ├── acceptance/
|
|
291
|
+
│ │ ├── auth/
|
|
292
|
+
│ │ │ ├── login.spec.ts
|
|
293
|
+
│ │ │ ├── logout.spec.ts
|
|
294
|
+
│ │ │ └── password-reset.spec.ts
|
|
295
|
+
│ │ ├── checkout/
|
|
296
|
+
│ │ │ ├── cart.spec.ts
|
|
297
|
+
│ │ │ └── payment.spec.ts
|
|
298
|
+
│ │ └── fixtures/
|
|
299
|
+
│ │ └── test-data.json
|
|
300
|
+
│ ├── pages/
|
|
301
|
+
│ │ ├── LoginPage.ts
|
|
302
|
+
│ │ └── CheckoutPage.ts
|
|
303
|
+
│ └── helpers/
|
|
304
|
+
│ ├── test-data.ts
|
|
305
|
+
│ └── mailbox.ts
|
|
306
|
+
├── playwright.config.ts
|
|
307
|
+
└── package.json
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## ATDD vs TDD vs BDD
|
|
311
|
+
|
|
312
|
+
| Aspect | ATDD | TDD | BDD |
|
|
313
|
+
|--------|------|-----|-----|
|
|
314
|
+
| Focus | Acceptance criteria | Unit behavior | Business behavior |
|
|
315
|
+
| Level | System/E2E | Unit/Integration | Feature |
|
|
316
|
+
| Audience | Stakeholders | Developers | All team |
|
|
317
|
+
| Tests | Acceptance tests | Unit tests | Gherkin scenarios |
|
|
318
|
+
| When | Before implementation | During implementation | Before implementation |
|
|
319
|
+
| Sign-off | Required | Not required | Collaborative |
|
|
320
|
+
|
|
321
|
+
## Best Practices
|
|
322
|
+
|
|
323
|
+
### Do's
|
|
324
|
+
- Write acceptance tests before coding
|
|
325
|
+
- Include stakeholders in criteria discussion
|
|
326
|
+
- Keep tests focused on user-visible behavior
|
|
327
|
+
- Use clear, business-language test names
|
|
328
|
+
- Maintain test independence
|
|
329
|
+
|
|
330
|
+
### Don'ts
|
|
331
|
+
- Don't test implementation details
|
|
332
|
+
- Don't skip the discussion phase
|
|
333
|
+
- Don't write tests after implementation
|
|
334
|
+
- Don't make tests dependent on each other
|
|
335
|
+
- Don't ignore flaky tests
|
|
336
|
+
|
|
337
|
+
## When to Use ATDD
|
|
338
|
+
|
|
339
|
+
**Good for:**
|
|
340
|
+
- Features requiring stakeholder approval
|
|
341
|
+
- Complex business workflows
|
|
342
|
+
- Regulatory/compliance requirements
|
|
343
|
+
- Critical user journeys
|
|
344
|
+
- Customer-facing features
|
|
345
|
+
|
|
346
|
+
**Less suitable for:**
|
|
347
|
+
- Internal tools
|
|
348
|
+
- Technical refactoring
|
|
349
|
+
- Infrastructure changes
|
|
350
|
+
- Rapid prototyping
|
|
351
|
+
|
|
352
|
+
## Output
|
|
353
|
+
|
|
354
|
+
**Produces:**
|
|
355
|
+
- Acceptance test suite aligned with criteria
|
|
356
|
+
- Feature implementation meeting requirements
|
|
357
|
+
- Stakeholder demonstration and sign-off
|
|
358
|
+
- Documentation of accepted behavior
|
|
359
|
+
|
|
360
|
+
**Success Criteria:**
|
|
361
|
+
- All acceptance tests passing
|
|
362
|
+
- Stakeholder approval obtained
|
|
363
|
+
- Acceptance criteria fully covered
|
|
364
|
+
- Feature deployed and verified
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bdd-methodology
|
|
3
|
+
category: patterns
|
|
4
|
+
description: Behavior-Driven Development using Gherkin syntax and collaborative specification
|
|
5
|
+
usage: Use when business stakeholders need to understand tests and behavior specifications
|
|
6
|
+
input: User stories, business requirements, acceptance criteria in natural language
|
|
7
|
+
output: Executable specifications with Given-When-Then scenarios, living documentation
|
|
8
|
+
config_required:
|
|
9
|
+
- TEST_FRAMEWORK: "BDD test framework (e.g., Cucumber, Playwright BDD, Vitest-cucumber)"
|
|
10
|
+
- FEATURE_DIR: "Directory for feature files (e.g., features/)"
|
|
11
|
+
- STEP_DEFINITIONS_DIR: "Directory for step definitions (e.g., steps/)"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# BDD Methodology
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
Behavior-Driven Development (BDD) is a collaborative approach that bridges the gap between technical and non-technical stakeholders through shared language and executable specifications.
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
| Setting | Description | Example |
|
|
23
|
+
|---------|-------------|---------|
|
|
24
|
+
| TEST_FRAMEWORK | BDD framework | `Cucumber`, `Playwright BDD`, `Vitest-cucumber` |
|
|
25
|
+
| FEATURE_DIR | Feature files location | `features/`, `specs/` |
|
|
26
|
+
| STEP_DEFINITIONS_DIR | Step definitions | `steps/`, `step-definitions/` |
|
|
27
|
+
| REPORT_FORMAT | Report output | `html`, `json`, `junit` |
|
|
28
|
+
|
|
29
|
+
## The BDD Cycle
|
|
30
|
+
|
|
31
|
+
### Discovery → Formulation → Automation
|
|
32
|
+
|
|
33
|
+
1. **Discovery**: Collaborate to understand behavior
|
|
34
|
+
2. **Formulation**: Write scenarios in Gherkin
|
|
35
|
+
3. **Automation**: Implement step definitions
|
|
36
|
+
|
|
37
|
+
## Gherkin Syntax
|
|
38
|
+
|
|
39
|
+
### Feature Files
|
|
40
|
+
|
|
41
|
+
```gherkin
|
|
42
|
+
# features/user-registration.feature
|
|
43
|
+
Feature: User Registration
|
|
44
|
+
As a new visitor
|
|
45
|
+
I want to create an account
|
|
46
|
+
So that I can access member features
|
|
47
|
+
|
|
48
|
+
Background:
|
|
49
|
+
Given the registration page is open
|
|
50
|
+
|
|
51
|
+
Scenario: Successful registration with valid data
|
|
52
|
+
Given I am on the registration page
|
|
53
|
+
When I fill in "email" with "user@example.com"
|
|
54
|
+
And I fill in "password" with "SecurePass123!"
|
|
55
|
+
And I fill in "confirm_password" with "SecurePass123!"
|
|
56
|
+
And I click the "Register" button
|
|
57
|
+
Then I should see "Registration successful"
|
|
58
|
+
And I should receive a confirmation email
|
|
59
|
+
|
|
60
|
+
Scenario: Registration fails with existing email
|
|
61
|
+
Given a user exists with email "existing@example.com"
|
|
62
|
+
When I fill in "email" with "existing@example.com"
|
|
63
|
+
And I fill in "password" with "SecurePass123!"
|
|
64
|
+
And I click the "Register" button
|
|
65
|
+
Then I should see "Email already registered"
|
|
66
|
+
|
|
67
|
+
Scenario Outline: Registration validation
|
|
68
|
+
When I fill in "email" with "<email>"
|
|
69
|
+
And I fill in "password" with "<password>"
|
|
70
|
+
And I click the "Register" button
|
|
71
|
+
Then I should see "<error_message>"
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
| email | password | error_message |
|
|
75
|
+
| invalid-email | Pass123! | Invalid email format |
|
|
76
|
+
| user@test.com | short | Password too short |
|
|
77
|
+
| user@test.com | nodigits | Password needs a number |
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step Definitions
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// steps/registration.steps.ts
|
|
84
|
+
import { Given, When, Then } from '@cucumber/cucumber';
|
|
85
|
+
import { expect } from '@playwright/test';
|
|
86
|
+
|
|
87
|
+
Given('the registration page is open', async function () {
|
|
88
|
+
await this.page.goto('/register');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
Given('I am on the registration page', async function () {
|
|
92
|
+
await expect(this.page).toHaveURL('/register');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
Given('a user exists with email {string}', async function (email: string) {
|
|
96
|
+
await this.db.users.create({
|
|
97
|
+
data: { email, password: 'hashed-password' }
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
When('I fill in {string} with {string}', async function (field: string, value: string) {
|
|
102
|
+
await this.page.locator(`[name="${field}"]`).fill(value);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
When('I click the {string} button', async function (buttonText: string) {
|
|
106
|
+
await this.page.getByRole('button', { name: buttonText }).click();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
Then('I should see {string}', async function (text: string) {
|
|
110
|
+
await expect(this.page.getByText(text)).toBeVisible();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
Then('I should receive a confirmation email', async function () {
|
|
114
|
+
const emails = await this.mailbox.getEmails(this.testEmail);
|
|
115
|
+
expect(emails).toHaveLength(1);
|
|
116
|
+
expect(emails[0].subject).toContain('Confirm your email');
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Best Practices
|
|
121
|
+
|
|
122
|
+
### Writing Good Scenarios
|
|
123
|
+
|
|
124
|
+
```gherkin
|
|
125
|
+
# Good - Business language, declarative
|
|
126
|
+
Scenario: Customer places order with valid payment
|
|
127
|
+
Given the customer has items in their cart
|
|
128
|
+
And the customer has a valid payment method
|
|
129
|
+
When the customer completes checkout
|
|
130
|
+
Then the order should be confirmed
|
|
131
|
+
And the customer should receive an order confirmation
|
|
132
|
+
|
|
133
|
+
# Bad - Technical, imperative
|
|
134
|
+
Scenario: Order creation
|
|
135
|
+
Given I click on cart icon
|
|
136
|
+
And I click checkout button
|
|
137
|
+
And I enter "4111111111111111" in credit card field
|
|
138
|
+
And I click submit
|
|
139
|
+
Then database should have new order record
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Scenario Organization
|
|
143
|
+
|
|
144
|
+
```gherkin
|
|
145
|
+
Feature: Shopping Cart Management
|
|
146
|
+
|
|
147
|
+
# Group related scenarios
|
|
148
|
+
@cart @add-items
|
|
149
|
+
Scenario: Add single item to cart
|
|
150
|
+
...
|
|
151
|
+
|
|
152
|
+
@cart @add-items
|
|
153
|
+
Scenario: Add multiple items to cart
|
|
154
|
+
...
|
|
155
|
+
|
|
156
|
+
@cart @remove-items
|
|
157
|
+
Scenario: Remove item from cart
|
|
158
|
+
...
|
|
159
|
+
|
|
160
|
+
@cart @edge-cases
|
|
161
|
+
Scenario: Add item when cart is at maximum capacity
|
|
162
|
+
...
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Three Amigos Session
|
|
166
|
+
|
|
167
|
+
### Participants
|
|
168
|
+
- **Business**: Product Owner, Business Analyst
|
|
169
|
+
- **Development**: Developer, Tech Lead
|
|
170
|
+
- **Testing**: QA Engineer, Tester
|
|
171
|
+
|
|
172
|
+
### Process
|
|
173
|
+
|
|
174
|
+
1. **Present User Story**: Business explains the feature
|
|
175
|
+
2. **Ask Questions**: Team clarifies requirements
|
|
176
|
+
3. **Write Scenarios**: Collaboratively draft Gherkin
|
|
177
|
+
4. **Review**: Ensure shared understanding
|
|
178
|
+
5. **Refine**: Polish scenarios after discussion
|
|
179
|
+
|
|
180
|
+
### Example Session Output
|
|
181
|
+
|
|
182
|
+
```gherkin
|
|
183
|
+
# Before Three Amigos - Vague
|
|
184
|
+
Scenario: User logs in
|
|
185
|
+
Given a user
|
|
186
|
+
When they log in
|
|
187
|
+
Then it works
|
|
188
|
+
|
|
189
|
+
# After Three Amigos - Clear
|
|
190
|
+
Scenario: Registered user logs in with correct credentials
|
|
191
|
+
Given a registered user with email "user@example.com"
|
|
192
|
+
And the user has password "ValidPass123!"
|
|
193
|
+
When the user submits login with email "user@example.com" and password "ValidPass123!"
|
|
194
|
+
Then the user should be redirected to the dashboard
|
|
195
|
+
And the user should see their name in the header
|
|
196
|
+
And the last login timestamp should be updated
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Project Structure
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
project/
|
|
203
|
+
├── features/
|
|
204
|
+
│ ├── authentication/
|
|
205
|
+
│ │ ├── login.feature
|
|
206
|
+
│ │ ├── logout.feature
|
|
207
|
+
│ │ └── password-reset.feature
|
|
208
|
+
│ ├── cart/
|
|
209
|
+
│ │ ├── add-items.feature
|
|
210
|
+
│ │ └── checkout.feature
|
|
211
|
+
│ └── support/
|
|
212
|
+
│ ├── world.ts # Test context/world
|
|
213
|
+
│ └── hooks.ts # Before/After hooks
|
|
214
|
+
├── steps/
|
|
215
|
+
│ ├── authentication.steps.ts
|
|
216
|
+
│ ├── cart.steps.ts
|
|
217
|
+
│ └── common.steps.ts # Shared steps
|
|
218
|
+
└── cucumber.config.ts
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Configuration Example
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// cucumber.config.ts
|
|
225
|
+
export default {
|
|
226
|
+
paths: ['features/**/*.feature'],
|
|
227
|
+
require: ['steps/**/*.steps.ts'],
|
|
228
|
+
requireModule: ['ts-node/register'],
|
|
229
|
+
format: [
|
|
230
|
+
'progress-bar',
|
|
231
|
+
['html', 'reports/cucumber-report.html'],
|
|
232
|
+
['json', 'reports/cucumber-report.json']
|
|
233
|
+
],
|
|
234
|
+
formatOptions: {
|
|
235
|
+
snippetInterface: 'async-await'
|
|
236
|
+
},
|
|
237
|
+
worldParameters: {
|
|
238
|
+
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## BDD vs TDD
|
|
244
|
+
|
|
245
|
+
| Aspect | BDD | TDD |
|
|
246
|
+
|--------|-----|-----|
|
|
247
|
+
| Language | Business/Natural | Technical |
|
|
248
|
+
| Audience | All stakeholders | Developers |
|
|
249
|
+
| Focus | Behavior | Implementation |
|
|
250
|
+
| Format | Gherkin scenarios | Unit tests |
|
|
251
|
+
| Collaboration | Three Amigos | Developer-focused |
|
|
252
|
+
| Documentation | Living docs | Code comments |
|
|
253
|
+
|
|
254
|
+
## When to Use BDD
|
|
255
|
+
|
|
256
|
+
**Good for:**
|
|
257
|
+
- Complex business rules
|
|
258
|
+
- Stakeholder collaboration
|
|
259
|
+
- Acceptance testing
|
|
260
|
+
- Living documentation
|
|
261
|
+
- User-facing features
|
|
262
|
+
|
|
263
|
+
**Less suitable for:**
|
|
264
|
+
- Internal utilities
|
|
265
|
+
- Pure technical implementations
|
|
266
|
+
- Low-level unit tests
|
|
267
|
+
- Rapid prototyping
|
|
268
|
+
|
|
269
|
+
## Output
|
|
270
|
+
|
|
271
|
+
**Produces:**
|
|
272
|
+
- Feature files with Gherkin scenarios
|
|
273
|
+
- Step definition implementations
|
|
274
|
+
- Living documentation
|
|
275
|
+
- Executable specifications
|
|
276
|
+
|
|
277
|
+
**Success Criteria:**
|
|
278
|
+
- All scenarios passing
|
|
279
|
+
- Stakeholders can read and understand tests
|
|
280
|
+
- Scenarios cover acceptance criteria
|
|
281
|
+
- Documentation stays current with code
|