omgkit 2.1.1 → 2.2.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 (50) hide show
  1. package/package.json +1 -1
  2. package/plugin/skills/SKILL_STANDARDS.md +743 -0
  3. package/plugin/skills/databases/mongodb/SKILL.md +797 -28
  4. package/plugin/skills/databases/prisma/SKILL.md +776 -30
  5. package/plugin/skills/databases/redis/SKILL.md +885 -25
  6. package/plugin/skills/devops/aws/SKILL.md +686 -28
  7. package/plugin/skills/devops/github-actions/SKILL.md +684 -29
  8. package/plugin/skills/devops/kubernetes/SKILL.md +621 -24
  9. package/plugin/skills/frameworks/django/SKILL.md +920 -20
  10. package/plugin/skills/frameworks/express/SKILL.md +1361 -35
  11. package/plugin/skills/frameworks/fastapi/SKILL.md +1260 -33
  12. package/plugin/skills/frameworks/laravel/SKILL.md +1244 -31
  13. package/plugin/skills/frameworks/nestjs/SKILL.md +1005 -26
  14. package/plugin/skills/frameworks/rails/SKILL.md +594 -28
  15. package/plugin/skills/frameworks/spring/SKILL.md +528 -35
  16. package/plugin/skills/frameworks/vue/SKILL.md +1296 -27
  17. package/plugin/skills/frontend/accessibility/SKILL.md +1108 -34
  18. package/plugin/skills/frontend/frontend-design/SKILL.md +1304 -26
  19. package/plugin/skills/frontend/responsive/SKILL.md +847 -21
  20. package/plugin/skills/frontend/shadcn-ui/SKILL.md +976 -38
  21. package/plugin/skills/frontend/tailwindcss/SKILL.md +831 -35
  22. package/plugin/skills/frontend/threejs/SKILL.md +1298 -29
  23. package/plugin/skills/languages/javascript/SKILL.md +935 -31
  24. package/plugin/skills/methodology/brainstorming/SKILL.md +597 -23
  25. package/plugin/skills/methodology/defense-in-depth/SKILL.md +832 -34
  26. package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +665 -31
  27. package/plugin/skills/methodology/executing-plans/SKILL.md +556 -24
  28. package/plugin/skills/methodology/finishing-development-branch/SKILL.md +595 -25
  29. package/plugin/skills/methodology/problem-solving/SKILL.md +429 -61
  30. package/plugin/skills/methodology/receiving-code-review/SKILL.md +536 -24
  31. package/plugin/skills/methodology/requesting-code-review/SKILL.md +632 -21
  32. package/plugin/skills/methodology/root-cause-tracing/SKILL.md +641 -30
  33. package/plugin/skills/methodology/sequential-thinking/SKILL.md +262 -3
  34. package/plugin/skills/methodology/systematic-debugging/SKILL.md +571 -32
  35. package/plugin/skills/methodology/test-driven-development/SKILL.md +779 -24
  36. package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +691 -29
  37. package/plugin/skills/methodology/token-optimization/SKILL.md +598 -29
  38. package/plugin/skills/methodology/verification-before-completion/SKILL.md +543 -22
  39. package/plugin/skills/methodology/writing-plans/SKILL.md +590 -18
  40. package/plugin/skills/omega/omega-architecture/SKILL.md +838 -39
  41. package/plugin/skills/omega/omega-coding/SKILL.md +636 -39
  42. package/plugin/skills/omega/omega-sprint/SKILL.md +855 -48
  43. package/plugin/skills/omega/omega-testing/SKILL.md +940 -41
  44. package/plugin/skills/omega/omega-thinking/SKILL.md +703 -50
  45. package/plugin/skills/security/better-auth/SKILL.md +1065 -28
  46. package/plugin/skills/security/oauth/SKILL.md +968 -31
  47. package/plugin/skills/security/owasp/SKILL.md +894 -33
  48. package/plugin/skills/testing/playwright/SKILL.md +764 -38
  49. package/plugin/skills/testing/pytest/SKILL.md +873 -36
  50. package/plugin/skills/testing/vitest/SKILL.md +980 -35
@@ -1,71 +1,970 @@
1
1
  ---
2
2
  name: omega-testing
3
- description: Comprehensive Omega testing. Use for thorough test coverage.
3
+ description: Comprehensive testing strategies covering all dimensions - accuracy, performance, security, and accessibility
4
+ category: omega
5
+ triggers:
6
+ - omega testing
7
+ - comprehensive testing
8
+ - test strategy
9
+ - quality assurance
10
+ - test pyramid
11
+ - test coverage
12
+ - testing best practices
4
13
  ---
5
14
 
6
- # Omega Testing Skill
15
+ # Omega Testing
7
16
 
8
- ## Testing Pyramid
17
+ Master **comprehensive testing strategies** that cover all quality dimensions - accuracy, performance, security, and accessibility. This skill provides frameworks for building confidence in your code through systematic, thorough testing.
18
+
19
+ ## Purpose
20
+
21
+ Achieve Omega-level quality assurance:
22
+
23
+ - Design test strategies that catch bugs before production
24
+ - Build layered test suites (unit, integration, E2E)
25
+ - Test all quality dimensions, not just functionality
26
+ - Create maintainable, fast, and reliable tests
27
+ - Implement property-based and mutation testing
28
+ - Achieve meaningful coverage metrics
29
+ - Enable confident refactoring and deployment
30
+
31
+ ## Features
32
+
33
+ ### 1. The Omega Testing Pyramid
34
+
35
+ ```markdown
36
+ ## Multi-Dimensional Testing Pyramid
37
+
38
+ ┌─────────────────────────────────────────────────────────────────────────┐
39
+ │ OMEGA TESTING PYRAMID │
40
+ ├─────────────────────────────────────────────────────────────────────────┤
41
+ │ │
42
+ │ /\ │
43
+ │ /E2E\ ← Critical paths only │
44
+ │ /─────\ Slowest, most expensive │
45
+ │ / \ │
46
+ │ / Visual \ ← Screenshot comparisons │
47
+ │ /───────────\ │
48
+ │ / \ │
49
+ │ / Integration \ ← Service boundaries │
50
+ │ /─────────────────\ API contracts │
51
+ │ / \ │
52
+ │ / Component \ ← UI components isolated │
53
+ │ /───────────────────────\ │
54
+ │ / \ │
55
+ │ / Unit \ ← Fast, isolated │
56
+ │ /─────────────────────────────\ Business logic │
57
+ │ │
58
+ │ Target Coverage by Layer: │
59
+ │ • Unit: 80%+ (pure functions, business logic) │
60
+ │ • Component: 70%+ (UI components with mocks) │
61
+ │ • Integration: 60%+ (API endpoints, data flow) │
62
+ │ • E2E: Critical paths 100% (happy paths, auth, checkout) │
63
+ │ │
64
+ └─────────────────────────────────────────────────────────────────────────┘
9
65
  ```
10
- /\
11
- /E2E\
12
- /─────\
13
- /Integ. \
14
- /─────────\
15
- / Unit \
16
- /─────────────\
66
+
67
+ ### 2. Four Dimensions of Quality Testing
68
+
69
+ ```typescript
70
+ /**
71
+ * Omega Testing covers ALL quality dimensions
72
+ * Don't just test functionality - test quality
73
+ */
74
+
75
+ type QualityDimension =
76
+ | 'accuracy' // Does it work correctly?
77
+ | 'performance' // Does it work fast enough?
78
+ | 'security' // Is it safe from attacks?
79
+ | 'accessibility'; // Can everyone use it?
80
+
81
+ interface OmegaTestSuite {
82
+ accuracy: AccuracyTests;
83
+ performance: PerformanceTests;
84
+ security: SecurityTests;
85
+ accessibility: AccessibilityTests;
86
+ }
87
+
88
+ // Dimension 1: Accuracy (Functional Correctness)
89
+ interface AccuracyTests {
90
+ happyPath: Test[]; // Normal use cases work
91
+ edgeCases: Test[]; // Boundary conditions handled
92
+ errorCases: Test[]; // Failures handled gracefully
93
+ regressions: Test[]; // Previously fixed bugs stay fixed
94
+ }
95
+
96
+ // Dimension 2: Performance
97
+ interface PerformanceTests {
98
+ responseTime: Test[]; // Operations complete in time
99
+ throughput: Test[]; // System handles expected load
100
+ memory: Test[]; // No memory leaks
101
+ scalability: Test[]; // Performance under scale
102
+ }
103
+
104
+ // Dimension 3: Security
105
+ interface SecurityTests {
106
+ authentication: Test[]; // Auth works correctly
107
+ authorization: Test[]; // Permissions enforced
108
+ injection: Test[]; // SQL, XSS, etc. prevented
109
+ dataProtection: Test[]; // Sensitive data secured
110
+ }
111
+
112
+ // Dimension 4: Accessibility
113
+ interface AccessibilityTests {
114
+ screenReader: Test[]; // Works with assistive tech
115
+ keyboard: Test[]; // Keyboard navigation works
116
+ contrast: Test[]; // Visual contrast sufficient
117
+ motion: Test[]; // Respects motion preferences
118
+ }
119
+ ```
120
+
121
+ ### 3. Unit Testing Patterns
122
+
123
+ ```typescript
124
+ /**
125
+ * Unit Tests: Fast, isolated, focused on business logic
126
+ */
127
+
128
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
129
+
130
+ // Pattern 1: Arrange-Act-Assert (AAA)
131
+ describe('calculateDiscount', () => {
132
+ it('applies 10% discount for orders over $100', () => {
133
+ // Arrange
134
+ const order = createOrder({ subtotal: 150 });
135
+ const discountRules = createDiscountRules();
136
+
137
+ // Act
138
+ const result = calculateDiscount(order, discountRules);
139
+
140
+ // Assert
141
+ expect(result.discount).toBe(15);
142
+ expect(result.total).toBe(135);
143
+ });
144
+ });
145
+
146
+ // Pattern 2: Testing Edge Cases Systematically
147
+ describe('validateEmail', () => {
148
+ // Happy path
149
+ it('accepts valid email formats', () => {
150
+ const validEmails = [
151
+ 'user@example.com',
152
+ 'user.name@example.co.uk',
153
+ 'user+tag@example.org'
154
+ ];
155
+
156
+ validEmails.forEach(email => {
157
+ expect(validateEmail(email)).toBe(true);
158
+ });
159
+ });
160
+
161
+ // Edge cases
162
+ it.each([
163
+ ['missing @', 'userexample.com'],
164
+ ['missing domain', 'user@'],
165
+ ['missing local part', '@example.com'],
166
+ ['invalid characters', 'user<script>@example.com'],
167
+ ['empty string', ''],
168
+ ['whitespace only', ' '],
169
+ ])('rejects %s: %s', (_description, email) => {
170
+ expect(validateEmail(email)).toBe(false);
171
+ });
172
+
173
+ // Boundary conditions
174
+ it('handles maximum length email', () => {
175
+ const longEmail = 'a'.repeat(64) + '@' + 'b'.repeat(63) + '.com';
176
+ expect(validateEmail(longEmail)).toBe(true);
177
+ });
178
+
179
+ it('rejects email exceeding maximum length', () => {
180
+ const tooLongEmail = 'a'.repeat(65) + '@' + 'b'.repeat(64) + '.com';
181
+ expect(validateEmail(tooLongEmail)).toBe(false);
182
+ });
183
+ });
184
+
185
+ // Pattern 3: Testing Error Handling
186
+ describe('fetchUserData', () => {
187
+ const mockApi = vi.fn();
188
+
189
+ beforeEach(() => {
190
+ mockApi.mockReset();
191
+ });
192
+
193
+ it('throws UserNotFoundError when user does not exist', async () => {
194
+ mockApi.mockRejectedValue(new Error('404'));
195
+
196
+ await expect(fetchUserData('nonexistent-id', mockApi))
197
+ .rejects
198
+ .toThrow(UserNotFoundError);
199
+ });
200
+
201
+ it('retries on transient failures', async () => {
202
+ mockApi
203
+ .mockRejectedValueOnce(new Error('timeout'))
204
+ .mockRejectedValueOnce(new Error('timeout'))
205
+ .mockResolvedValueOnce({ id: '123', name: 'Test' });
206
+
207
+ const result = await fetchUserData('123', mockApi);
208
+
209
+ expect(mockApi).toHaveBeenCalledTimes(3);
210
+ expect(result.name).toBe('Test');
211
+ });
212
+
213
+ it('gives up after max retries', async () => {
214
+ mockApi.mockRejectedValue(new Error('timeout'));
215
+
216
+ await expect(fetchUserData('123', mockApi))
217
+ .rejects
218
+ .toThrow(MaxRetriesExceededError);
219
+
220
+ expect(mockApi).toHaveBeenCalledTimes(3);
221
+ });
222
+ });
223
+
224
+ // Pattern 4: Testing Pure Functions with Properties
225
+ describe('sortUsers (property-based)', () => {
226
+ it('output length equals input length', () => {
227
+ fc.assert(
228
+ fc.property(fc.array(fc.record({
229
+ id: fc.string(),
230
+ name: fc.string(),
231
+ age: fc.nat()
232
+ })), (users) => {
233
+ const sorted = sortUsers(users, 'name');
234
+ return sorted.length === users.length;
235
+ })
236
+ );
237
+ });
238
+
239
+ it('maintains all original elements', () => {
240
+ fc.assert(
241
+ fc.property(fc.array(userArbitrary), (users) => {
242
+ const sorted = sortUsers(users, 'name');
243
+ const originalIds = new Set(users.map(u => u.id));
244
+ const sortedIds = new Set(sorted.map(u => u.id));
245
+ return setsEqual(originalIds, sortedIds);
246
+ })
247
+ );
248
+ });
249
+
250
+ it('result is actually sorted', () => {
251
+ fc.assert(
252
+ fc.property(fc.array(userArbitrary), (users) => {
253
+ const sorted = sortUsers(users, 'name');
254
+ return sorted.every((user, i) =>
255
+ i === 0 || user.name >= sorted[i - 1].name
256
+ );
257
+ })
258
+ );
259
+ });
260
+ });
17
261
  ```
18
262
 
19
- ## Coverage Targets
20
- - Unit: 80%+
21
- - Integration: 60%+
22
- - E2E: Critical paths 100%
263
+ ### 4. Integration Testing Patterns
264
+
265
+ ```typescript
266
+ /**
267
+ * Integration Tests: Test service boundaries and contracts
268
+ */
269
+
270
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
271
+ import { createTestDatabase, cleanupTestDatabase } from './test-utils';
272
+
273
+ describe('UserService Integration', () => {
274
+ let db: TestDatabase;
275
+ let userService: UserService;
276
+
277
+ beforeAll(async () => {
278
+ db = await createTestDatabase();
279
+ userService = new UserService(db);
280
+ });
281
+
282
+ afterAll(async () => {
283
+ await cleanupTestDatabase(db);
284
+ });
285
+
286
+ // Test real database interactions
287
+ describe('createUser', () => {
288
+ it('persists user to database', async () => {
289
+ const userData = {
290
+ email: 'test@example.com',
291
+ name: 'Test User'
292
+ };
293
+
294
+ const user = await userService.createUser(userData);
295
+
296
+ // Verify in database directly
297
+ const dbUser = await db.query('SELECT * FROM users WHERE id = $1', [user.id]);
298
+ expect(dbUser.email).toBe(userData.email);
299
+ expect(dbUser.name).toBe(userData.name);
300
+ });
301
+
302
+ it('enforces unique email constraint', async () => {
303
+ const userData = { email: 'duplicate@example.com', name: 'User 1' };
304
+ await userService.createUser(userData);
305
+
306
+ await expect(userService.createUser({
307
+ email: 'duplicate@example.com',
308
+ name: 'User 2'
309
+ })).rejects.toThrow(DuplicateEmailError);
310
+ });
311
+ });
312
+
313
+ // Test transactions
314
+ describe('transferCredits', () => {
315
+ it('atomically transfers credits between users', async () => {
316
+ const sender = await userService.createUser({ credits: 100 });
317
+ const receiver = await userService.createUser({ credits: 0 });
318
+
319
+ await userService.transferCredits(sender.id, receiver.id, 50);
320
+
321
+ const [updatedSender, updatedReceiver] = await Promise.all([
322
+ userService.getUser(sender.id),
323
+ userService.getUser(receiver.id)
324
+ ]);
325
+
326
+ expect(updatedSender.credits).toBe(50);
327
+ expect(updatedReceiver.credits).toBe(50);
328
+ });
329
+
330
+ it('rolls back on failure', async () => {
331
+ const sender = await userService.createUser({ credits: 100 });
332
+ const receiver = await userService.createUser({ credits: 0 });
333
+
334
+ // Simulate failure mid-transaction
335
+ vi.spyOn(db, 'commit').mockRejectedValueOnce(new Error('DB error'));
336
+
337
+ await expect(
338
+ userService.transferCredits(sender.id, receiver.id, 50)
339
+ ).rejects.toThrow();
340
+
341
+ // Verify no changes persisted
342
+ const [s, r] = await Promise.all([
343
+ userService.getUser(sender.id),
344
+ userService.getUser(receiver.id)
345
+ ]);
346
+
347
+ expect(s.credits).toBe(100);
348
+ expect(r.credits).toBe(0);
349
+ });
350
+ });
351
+ });
352
+
353
+ // API Contract Testing
354
+ describe('API Contract Tests', () => {
355
+ it('GET /users/:id returns correct schema', async () => {
356
+ const response = await api.get('/users/123');
23
357
 
24
- ## Test Categories
358
+ expect(response.status).toBe(200);
359
+ expect(response.body).toMatchSchema({
360
+ type: 'object',
361
+ required: ['id', 'email', 'name', 'createdAt'],
362
+ properties: {
363
+ id: { type: 'string', format: 'uuid' },
364
+ email: { type: 'string', format: 'email' },
365
+ name: { type: 'string', minLength: 1 },
366
+ createdAt: { type: 'string', format: 'date-time' }
367
+ }
368
+ });
369
+ });
370
+
371
+ it('POST /users validates request body', async () => {
372
+ const response = await api.post('/users', {
373
+ body: { email: 'invalid-email' } // Missing name, invalid email
374
+ });
375
+
376
+ expect(response.status).toBe(400);
377
+ expect(response.body.errors).toContainEqual(
378
+ expect.objectContaining({ field: 'email', message: expect.any(String) })
379
+ );
380
+ expect(response.body.errors).toContainEqual(
381
+ expect.objectContaining({ field: 'name', message: expect.any(String) })
382
+ );
383
+ });
384
+ });
385
+ ```
386
+
387
+ ### 5. E2E Testing Patterns
25
388
 
26
- ### 1. Happy Path
27
389
  ```typescript
28
- it('creates user successfully', async () => {
29
- const user = await createUser({ email: 'test@example.com' });
30
- expect(user.email).toBe('test@example.com');
390
+ /**
391
+ * E2E Tests: Test critical user journeys
392
+ * Use sparingly - slow and expensive
393
+ */
394
+
395
+ import { test, expect } from '@playwright/test';
396
+
397
+ // Critical Path: User Registration & Login
398
+ test.describe('Authentication Flow', () => {
399
+ test('new user can register and login', async ({ page }) => {
400
+ const testEmail = `test-${Date.now()}@example.com`;
401
+
402
+ // Registration
403
+ await page.goto('/register');
404
+ await page.fill('[data-testid="email"]', testEmail);
405
+ await page.fill('[data-testid="password"]', 'SecurePass123!');
406
+ await page.fill('[data-testid="confirm-password"]', 'SecurePass123!');
407
+ await page.click('[data-testid="register-button"]');
408
+
409
+ // Verify registration success
410
+ await expect(page).toHaveURL('/verify-email');
411
+ await expect(page.locator('[data-testid="success-message"]'))
412
+ .toContainText('verification email sent');
413
+
414
+ // Simulate email verification (in test environment)
415
+ await verifyEmailInTestMode(testEmail);
416
+
417
+ // Login
418
+ await page.goto('/login');
419
+ await page.fill('[data-testid="email"]', testEmail);
420
+ await page.fill('[data-testid="password"]', 'SecurePass123!');
421
+ await page.click('[data-testid="login-button"]');
422
+
423
+ // Verify login success
424
+ await expect(page).toHaveURL('/dashboard');
425
+ await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
426
+ });
427
+
428
+ test('handles invalid credentials', async ({ page }) => {
429
+ await page.goto('/login');
430
+ await page.fill('[data-testid="email"]', 'wrong@example.com');
431
+ await page.fill('[data-testid="password"]', 'wrongpassword');
432
+ await page.click('[data-testid="login-button"]');
433
+
434
+ await expect(page.locator('[data-testid="error-message"]'))
435
+ .toContainText('Invalid email or password');
436
+ await expect(page).toHaveURL('/login');
437
+ });
438
+ });
439
+
440
+ // Critical Path: E-commerce Checkout
441
+ test.describe('Checkout Flow', () => {
442
+ test.beforeEach(async ({ page }) => {
443
+ // Login as test user
444
+ await loginAsTestUser(page);
445
+ });
446
+
447
+ test('complete purchase flow', async ({ page }) => {
448
+ // Add item to cart
449
+ await page.goto('/products/test-product');
450
+ await page.click('[data-testid="add-to-cart"]');
451
+ await expect(page.locator('[data-testid="cart-count"]')).toHaveText('1');
452
+
453
+ // Go to checkout
454
+ await page.click('[data-testid="cart-icon"]');
455
+ await page.click('[data-testid="checkout-button"]');
456
+
457
+ // Fill shipping info
458
+ await page.fill('[data-testid="address"]', '123 Test St');
459
+ await page.fill('[data-testid="city"]', 'Test City');
460
+ await page.fill('[data-testid="zip"]', '12345');
461
+ await page.click('[data-testid="continue-to-payment"]');
462
+
463
+ // Payment (use test card)
464
+ await page.fill('[data-testid="card-number"]', '4242424242424242');
465
+ await page.fill('[data-testid="expiry"]', '12/25');
466
+ await page.fill('[data-testid="cvc"]', '123');
467
+ await page.click('[data-testid="place-order"]');
468
+
469
+ // Verify success
470
+ await expect(page).toHaveURL(/\/orders\/[a-z0-9-]+/);
471
+ await expect(page.locator('[data-testid="order-status"]'))
472
+ .toHaveText('Order Confirmed');
473
+ });
474
+ });
475
+
476
+ // Visual Regression Testing
477
+ test.describe('Visual Regression', () => {
478
+ test('dashboard matches snapshot', async ({ page }) => {
479
+ await loginAsTestUser(page);
480
+ await page.goto('/dashboard');
481
+ await page.waitForLoadState('networkidle');
482
+
483
+ await expect(page).toHaveScreenshot('dashboard.png', {
484
+ maxDiffPixelRatio: 0.01
485
+ });
486
+ });
487
+
488
+ test('responsive layout on mobile', async ({ page }) => {
489
+ await page.setViewportSize({ width: 375, height: 667 });
490
+ await page.goto('/');
491
+
492
+ await expect(page).toHaveScreenshot('home-mobile.png');
493
+ });
31
494
  });
32
495
  ```
33
496
 
34
- ### 2. Edge Cases
497
+ ### 6. Performance Testing
498
+
35
499
  ```typescript
36
- it('handles empty input', () => {
37
- expect(() => createUser({ email: '' })).toThrow();
500
+ /**
501
+ * Performance Tests: Ensure system meets performance requirements
502
+ */
503
+
504
+ import { describe, it, expect } from 'vitest';
505
+
506
+ // Response Time Testing
507
+ describe('API Performance', () => {
508
+ it('GET /users responds within 100ms', async () => {
509
+ const iterations = 100;
510
+ const times: number[] = [];
511
+
512
+ for (let i = 0; i < iterations; i++) {
513
+ const start = performance.now();
514
+ await api.get('/users');
515
+ times.push(performance.now() - start);
516
+ }
517
+
518
+ const p50 = percentile(times, 50);
519
+ const p95 = percentile(times, 95);
520
+ const p99 = percentile(times, 99);
521
+
522
+ expect(p50).toBeLessThan(50); // Median under 50ms
523
+ expect(p95).toBeLessThan(100); // 95th percentile under 100ms
524
+ expect(p99).toBeLessThan(200); // 99th percentile under 200ms
525
+ });
526
+
527
+ it('handles concurrent requests', async () => {
528
+ const concurrency = 50;
529
+ const requests = Array(concurrency).fill(null).map(() =>
530
+ api.get('/users')
531
+ );
532
+
533
+ const start = performance.now();
534
+ const responses = await Promise.all(requests);
535
+ const duration = performance.now() - start;
536
+
537
+ // All should succeed
538
+ expect(responses.every(r => r.status === 200)).toBe(true);
539
+ // Should complete in reasonable time
540
+ expect(duration).toBeLessThan(1000);
541
+ });
38
542
  });
543
+
544
+ // Memory Leak Detection
545
+ describe('Memory Stability', () => {
546
+ it('does not leak memory over many operations', async () => {
547
+ const initialMemory = process.memoryUsage().heapUsed;
548
+
549
+ // Perform many operations
550
+ for (let i = 0; i < 10000; i++) {
551
+ await processData(generateLargePayload());
552
+ }
553
+
554
+ // Force garbage collection if available
555
+ if (global.gc) global.gc();
556
+
557
+ const finalMemory = process.memoryUsage().heapUsed;
558
+ const growth = finalMemory - initialMemory;
559
+
560
+ // Memory should not grow significantly (< 10MB)
561
+ expect(growth).toBeLessThan(10 * 1024 * 1024);
562
+ });
563
+ });
564
+
565
+ // Load Testing Configuration
566
+ const loadTestConfig = {
567
+ scenarios: {
568
+ normalLoad: {
569
+ executor: 'ramping-vus',
570
+ startVUs: 0,
571
+ stages: [
572
+ { duration: '2m', target: 100 }, // Ramp up
573
+ { duration: '5m', target: 100 }, // Steady state
574
+ { duration: '2m', target: 0 } // Ramp down
575
+ ],
576
+ gracefulRampDown: '30s'
577
+ },
578
+
579
+ stressTest: {
580
+ executor: 'ramping-vus',
581
+ startVUs: 0,
582
+ stages: [
583
+ { duration: '2m', target: 200 },
584
+ { duration: '5m', target: 200 },
585
+ { duration: '2m', target: 400 }, // Push beyond normal
586
+ { duration: '5m', target: 400 },
587
+ { duration: '2m', target: 0 }
588
+ ]
589
+ },
590
+
591
+ spikeTest: {
592
+ executor: 'ramping-vus',
593
+ startVUs: 0,
594
+ stages: [
595
+ { duration: '10s', target: 500 }, // Sudden spike
596
+ { duration: '1m', target: 500 },
597
+ { duration: '10s', target: 0 }
598
+ ]
599
+ }
600
+ },
601
+
602
+ thresholds: {
603
+ http_req_duration: ['p(95)<200', 'p(99)<500'],
604
+ http_req_failed: ['rate<0.01'],
605
+ http_reqs: ['rate>100']
606
+ }
607
+ };
39
608
  ```
40
609
 
41
- ### 3. Error Cases
610
+ ### 7. Security Testing
611
+
42
612
  ```typescript
43
- it('handles database failure', async () => {
44
- db.fail();
45
- await expect(createUser({})).rejects.toThrow(DatabaseError);
613
+ /**
614
+ * Security Tests: Verify protection against common attacks
615
+ */
616
+
617
+ describe('Security Tests', () => {
618
+ // SQL Injection Prevention
619
+ describe('SQL Injection', () => {
620
+ const sqlInjectionPayloads = [
621
+ "'; DROP TABLE users; --",
622
+ "' OR '1'='1",
623
+ "'; INSERT INTO users VALUES ('hacker', 'hacked'); --",
624
+ "1; UPDATE users SET role='admin' WHERE id=1; --"
625
+ ];
626
+
627
+ it.each(sqlInjectionPayloads)(
628
+ 'safely handles SQL injection attempt: %s',
629
+ async (payload) => {
630
+ const response = await api.get(`/users?search=${encodeURIComponent(payload)}`);
631
+
632
+ // Should not error (indicates parameterized queries)
633
+ expect(response.status).not.toBe(500);
634
+
635
+ // Verify database integrity
636
+ const users = await db.query('SELECT * FROM users');
637
+ expect(users).toBeDefined();
638
+ }
639
+ );
640
+ });
641
+
642
+ // XSS Prevention
643
+ describe('XSS Prevention', () => {
644
+ const xssPayloads = [
645
+ '<script>alert("xss")</script>',
646
+ '<img src=x onerror=alert("xss")>',
647
+ '"><script>alert(document.cookie)</script>',
648
+ "javascript:alert('xss')"
649
+ ];
650
+
651
+ it.each(xssPayloads)(
652
+ 'escapes XSS payload: %s',
653
+ async (payload) => {
654
+ // Create content with XSS payload
655
+ await api.post('/posts', { body: { content: payload } });
656
+
657
+ // Retrieve and verify it's escaped
658
+ const response = await api.get('/posts');
659
+ const html = response.body.posts[0].content;
660
+
661
+ expect(html).not.toContain('<script>');
662
+ expect(html).not.toContain('onerror=');
663
+ expect(html).not.toContain('javascript:');
664
+ }
665
+ );
666
+ });
667
+
668
+ // Authentication Security
669
+ describe('Authentication', () => {
670
+ it('rate limits login attempts', async () => {
671
+ const attempts = 10;
672
+ const responses: Response[] = [];
673
+
674
+ for (let i = 0; i < attempts; i++) {
675
+ responses.push(await api.post('/login', {
676
+ body: { email: 'test@example.com', password: 'wrong' }
677
+ }));
678
+ }
679
+
680
+ // Later attempts should be rate limited
681
+ const rateLimited = responses.filter(r => r.status === 429);
682
+ expect(rateLimited.length).toBeGreaterThan(0);
683
+ });
684
+
685
+ it('uses secure session cookies', async () => {
686
+ const response = await api.post('/login', {
687
+ body: { email: 'test@example.com', password: 'correct' }
688
+ });
689
+
690
+ const sessionCookie = response.headers['set-cookie'];
691
+ expect(sessionCookie).toContain('HttpOnly');
692
+ expect(sessionCookie).toContain('Secure');
693
+ expect(sessionCookie).toContain('SameSite');
694
+ });
695
+
696
+ it('invalidates session on logout', async () => {
697
+ const loginResponse = await api.post('/login', {
698
+ body: { email: 'test@example.com', password: 'correct' }
699
+ });
700
+ const sessionToken = extractSessionToken(loginResponse);
701
+
702
+ await api.post('/logout', { headers: { Cookie: sessionToken } });
703
+
704
+ // Old session should be invalid
705
+ const response = await api.get('/me', {
706
+ headers: { Cookie: sessionToken }
707
+ });
708
+ expect(response.status).toBe(401);
709
+ });
710
+ });
711
+
712
+ // Authorization Testing
713
+ describe('Authorization', () => {
714
+ it('prevents accessing other users data', async () => {
715
+ const user1Token = await loginAs('user1');
716
+ const user2Token = await loginAs('user2');
717
+
718
+ // User 1 tries to access User 2's data
719
+ const response = await api.get('/users/user2/private-data', {
720
+ headers: { Authorization: `Bearer ${user1Token}` }
721
+ });
722
+
723
+ expect(response.status).toBe(403);
724
+ });
725
+
726
+ it('admin routes require admin role', async () => {
727
+ const userToken = await loginAs('regular-user');
728
+
729
+ const response = await api.get('/admin/users', {
730
+ headers: { Authorization: `Bearer ${userToken}` }
731
+ });
732
+
733
+ expect(response.status).toBe(403);
734
+ });
735
+ });
46
736
  });
47
737
  ```
48
738
 
49
- ### 4. Performance
739
+ ### 8. Accessibility Testing
740
+
50
741
  ```typescript
51
- it('responds within 100ms', async () => {
52
- const start = Date.now();
53
- await fetchUsers();
54
- expect(Date.now() - start).toBeLessThan(100);
742
+ /**
743
+ * Accessibility Tests: Ensure usability for all users
744
+ */
745
+
746
+ import { test, expect } from '@playwright/test';
747
+ import AxeBuilder from '@axe-core/playwright';
748
+
749
+ test.describe('Accessibility', () => {
750
+ // Automated WCAG Compliance
751
+ test('home page has no accessibility violations', async ({ page }) => {
752
+ await page.goto('/');
753
+
754
+ const results = await new AxeBuilder({ page })
755
+ .withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
756
+ .analyze();
757
+
758
+ expect(results.violations).toEqual([]);
759
+ });
760
+
761
+ // Keyboard Navigation
762
+ test('all interactive elements are keyboard accessible', async ({ page }) => {
763
+ await page.goto('/');
764
+
765
+ // Tab through all focusable elements
766
+ const focusableSelectors = 'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])';
767
+ const elements = await page.locator(focusableSelectors).all();
768
+
769
+ for (const element of elements) {
770
+ await page.keyboard.press('Tab');
771
+ const focused = await page.evaluate(() => document.activeElement?.tagName);
772
+ expect(focused).toBeDefined();
773
+ }
774
+ });
775
+
776
+ // Focus Management
777
+ test('modal traps focus correctly', async ({ page }) => {
778
+ await page.goto('/');
779
+ await page.click('[data-testid="open-modal"]');
780
+
781
+ // Focus should be on modal
782
+ const modalFocused = await page.locator('[data-testid="modal"]').evaluate(
783
+ el => el.contains(document.activeElement)
784
+ );
785
+ expect(modalFocused).toBe(true);
786
+
787
+ // Tab should stay within modal
788
+ for (let i = 0; i < 10; i++) {
789
+ await page.keyboard.press('Tab');
790
+ const stillInModal = await page.locator('[data-testid="modal"]').evaluate(
791
+ el => el.contains(document.activeElement)
792
+ );
793
+ expect(stillInModal).toBe(true);
794
+ }
795
+
796
+ // Escape closes modal
797
+ await page.keyboard.press('Escape');
798
+ await expect(page.locator('[data-testid="modal"]')).not.toBeVisible();
799
+ });
800
+
801
+ // Screen Reader Compatibility
802
+ test('images have alt text', async ({ page }) => {
803
+ await page.goto('/');
804
+
805
+ const images = await page.locator('img').all();
806
+ for (const img of images) {
807
+ const alt = await img.getAttribute('alt');
808
+ expect(alt).toBeDefined();
809
+ expect(alt?.length).toBeGreaterThan(0);
810
+ }
811
+ });
812
+
813
+ // Color Contrast
814
+ test('text has sufficient contrast', async ({ page }) => {
815
+ await page.goto('/');
816
+
817
+ const results = await new AxeBuilder({ page })
818
+ .withRules(['color-contrast'])
819
+ .analyze();
820
+
821
+ expect(results.violations).toEqual([]);
822
+ });
823
+
824
+ // Reduced Motion
825
+ test('respects prefers-reduced-motion', async ({ page }) => {
826
+ await page.emulateMedia({ reducedMotion: 'reduce' });
827
+ await page.goto('/');
828
+
829
+ // Check animations are disabled
830
+ const animatedElement = page.locator('[data-animated]');
831
+ const animationDuration = await animatedElement.evaluate(el =>
832
+ getComputedStyle(el).animationDuration
833
+ );
834
+
835
+ expect(animationDuration).toBe('0s');
836
+ });
55
837
  });
56
838
  ```
57
839
 
58
- ### 5. Security
840
+ ## Use Cases
841
+
842
+ ### Testing a New Feature
843
+
59
844
  ```typescript
60
- it('rejects SQL injection', () => {
61
- const input = "'; DROP TABLE users; --";
62
- expect(() => query(input)).not.toThrow();
845
+ /**
846
+ * Complete test suite for a new user profile feature
847
+ */
848
+
849
+ // Unit Tests
850
+ describe('ProfileService', () => {
851
+ it('validates profile data', () => {
852
+ expect(validateProfile({ name: '' })).toEqual({
853
+ valid: false,
854
+ errors: ['Name is required']
855
+ });
856
+ });
857
+
858
+ it('sanitizes bio field', () => {
859
+ const result = sanitizeProfile({
860
+ bio: '<script>alert("xss")</script>Hello'
861
+ });
862
+ expect(result.bio).toBe('Hello');
863
+ });
864
+ });
865
+
866
+ // Integration Tests
867
+ describe('Profile API', () => {
868
+ it('updates profile in database', async () => {
869
+ const response = await api.put('/profile', {
870
+ body: { name: 'New Name', bio: 'New bio' }
871
+ });
872
+
873
+ expect(response.status).toBe(200);
874
+
875
+ const dbProfile = await db.profiles.findById(userId);
876
+ expect(dbProfile.name).toBe('New Name');
877
+ });
63
878
  });
879
+
880
+ // E2E Tests
881
+ test('user can update their profile', async ({ page }) => {
882
+ await loginAsTestUser(page);
883
+ await page.goto('/settings/profile');
884
+ await page.fill('[data-testid="name"]', 'Updated Name');
885
+ await page.click('[data-testid="save"]');
886
+
887
+ await expect(page.locator('[data-testid="success"]')).toBeVisible();
888
+ });
889
+ ```
890
+
891
+ ### CI/CD Test Configuration
892
+
893
+ ```yaml
894
+ # .github/workflows/test.yml
895
+ name: Test Suite
896
+
897
+ on: [push, pull_request]
898
+
899
+ jobs:
900
+ unit-tests:
901
+ runs-on: ubuntu-latest
902
+ steps:
903
+ - uses: actions/checkout@v4
904
+ - name: Run unit tests
905
+ run: npm run test:unit -- --coverage
906
+ - name: Upload coverage
907
+ uses: codecov/codecov-action@v4
908
+
909
+ integration-tests:
910
+ runs-on: ubuntu-latest
911
+ services:
912
+ postgres:
913
+ image: postgres:15
914
+ env:
915
+ POSTGRES_PASSWORD: test
916
+ steps:
917
+ - uses: actions/checkout@v4
918
+ - name: Run integration tests
919
+ run: npm run test:integration
920
+
921
+ e2e-tests:
922
+ runs-on: ubuntu-latest
923
+ steps:
924
+ - uses: actions/checkout@v4
925
+ - name: Install Playwright
926
+ run: npx playwright install --with-deps
927
+ - name: Run E2E tests
928
+ run: npm run test:e2e
929
+ - uses: actions/upload-artifact@v4
930
+ if: failure()
931
+ with:
932
+ name: playwright-report
933
+ path: playwright-report/
64
934
  ```
65
935
 
66
- ## Omega Quality
67
- Test for ALL dimensions:
68
- - Accuracy
69
- - Performance
70
- - Security
71
- - Accessibility
936
+ ## Best Practices
937
+
938
+ ### Do's
939
+
940
+ - **Test all four quality dimensions** (accuracy, performance, security, accessibility)
941
+ - **Follow the test pyramid** - more unit tests, fewer E2E tests
942
+ - **Use descriptive test names** that explain the expected behavior
943
+ - **Test edge cases and error conditions** systematically
944
+ - **Keep tests independent** - no shared state between tests
945
+ - **Use appropriate assertions** that give helpful error messages
946
+ - **Mock external dependencies** in unit tests
947
+ - **Test real integrations** in integration tests
948
+ - **Run tests in CI/CD** on every commit
949
+ - **Maintain test data factories** for consistent test data
950
+
951
+ ### Don'ts
952
+
953
+ - Don't test implementation details - test behavior
954
+ - Don't write flaky tests - fix or delete them
955
+ - Don't skip tests without documented reason
956
+ - Don't test framework code - trust your dependencies
957
+ - Don't use sleep/delays - use proper async handling
958
+ - Don't hardcode test data - use factories
959
+ - Don't ignore failing tests - fix them immediately
960
+ - Don't over-mock - some integration is valuable
961
+ - Don't write tests after bugs escape - prevent them
962
+ - Don't chase 100% coverage - chase meaningful coverage
963
+
964
+ ## References
965
+
966
+ - [Testing Library](https://testing-library.com/)
967
+ - [Vitest Documentation](https://vitest.dev/)
968
+ - [Playwright Documentation](https://playwright.dev/)
969
+ - [OWASP Testing Guide](https://owasp.org/www-project-web-security-testing-guide/)
970
+ - [Web Content Accessibility Guidelines](https://www.w3.org/WAI/standards-guidelines/wcag/)