@educa-corp/sdd-framework 0.9.3 → 0.9.4
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/bin/build.js +11 -0
- package/bin/qc-base-map.json +119 -49
- package/bin/self-check.js +30 -0
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/qc-analyze.md +6 -119
- package/core/commands/qc-design-test.md +123 -143
- package/core/commands/qc-plan.md +6 -119
- package/core/commands/qc-review.md +59 -125
- package/core/commands/qc-run-test.md +6 -119
- package/core/commands/setup-ai-first.md +5 -5
- package/core/commands/update-framework.md +1 -1
- package/core/commands/validate-traces.md +1 -1
- package/core/rules/workflow.md +1 -1
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +1 -1
- package/core/skills/qc/qa-analyst/spec-breakdown.md +2 -2
- package/core/skills/qc/qa-designer/api/auth-chain.md +155 -0
- package/core/skills/qc/qa-designer/api/auth-sequence.md +75 -0
- package/core/skills/qc/qa-designer/api/common-headers.md +61 -0
- package/core/skills/qc/qa-designer/api/crud-sequence.md +122 -0
- package/core/skills/qc/qa-designer/api/endpoint.md +231 -0
- package/core/skills/qc/qa-designer/api/http-status-codes.md +102 -0
- package/core/skills/qc/qa-designer/e2e/journey.md +13 -8
- package/core/skills/qc/qa-designer/exploratory/charter.md +2 -0
- package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +7 -4
- package/core/skills/qc/qa-designer/functional/api.md +87 -18
- package/core/skills/qc/qa-designer/functional/gui-feature.md +12 -9
- package/core/skills/qc/qa-designer/functional/gui-screen.md +12 -10
- package/core/skills/qc/qa-designer/integration/api.md +12 -5
- package/core/skills/qc/qa-designer/integration/db.md +12 -6
- package/core/skills/qc/qa-designer/integration/gui.md +12 -5
- package/core/skills/qc/qa-designer/integration/kafka.md +12 -5
- package/core/skills/qc/qa-designer/non-functional.md +12 -5
- package/core/skills/qc/qa-designer/shared/action-keywords-glossary.md +91 -0
- package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +105 -0
- package/core/skills/qc/qa-designer/shared/implicit-scenarios.md +22 -0
- package/core/skills/qc/qa-designer/shared/precision-rules.md +198 -0
- package/core/skills/qc/qa-designer/shared/read-doc-gap-inputs.md +25 -0
- package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +93 -0
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +243 -0
- package/core/skills/qc/qa-planner/risk-model.md +1 -1
- package/core/skills/qc/qa-reviewer/script/e2e.md +9 -1
- package/core/skills/qc/qa-reviewer/script/exploratory.md +9 -1
- package/core/skills/qc/qa-reviewer/script/functional.md +9 -1
- package/core/skills/qc/qa-reviewer/script/integration.md +9 -1
- package/core/skills/qc/qa-reviewer/script/non-functional.md +9 -1
- package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +26 -0
- package/core/skills/qc/qa-reviewer/shared/review-check-groups.md +207 -0
- package/core/skills/qc/qa-reviewer/shared/review-file-template.md +228 -0
- package/core/skills/qc/qa-reviewer/test-case/e2e.md +71 -13
- package/core/skills/qc/qa-reviewer/test-case/exploratory.md +53 -4
- package/core/skills/qc/qa-reviewer/test-case/functional.md +63 -15
- package/core/skills/qc/qa-reviewer/test-case/integration.md +64 -12
- package/core/skills/qc/qa-reviewer/test-case/non-functional.md +72 -13
- package/core/skills/qc/qa-runner/e2e.md +1 -1
- package/docs/02-concepts/pipeline-steps/09-validate-traces.md +1 -1
- package/docs/04-reference/trace-schema.md +1 -1
- package/docs/explain/00-setup-ai-first.md +1 -1
- package/docs/plans/qc-implementation-log.md +145 -3
- package/package.json +1 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-04
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-designer/shared/precision-rules.md
|
|
6
|
+
upstream_sha: 1c2005b55bd94c3e8fa25dfa12a29c8b23f7c01e
|
|
7
|
+
---
|
|
8
|
+
# Precision Rules — Quy Tắc Độ Chính Xác
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Cấm từ mơ hồ — Bắt buộc lượng hóa
|
|
13
|
+
|
|
14
|
+
| ❌ Mơ hồ — KHÔNG viết | ✅ Chuẩn — Thay bằng |
|
|
15
|
+
|---|---|
|
|
16
|
+
| "hiển thị nhanh" | "response time < 2 giây (đo P95)" |
|
|
17
|
+
| "giao diện đẹp" | Không test (không đo được — bỏ qua) |
|
|
18
|
+
| "phù hợp" | Chỉ rõ phù hợp với điều gì: "khớp với AC-03 của BR-12" |
|
|
19
|
+
| "hiển thị đúng" | "displays text 'Tên lớp: Toán 6A'" |
|
|
20
|
+
| "hoạt động bình thường" | Liệt kê hành vi cụ thể: "button enabled, click được, navigates to /dashboard" |
|
|
21
|
+
| "không lỗi" | "HTTP 200, không có error message, field is empty" |
|
|
22
|
+
| "dữ liệu chính xác" | "body.name = 'Toán 6A', body.teacher_id = 42" |
|
|
23
|
+
| "validate thành công" | "Error message không hiển thị, form submits successfully" |
|
|
24
|
+
| "load được" | "Page displays within 3 seconds, no console error" |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Assertion Granularity — Mỗi assertion 1 điều kiện
|
|
29
|
+
|
|
30
|
+
**Nguyên tắc (ATOMIC — QC chốt 2026-07-09):** Mỗi TC có **đúng 1** `#### Expected Result` với **ĐÚNG 1 bullet** (1 outcome; bullet có thể compound `A AND B` trên cùng 1 outcome). **Nhiều bullet / điểm-kiểm → TÁCH thành nhiều TC ĐỘC LẬP, mỗi TC 1 bullet** (không còn gộp checkpoint). Test Steps chỉ `[Action]`/`[Verify]`, **không** gắn `→ [Expected]` ở bước (chi tiết tách + renumber đồng bộ: `tc-metadata-format.md §"1 bullet Expected = 1 TC ĐỘC LẬP"`).
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
✅ ĐÚNG — 1 outcome, nhiều assertion liên quan:
|
|
34
|
+
Assert: HTTP 201 AND body.id exists AND body.name = "Toán 6A" AND body.teacher_id = 42
|
|
35
|
+
|
|
36
|
+
✅ ĐÚNG — 1 assertion đơn lẻ:
|
|
37
|
+
Assert: Error message "Email không hợp lệ" displays below email field
|
|
38
|
+
|
|
39
|
+
❌ SAI — 2 outcome khác nhau gom chung:
|
|
40
|
+
Assert: HTTP 201 AND trên UI hiển thị lớp mới trong danh sách
|
|
41
|
+
→ Tách thành 2 TC riêng: TC API (HTTP 201) + TC UI (danh sách cập nhật)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2.1 Chế độ ATOMIC TỐI ĐA (QC chốt 2026-07-14 — khi user yêu cầu "tách tới mức nhỏ nhất")
|
|
45
|
+
|
|
46
|
+
Mặc định trên vẫn cho compound `A AND B` **cùng 1 outcome**. Nhưng khi chủ dự án YÊU CẦU THẲNG tách nhỏ nhất, áp **atomic tối đa — mỗi assertion độc-lập-fail = 1 TC**, gồm **nổ completeness list theo từng thành phần**:
|
|
47
|
+
- Thẻ/card "hiển thị **đủ** [A, B, C, D, E]" → **mỗi thành phần 1 TC** (vd thẻ khung giờ: ảnh GV / ngày·giờ / tên GV / tên bài / ô chọn = 5 TC; info card 4 mục = 4 TC; hero: tiêu đề / khẩu hiệu / linh vật = 3 TC).
|
|
48
|
+
- Đa-outcome BẮT BUỘC tách kể cả khi liên quan: popup + data-state · silent-handoff (điều hướng + không-popup) · mỗi con (`profile_id` A / B) · mỗi element/breakpoint responsive · mỗi touch-target · include vs exclude của cùng 1 filter.
|
|
49
|
+
|
|
50
|
+
**⛔ RANH GIỚI — GIỮ 1 TC (đừng over-split vô nghĩa) kể cả ở chế độ tối đa:**
|
|
51
|
+
- *Predicate đa-điều-kiện định-nghĩa-1-khái-niệm*: "chưa bắt đầu **và** còn ≥10' = slot-hợp-lệ" → 1 TC.
|
|
52
|
+
- *Ngưỡng*: "≥44pt/48dp", "WCAG AA ≥4.5:1" → 1 TC (không tách iOS/Android, không tách chữ-thường/chữ-lớn).
|
|
53
|
+
- *Exclusivity* chọn-một; *qualifier* ("không chỉ bằng màu").
|
|
54
|
+
- Bỏ vế TRÙNG nghĩa với TC khác (vd a11y "nút mở sau chọn" trùng TC chọn-1-khung → cắt, không nhân bản).
|
|
55
|
+
|
|
56
|
+
**Thủ tục bắt buộc trước khi thực thi (chênh quy mô lớn — FEAT-01-4: 82→WEB 132/APP 130):**
|
|
57
|
+
1. **HỎI 1 câu chốt ranh giới completeness** (giữ-1-completeness ~95 TC vs nổ-từng-thành-phần ~130 TC) — quy mô rất khác, phải để user quyết.
|
|
58
|
+
2. Dựng **bản đồ tách** (số mảnh mỗi TC cha) trước, KHÔNG để agent con tự suy diễn → giảm sai + giảm cắt cụt.
|
|
59
|
+
3. Ưu tiên (P0/P1) TC con **kế thừa** từ cha; renumber tuần tự + đồng bộ Mục lục/Tổng hợp(đếm lại P0/P1 từ tag)/Trace Matrix(expand cha→con).
|
|
60
|
+
4. **Làm CẢ 2 nền WEB+APP** (nhóm NFR khác nền: web a11y/responsive vs app safe-area/touch/back-gesture → tổng có thể lệch, granularity atomic tương đương).
|
|
61
|
+
5. **Verify bằng DIFF, không tin lời đếm của agent**: ID tuần tự · `###`=`#### Expected` · mỗi Expected 1 bullet · 0 bảng `|` · Trace Matrix không ID chết · P0/P1 khớp tag (bug renumber KHÔNG throw — xem `qa-agents-large-write-unreliable`).
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 3. Đơn vị chuẩn theo domain
|
|
66
|
+
|
|
67
|
+
| Domain | Đơn vị bắt buộc | Ví dụ |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Thời gian phản hồi | `ms` hoặc `giây` + percentile | "< 500ms (P95)" |
|
|
70
|
+
| Throughput | `req/s` hoặc `req/phút` | "≥ 100 req/s" |
|
|
71
|
+
| Tải concurrent | `users` | "50 concurrent users" |
|
|
72
|
+
| Dung lượng file | `KB` hoặc `MB` | "< 5MB" |
|
|
73
|
+
| Ký tự | `ký tự` | "≤ 100 ký tự" |
|
|
74
|
+
| Accessibility | WCAG level + version | "WCAG 2.1 AA" |
|
|
75
|
+
| HTTP status | Mã số đầy đủ | "HTTP 201", "HTTP 400" (không "success") |
|
|
76
|
+
| DB record | Bảng + cột + giá trị | "users.email = 'test@gmail.com'" |
|
|
77
|
+
| Error message | Chuỗi chính xác in nghiêng | `"Email không hợp lệ"` |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 4. Toán tử so sánh — Dùng thống nhất
|
|
82
|
+
|
|
83
|
+
| Ý nghĩa | Ký hiệu | Ví dụ |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| Bằng chính xác | `=` | `body.status = "active"` |
|
|
86
|
+
| Nhỏ hơn | `<` | `response time < 2s` |
|
|
87
|
+
| Nhỏ hơn hoặc bằng | `≤` | `file size ≤ 5MB` |
|
|
88
|
+
| Lớn hơn | `>` | `list.count > 0` |
|
|
89
|
+
| Lớn hơn hoặc bằng | `≥` | `throughput ≥ 100 req/s` |
|
|
90
|
+
| Tồn tại | `exists` | `body.id exists` |
|
|
91
|
+
| Không tồn tại | `not exists` | `error_message not exists` |
|
|
92
|
+
| Chứa chuỗi | `contains` | `body.message contains "thành công"` |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 5. Test Data sourcing — Dữ liệu test từ đâu
|
|
97
|
+
|
|
98
|
+
**Quy tắc:**
|
|
99
|
+
- **Không hardcode** giá trị nhạy cảm (password, token, production data) vào TC.
|
|
100
|
+
- **Dùng placeholder** rõ nghĩa: `<valid_email>`, `<teacher_password>`, `<existing_class_id>`.
|
|
101
|
+
- **Ghi nguồn dữ liệu** khi cần setup: "Seed: tạo 1 lớp học với teacher_id = fixture.teacher.id".
|
|
102
|
+
- **Biên dữ liệu** (BVA) phải ghi rõ giá trị cụ thể: "10 ký tự (biên trên của maxlength=10)".
|
|
103
|
+
|
|
104
|
+
**Baseline cho NFR:**
|
|
105
|
+
- Lấy từ **SLA document** trong `{paths.specs_dir}` (nếu có).
|
|
106
|
+
- Lấy từ **AC** trong PRD (vd "AC-05: response < 3s").
|
|
107
|
+
- Nếu không có document → ghi rõ `[Cần xác nhận baseline với PO]` trong Test Data.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 6. Format Expected Result chuẩn theo lane
|
|
112
|
+
|
|
113
|
+
**UI:**
|
|
114
|
+
```
|
|
115
|
+
Assert: <element> <trạng thái> — ví dụ: "Error message 'Email không hợp lệ' is visible below field"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**API:**
|
|
119
|
+
```
|
|
120
|
+
Assert: HTTP <code> AND body.<field> <toán tử> <giá trị> — ví dụ: "HTTP 201 AND body.id exists AND body.name = 'Toán 6A'"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**E2E:**
|
|
124
|
+
```
|
|
125
|
+
Assert: <chuỗi verify point> — ví dụ: "Class 'Toán 6A' displays in list AND teacher dashboard shows 1 new class"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**NFR:**
|
|
129
|
+
```
|
|
130
|
+
Assert: <metric> <toán tử> <ngưỡng> (<đơn vị>) — ví dụ: "P95 response time < 500ms at 50 concurrent users"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Integration:**
|
|
134
|
+
```
|
|
135
|
+
Assert: <Module A state> AND <Module B state> — ví dụ: "HTTP 201 AND DB: classes.id = new_id AND Kafka: event 'class.created' published"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 7. Decision Table — Quy tắc coverage
|
|
141
|
+
|
|
142
|
+
**Standard coverage (ISTQB CTFL v4.0):** mỗi rule (cột) = 1 TC tối thiểu.
|
|
143
|
+
|
|
144
|
+
| Điều kiện | Rule 1 | Rule 2 | Rule 3 | Rule 4 |
|
|
145
|
+
|---|---|---|---|---|
|
|
146
|
+
| user.role = admin | T | T | F | F |
|
|
147
|
+
| resource.owner = self | T | F | T | F |
|
|
148
|
+
| **Action** | 200 OK | 403 | 200 OK | 403 |
|
|
149
|
+
|
|
150
|
+
→ 4 rules = 4 TC (1 happy + 3 negative/edge).
|
|
151
|
+
|
|
152
|
+
**BVA — 3 giá trị hay 4 giá trị?**
|
|
153
|
+
|
|
154
|
+
| Spec | Giá trị phải test |
|
|
155
|
+
|---|---|
|
|
156
|
+
| Range 2 biên (`min ≤ x ≤ max`) | **4 giá trị:** min−1, min, max, max+1 |
|
|
157
|
+
| Biên trên chỉ (`x ≤ max`) | **3 giá trị:** max−1, max, max+1 |
|
|
158
|
+
| Biên dưới chỉ (`x ≥ min`) | **3 giá trị:** min−1, min, min+1 |
|
|
159
|
+
| Đúng 1 giá trị hợp lệ | **3 giá trị:** value−1, value, value+1 |
|
|
160
|
+
|
|
161
|
+
**Don't-care conditions:** condition không ảnh hưởng action → gộp rule, ghi `DC` (don't care) trong bảng. Ví dụ: `resource.owner` không quan trọng khi `user.role = superadmin` → gộp 2 rules thành 1 TC.
|
|
162
|
+
|
|
163
|
+
**Đếm TC từ Decision Table:** N unique rules sau gộp don't-care = N TC tối thiểu. Nếu spec không có Decision Table sẵn → tự xây bảng trong Phase Clarify trước khi viết TC.
|
|
164
|
+
|
|
165
|
+
**Phủ ĐỦ mọi ô — kể cả ô "không hành động".** Mỗi tổ hợp điều kiện phải có TC, kể cả ô mà kết quả là "không làm gì / không hiển thị" (vd: cả 2 trục cùng đủ rõ → KHÔNG hỏi câu phụ; cả 2 cùng chưa rõ → KHÔNG hỏi). Không được bỏ ô vì "không có hành động".
|
|
166
|
+
|
|
167
|
+
**Kết hợp Decision Table + BVA, không trộn lẫn:**
|
|
168
|
+
- Giá trị trong TC Decision Table nên **cách biệt rõ** so với ngưỡng (vd chênh lệch 25 so với ngưỡng 20) để cô lập đúng rule.
|
|
169
|
+
- Điểm **sát biên** (ngưỡng−1 / = ngưỡng / ngưỡng+1) tách thành TC **BVA riêng**, không nhét vào TC Decision Table.
|
|
170
|
+
|
|
171
|
+
**Báo coverage bằng TC ID cụ thể.** Khi tổng kết độ phủ cho logic điều kiện/ngưỡng: lập bảng ánh xạ từng rule/điểm biên → TC ID, đánh dấu rõ ô nào đủ/thiếu. Không kết luận "phủ gián tiếp" chung chung.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 8. Teardown Data Strategy
|
|
176
|
+
|
|
177
|
+
### 3 mức cleanup:
|
|
178
|
+
|
|
179
|
+
| Mức | Khi nào | Cách thực hiện |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| **Inline** | TC tạo 1 bản ghi độc lập | Bước cuối Steps: `[Teardown] DELETE /api/v1/resource/{created_id}` |
|
|
182
|
+
| **Fixture** | Nhiều TC dùng chung 1 tập data | Preconditions: `Fixture: seed_class()` — teardown trong `conftest.py` scope=function |
|
|
183
|
+
| **Reset env** | TC thay đổi trạng thái hệ thống (email sent, payment, notification) | Ghi vào TC: `⚠️ Manual teardown: [bước cụ thể]` |
|
|
184
|
+
|
|
185
|
+
### Format Teardown trong TC:
|
|
186
|
+
|
|
187
|
+
```markdown
|
|
188
|
+
#### Teardown
|
|
189
|
+
- DELETE /api/v1/classes/{created_id} — xóa lớp đã tạo trong Steps
|
|
190
|
+
- Hoặc: [Reset: fixture scope=function tự cleanup sau mỗi test]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Quy tắc:
|
|
194
|
+
- TC tạo bản ghi DB hoặc state THẬT (ghi vào tài khoản test) → **bắt buộc** ghi Teardown (API DELETE hoặc fixture rollback / reset tài khoản).
|
|
195
|
+
- TC chỉ đọc (GET) hoặc chỉ verify UI tĩnh → không cần Teardown.
|
|
196
|
+
- **TC chỉ cấu hình mock / route intercept / network monitoring → KHÔNG cần Teardown.** Reset mock về default là trách nhiệm của fixture `conftest.py` (scope=function tự teardown). Ghi "Reset mock về default" trong từng TC là **thừa** — không thêm. (Lane test qua mock hoàn toàn, vd UI/E2E khi API SKIP, hầu hết TC KHÔNG có Teardown.)
|
|
197
|
+
- TC mobile/E2E tạo account → ghi `[Teardown: deactivate user via admin API]`.
|
|
198
|
+
- TC không cleanup được → đánh dấu `⚠️ Manual teardown required` + ghi hướng dẫn chi tiết.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-04
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-designer/shared/read-doc-gap-inputs.md
|
|
6
|
+
upstream_sha: a7e113b19f35aa47acf91e55cdfb3f630539806c
|
|
7
|
+
---
|
|
8
|
+
# Thủ tục: Nạp TOÀN BỘ tài liệu input từ DOC_GAP (BẮT BUỘC trước khi thiết kế/review TC)
|
|
9
|
+
|
|
10
|
+
> Mục tiêu: designer/reviewer phải đọc **đúng bộ tài liệu nguồn mà qa-tc-analyst đã dùng** để dựng TEST_PLAN + DOC_GAP — không chỉ file domain. Tránh thiết kế/review TC trên ngữ cảnh thiếu, dẫn tới bỏ sót nghiệp vụ hoặc hiểu sai contract.
|
|
11
|
+
|
|
12
|
+
## Các bước
|
|
13
|
+
|
|
14
|
+
1. **Tìm file DOC_GAP** tại `{qc_artifact_dir}DOC_GAP.md` — **một file cho cả PRD**, các UC là các hàng phân biệt bằng cột `UC` (xem `/qc-analyze`). Không có → chạy `/qc-analyze {TICKET-ID} {platform}` trước; **đừng thiết kế TC trên ngữ cảnh thiếu**.
|
|
15
|
+
2. **`Read` toàn bộ DOC_GAP.** Định vị mục **`## Tài liệu đầu vào đã đọc để phân tích`** — bảng liệt kê **đầy đủ** file nguồn (cột "Đường dẫn", tính từ `{paths.specs_dir}/`), kèm vai trò & phiên bản.
|
|
16
|
+
3. **`Read` TỪNG file trong bảng đó** — ghép prefix `{paths.specs_dir}/` vào đường dẫn ở cột. Đọc HẾT, không bỏ sót dòng nào (spec chính + ref bắt buộc + transitive 1-hop). Nếu bảng liệt kê phiên bản, kiểm tra file hiện tại khớp; lệch phiên bản → ghi chú, không tự bịa.
|
|
17
|
+
4. **Đối chiếu chéo:** nếu ngoài bảng DOC_GAP còn `## Coverage Attestation` / dòng "Tài liệu nguồn (spec chính)" ở header → xác nhận đã phủ hết; file nào có mặt ở header mà thiếu trong bảng → vẫn đọc.
|
|
18
|
+
5. Chỉ sau khi đã nạp xong toàn bộ input + file domain (`business-dictionary.md`, `product-definition/`) mới bắt đầu viết/soát TC.
|
|
19
|
+
|
|
20
|
+
## Nguyên tắc
|
|
21
|
+
|
|
22
|
+
- **Không tự suy diễn ngoài tài liệu.** Chỉ dùng nội dung thực có trong các file đã đọc.
|
|
23
|
+
- **Không đọc thiếu:** nếu DOC_GAP nói "Tổng: N tài liệu" thì phải mở đủ N (trừ file domain đã nạp riêng — vẫn nằm trong N).
|
|
24
|
+
- **Bỏ qua** phần Change log / Appendix / "Giả định AI" khi trích evidence (giống ràng buộc nguồn của analyst), nhưng vẫn được đọc để hiểu ngữ cảnh.
|
|
25
|
+
- Lane API: nếu DOC_GAP ghi SKIP (không có `openapi.yaml`/`.dbml`/`tdd/`) → không bịa endpoint.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-04
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-designer/shared/skill-decision-tree.md
|
|
6
|
+
upstream_sha: 57125f0c21512f2abcc55d00420e92c84c95fc8f
|
|
7
|
+
---
|
|
8
|
+
# Cây Quyết Định — Chọn Skill Đúng
|
|
9
|
+
|
|
10
|
+
> Đọc file này khi không chắc nên dùng skill nào. Trả lời lần lượt các câu hỏi từ trên xuống.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Bước 1 — Đối tượng test là gì?
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Đối tượng test
|
|
18
|
+
├── Hiển thị / validation / state của 1 screen → [A] Xét tiếp Bước 2 (UI vs Integration GUI)
|
|
19
|
+
├── User thực hiện workflow có mục tiêu nghiệp vụ → [B] Xét tiếp Bước 3 (E2E vs Integration)
|
|
20
|
+
├── 1 API endpoint (request/response/mã lỗi) → api-testcase-designer
|
|
21
|
+
├── NFR (performance/security/a11y/i18n) → nfr-testcase-designer
|
|
22
|
+
└── Luồng đa màn nằm trong 1 feature, không xuyên hệ thống → ui-testcase-designer (gui-feature)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Bước 2 — UI vs Integration GUI
|
|
28
|
+
|
|
29
|
+
**Câu hỏi:** TC này có thể chạy với dữ liệu tĩnh/mock mà vẫn valid không?
|
|
30
|
+
|
|
31
|
+
| Câu trả lời | Skill | Lý do (ISTQB) |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **Có** — mock data đủ để verify | `ui-testcase-designer` | Component testing: verify UI behavior độc lập với backend |
|
|
34
|
+
| **Không** — phải có API thật/stub mới verify được | `integration/gui` trong `integration-testcase-designer` | Integration testing: verify contract UI layer ↔ API layer |
|
|
35
|
+
|
|
36
|
+
**Ví dụ phân biệt:**
|
|
37
|
+
|
|
38
|
+
| Tình huống | Skill | Lý do |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| Dropdown có placeholder, đóng khi click ngoài | UI | Behavior tĩnh, không cần API |
|
|
41
|
+
| Dropdown hiển thị đúng N item từ API response | Integration GUI | Verify data flow API → render |
|
|
42
|
+
| Form validate email format | UI | Client-side validation, không cần server |
|
|
43
|
+
| Form validate email "đã tồn tại" qua API | Integration GUI | Server-side validation = API call |
|
|
44
|
+
| Bảng danh sách render đúng số cột, format | UI | Layout/display |
|
|
45
|
+
| Bảng danh sách phản ánh đúng dữ liệu từ GET /list | Integration GUI | API data → UI sync |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Bước 3 — E2E vs Integration
|
|
50
|
+
|
|
51
|
+
**Câu hỏi:** Chủ thể của test là ai/cái gì?
|
|
52
|
+
|
|
53
|
+
| Câu trả lời | Skill | Lý do (ISTQB) |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| **User** hoàn thành 1 mục tiêu nghiệp vụ từ đầu đến cuối | `e2e-testcase-designer` | System testing: user journey perspective |
|
|
56
|
+
| **Module A ↔ Module B** trao đổi dữ liệu/contract đúng | `integration-testcase-designer` | Integration testing: system contract perspective |
|
|
57
|
+
|
|
58
|
+
**Câu hỏi phụ để phân biệt rõ hơn:**
|
|
59
|
+
|
|
60
|
+
> "Nếu tôi xóa hết step UI và chỉ test phần trao đổi dữ liệu, TC vẫn còn ý nghĩa không?"
|
|
61
|
+
> - Có → Integration (bản chất là test handshake, UI chỉ là trigger)
|
|
62
|
+
> - Không → E2E (user journey là trọng tâm, không thể tách ra)
|
|
63
|
+
|
|
64
|
+
**Ví dụ phân biệt:**
|
|
65
|
+
|
|
66
|
+
| Tình huống | Skill | Lý do |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| User đăng ký → nhận email → login → vào dashboard | E2E | User journey hoàn chỉnh, verify goal đạt được |
|
|
69
|
+
| User tạo lớp học → lớp hiện trong danh sách | E2E | End-to-end từ action đến kết quả nhìn thấy |
|
|
70
|
+
| Frontend gọi POST /enroll → DB ghi đúng bản ghi | Integration | Module contract: API ↔ DB, không phụ thuộc UI |
|
|
71
|
+
| Service A gửi event Kafka → Service B xử lý đúng | Integration | System-to-system, không liên quan user |
|
|
72
|
+
| Tạo đơn hàng qua UI → kiểm tra DB có bản ghi | Cả hai? | Nếu mục tiêu là "user đặt hàng thành công" → E2E; nếu mục tiêu là "POST /order ghi DB đúng" → Integration |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Tóm tắt nhanh
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Có API thật mới verify được?
|
|
80
|
+
└─ Không → UI
|
|
81
|
+
└─ Có, verify data flow 1 điểm → Integration GUI
|
|
82
|
+
└─ Có, user journey đầu-cuối → E2E
|
|
83
|
+
└─ Có, handshake 2 module/hệ thống → Integration
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Quy tắc ưu tiên khi vẫn còn mơ hồ
|
|
89
|
+
|
|
90
|
+
1. **UI ưu tiên nhỏ nhất:** viết TC nhỏ nhất có thể verify 1 behavior cụ thể.
|
|
91
|
+
2. **Integration GUI** khi có server-side behavior: validation, lookup, list.
|
|
92
|
+
3. **E2E chỉ cho P0/P1 critical path** (ISTQB Test Pyramid: E2E ít nhất, UI/Unit nhiều nhất).
|
|
93
|
+
4. **Integration** khi tách được khỏi UI và vẫn có giá trị test.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-04
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-designer/shared/tc-metadata-format.md
|
|
6
|
+
upstream_sha: a31d66a7a8dab19cf821c9102a88282b09e16cb9
|
|
7
|
+
---
|
|
8
|
+
# TC Metadata Format (Chuẩn chung)
|
|
9
|
+
|
|
10
|
+
## ⚠️ Nguyên tắc format file TC (BẮT BUỘC — QC yêu cầu)
|
|
11
|
+
|
|
12
|
+
- **TOÀN BỘ file TC viết dạng LIST — KHÔNG dùng bảng Markdown** (không ký tự `|`). Áp dụng cho: Test Steps, Tổng hợp TC, Trace Matrix, TC bị Block, metadata đầu file. *(Chỉ file TC output; tài liệu skill này giữ bảng minh hoạ bình thường.)*
|
|
13
|
+
- **Gom nhóm theo LOẠI test** (không theo luồng nghiệp vụ): thứ tự cố định **GUI → Validation → Functional → Integration → NFR → E2E** (xem §Phân nhóm).
|
|
14
|
+
- Khi tái cấu trúc/đảo nhóm: **GIỮ NGUYÊN mã `TC_<FEATURE>_NNN`**, chỉ đổi vị trí (mã không cần liền mạch theo thứ tự đọc).
|
|
15
|
+
- **App/Web là 2 bộ TC ĐỘC LẬP, mỗi nền chạy FULL business-logic** — trùng logic giữa 2 nền là chủ đích, KHÔNG tính duplicate defect; mỗi file phải độc lập đạt full coverage — mỗi nền một thư mục riêng (`{qc_dir}/{TICKET-ID}/web/` vs `/app/`), và sổ trace cũng tách theo nền.
|
|
16
|
+
|
|
17
|
+
## ⚠️ Quy tắc "1 bullet Expected = 1 TC ĐỘC LẬP" (BẮT BUỘC — QC yêu cầu, testcase ATOMIC)
|
|
18
|
+
|
|
19
|
+
> **Cập nhật 2026-07-09 (QC chốt — ĐẢO rule cũ):** trước đây cho GỘP nhiều checkpoint cùng-1-hành-vi vào 1 Expected nhiều bullet. **Nay: mỗi Expected chỉ ĐÚNG 1 bullet; mọi TC nhiều bullet phải TÁCH thành nhiều TC độc lập.** KHÔNG còn ngoại lệ "gộp checkpoint".
|
|
20
|
+
|
|
21
|
+
- **Test Steps chỉ chứa hành động.** Mỗi bước là `[Action]` hoặc `[Verify]` THUẦN — **KHÔNG gắn `→ [Expected] ...` ở cuối bước.** Oracle nằm ở `#### Expected Result`.
|
|
22
|
+
- **Atomic = 1 OUTCOME, không chỉ đếm "1 bullet".** Mỗi TC đúng 1 `#### Expected Result` với ĐÚNG 1 bullet. Bullet compound (`A, B`) **chỉ OK khi cùng 1 outcome** (vd "chỉ 5 slide: đúng 5 dots; slide 6,7 không xuất hiện" · "form hiển thị đủ 3 trường"). **Bullet nối bằng `;` kiểu "khẳng-định + phủ-định/outcome độc lập"** (vd "Có lối Đăng nhập**;** KHÔNG có OTP" · "sang routing**;** không OTP") **= 2 outcome → TÁCH tiếp** — soi nhanh khi review: grep bullet chứa `;` + `không/KHÔNG`. Tuyệt đối KHÔNG ≥2 bullet trong 1 Expected.
|
|
23
|
+
- **Nhiều điểm-kiểm / outcome → TÁCH thành nhiều TC ĐỘC LẬP, mỗi TC 1 bullet.** Áp cho MỌI trường hợp: outcome độc lập (BVA/Decision-rule/tiền đề khác) LẪN nhiều checkpoint của **cùng 1 hành vi** (VD "màn hiển thị đủ ô A + nút B + lối C" → **3 TC**, không còn gộp).
|
|
24
|
+
- **⚠️ Chế độ ATOMIC TỐI ĐA (QC chốt 2026-07-14 — GIẢI mâu thuẫn 2 gạch trên):** khi user YÊU CẦU THẲNG "tách nhỏ nhất", **completeness list nổ từng thành phần** (kể cả "form đủ 3 trường" → **3 TC**; thẻ khung giờ đủ 5 field → 5 TC) — tức áp gạch "→ 3 TC", KHÔNG dùng ngoại lệ "compound cùng-1-outcome" cho completeness. **NHƯNG GIỮ 1 TC** cho: *predicate đa-điều-kiện định-nghĩa-1-khái-niệm* ("chưa bắt đầu & ≥10' = slot-hợp-lệ"), *ngưỡng* ("≥44pt·48dp", "WCAG AA ≥4.5:1"), *exclusivity* chọn-một, *qualifier* ("không chỉ bằng màu"). Trước khi thực thi: **hỏi 1 câu chốt ranh giới completeness** (quy mô ~95 vs ~130 TC) + dựng **bản đồ tách** (số mảnh/TC cha) rồi mới ghi. Chi tiết + thủ tục verify: `precision-rules.md §2.1`. (Mặc định lúc SINH MỚI vẫn cho compound cùng-1-outcome; chế độ tối đa chỉ khi user yêu cầu.)
|
|
25
|
+
- **Mỗi TC tách là testcase ĐỘC LẬP** — KHÔNG phải "con", KHÔNG đánh `(1/N)`, KHÔNG suffix `001a/001b`:
|
|
26
|
+
- **Tiêu đề mô tả riêng** self-contained (ngữ cảnh màn/hành vi + điểm được kiểm), heading khớp `**Title:**`.
|
|
27
|
+
- **Giữ FULL Test Steps** — lặp đủ bước để tới trạng thái assert (KHÔNG cắt bước theo từng bullet).
|
|
28
|
+
- Metadata (Feature/Module/Priority/Status/Tags/Trace) + Preconditions **copy nguyên** từ TC gốc.
|
|
29
|
+
- **`#### Teardown` là SECTION riêng, KHÔNG phải bullet Expected.** Khi tách bằng script: parse `#### Teardown` riêng — **đừng nuốt bullet teardown vào `#### Expected Result`** (bug đã gặp → sinh "TC teardown giả" có Expected="Xoá dữ liệu test…", steps↔expected mâu thuẫn, không pass/fail được). Mỗi TC tách **TẠO bản ghi DB** (register/tạo tài khoản mới) phải giữ `#### Teardown` riêng; flow **login trên seed** không cần.
|
|
30
|
+
- **Renumber TUẦN TỰ toàn dải** khi tách. Đổi số cascade → **đồng bộ NGAY**: `Mục lục` (range mỗi nhóm) · `Tổng hợp` (count + priority) · note `· N TC` mỗi Nhóm · `Trace Matrix` (**expand range** cũ thành list id mới) · `TC bị Block` (map id cũ → các id con). Dùng script xác định + backup trước–sau (agent ghi file lớn hay lỗi âm thầm — xem gạch cuối mục này).
|
|
31
|
+
- **Assertion loại-trừ (KHÔNG hiển thị / KHÔNG xảy ra) là oracle THẬT** → mỗi cái là 1 bullet = 1 TC riêng. Khi tách bằng script cơ học, **kiểm lại không đánh rơi** (đối chiếu backup).
|
|
32
|
+
- **Bullet metadata KHÔNG phải outcome.** `- Mobile: \`@pytest.mark.flaky(...)\`` lọt trong Expected là **marker** → loại khỏi phép đếm outcome, **dời ra meta** (`- **Chạy (mobile):** …`). Đếm nhầm marker là "bullet thứ 2" sẽ kết luận SAI rằng file cần tách. Reviewer cờ `[MARKER_IN_EXPECTED]`.
|
|
33
|
+
- **⚠️ Trước khi viết script tách/renumber — biết 5 bẫy này trước.** 5 bug **không throw exception** (script "chạy xong" rồi ghi file hỏng):
|
|
34
|
+
1. **Double-remap**: transformer vừa *sinh* ID vừa *remap* ID → regex khớp luôn **heading vừa sinh** → ID trùng. **Chỉ remap `preamble` + `tail`, KHÔNG remap phần vừa sinh.**
|
|
35
|
+
2. **2 namespace ID**: liệt kê namespace TRƯỚC khi rename (vd FEAT-01-2: nội bộ `TC_FEAT-01-2_{APP,WEB}_NNN` remap ĐƯỢC · **master** `TC_NNN`/`TC_FEAT-01-2_NNN` ở BLOCKED/TODO **KHÔNG remap**). Verify: `diff` tập master-ID backup↔new.
|
|
36
|
+
3. **Replace-section làm rơi dòng chưa mô hình hoá** (dòng `>` note trong Expected). Giữ trailing note.
|
|
37
|
+
4. **Tiêu đề cha ≠ prefix con**: auto-title `"<heading cha> — <bullet>"` nhân đôi khi heading cha liệt kê cả 2 vế.
|
|
38
|
+
5. **Invariant phải gồm DIFF ĐỊNH DẠNG**, không chỉ đếm: liên tục ID · 0 trùng · 1 bullet/TC · oracle lossless (diff vs backup) · 0 dead-ref · **0 dòng-trống-kép/nhiễu whitespace** · master-ID không đổi.
|
|
39
|
+
- **Có file ĐÃ atomic sẵn** — phân tích phân bố bullet/TC trước, đừng tách lấy được. Quy trình bền: sửa **source/backup** → **tái sinh** bằng script xác định → verify → sai thì restore.
|
|
40
|
+
|
|
41
|
+
## Content Oracle — exact-copy phải self-contained + đúng nguồn
|
|
42
|
+
|
|
43
|
+
- Chuỗi text spec-defined mà TC assert (tiêu đề màn, nhãn, copy nút, thông báo lỗi) → **ghi nguyên văn trong Expected Result** để TC tự chứa, người đọc không phải mở spec mới biết kỳ vọng.
|
|
44
|
+
- **BẮT BUỘC kiểm nguồn ĐÚNG feature trước khi chép:** mở design-spec/PRD của **chính feature đó** và xác nhận chuỗi tồn tại. **KHÔNG mượn chuỗi từ feature anh em** — VD copy P2 của FEAT-01-1 là *"Việc tạo **tài khoản** đang tạm thời bị gián đoạn…"* còn FEAT-01-2 là *"Việc tạo **câu hỏi** đang tạm thời bị gián đoạn…"*; chép nhầm → oracle sai.
|
|
45
|
+
- Chuỗi **chưa** có trong PRD/design-spec (chỉ ở Figma / chưa chốt) → **KHÔNG bịa oracle**: để trống + gắn `🚫 Block: [GAP-UC{N}-{nnn}]` hoặc `Status: PENDING`, ghi rõ chờ ai chốt.
|
|
46
|
+
- Cờ "MIỄN coverage / thuộc Design Spec" trong BDD **không** cấm assert nếu PRD/design-spec vẫn enumerate đủ chuỗi — vẫn được đưa vào Expected Result; chỉ hạ về mức generic khi thực sự không có nguồn chốt.
|
|
47
|
+
|
|
48
|
+
## Metadata (bắt buộc, dạng list)
|
|
49
|
+
|
|
50
|
+
Mỗi trường 1 dòng, không bảng, không emoji dư:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
- **Title:** <tên TC ngắn gọn>
|
|
54
|
+
- **Feature:** <tên feature>
|
|
55
|
+
- **Priority:** P0 | P1 | P2
|
|
56
|
+
- **Status:** Draft
|
|
57
|
+
- **Author:** AI
|
|
58
|
+
- **Tags:** <lane>, <loại: smoke|sanity|regression>, <feature-tag>
|
|
59
|
+
- **Trace:** BR-xx (ID gốc trong PRD/BDD ở `{paths.specs_dir}`)
|
|
60
|
+
- **🚫 Block:** [GAP-UC{N}-{nnn}](../DOC_GAP.md) — <lý do> *(chỉ khi có)*
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quy tắc Trace & Block
|
|
64
|
+
|
|
65
|
+
- **Trace:** ghi `BR-xx` lấy từ ID trong `{paths.specs_dir}`; không có BR → `⚠️ Chưa có Business Rule`.
|
|
66
|
+
- **🚫 Block:** TC phụ thuộc gap **vẫn viết đủ** + ghi `[GAP-UC{N}-{nnn}] — lý do`; chưa chạy tới khi gap Answered.
|
|
67
|
+
|
|
68
|
+
## Cấu trúc TC
|
|
69
|
+
|
|
70
|
+
```markdown
|
|
71
|
+
### [TC_ID] — [Tên TC]
|
|
72
|
+
- **Title:** ...
|
|
73
|
+
- **Feature:** ...
|
|
74
|
+
- **Priority:** P0|P1|P2
|
|
75
|
+
- **Status:** Draft
|
|
76
|
+
- **Author:** AI
|
|
77
|
+
- **Tags:** ...
|
|
78
|
+
- **Trace:** BR-xx
|
|
79
|
+
- **🚫 Block:** (nếu có)
|
|
80
|
+
|
|
81
|
+
#### Preconditions
|
|
82
|
+
- ...
|
|
83
|
+
|
|
84
|
+
#### Test Data
|
|
85
|
+
- field: giá trị
|
|
86
|
+
|
|
87
|
+
#### Test Steps
|
|
88
|
+
1. [Action] ... ← chỉ hành động; KHÔNG gắn "→ [Expected] ..."
|
|
89
|
+
2. [Verify] ... ← chỉ điểm quan sát; oracle nằm ở Expected Result
|
|
90
|
+
|
|
91
|
+
#### Expected Result
|
|
92
|
+
- <1 bullet kết quả cuối cụ thể, đo được — xem §"1 Expected Result / TC">
|
|
93
|
+
|
|
94
|
+
#### Teardown ← CHỈ khi TC tạo/sửa bản ghi hoặc state THẬT
|
|
95
|
+
- <cách cleanup: API DELETE / reset tài khoản test / fixture / `⚠️ Manual teardown required`>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Quy tắc Teardown (khi nào CÓ / KHÔNG)
|
|
99
|
+
|
|
100
|
+
- **CÓ Teardown** chỉ khi TC tạo/sửa **bản ghi DB hoặc state thật** tồn tại sau test (vd: ghi phân khúc vào tài khoản test, tạo bản ghi qua API thật).
|
|
101
|
+
- **KHÔNG cần Teardown** khi TC chỉ cấu hình **mock / route intercept / network monitoring** — việc reset mock về default là trách nhiệm của **fixture `conftest.py`** (scope `function` tự teardown mỗi test). Ghi "Reset mock về default" trong từng TC là **thừa** → không thêm.
|
|
102
|
+
- Lane test qua mock hoàn toàn (vd lane UI/E2E khi API SKIP) → hầu hết TC KHÔNG có Teardown; chỉ TC chạm tài khoản/state thật mới có.
|
|
103
|
+
|
|
104
|
+
## Phân nhóm TC & đánh số nhóm (chuẩn chung)
|
|
105
|
+
|
|
106
|
+
TC trong file được gom theo **nhóm phân loại nội dung** và đánh **số CỐ ĐỊNH theo LOẠI** — số nhóm gắn cứng với loại, loại KHÔNG có TC thì **BỎ TRỐNG số đó** (KHÔNG đánh tuần tự lại). *(QC chốt 2026-07-08 — thay quy ước "liên tục" cũ.)*
|
|
107
|
+
|
|
108
|
+
Gom theo **LOẠI test**, số nhóm CỐ ĐỊNH theo loại, chỉ tạo nhóm THỰC SỰ có TC:
|
|
109
|
+
|
|
110
|
+
1. **GUI** — UI tĩnh, label, layout, placeholder, icon, trạng thái hiển thị (không đổi state).
|
|
111
|
+
2. **Validation** — field-level: validate input, EP/BVA, biên, error message, trạng thái nút enabled/disabled theo điều kiện, read-only, ràng buộc.
|
|
112
|
+
3. **Functional** — nghiệp vụ/luồng: business logic, submit/navigation, decision table, use case hoàn chỉnh.
|
|
113
|
+
4. **Integration** — bắt tay ≥2 module/dịch vụ (kể cả qua mock): đọc/ghi cross-service, handshake, data flow, contract.
|
|
114
|
+
5. **NFR** — phi chức năng: performance, a11y/keyboard, WCAG, security, i18n, compatibility.
|
|
115
|
+
6. **E2E** — journey đầu-cuối nhiều use case.
|
|
116
|
+
|
|
117
|
+
**Quy tắc đánh số & phân nhóm:**
|
|
118
|
+
- Gán số CỐ ĐỊNH theo loại: **GUI=1 · Validation=2 · Functional=3 · Integration=4 · NFR=5 · E2E=6**. Loại KHÔNG có TC → **BỎ TRỐNG số đó**. VD file chỉ có GUI + Validation + Functional + E2E → `Nhóm 1 — GUI` / `Nhóm 2 — Validation` / `Nhóm 3 — Functional` / **`Nhóm 6 — E2E`** (bỏ trống 4 Integration, 5 NFR). **E2E LUÔN là Nhóm 6, NFR luôn 5, Integration luôn 4** — KHÔNG dồn số.
|
|
119
|
+
- Phân vân **Validation vs Functional**: chỉ test trạng thái field/nút/biên → Validation; có luồng/submit/navigation/logic → Functional. **KHÔNG tạo nhóm "Tương tác"/"Happy Path" riêng.**
|
|
120
|
+
- Lane chỉ có functional (API/Integration/NFR, không có GUI) → bỏ nhóm GUI, bắt đầu từ nhóm phù hợp.
|
|
121
|
+
- **GIỮ NGUYÊN mã TC** khi gom/đảo nhóm — chỉ đổi vị trí; mã không cần liền mạch theo thứ tự đọc.
|
|
122
|
+
- Mọi tham chiếu số nhóm trong file (Trace Matrix, ghi chú) phải khớp số CỐ ĐỊNH đã gán.
|
|
123
|
+
|
|
124
|
+
## Cuối file (bắt buộc)
|
|
125
|
+
|
|
126
|
+
Cả 2 mục dạng LIST (không bảng):
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
## Trace Matrix
|
|
130
|
+
- **BR-xx:** TC_001, TC_002
|
|
131
|
+
- **⚠️ BR-yy:** — (Chưa có TC)
|
|
132
|
+
|
|
133
|
+
## TC bị Block
|
|
134
|
+
- **GAP-03** — TC_005: Chờ openapi.yaml
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> Không thêm section `#### Python Test Mapping`. Bỏ nội dung gạch ngang.
|
|
138
|
+
|
|
139
|
+
> ⚠️ **Bổ sung khi Edit thêm TC mới:** nối bullet mới **ngay liền sau bullet cuối** của list (Trace Matrix / TC bị Block), KHÔNG chèn dòng trắng giữa các bullet. Kiểm lại số TC khớp sau khi thêm.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Tài liệu shared liên quan (bắt buộc nạp khi viết TC)
|
|
144
|
+
|
|
145
|
+
| File | Mục đích |
|
|
146
|
+
|---|---|
|
|
147
|
+
| `shared/action-keywords-glossary.md` | Từ điển action keywords chuẩn — Click/Enter/Verify/Assert... |
|
|
148
|
+
| `shared/precision-rules.md` | Quy tắc lượng hóa Expected Result, cấm từ mơ hồ, đơn vị chuẩn |
|
|
149
|
+
| `shared/duplicate-check-procedure.md` | Quy trình kiểm tra TC trùng lặp trước khi viết mới |
|
|
150
|
+
| `shared/implicit-scenarios.md` | Danh sách implicit scenarios cần xét thêm |
|
|
151
|
+
| `shared/skill-decision-tree.md` | Cây quyết định chọn đúng skill |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Gap Escalation Path (Xử lý khi TC bị Block)
|
|
156
|
+
|
|
157
|
+
Khi TC có `🚫 Block: [GAP-UC{N}-{nnn}]` — thực hiện theo timeline:
|
|
158
|
+
|
|
159
|
+
| Thời điểm | Hành động |
|
|
160
|
+
|---|---|
|
|
161
|
+
| **T+0 (phát hiện gap)** | Ghi GAP vào `DOC_GAP.md` — ID, loại, mô tả, tác động, nguồn |
|
|
162
|
+
| **T+2 (2 ngày)** | Chưa có phản hồi → ping QA Lead / PO |
|
|
163
|
+
| **T+5 (5 ngày)** | Vẫn chưa có → ghi **assumption tạm thời** vào TC bị Block |
|
|
164
|
+
| **T+7 (7 ngày)** | Leo thang PO/PM — gap ảnh hưởng sprint delivery |
|
|
165
|
+
|
|
166
|
+
### Format Assumption khi gap chưa được trả lời (T+5):
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
⚠️ Assumption (T+5): API trả về HTTP 422 khi tên lớp trùng — dựa trên pattern UC1.
|
|
170
|
+
Nếu behavior khác → cập nhật Expected Result và re-review.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Quy trình khi gap được giải quyết (Answered):
|
|
174
|
+
1. Cập nhật `DOC_GAP.md`: status → `Answered`, ghi note giải thích.
|
|
175
|
+
2. Bỏ `🚫 Block` trong TC → cập nhật Expected Result nếu có assumption sai.
|
|
176
|
+
3. Thông báo `qa-tc-reviewer` review lại TC.
|
|
177
|
+
4. Nếu answer thay đổi scope → tạo TC mới hoặc split TC hiện tại.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
# Phần riêng của framework *(B12 — không có ở upstream)*
|
|
182
|
+
|
|
183
|
+
Mọi thứ trên là chuẩn của đội QC. Bốn thứ dưới đây là **của framework**, và mọi skill tầng test
|
|
184
|
+
đều theo — đừng lặp lại chúng trong từng skill.
|
|
185
|
+
|
|
186
|
+
## Hai file TC, chia theo "có qua giao diện"
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
{qc_artifact_dir}test-cases/
|
|
190
|
+
├── TC_<FEATURE>.Test.md ← mặc định
|
|
191
|
+
│ ## Nhóm 1 — GUI ## Nhóm 4 — Integration (qua UI)
|
|
192
|
+
│ ## Nhóm 2 — Validation ## Nhóm 5 — NFR
|
|
193
|
+
│ ## Nhóm 3 — Functional ## Nhóm 6 — E2E
|
|
194
|
+
└── TC_<FEATURE>_API.Test.md ← cờ --api
|
|
195
|
+
## Nhóm 1 — Endpoint
|
|
196
|
+
## Nhóm 2 — Integration API/DB/Kafka
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Câu hỏi phân file:** *"TC này verify được mà **không cần UI** không?"*
|
|
200
|
+
→ **có** = file API · **không** = file giao diện. *(Trùng Bước 2 của `skill-decision-tree.md`.)*
|
|
201
|
+
|
|
202
|
+
⚠️ **Đuôi file là `.Test.md`, không phải `.md`.** `/qc-run-test` và `/qc-review` tìm `*.Test.md`;
|
|
203
|
+
ghi ra file thiếu phần `.Test` là ghi ra thứ **không trạm nào tìm thấy**, và không có gì báo lỗi.
|
|
204
|
+
|
|
205
|
+
Đánh số `TC_<FEATURE>_NNN` **liên tục toàn file**, không đánh lại theo từng nhóm.
|
|
206
|
+
|
|
207
|
+
## Trace — hai hệ, ghi cả hai
|
|
208
|
+
|
|
209
|
+
| Trường | Dạng | Vì sao cần |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `**Trace:**` | `[BR-xx](../REQUIREMENT_ANALYSIS.md#3-business-rules)` — không có BR → `⚠️ Chưa có Business Rule` | truy về luật nghiệp vụ |
|
|
212
|
+
| `**@trace.verifies:**` | `{UC-ID}-SC{N}` (lấy từ `@trace.scenario` của file `.feature`) | **join key** để `/qc-run-test` ghi `qc_status` theo từng kịch bản vào sổ trace |
|
|
213
|
+
|
|
214
|
+
Một `SC` map được nhiều TC. **Thiếu `@trace.verifies` thì kết quả chạy không vào được sổ** — TC
|
|
215
|
+
vẫn chạy, vẫn pass/fail, nhưng không ai biết nó phủ kịch bản nào.
|
|
216
|
+
|
|
217
|
+
Cuối file: **Trace matrix** (BR ↔ TC ↔ SC) + **danh sách TC bị block** — cả hai **dạng danh
|
|
218
|
+
sách**, không bảng (§Nguyên tắc format file đầu tài liệu này).
|
|
219
|
+
|
|
220
|
+
## `🚫 Block` trỏ về file gap cấp PRD
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
- **🚫 Block:** [GAP-UC{N}-{nnn}](../DOC_GAP.md) — <lý do>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
`DOC_GAP.md` nằm ở **thư mục cha** của `test-cases/`, nên liên kết đi lên một cấp. Mã gap mang
|
|
227
|
+
UC (`GAP-UC1-001`) vì một file gap phủ cả PRD.
|
|
228
|
+
|
|
229
|
+
## Dòng `Test-ID attribute`
|
|
230
|
+
|
|
231
|
+
Ghi một dòng ở phần metadata **đầu file**:
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
Test-ID attribute: {attr}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Đọc `@trace.testid_attr` từ header tech-doc gộp (do `/map-testids` ghi). Bảng §4.5.6 chỉ cho
|
|
238
|
+
**giá trị** test-id; đây là **tên thuộc tính** chứa chúng. `/qc-run-test` cần nó để cấu hình
|
|
239
|
+
locator, `/qc-review` cần nó để biết selector trong script có đúng hợp đồng không.
|
|
240
|
+
|
|
241
|
+
Thiếu field trong tech-doc → ghi `Test-ID attribute: — (thiếu @trace.testid_attr, chạy /map-testids)`.
|
|
242
|
+
**Đừng bỏ trống và đừng tự đoán** — đoán sai thì mọi locator trượt 100%, và trượt vì lý do
|
|
243
|
+
không liên quan gì tới thứ đang test.
|
|
@@ -102,5 +102,5 @@ tiền không đáng.
|
|
|
102
102
|
|---|---|---|---|---|---|
|
|
103
103
|
| … | 2 · tiền | Cao | Cao | **P0** | functional/api + giá trị biên; e2e luồng thanh toán |
|
|
104
104
|
|
|
105
|
-
Mỗi dòng rủi ro phải **trỏ được về BR-xx hoặc GAP-
|
|
105
|
+
Mỗi dòng rủi ro phải **trỏ được về `BR-xx` hoặc `GAP-UC{N}-{nnn}`** đã có ở `REQUIREMENT_ANALYSIS.md` /
|
|
106
106
|
`DOC_GAP.md` — rủi ro không neo vào yêu cầu nào là rủi ro tự nghĩ ra.
|
|
@@ -84,4 +84,12 @@ F. CONVENTION:
|
|
|
84
84
|
|
|
85
85
|
Mỗi issue: `file:line` | severity | mô tả | suggestion fix.
|
|
86
86
|
Severity: 🔴 fix ngay (missing cleanup, dữ liệu không verify cross-module, shortcut journey) · 🟠 quan trọng (timeout thiếu, assertion chỉ ở bước cuối) · 🟡 nhỏ (style, docstring/title sai).
|
|
87
|
-
|
|
87
|
+
**Điểm `XX/100`** — ánh xạ mức độ sang điểm trừ: 🔴 = `FAIL` (−5đ) · 🟠 = `WARN` (−2đ) ·
|
|
88
|
+
🟡 = ghi nhận, không trừ. ≥80 đạt · 60–79 cần cải thiện · <60 không đạt.
|
|
89
|
+
**Verdict:** `≥80` VÀ không còn 🔴 → **`APPROVED`**; ngược lại **`NEEDS_FIX`**.
|
|
90
|
+
|
|
91
|
+
**Ghi vào `{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — thêm một hàng vào bảng Tổng quan
|
|
92
|
+
(cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
|
|
93
|
+
Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
|
|
94
|
+
|
|
95
|
+
**KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
|
|
@@ -39,7 +39,15 @@ Review session note sau khi test, coaching QC cải thiện kỹ năng.
|
|
|
39
39
|
|
|
40
40
|
## Output
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
**Điểm `XX/100`** — ánh xạ mức độ sang điểm trừ: 🔴 = `FAIL` (−5đ) · 🟠 = `WARN` (−2đ) ·
|
|
43
|
+
🟡 = ghi nhận, không trừ. ≥80 đạt · 60–79 cần cải thiện · <60 không đạt.
|
|
44
|
+
**Verdict:** `≥80` VÀ không còn 🔴 → **`APPROVED`**; ngược lại **`NEEDS_FIX`**.
|
|
45
|
+
|
|
46
|
+
**Ghi vào `{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — thêm một hàng vào bảng Tổng quan
|
|
47
|
+
(cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
|
|
48
|
+
Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
|
|
49
|
+
|
|
50
|
+
**KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
|
|
43
51
|
Mỗi tiêu chí: ✅/⚠️/❌ + feedback cụ thể
|
|
44
52
|
Top 3 improvement suggestions (coaching tone)
|
|
45
53
|
Đề xuất charter tiếp theo nếu chưa đủ coverage
|
|
@@ -98,4 +98,12 @@ empty step `:pass` · test gọi `_private()` · Counter≠Pagination → xfail
|
|
|
98
98
|
|
|
99
99
|
Mỗi issue: file:line | severity | mô tả | suggestion fix.
|
|
100
100
|
Severity: 🔴 fix ngay (sai logic, POM breach, silent fail) · 🟠 quan trọng (fragile selector, wrong column, missing assert) · 🟡 nhỏ (style, thừa wait, orphan constant).
|
|
101
|
-
|
|
101
|
+
**Điểm `XX/100`** — ánh xạ mức độ sang điểm trừ: 🔴 = `FAIL` (−5đ) · 🟠 = `WARN` (−2đ) ·
|
|
102
|
+
🟡 = ghi nhận, không trừ. ≥80 đạt · 60–79 cần cải thiện · <60 không đạt.
|
|
103
|
+
**Verdict:** `≥80` VÀ không còn 🔴 → **`APPROVED`**; ngược lại **`NEEDS_FIX`**.
|
|
104
|
+
|
|
105
|
+
**Ghi vào `{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — thêm một hàng vào bảng Tổng quan
|
|
106
|
+
(cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
|
|
107
|
+
Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
|
|
108
|
+
|
|
109
|
+
**KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
|
|
@@ -88,4 +88,12 @@ F. CONVENTION:
|
|
|
88
88
|
|
|
89
89
|
Mỗi issue: `file:line` | severity | mô tả | suggestion fix.
|
|
90
90
|
Severity: 🔴 fix ngay (mock thay real call, missing DB verify, no cleanup) · 🟠 quan trọng (thiếu error state, hardcode ID, timeout ngắn) · 🟡 nhỏ (style, marker thiếu sub-domain).
|
|
91
|
-
|
|
91
|
+
**Điểm `XX/100`** — ánh xạ mức độ sang điểm trừ: 🔴 = `FAIL` (−5đ) · 🟠 = `WARN` (−2đ) ·
|
|
92
|
+
🟡 = ghi nhận, không trừ. ≥80 đạt · 60–79 cần cải thiện · <60 không đạt.
|
|
93
|
+
**Verdict:** `≥80` VÀ không còn 🔴 → **`APPROVED`**; ngược lại **`NEEDS_FIX`**.
|
|
94
|
+
|
|
95
|
+
**Ghi vào `{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — thêm một hàng vào bảng Tổng quan
|
|
96
|
+
(cột `Tầng` phân biệt vai soát-code với vai soát-kịch-bản; **không ghi đè** hàng của vai kia).
|
|
97
|
+
Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
|
|
98
|
+
|
|
99
|
+
**KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-run-test`.
|