agentic-team-templates 0.4.2 → 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 +69 -5
- package/bin/cli.js +4 -1
- package/package.json +8 -3
- package/src/index.js +776 -134
- package/src/index.test.js +947 -0
- package/templates/testing/.cursorrules/advanced-techniques.md +596 -0
- package/templates/testing/.cursorrules/ci-cd-integration.md +603 -0
- package/templates/testing/.cursorrules/overview.md +163 -0
- package/templates/testing/.cursorrules/performance-testing.md +536 -0
- package/templates/testing/.cursorrules/quality-metrics.md +456 -0
- package/templates/testing/.cursorrules/reliability.md +557 -0
- package/templates/testing/.cursorrules/tdd-methodology.md +294 -0
- package/templates/testing/.cursorrules/test-data.md +565 -0
- package/templates/testing/.cursorrules/test-design.md +511 -0
- package/templates/testing/.cursorrules/test-types.md +398 -0
- package/templates/testing/CLAUDE.md +1134 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# CI/CD Integration
|
|
2
|
+
|
|
3
|
+
Guidelines for integrating testing into continuous integration and deployment pipelines.
|
|
4
|
+
|
|
5
|
+
## Pipeline Architecture
|
|
6
|
+
|
|
7
|
+
### Test Stages
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ CI/CD Pipeline │
|
|
12
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
13
|
+
│ │
|
|
14
|
+
│ ┌─────────┐ ┌──────────┐ ┌─────────────┐ ┌───────────┐ │
|
|
15
|
+
│ │ Static │ → │ Unit │ → │ Integration │ → │ E2E │ │
|
|
16
|
+
│ │Analysis │ │ Tests │ │ Tests │ │ Tests │ │
|
|
17
|
+
│ └─────────┘ └──────────┘ └─────────────┘ └───────────┘ │
|
|
18
|
+
│ ↓ ↓ │
|
|
19
|
+
│ ┌─────────┐ ┌───────────┐ │
|
|
20
|
+
│ │ Quality │ │Performance│ │
|
|
21
|
+
│ │ Gates │ │ Tests │ │
|
|
22
|
+
│ └─────────┘ └───────────┘ │
|
|
23
|
+
│ │
|
|
24
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Fast Feedback First
|
|
28
|
+
|
|
29
|
+
Order tests by speed and confidence:
|
|
30
|
+
|
|
31
|
+
1. **Static Analysis** (seconds) - Catch obvious errors
|
|
32
|
+
2. **Unit Tests** (seconds-minutes) - Fast, isolated
|
|
33
|
+
3. **Integration Tests** (minutes) - Real dependencies
|
|
34
|
+
4. **E2E Tests** (minutes-hours) - Full system
|
|
35
|
+
5. **Performance Tests** (hours) - Load testing
|
|
36
|
+
|
|
37
|
+
## GitHub Actions Configuration
|
|
38
|
+
|
|
39
|
+
### Complete Test Pipeline
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
# .github/workflows/test.yml
|
|
43
|
+
name: Test Pipeline
|
|
44
|
+
|
|
45
|
+
on:
|
|
46
|
+
push:
|
|
47
|
+
branches: [main, develop]
|
|
48
|
+
pull_request:
|
|
49
|
+
branches: [main, develop]
|
|
50
|
+
|
|
51
|
+
concurrency:
|
|
52
|
+
group: test-${{ github.ref }}
|
|
53
|
+
cancel-in-progress: true
|
|
54
|
+
|
|
55
|
+
jobs:
|
|
56
|
+
# Stage 1: Static Analysis (fastest)
|
|
57
|
+
static-analysis:
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
- uses: actions/setup-node@v4
|
|
63
|
+
with:
|
|
64
|
+
node-version: '20'
|
|
65
|
+
cache: 'npm'
|
|
66
|
+
|
|
67
|
+
- run: npm ci
|
|
68
|
+
|
|
69
|
+
- name: Type Check
|
|
70
|
+
run: npm run type-check
|
|
71
|
+
|
|
72
|
+
- name: Lint
|
|
73
|
+
run: npm run lint
|
|
74
|
+
|
|
75
|
+
- name: Format Check
|
|
76
|
+
run: npm run format:check
|
|
77
|
+
|
|
78
|
+
# Stage 2: Unit Tests (fast)
|
|
79
|
+
unit-tests:
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
needs: static-analysis
|
|
82
|
+
steps:
|
|
83
|
+
- uses: actions/checkout@v4
|
|
84
|
+
|
|
85
|
+
- uses: actions/setup-node@v4
|
|
86
|
+
with:
|
|
87
|
+
node-version: '20'
|
|
88
|
+
cache: 'npm'
|
|
89
|
+
|
|
90
|
+
- run: npm ci
|
|
91
|
+
|
|
92
|
+
- name: Run Unit Tests
|
|
93
|
+
run: npm run test:unit -- --coverage --reporter=junit --outputFile=test-results/junit.xml
|
|
94
|
+
|
|
95
|
+
- name: Upload Coverage
|
|
96
|
+
uses: codecov/codecov-action@v4
|
|
97
|
+
with:
|
|
98
|
+
files: coverage/lcov.info
|
|
99
|
+
fail_ci_if_error: true
|
|
100
|
+
|
|
101
|
+
- name: Upload Test Results
|
|
102
|
+
if: always()
|
|
103
|
+
uses: actions/upload-artifact@v4
|
|
104
|
+
with:
|
|
105
|
+
name: unit-test-results
|
|
106
|
+
path: test-results/
|
|
107
|
+
|
|
108
|
+
# Stage 3: Integration Tests (medium)
|
|
109
|
+
integration-tests:
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
needs: unit-tests
|
|
112
|
+
services:
|
|
113
|
+
postgres:
|
|
114
|
+
image: postgres:16
|
|
115
|
+
env:
|
|
116
|
+
POSTGRES_PASSWORD: test
|
|
117
|
+
POSTGRES_DB: test
|
|
118
|
+
options: >-
|
|
119
|
+
--health-cmd pg_isready
|
|
120
|
+
--health-interval 10s
|
|
121
|
+
--health-timeout 5s
|
|
122
|
+
--health-retries 5
|
|
123
|
+
ports:
|
|
124
|
+
- 5432:5432
|
|
125
|
+
|
|
126
|
+
redis:
|
|
127
|
+
image: redis:7
|
|
128
|
+
ports:
|
|
129
|
+
- 6379:6379
|
|
130
|
+
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v4
|
|
133
|
+
|
|
134
|
+
- uses: actions/setup-node@v4
|
|
135
|
+
with:
|
|
136
|
+
node-version: '20'
|
|
137
|
+
cache: 'npm'
|
|
138
|
+
|
|
139
|
+
- run: npm ci
|
|
140
|
+
|
|
141
|
+
- name: Run Migrations
|
|
142
|
+
run: npm run db:migrate
|
|
143
|
+
env:
|
|
144
|
+
DATABASE_URL: postgres://postgres:test@localhost:5432/test
|
|
145
|
+
|
|
146
|
+
- name: Run Integration Tests
|
|
147
|
+
run: npm run test:integration -- --reporter=junit --outputFile=test-results/junit.xml
|
|
148
|
+
env:
|
|
149
|
+
DATABASE_URL: postgres://postgres:test@localhost:5432/test
|
|
150
|
+
REDIS_URL: redis://localhost:6379
|
|
151
|
+
|
|
152
|
+
- name: Upload Test Results
|
|
153
|
+
if: always()
|
|
154
|
+
uses: actions/upload-artifact@v4
|
|
155
|
+
with:
|
|
156
|
+
name: integration-test-results
|
|
157
|
+
path: test-results/
|
|
158
|
+
|
|
159
|
+
# Stage 4: E2E Tests (slow)
|
|
160
|
+
e2e-tests:
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
needs: integration-tests
|
|
163
|
+
steps:
|
|
164
|
+
- uses: actions/checkout@v4
|
|
165
|
+
|
|
166
|
+
- uses: actions/setup-node@v4
|
|
167
|
+
with:
|
|
168
|
+
node-version: '20'
|
|
169
|
+
cache: 'npm'
|
|
170
|
+
|
|
171
|
+
- run: npm ci
|
|
172
|
+
|
|
173
|
+
- name: Install Playwright
|
|
174
|
+
run: npx playwright install --with-deps chromium
|
|
175
|
+
|
|
176
|
+
- name: Build Application
|
|
177
|
+
run: npm run build
|
|
178
|
+
|
|
179
|
+
- name: Start Application
|
|
180
|
+
run: npm run start &
|
|
181
|
+
env:
|
|
182
|
+
NODE_ENV: test
|
|
183
|
+
|
|
184
|
+
- name: Wait for Application
|
|
185
|
+
run: npx wait-on http://localhost:3000 --timeout 60000
|
|
186
|
+
|
|
187
|
+
- name: Run E2E Tests
|
|
188
|
+
run: npm run test:e2e
|
|
189
|
+
|
|
190
|
+
- name: Upload Playwright Report
|
|
191
|
+
if: always()
|
|
192
|
+
uses: actions/upload-artifact@v4
|
|
193
|
+
with:
|
|
194
|
+
name: playwright-report
|
|
195
|
+
path: playwright-report/
|
|
196
|
+
|
|
197
|
+
- name: Upload Screenshots
|
|
198
|
+
if: failure()
|
|
199
|
+
uses: actions/upload-artifact@v4
|
|
200
|
+
with:
|
|
201
|
+
name: e2e-screenshots
|
|
202
|
+
path: test-results/
|
|
203
|
+
|
|
204
|
+
# Quality Gates
|
|
205
|
+
quality-gates:
|
|
206
|
+
runs-on: ubuntu-latest
|
|
207
|
+
needs: [unit-tests, integration-tests]
|
|
208
|
+
steps:
|
|
209
|
+
- uses: actions/checkout@v4
|
|
210
|
+
|
|
211
|
+
- uses: actions/setup-node@v4
|
|
212
|
+
with:
|
|
213
|
+
node-version: '20'
|
|
214
|
+
cache: 'npm'
|
|
215
|
+
|
|
216
|
+
- run: npm ci
|
|
217
|
+
|
|
218
|
+
- name: Check Coverage Threshold
|
|
219
|
+
run: |
|
|
220
|
+
npm run test:unit -- --coverage
|
|
221
|
+
COVERAGE=$(jq '.total.lines.pct' coverage/coverage-summary.json)
|
|
222
|
+
echo "Coverage: $COVERAGE%"
|
|
223
|
+
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
|
|
224
|
+
echo "Coverage $COVERAGE% is below 80% threshold"
|
|
225
|
+
exit 1
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
- name: Run Mutation Tests
|
|
229
|
+
run: npx stryker run
|
|
230
|
+
continue-on-error: true
|
|
231
|
+
|
|
232
|
+
- name: Upload Mutation Report
|
|
233
|
+
uses: actions/upload-artifact@v4
|
|
234
|
+
with:
|
|
235
|
+
name: mutation-report
|
|
236
|
+
path: reports/mutation/
|
|
237
|
+
|
|
238
|
+
# Performance Tests (main branch only)
|
|
239
|
+
performance-tests:
|
|
240
|
+
runs-on: ubuntu-latest
|
|
241
|
+
needs: e2e-tests
|
|
242
|
+
if: github.ref == 'refs/heads/main'
|
|
243
|
+
steps:
|
|
244
|
+
- uses: actions/checkout@v4
|
|
245
|
+
|
|
246
|
+
- name: Deploy to Staging
|
|
247
|
+
run: ./scripts/deploy-staging.sh
|
|
248
|
+
|
|
249
|
+
- name: Run Load Tests
|
|
250
|
+
uses: grafana/k6-action@v0.3.1
|
|
251
|
+
with:
|
|
252
|
+
filename: load-tests/smoke.js
|
|
253
|
+
flags: --out json=results.json
|
|
254
|
+
|
|
255
|
+
- name: Check Performance Thresholds
|
|
256
|
+
run: |
|
|
257
|
+
ERROR_RATE=$(jq '.metrics.http_req_failed.values.rate' results.json)
|
|
258
|
+
if (( $(echo "$ERROR_RATE > 0.01" | bc -l) )); then
|
|
259
|
+
echo "Error rate $ERROR_RATE exceeds 1% threshold"
|
|
260
|
+
exit 1
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
- name: Upload Performance Results
|
|
264
|
+
uses: actions/upload-artifact@v4
|
|
265
|
+
with:
|
|
266
|
+
name: performance-results
|
|
267
|
+
path: results.json
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Parallel Test Execution
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
# Run tests in parallel across multiple jobs
|
|
274
|
+
integration-tests:
|
|
275
|
+
runs-on: ubuntu-latest
|
|
276
|
+
strategy:
|
|
277
|
+
fail-fast: false
|
|
278
|
+
matrix:
|
|
279
|
+
shard: [1, 2, 3, 4]
|
|
280
|
+
|
|
281
|
+
steps:
|
|
282
|
+
- uses: actions/checkout@v4
|
|
283
|
+
|
|
284
|
+
- run: npm ci
|
|
285
|
+
|
|
286
|
+
- name: Run Tests (Shard ${{ matrix.shard }}/4)
|
|
287
|
+
run: npm run test:integration -- --shard=${{ matrix.shard }}/4
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Test Caching
|
|
291
|
+
|
|
292
|
+
```yaml
|
|
293
|
+
# Cache test dependencies and build artifacts
|
|
294
|
+
- name: Cache Dependencies
|
|
295
|
+
uses: actions/cache@v4
|
|
296
|
+
with:
|
|
297
|
+
path: |
|
|
298
|
+
~/.npm
|
|
299
|
+
node_modules
|
|
300
|
+
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
|
301
|
+
restore-keys: |
|
|
302
|
+
${{ runner.os }}-node-
|
|
303
|
+
|
|
304
|
+
- name: Cache Build
|
|
305
|
+
uses: actions/cache@v4
|
|
306
|
+
with:
|
|
307
|
+
path: .next
|
|
308
|
+
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
|
|
309
|
+
restore-keys: |
|
|
310
|
+
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Pull Request Checks
|
|
314
|
+
|
|
315
|
+
### Required Checks
|
|
316
|
+
|
|
317
|
+
```yaml
|
|
318
|
+
# .github/workflows/pr-checks.yml
|
|
319
|
+
name: PR Checks
|
|
320
|
+
|
|
321
|
+
on: pull_request
|
|
322
|
+
|
|
323
|
+
jobs:
|
|
324
|
+
test-coverage-diff:
|
|
325
|
+
runs-on: ubuntu-latest
|
|
326
|
+
steps:
|
|
327
|
+
- uses: actions/checkout@v4
|
|
328
|
+
with:
|
|
329
|
+
fetch-depth: 0
|
|
330
|
+
|
|
331
|
+
- run: npm ci
|
|
332
|
+
|
|
333
|
+
- name: Get Changed Files
|
|
334
|
+
id: changed-files
|
|
335
|
+
uses: tj-actions/changed-files@v44
|
|
336
|
+
with:
|
|
337
|
+
files: |
|
|
338
|
+
src/**/*.ts
|
|
339
|
+
src/**/*.tsx
|
|
340
|
+
|
|
341
|
+
- name: Check New Code Has Tests
|
|
342
|
+
if: steps.changed-files.outputs.any_changed == 'true'
|
|
343
|
+
run: |
|
|
344
|
+
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
|
345
|
+
if [[ "$file" == *.test.* ]]; then
|
|
346
|
+
continue
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
TEST_FILE="${file%.ts}.test.ts"
|
|
350
|
+
if [[ ! -f "$TEST_FILE" ]]; then
|
|
351
|
+
echo "Missing test file for: $file"
|
|
352
|
+
# Warn but don't fail
|
|
353
|
+
fi
|
|
354
|
+
done
|
|
355
|
+
|
|
356
|
+
- name: Run Tests for Changed Files
|
|
357
|
+
run: |
|
|
358
|
+
npm run test:unit -- --changed --coverage
|
|
359
|
+
|
|
360
|
+
lint-commit-messages:
|
|
361
|
+
runs-on: ubuntu-latest
|
|
362
|
+
steps:
|
|
363
|
+
- uses: actions/checkout@v4
|
|
364
|
+
with:
|
|
365
|
+
fetch-depth: 0
|
|
366
|
+
|
|
367
|
+
- name: Lint Commit Messages
|
|
368
|
+
uses: wagoid/commitlint-github-action@v5
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### PR Comment with Results
|
|
372
|
+
|
|
373
|
+
```yaml
|
|
374
|
+
- name: Comment Test Results
|
|
375
|
+
uses: actions/github-script@v7
|
|
376
|
+
if: always() && github.event_name == 'pull_request'
|
|
377
|
+
with:
|
|
378
|
+
script: |
|
|
379
|
+
const fs = require('fs');
|
|
380
|
+
|
|
381
|
+
let coverage = 'N/A';
|
|
382
|
+
try {
|
|
383
|
+
const summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json'));
|
|
384
|
+
coverage = `${summary.total.lines.pct.toFixed(1)}%`;
|
|
385
|
+
} catch (e) {}
|
|
386
|
+
|
|
387
|
+
const body = `## Test Results
|
|
388
|
+
|
|
389
|
+
| Metric | Value |
|
|
390
|
+
|--------|-------|
|
|
391
|
+
| Coverage | ${coverage} |
|
|
392
|
+
| Status | ${{ job.status }} |
|
|
393
|
+
|
|
394
|
+
[View detailed report](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})
|
|
395
|
+
`;
|
|
396
|
+
|
|
397
|
+
github.rest.issues.createComment({
|
|
398
|
+
issue_number: context.issue.number,
|
|
399
|
+
owner: context.repo.owner,
|
|
400
|
+
repo: context.repo.repo,
|
|
401
|
+
body: body
|
|
402
|
+
});
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Test Environment Management
|
|
406
|
+
|
|
407
|
+
### Docker Compose for Local CI
|
|
408
|
+
|
|
409
|
+
```yaml
|
|
410
|
+
# docker-compose.test.yml
|
|
411
|
+
version: '3.8'
|
|
412
|
+
|
|
413
|
+
services:
|
|
414
|
+
app:
|
|
415
|
+
build: .
|
|
416
|
+
environment:
|
|
417
|
+
- NODE_ENV=test
|
|
418
|
+
- DATABASE_URL=postgres://postgres:test@db:5432/test
|
|
419
|
+
- REDIS_URL=redis://redis:6379
|
|
420
|
+
depends_on:
|
|
421
|
+
db:
|
|
422
|
+
condition: service_healthy
|
|
423
|
+
redis:
|
|
424
|
+
condition: service_started
|
|
425
|
+
|
|
426
|
+
db:
|
|
427
|
+
image: postgres:16
|
|
428
|
+
environment:
|
|
429
|
+
POSTGRES_PASSWORD: test
|
|
430
|
+
POSTGRES_DB: test
|
|
431
|
+
healthcheck:
|
|
432
|
+
test: ["CMD-SHELL", "pg_isready"]
|
|
433
|
+
interval: 10s
|
|
434
|
+
timeout: 5s
|
|
435
|
+
retries: 5
|
|
436
|
+
|
|
437
|
+
redis:
|
|
438
|
+
image: redis:7
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Testcontainers
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
// test/setup.ts
|
|
445
|
+
import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';
|
|
446
|
+
import { RedisContainer, StartedRedisContainer } from '@testcontainers/redis';
|
|
447
|
+
|
|
448
|
+
let postgres: StartedPostgreSqlContainer;
|
|
449
|
+
let redis: StartedRedisContainer;
|
|
450
|
+
|
|
451
|
+
export async function setupTestContainers() {
|
|
452
|
+
postgres = await new PostgreSqlContainer()
|
|
453
|
+
.withDatabase('test')
|
|
454
|
+
.start();
|
|
455
|
+
|
|
456
|
+
redis = await new RedisContainer().start();
|
|
457
|
+
|
|
458
|
+
process.env.DATABASE_URL = postgres.getConnectionUri();
|
|
459
|
+
process.env.REDIS_URL = `redis://${redis.getHost()}:${redis.getPort()}`;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export async function teardownTestContainers() {
|
|
463
|
+
await postgres?.stop();
|
|
464
|
+
await redis?.stop();
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Reporting and Visibility
|
|
469
|
+
|
|
470
|
+
### Test Report Generation
|
|
471
|
+
|
|
472
|
+
```ts
|
|
473
|
+
// vitest.config.ts
|
|
474
|
+
export default {
|
|
475
|
+
test: {
|
|
476
|
+
reporters: [
|
|
477
|
+
'default',
|
|
478
|
+
'junit',
|
|
479
|
+
'html',
|
|
480
|
+
['vitest-sonar-reporter', { outputFile: 'sonar-report.xml' }],
|
|
481
|
+
],
|
|
482
|
+
outputFile: {
|
|
483
|
+
junit: 'test-results/junit.xml',
|
|
484
|
+
html: 'test-results/report.html',
|
|
485
|
+
},
|
|
486
|
+
coverage: {
|
|
487
|
+
reporter: ['text', 'json', 'html', 'lcov'],
|
|
488
|
+
reportsDirectory: 'coverage',
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### SonarQube Integration
|
|
495
|
+
|
|
496
|
+
```yaml
|
|
497
|
+
- name: SonarQube Scan
|
|
498
|
+
uses: SonarSource/sonarqube-scan-action@master
|
|
499
|
+
env:
|
|
500
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
501
|
+
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
```properties
|
|
505
|
+
# sonar-project.properties
|
|
506
|
+
sonar.projectKey=my-project
|
|
507
|
+
sonar.sources=src
|
|
508
|
+
sonar.tests=src
|
|
509
|
+
sonar.test.inclusions=**/*.test.ts
|
|
510
|
+
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
|
511
|
+
sonar.testExecutionReportPaths=sonar-report.xml
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## Deployment Gates
|
|
515
|
+
|
|
516
|
+
### Staging Deployment
|
|
517
|
+
|
|
518
|
+
```yaml
|
|
519
|
+
deploy-staging:
|
|
520
|
+
needs: [e2e-tests]
|
|
521
|
+
runs-on: ubuntu-latest
|
|
522
|
+
environment:
|
|
523
|
+
name: staging
|
|
524
|
+
url: https://staging.example.com
|
|
525
|
+
steps:
|
|
526
|
+
- uses: actions/checkout@v4
|
|
527
|
+
|
|
528
|
+
- name: Deploy to Staging
|
|
529
|
+
run: ./scripts/deploy.sh staging
|
|
530
|
+
|
|
531
|
+
- name: Run Smoke Tests
|
|
532
|
+
run: npm run test:smoke -- --base-url=https://staging.example.com
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Production Deployment
|
|
536
|
+
|
|
537
|
+
```yaml
|
|
538
|
+
deploy-production:
|
|
539
|
+
needs: [performance-tests]
|
|
540
|
+
runs-on: ubuntu-latest
|
|
541
|
+
if: github.ref == 'refs/heads/main'
|
|
542
|
+
environment:
|
|
543
|
+
name: production
|
|
544
|
+
url: https://example.com
|
|
545
|
+
steps:
|
|
546
|
+
- uses: actions/checkout@v4
|
|
547
|
+
|
|
548
|
+
- name: Deploy to Production
|
|
549
|
+
run: ./scripts/deploy.sh production
|
|
550
|
+
|
|
551
|
+
- name: Run Health Checks
|
|
552
|
+
run: |
|
|
553
|
+
for i in {1..30}; do
|
|
554
|
+
if curl -s https://example.com/health | grep -q "ok"; then
|
|
555
|
+
exit 0
|
|
556
|
+
fi
|
|
557
|
+
sleep 10
|
|
558
|
+
done
|
|
559
|
+
exit 1
|
|
560
|
+
|
|
561
|
+
- name: Notify Slack
|
|
562
|
+
if: always()
|
|
563
|
+
uses: slackapi/slack-github-action@v1
|
|
564
|
+
with:
|
|
565
|
+
payload: |
|
|
566
|
+
{
|
|
567
|
+
"text": "Deployment to production: ${{ job.status }}"
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Best Practices
|
|
572
|
+
|
|
573
|
+
### 1. Fail Fast
|
|
574
|
+
|
|
575
|
+
Run fastest tests first. If static analysis fails, skip slower tests.
|
|
576
|
+
|
|
577
|
+
### 2. Parallelize Everything
|
|
578
|
+
|
|
579
|
+
Split tests across workers and shards for faster execution.
|
|
580
|
+
|
|
581
|
+
### 3. Cache Aggressively
|
|
582
|
+
|
|
583
|
+
Cache dependencies, build artifacts, and test databases.
|
|
584
|
+
|
|
585
|
+
### 4. Isolate Test Environments
|
|
586
|
+
|
|
587
|
+
Each test run should have isolated resources.
|
|
588
|
+
|
|
589
|
+
### 5. Artifact Everything
|
|
590
|
+
|
|
591
|
+
Upload test results, coverage, screenshots for debugging.
|
|
592
|
+
|
|
593
|
+
### 6. Notify on Failure
|
|
594
|
+
|
|
595
|
+
Alert team immediately when tests fail on main branch.
|
|
596
|
+
|
|
597
|
+
### 7. Track Metrics Over Time
|
|
598
|
+
|
|
599
|
+
Store test duration, coverage, flakiness metrics historically.
|
|
600
|
+
|
|
601
|
+
### 8. Review Test Reports in PRs
|
|
602
|
+
|
|
603
|
+
Make test results visible and actionable in pull requests.
|