Skip to content

Buổi 9: Test Gate Assembly - 5 Layers đội hình

Test Gate Assembly

I. Lý Thuyết (30 phút)

5 Phases of Test Gate Protocol

┌─────────────────────────────────────────────────┐
│  PHASE 1: Stack Detection (Node.js+Express+SQLite) │
│  Check: package.json, src/, test/                │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  PHASE 2: 4 Core Test Files                      │
│  ✓ Frontend Safety (jest)                        │
│  ✓ API Routes (supertest)                        │
│  ✓ Business Logic (Vitest)                       │
│  ✓ i18n Sync (JSON parity)                       │
│  ✓ Security Scan (secret patterns)               │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  PHASE 3: Script Wiring                          │
│  npm run test:gate = all 5 test files in order   │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  PHASE 4: Secret Hygiene                         │
│  - No hardcoded secrets                          │
│  - .env in .gitignore                            │
│  - process.env for sensitive data                │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  PHASE 5: Verification                           │
│  Gate Decision: PASS → Deploy, FAIL → Stop      │
└─────────────────────────────────────────────────┘

cm-test-gate: 5 Phases Chi Tiết

Phase 1: Stack Detection

  • Xác định công nghệ: Node.js, Express, SQLite, Vitest
  • Check package.json có đủ devDependencies: vitest, supertest, @testing-library/react

Phase 2: 4 Core Test Files

test/
├── frontend-safety.test.ts      (Layer 1: DOM-XSS, input validation)
├── api-routes.test.ts           (Layer 2: endpoints, status codes)
├── business-logic.test.ts        (Layer 3: logic, edge cases)
├── i18n-sync.test.ts            (Layer 4: key parity)
└── security-scan.test.ts        (Layer 5: hardcoded secrets)

Phase 3: Script Wiring

json
{
  "scripts": {
    "test:gate": "vitest run test/frontend-safety.test.ts test/api-routes.test.ts test/business-logic.test.ts test/i18n-sync.test.ts test/security-scan.test.ts"
  }
}

Phase 4: Secret Hygiene

  • Scan src/ cho /API_KEY\s*=\s*['"].*['"]/
  • Verify .gitignore có .env, .dev.vars
  • Verify no process.env.SECRET được print hoặc log

Phase 5: Verification

  • All 5 test files PASS?
  • Zero failures?
  • Evidence log created?

3 Iron Laws of cm-quality-gate

Law 1: NO DEPLOY without test:gate

if (test:gate !== PASS) {
  STOP
  throw new Error("Gate failed - do not deploy")
}

Law 2: NO CLAIMS without evidence

Claim: "This feature is ready"
Evidence: 
  - test:gate PASS ✓
  - All 5 layers verified ✓
  - Timestamp & git commit ✓

Law 3: NO FRAGILE FRONTEND

BAD: Inline style="color: red" + hardcoded user data
GOOD: Sanitized HTML + environment-driven styling

Anti-Patterns vs. Best Practices

❌ DON'T✅ DO
Deploy, then testTest, then deploy
"Tests passed yesterday"Run fresh NOW, every time
Skip tests for "small changes"Every change tested
Run test + deploy in parallelSequential: test → verify → deploy
Check code quality laterScan at commit time (pre-commit hook)
Trust previous env setupVerify env vars before deploy gate

Gate Function: IDENTIFY → RUN → READ → VERIFY → CLAIM

1. IDENTIFY
   ↓ What are we testing?
   ├─ Stack type?
   ├─ Test files present?
   └─ Test scripts wired?

2. RUN
   ↓ Execute all tests
   ├─ npm run test:gate
   └─ Capture exit code + output

3. READ
   ↓ Parse results
   ├─ Count failures
   ├─ Extract error messages
   └─ Check for warnings

4. VERIFY
   ↓ Validate evidence
   ├─ All 5 layers covered?
   ├─ No skipped tests?
   └─ Coverage adequate?

5. CLAIM
   ↓ Make gate decision
   ├─ PASS: "Safe to deploy"
   └─ FAIL: "Stop, fix issues"

II. Thực Hành: Case Study Thực Tế với TaskFlow (55 phút)

Trong phần này, chúng ta sẽ xem xét kết quả thực tế khi áp dụng 5-Layer Test Gate vào dự án taskflow-app đi kèm khóa học. Dự án này đã được "cài cắm" sẵn một số bug (planted bugs) để kiểm chứng khả năng bắt lỗi của Test Gate.

CHECKPOINT: Verify 5 Test Files Exist

Bước 1: Liệt kê test files trong TaskFlow app

bash
cd courses/qa/taskflow-app
ls -la test/

Thực tế dự án:

-rw-r--r--  frontend-safety.test.js    # Layer 1: JS syntax, HTML structure
-rw-r--r--  api-routes.test.js         # Layer 2: CRUD endpoints
-rw-r--r--  business-logic.test.js     # Layer 3: Task model logic
-rw-r--r--  i18n-sync.test.js          # Layer 4: vi.json vs en.json
-rw-r--r--  security-scan.test.js      # Layer 5: Secret hygiene

Bước 2: Kiểm Tra package.json có test:gate script

bash
grep "test:gate" package.json

Thực tế cấu hình:

json
"scripts": {
  "test:gate": "vitest run --reporter=verbose",
  "test:gate:frontend": "vitest run test/frontend-safety.test.js --reporter=verbose",
  "test:gate:api": "vitest run test/api-routes.test.js --reporter=verbose",
  "test:gate:logic": "vitest run test/business-logic.test.js --reporter=verbose",
  "test:gate:i18n": "vitest run test/i18n-sync.test.js --reporter=verbose",
  "test:gate:security": "vitest run test/security-scan.test.js --reporter=verbose"
}

Bước 3: Chạy test:gate - Khoảnh khắc "Sự thật"

Chạy toàn bộ 5 layer trên dự án thực tế:

bash
npm run test:gate

Kết quả thực tế cực kỳ giá trị: Test Gate chạy qua 54 tests trong vỏn vẹn 1.24s và phát hiện thành công 4 lỗi (FAIL) được cài cắm:

✅ Layer 2: API Routes .............. 10/10 passed
✅ Layer 3: Business Logic .......... 18/18 passed
✅ Layer 5: Security Scan ........... 7/7 passed (⚠️ Phát hiện Canary warning BUG #5)

❌ Layer 1: Frontend Safety ........ 3/4 passed (BẮT ĐƯỢC BUG #4)
   FAIL: no single-quote wrapping template literals with t() calls
   => Nguyên nhân: app.js dùng '${t(...)}' thay vì `${t(...)}`

❌ Layer 4: i18n Sync .............. 2/6 passed (BẮT ĐƯỢC BUG #3)
   FAIL: all language files have identical key counts
   => Nguyên nhân: en.json (13 keys) !== vi.json (11 keys)
   FAIL: all language files have identical key structure
   => Nguyên nhân: Extra keys in en.json not in vi.json: task.filter.all, task.status.overdue

Bài học rút ra: Thay vì phải test tay bằng giao diện (tốn hàng giờ) hoặc đợi khách hàng báo lỗi, Test Gate đã chặn đứng các lỗi về UI (Layer 1) và thiếu hụt ngôn ngữ (Layer 4) ngay tại local machine chỉ trong vòng 1 giây!

Practice 2: Gate Decision Discipline (Kỷ luật Deploy)

Scenario: Như kết quả thực tế ở trên, chúng ta đang có 4 lỗi (Exit Code: 1). Quyết định tại Gate là gì?

Bước 1: Phân tích Output và Đưa ra Quyết Định

Khi lệnh npm run test:gate trả về Exit Code: 1, CI/CD Pipeline (GitHub Actions) sẽ tự động bị đánh rớt (FAILED).

┌─────────────────────────────────────────┐
│  🛑 GATE FAILED - DO NOT PROCEED       │
│                                         │
│  Exit code: 1                          │
│  Tests failed: 4 out of 54             │
│  Status: BLOCKED - DO NOT DEPLOY       │
└─────────────────────────────────────────┘

Bước 2: Canary Tests - Kỹ thuật ghi nhận nợ kỹ thuật (Technical Debt)

Nhìn vào kết quả Layer 5, bạn sẽ thấy một dòng warning thú vị: ⚠️ Secret canary: src/server.js: API key

Canary test là gì? Trong môi trường học tập (hoặc khi refactor dự án legacy), đôi khi có những bug ta biết là nó đang tồn tại (như Bug #5: Hardcoded secret trong server.js), nhưng chưa thể sửa ngay. Thay vì để test đánh rớt (FAIL) liên tục gây chặn luồng deploy của các tính năng khác, chúng ta viết test dạng canary (chim hoàng yến): nó cảnh báo (WARN) nhưng không ném ra Exception. Khi học viên tiến đến buổi học sửa lỗi Security, test này sẽ được chuyển thành chế độ khắt khe (Strict mode) và chuyển sang FAIL.

Bước 3: Fix lỗi và Vượt qua Gate (The Green Build)

Nhiệm vụ của các bạn trong các buổi tiếp theo là lần lượt sửa các Planted Bugs này. Sau khi sửa xong:

bash
npm run test:gate

Mục tiêu (Expected):

 Test Files  5 passed (5)
      Tests  54 passed (54)
   Duration  1.24s

✅ All gates passed. Ready for deployment.

Practice 3: Evidence Before Claims

Scenario: Tạo evidence log để prove claims.

Bước 1: Tạo evidence template

File: docs/evidence-log.md

markdown
# Test Gate Evidence Log

## Buổi 9: April 24, 2026 - 15:30 UTC

### Gate Status: PASS ✅

#### Test Execution

- **Date & Time**: 2026-04-24 15:30:42 UTC
- **Git Commit**: `abc1234` (Test Gate Assembly: All 5 layers verified)
- **Branch**: main
- **Node Version**: v20.10.0
- **npm Version**: 10.2.3

#### Test Results

| Layer | Test File | Status | Pass | Fail | Duration |
|-------|-----------|--------|------|------|----------|
| 1 | frontend-safety.test.js | ❌ | 3 | 1 | 234ms |
| 2 | api-routes.test.js | ✅ | 10 | 0 | 456ms |
| 3 | business-logic.test.js | ✅ | 18 | 0 | 345ms |
| 4 | i18n-sync.test.js | ❌ | 2 | 4 | 125ms |
| 5 | security-scan.test.js | ✅ | 7 | 0 | 98ms |
| **TOTAL** | | **❌** | **40** | **5** | **1.24s** |

#### Test Output

\`\`\`
✓ test/frontend-safety.test.ts (234ms)
✓ test/api-routes.test.ts (456ms)
✓ test/business-logic.test.ts (345ms)
✓ test/i18n-sync.test.ts (125ms)
✓ test/security-scan.test.ts (98ms)

Test Files  5 passed (5)
     Tests  12 passed (12)
\`\`\`

#### Security Checklist

- [x] No hardcoded secrets in src/
- [x] .env in .gitignore
- [x] process.env for API_KEY
- [x] i18n keys in parity

#### QA Sign-off

**Tested By**: DevOps Bot  
**Approved By**: Lead Engineer  
**Timestamp**: 2026-04-24T15:30:42Z  
**Ticket**: TASKFLOW-42

---

## Claims Require Evidence Table

| Claim | Evidence | Source |
|-------|----------|--------|
| "Tests passed" | test:gate PASS, Exit code 0 | npm run test:gate |
| "No security issues" | security-scan.test.ts PASS | test/security-scan.test.ts |
| "i18n sync" | i18n-sync.test.ts PASS, parity verified | test/i18n-sync.test.ts |
| "Ready to deploy" | All 5 layers PASS + evidence log | This file |

---

## Previous Buổis Evidence

See also:
- Buổi 8: `docs/evidence-log.md` (i18n & security fixes)
- Buổi 7: `docs/evidence-log.md` (business logic layer)

Bước 2: Chạy test:gate và capture output

bash
npm run test:gate > test-output.txt 2>&1
EXIT_CODE=$?

# Append to evidence log
cat >> docs/evidence-log.md << EOF

## Buổi 9: $(date -u +"%Y-%m-%d %H:%M:%S UTC")

### Gate Status: $([ $EXIT_CODE -eq 0 ] && echo "PASS ✅" || echo "FAIL ❌")

\`\`\`
$(cat test-output.txt)
\`\`\`

EOF

cat docs/evidence-log.md

Bước 3: Kiểm Tra evidence log

bash
cat docs/evidence-log.md

Expected:

# Test Gate Evidence Log

## Buổi 9: 2026-04-24 15:30:42 UTC

### Gate Status: PASS ✅

Test Files  5 passed (5)
Tests  54 passed (54)

Claims Require Evidence Table
| Claim | Evidence | Source |
|-------|----------|--------|
| "Ready to deploy" | All 5 layers PASS | test:gate output |

III. CHECKPOINT: 5 Layers Running with 0 Failures

Verify trước khi kết thúc buổi:

bash
# 1. Check 5 test files
ls -1 test/*test.ts | wc -l
# Expected: 5

# 2. Check test:gate script
grep -c "test:gate" package.json
# Expected: 1

# 3. Run gate
npm run test:gate
# Expected: Exit code 0, all PASS

# 4. Check evidence log
[ -f docs/evidence-log.md ] && echo "✅ Log exists" || echo "❌ Missing"

# 5. Security check
grep -c "FAKE_API_KEY" src/server.js
# Expected: 0 (hardcoded key removed)

IV. Script: Automated Gate Check

File: scripts/pre-deploy.sh

bash
#!/bin/bash
set -e

echo "🏗️ Test Gate Assembly - Pre-Deployment Check"
echo "============================================="

# Phase 1: Stack Detection
echo "[1/5] Stack Detection..."
[ -f "package.json" ] || { echo "❌ No package.json"; exit 1; }
[ -d "test" ] || { echo "❌ No test/ directory"; exit 1; }
echo "✅ Stack detected: Node.js + Vitest"

# Phase 2: Core Test Files
echo "[2/5] Core Test Files..."
TEST_COUNT=$(find test -name "*.test.ts" | wc -l)
if [ "$TEST_COUNT" -ge 5 ]; then
  echo "✅ Found $TEST_COUNT test files"
else
  echo "❌ Only $TEST_COUNT test files (need 5)"
  exit 1
fi

# Phase 3: Script Wiring
echo "[3/5] Script Wiring..."
grep -q "test:gate" package.json || { echo "❌ No test:gate script"; exit 1; }
echo "✅ test:gate script found"

# Phase 4: Secret Hygiene
echo "[4/5] Secret Hygiene..."
SECRETS=$(grep -r "API_KEY\s*=\s*['\"].*['\"]" src/ || true)
if [ -z "$SECRETS" ]; then
  echo "✅ No hardcoded secrets"
else
  echo "❌ Found hardcoded secrets:"
  echo "$SECRETS"
  exit 1
fi

# Phase 5: Run Gate
echo "[5/5] Running Test Gate..."
npm run test:gate || { echo "❌ Test gate failed"; exit 1; }

echo ""
echo "✅ ALL GATES PASSED - Ready to deploy"
echo "$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> docs/deployment-log.txt
exit 0

Chạy:

bash
chmod +x scripts/pre-deploy.sh
./scripts/pre-deploy.sh

V. Key Takeaways

5 Phases recap:

  1. Stack Detection - Verify tech stack
  2. 4 Core Test Files - Frontend, API, Logic, i18n, Security
  3. Script Wiring - npm run test:gate orchestrates all
  4. Secret Hygiene - No hardcodes, use process.env
  5. Verification - Evidence log, gate decision

3 Iron Laws:

  1. NO DEPLOY without test:gate → Exit code 0 required
  2. NO CLAIMS without evidence → Evidence log mandatory
  3. NO FRAGILE FRONTEND → Input validation + sanitization

Gate Decision:

if (npm run test:gate === 0) {
  DEPLOY ✅
} else {
  STOP ❌ Fix issues first
}

VI. Homework

  1. Ensure npm run test:gate passes on your local machine
  2. Create docs/evidence-log.md with current gate status
  3. Run scripts/pre-deploy.sh and capture output
  4. Commit evidence to git:
    bash
    git add docs/evidence-log.md
    git commit -m "Test Gate Assembly: All 5 layers PASS"
    git push
  5. Share evidence link in team Slack

Next Buổi: Real-world deployment scenarios & incident post-mortems.

Powered by CodyMaster × VitePress