@educa-corp/sdd-framework 0.9.7 → 0.9.8
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/qc-base-map.json +13 -11
- package/bin/self-check.js +49 -4
- package/bin/trace-schema.json +3226 -3187
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/qc-analyze.md +2 -2
- package/core/commands/qc-automation-assess.md +3 -3
- package/core/commands/qc-design-script.md +60 -30
- package/core/commands/qc-design-test.md +79 -7
- package/core/commands/qc-plan.md +1 -1
- package/core/commands/qc-report.md +85 -76
- package/core/commands/qc-review-script.md +25 -16
- package/core/commands/qc-review-testcase.md +8 -7
- package/core/commands/qc-run-manualtest.md +1 -1
- package/core/commands/qc-run-script.md +15 -8
- package/core/modules/qc-playwright-ts/module.yaml +13 -0
- package/core/modules/qc-playwright-ts/stack-profile.yaml +99 -0
- package/core/modules/qc-wdio-appium/module.yaml +20 -0
- package/core/modules/qc-wdio-appium/stack-profile.yaml +107 -0
- package/core/skills/qc/qa-analyst/data-flow.md +1 -1
- package/core/skills/qc/qa-automation-assess/matrix.md +6 -3
- package/core/skills/qc/{qa-runner → qa-designer}/exploratory/session.md +8 -2
- package/core/skills/qc/qa-designer/functional/api.md +1 -1
- package/core/skills/qc/qa-designer/functional/job.md +128 -0
- package/core/skills/qc/qa-designer/integration/api.md +1 -1
- package/core/skills/qc/qa-designer/integration/db.md +1 -1
- package/core/skills/qc/qa-designer/integration/{kafka.md → queue.md} +20 -4
- package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +17 -0
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +17 -0
- package/core/skills/qc/qa-reviewer/script/_shared/review-rules.md +121 -0
- package/core/skills/qc/qa-reviewer/script/api/auth.md +49 -0
- package/core/skills/qc/qa-reviewer/script/api/endpoint.md +89 -0
- package/core/skills/qc/qa-reviewer/script/api/security.md +46 -0
- package/core/skills/qc/qa-reviewer/script/exploratory.md +2 -2
- package/core/skills/qc/qa-reviewer/script/mobile/e2e.md +41 -0
- package/core/skills/qc/qa-reviewer/script/mobile/functional.md +90 -0
- package/core/skills/qc/qa-reviewer/script/mobile/integration.md +41 -0
- package/core/skills/qc/qa-reviewer/script/mobile/non-functional.md +43 -0
- package/core/skills/qc/qa-reviewer/script/web/e2e.md +46 -0
- package/core/skills/qc/qa-reviewer/script/web/functional.md +111 -0
- package/core/skills/qc/qa-reviewer/script/web/integration.md +46 -0
- package/core/skills/qc/qa-reviewer/script/web/non-functional.md +49 -0
- package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +1 -1
- package/core/skills/qc/qa-reviewer/shared/review-file-template.md +26 -7
- package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/integration.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
- package/core/skills/qc/qa-script-designer/_shared/api-conventions.md +94 -0
- package/core/skills/qc/qa-script-designer/_shared/file-naming-and-folders.md +109 -0
- package/core/skills/qc/qa-script-designer/_shared/mobile-conventions.md +196 -0
- package/core/skills/qc/qa-script-designer/_shared/web-conventions.md +257 -0
- package/core/skills/qc/qa-script-designer/api/auth.md +43 -0
- package/core/skills/qc/qa-script-designer/api/endpoint.md +61 -0
- package/core/skills/qc/qa-script-designer/api/security.md +41 -0
- package/core/skills/qc/qa-script-designer/mobile/e2e.md +35 -0
- package/core/skills/qc/qa-script-designer/mobile/functional/feature.md +32 -0
- package/core/skills/qc/qa-script-designer/mobile/functional/screen.md +42 -0
- package/core/skills/qc/qa-script-designer/mobile/integration.md +39 -0
- package/core/skills/qc/qa-script-designer/mobile/non-functional.md +39 -0
- package/core/skills/qc/qa-script-designer/web/e2e.md +36 -0
- package/core/skills/qc/qa-script-designer/web/functional/api.md +39 -0
- package/core/skills/qc/qa-script-designer/web/functional/gui-feature.md +34 -0
- package/core/skills/qc/qa-script-designer/web/functional/gui-screen.md +42 -0
- package/core/skills/qc/qa-script-designer/web/integration.md +43 -0
- package/core/skills/qc/qa-script-designer/web/non-functional.md +42 -0
- package/core/skills/qc/qa-script-runner/mobile/run.md +38 -0
- package/core/skills/qc/qa-script-runner/report.md +41 -0
- package/core/skills/qc/qa-script-runner/web/run.md +48 -0
- package/core/steps/qc-scope.md +43 -0
- package/core/steps/report-footer.md +2 -2
- package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +1 -1
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +10 -10
- package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +1 -1
- package/docs/02-concepts/traceability.md +1 -1
- package/docs/03-guides/developer.md +1 -1
- package/docs/03-guides/tester-qa.md +40 -12
- package/docs/04-reference/commands.md +1 -1
- package/docs/04-reference/modules.md +2 -1
- package/docs/explain/17-qc-design-test.md +2 -2
- package/docs/explain/19-qc-run-test.md +4 -4
- package/docs/explain/20-qc-report.md +1 -1
- package/docs/explain/23-fix-bug.md +2 -2
- package/docs/plans/qc-surgery/01-checklist.md +18 -6
- package/docs/plans/qc-surgery/PLAN_v2.md +295 -0
- package/docs/plans/qc-surgery/exec-S-ap-stack-typescript.md +420 -0
- package/docs/plans/qc-surgery/exec-S0-guard-cam-stack-cu.md +400 -0
- package/docs/plans/qc-surgery/exec-S1-hai-module-thay-qc-playwright.md +267 -0
- package/docs/plans/qc-surgery/exec-S2-qa-runner-thanh-script-designer-runner.md +340 -0
- package/docs/plans/qc-surgery/exec-S3-viet-lai-tieu-chi-review-script.md +322 -0
- package/docs/plans/qc-surgery/exec-S5-an-theo-don-dau-vet-stack-cu.md +292 -0
- package/package.json +1 -1
- package/core/modules/qc-playwright/stack-profile.yaml +0 -66
- package/core/skills/qc/qa-reviewer/script/e2e.md +0 -95
- package/core/skills/qc/qa-reviewer/script/functional.md +0 -109
- package/core/skills/qc/qa-reviewer/script/integration.md +0 -99
- package/core/skills/qc/qa-reviewer/script/non-functional.md +0 -134
- package/core/skills/qc/qa-runner/e2e.md +0 -49
- package/core/skills/qc/qa-runner/functional/api.md +0 -35
- package/core/skills/qc/qa-runner/functional/gui-feature.md +0 -57
- package/core/skills/qc/qa-runner/functional/gui-screen.md +0 -61
- package/core/skills/qc/qa-runner/integration.md +0 -47
- package/core/skills/qc/qa-runner/non-functional.md +0 -49
- package/core/skills/qc/qa-runner/report/report.md +0 -37
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# QC automation module — Python + pytest-playwright + Page Object
|
|
2
|
-
# Used by the /qc-* commands (the official QC automation pipeline ported from the QC team).
|
|
3
|
-
# This is the QC test-authoring/execution stack, independent of the dev implementation
|
|
4
|
-
# module (java-spring, react, flutter, …). Selected via tech_stack.qc_module or per /qc-* run.
|
|
5
|
-
|
|
6
|
-
build:
|
|
7
|
-
test: "python3 -m pytest"
|
|
8
|
-
e2e: "python3 -m pytest -m e2e"
|
|
9
|
-
report: "python3 -m pytest --html=reports/<feature>/report.html --self-contained-html"
|
|
10
|
-
show_trace: "python3 -m playwright show-trace <test-results/<nodeid>/trace.zip>"
|
|
11
|
-
|
|
12
|
-
architecture:
|
|
13
|
-
style: "Page Object Model over pytest-playwright — Markdown test-case first, Python second"
|
|
14
|
-
key_rules:
|
|
15
|
-
- "Markdown-first: never generate Python until a reviewed .Test.md exists for the feature"
|
|
16
|
-
- "No Allure, no hand-written dashboard, no record_video — use Playwright Trace + pytest-html"
|
|
17
|
-
- "No hard-coded URL/credential/timeout — read from Env.* and CONFIG[...]"
|
|
18
|
-
- "No time.sleep() — use Playwright auto-wait / expect()"
|
|
19
|
-
- "Each test independent via pytest-playwright fixtures (page / logged_in_page / …)"
|
|
20
|
-
- "Page Object extends slim BasePage; split 3 layers: locators _x(), actions verb_noun(), assertions assert_x() using expect()"
|
|
21
|
-
- "Locator priority: data-testid → role → label/text → CSS → avoid XPath"
|
|
22
|
-
- "test-id values come from the FE tech-design Test Selectors contract (tech-doc gộp cấp PRD: {TICKET-ID}-tech-design.md, bảng Test Selectors §4.5.6 — lọc theo cột 'Phục vụ SC') — prefer them (no runtime scan); fall back to role/text only when an actionable element has no test-id there, and note the gap"
|
|
23
|
-
- "Group tests by (role, account) so login/logout never interleaves across roles"
|
|
24
|
-
- "Cover 100% of TCs in the .Test.md — every TC ends Pass/Fail/Skip, none left Draft"
|
|
25
|
-
folder_structure: |
|
|
26
|
-
{qc_artifact_dir}test-cases/ ← test-case Markdown (.Test.md) — source of truth (mặc định docs/, lộ ra ngoài)
|
|
27
|
-
pages/ ← Page Object Model
|
|
28
|
-
│ ├── base_page.py ← slim BasePage (click/fill/wait/screenshot)
|
|
29
|
-
│ └── <feature>_page.py
|
|
30
|
-
tests/ ← pytest scripts, 1-1 with test-cases/
|
|
31
|
-
│ ├── conftest.py ← fixtures: browser, page, logged_in_page, tracing
|
|
32
|
-
│ └── <project>/test_<feature>.py
|
|
33
|
-
utils/ ← config_loader, logger, steps, test_ordering, report helpers
|
|
34
|
-
test_data/ ← JSON datasets
|
|
35
|
-
config/config.yaml ← browser, timeout, video/screenshot/trace toggles
|
|
36
|
-
reports/ test-results/ ← generated (gitignored): html report, trace.zip, screenshots
|
|
37
|
-
|
|
38
|
-
coding_standards:
|
|
39
|
-
naming:
|
|
40
|
-
test_case_id: "TC_<FEATURE>_<NNN>"
|
|
41
|
-
test_class: "TestFeatureHappyCase"
|
|
42
|
-
test_function: "test_TC<NNN>_<snake_case>"
|
|
43
|
-
page_object: "<feature>_page.py with <Feature>Page class extending BasePage"
|
|
44
|
-
files:
|
|
45
|
-
test_case_md: "{qc_artifact_dir}test-cases/TC_<FEATURE>.Test.md"
|
|
46
|
-
page_object: "pages/<feature>_page.py"
|
|
47
|
-
test_script: "tests/<project>/test_<feature>.py"
|
|
48
|
-
patterns:
|
|
49
|
-
steps: "wrap steps with `with step(\"…\")` (from utils.steps import step)"
|
|
50
|
-
assertions: "Playwright expect() — never bare assert on dynamic UI"
|
|
51
|
-
fixtures: "auth fixtures register via register_auth_fixtures([...]) in project conftest"
|
|
52
|
-
fail_triage: "classify each FAIL as script-bug (fix selector/logic) vs product-gap (keep FAIL + evidence, never fake-pass)"
|
|
53
|
-
|
|
54
|
-
testing:
|
|
55
|
-
layers: "functional (gui-screen / gui-feature / api), integration (api/db/gui/kafka), e2e (journey), non-functional, exploratory"
|
|
56
|
-
runner: "pytest-playwright; trace via context.tracing.start in conftest"
|
|
57
|
-
report: "pytest-html (--html ... --self-contained-html) + Playwright Trace viewer"
|
|
58
|
-
|
|
59
|
-
trace_tags:
|
|
60
|
-
# QC tests map back to the framework's scenarios — drives qc_status in the trace TSV.
|
|
61
|
-
verifies: "# @trace.verifies={UC-ID}-SC{N}"
|
|
62
|
-
source: "# @trace.source=specs/{domain}/{prd-slug}/bdd/{platform}/{UC-ID}-{slug}.feature"
|
|
63
|
-
test_type: "# @trace.test_type=functional|integration|e2e|non-functional"
|
|
64
|
-
|
|
65
|
-
# qc_status: /qc-run-script writes pass|fail|skip|not_run + qc_run_at into {trace_dir}/{UC-ID}.tsv
|
|
66
|
-
# (parallel to dev_selftest), surfaced in Living Docs as the OFFICIAL QC automation result.
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Review Test Script — E2E Journey
|
|
8
|
-
|
|
9
|
-
Review Python pytest script cho test end-to-end và đánh giá chất lượng code.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- "review script E2E cho [Feature]" / "check code E2E quality"
|
|
13
|
-
- Sau khi qa-runner sinh script E2E, trước khi merge
|
|
14
|
-
|
|
15
|
-
## Khi KHÔNG trigger
|
|
16
|
-
- Review script functional 1 màn → `script/functional`
|
|
17
|
-
- Review script integration → `script/integration`
|
|
18
|
-
- Review session note → `script/exploratory`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Phase 1 — Clarify
|
|
23
|
-
|
|
24
|
-
1. Đọc file Python test E2E được chỉ định (thường `tests/<project>/e2e/test_*.py`)
|
|
25
|
-
2. Đọc các Page Object liên quan (nhiều PO cho nhiều màn)
|
|
26
|
-
3. Đọc TC E2E Markdown gốc để so sánh coverage journey
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Phase 2 — Review
|
|
31
|
-
|
|
32
|
-
Đánh giá theo 6 tiêu chí:
|
|
33
|
-
|
|
34
|
-
A. JOURNEY COVERAGE:
|
|
35
|
-
- Mỗi journey trong TC E2E có test function tương ứng không?
|
|
36
|
-
- Test function có traverse đủ các màn/module của journey không?
|
|
37
|
-
- Main flow / alternate flow / exception flow đủ không?
|
|
38
|
-
|
|
39
|
-
B. CROSS-MODULE DATA INTEGRITY:
|
|
40
|
-
- Data nhập ở Page A có được verify ở Page B/DB/hệ thống ngoài không?
|
|
41
|
-
- Assertion sau mỗi chặng (không chỉ assert ở bước cuối)?
|
|
42
|
-
- Không bỏ qua bước trung gian để "shortcut" đến màn cuối?
|
|
43
|
-
|
|
44
|
-
C. FIXTURE & PRECONDITION:
|
|
45
|
-
- Precondition phức tạp (nhiều entity) có fixture riêng, không inline trong test?
|
|
46
|
-
- Fixture tạo data → có teardown/cleanup tương ứng (yield + cleanup)?
|
|
47
|
-
- Không hardcode ID của entity đã tạo ở bước trước → dùng biến trả về fixture?
|
|
48
|
-
- Fixture scope đúng (`function` cho E2E, không dùng `session`)?
|
|
49
|
-
|
|
50
|
-
D. WAIT & TIMING:
|
|
51
|
-
- Timeout đủ dài cho navigation giữa màn (≥15s cho `networkidle`)?
|
|
52
|
-
- Không `time.sleep()`; dùng `wait_for_url` / `wait_for_load_state` / `expect(...).to_be_visible`?
|
|
53
|
-
- Không timeout ngắn (<5s) cho API call cross-module?
|
|
54
|
-
|
|
55
|
-
E. ASSERTION DEPTH:
|
|
56
|
-
- Không chỉ assert URL cuối; phải assert nội dung tại mỗi chặng?
|
|
57
|
-
- Verify đúng data flow: giá trị nhập màn A xuất hiện đúng ở màn B?
|
|
58
|
-
- Negative journey (thất bại giữa chừng): assert đúng màn dừng lại + thông báo lỗi?
|
|
59
|
-
|
|
60
|
-
F. CONVENTION:
|
|
61
|
-
- Marker `@pytest.mark.e2e` + `@pytest.mark.smoke` (nếu critical journey)?
|
|
62
|
-
- Marker phân loại = tên journey; docstring = TC ID + mô tả journey?
|
|
63
|
-
- `with step(...)` (`from utils.steps`) rõ từng chặng (màn nào → hành động nào)?
|
|
64
|
-
- Docstring ghi TC ID + mô tả journey ngắn?
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Checklist chi tiết
|
|
69
|
-
|
|
70
|
-
### Page Objects
|
|
71
|
-
- Mỗi màn có PO riêng; test không gọi `page.click()` / `page.fill()` trực tiếp.
|
|
72
|
-
- Selector constants khai báo đầu class; không rải rác trong test.
|
|
73
|
-
- Action method `return self` để chain; assertion method gọi `take_screenshot()` cuối.
|
|
74
|
-
|
|
75
|
-
### Test file
|
|
76
|
-
- Fixture `logged_in_page` hoặc fixture composite (vd `logged_in_as_teacher`) làm base.
|
|
77
|
-
- Không dùng biến global chia sẻ state giữa test function.
|
|
78
|
-
- Compile & collect trước submit: `python3 -m py_compile` + `pytest --collect-only -q`.
|
|
79
|
-
- Số journey collect = số TC E2E trong `.md`.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Output
|
|
84
|
-
|
|
85
|
-
Mỗi issue: `file:line` | severity | mô tả | suggestion fix.
|
|
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
|
-
**Đ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-design-script`.
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Review Test Script — Functional
|
|
8
|
-
|
|
9
|
-
Review Python pytest script và đánh giá chất lượng code.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- "review script cho [Feature]" / "check code quality"
|
|
13
|
-
- Sau khi qa-runner xong, trước khi merge vào main
|
|
14
|
-
|
|
15
|
-
## Khi KHÔNG trigger
|
|
16
|
-
- Review TC nghiệp vụ → dùng qa-reviewer
|
|
17
|
-
- Review exploratory session note → dùng qa-reviewer/script/exploratory
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Phase 1 — Clarify
|
|
22
|
-
|
|
23
|
-
1. Đọc file Python test được chỉ định
|
|
24
|
-
2. Đọc Page Object liên quan
|
|
25
|
-
3. Đọc TC markdown gốc (để so sánh coverage)
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Phase 2 — Review
|
|
30
|
-
|
|
31
|
-
Đánh giá theo 6 tiêu chí:
|
|
32
|
-
|
|
33
|
-
A. LOCATOR:
|
|
34
|
-
- XPath dài/phức tạp → đề xuất data-testid / role
|
|
35
|
-
- Locator phụ thuộc text tiếng Việt → fragile khi đổi copy
|
|
36
|
-
- Locator nằm trong Page Object, KHÔNG hardcode trong test
|
|
37
|
-
- Dùng .first()/[n] → không reliable
|
|
38
|
-
|
|
39
|
-
B. WAIT & TIMING:
|
|
40
|
-
- time.sleep() → phải đổi sang Playwright auto-wait / expect
|
|
41
|
-
- Timeout quá ngắn (<3s) hoặc quá dài (>30s)
|
|
42
|
-
|
|
43
|
-
C. TEST INDEPENDENCE:
|
|
44
|
-
- Hardcode user ID/data ID → fragile
|
|
45
|
-
- Phụ thuộc thứ tự chạy (test_b cần test_a)
|
|
46
|
-
- Thiếu cleanup/teardown khi tạo data
|
|
47
|
-
- Global state
|
|
48
|
-
|
|
49
|
-
D. ASSERTION:
|
|
50
|
-
- assert True / not error → vô nghĩa
|
|
51
|
-
- Chỉ assert URL, không assert content → thiếu
|
|
52
|
-
- Thiếu negative assertion
|
|
53
|
-
|
|
54
|
-
E. CONVENTION:
|
|
55
|
-
- Marker đúng (@pytest.mark.functional + platform)?
|
|
56
|
-
- Tên: test_<feature>_<scenario>_<expected>?
|
|
57
|
-
- Docstring có TC_ID?
|
|
58
|
-
- Fixture từ conftest, không tự tạo browser?
|
|
59
|
-
|
|
60
|
-
F. PAGE OBJECT:
|
|
61
|
-
- Test gọi page.click() trực tiếp → phải qua PO
|
|
62
|
-
- PO method quá dài (>15 dòng) → tách
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Checklist chi tiết review code
|
|
67
|
-
|
|
68
|
-
### Phần 1 — Page Object (`pages/<feature>_page.py`)
|
|
69
|
-
- Kế thừa `BasePage`; selector constants `UPPER_SNAKE_CASE` tập trung đầu class (không rải rác).
|
|
70
|
-
- Tách 3 lớp: Locators (`_private()` chỉ trả `Locator`) → Actions (`public()` + `return self`, KHÔNG decorator) → Assertions (`assert_*()` + `expect()` + `take_screenshot()` cuối).
|
|
71
|
-
- Wait: KHÔNG `time.sleep()`; `wait_for_timeout()` chỉ khi cần (≤1000ms); sau nav/submit dùng `wait_for_load_state("networkidle")`; không `wait_for_timeout` ngay sau `networkidle`.
|
|
72
|
-
- KHÔNG hardcode URL/credential/timeout → `Env.*`, `CONFIG`.
|
|
73
|
-
- Column index dùng named constant (`COL_TTHAI = 7`), không magic number `cells[7]`.
|
|
74
|
-
- Assertion: dùng `expect()` cho element; `assert` Python cho logic (count/regex); screenshot tên `TC<NNN>_mo_ta`; KHÔNG silent fail → `raise AssertionError`, không `log.warning`.
|
|
75
|
-
- Lỗi assertion hay gặp: "ordered" phải verify thứ tự thật (`last_pos`); đúng cột; Counter ≠ Pagination total (không assert `==`); P0 strict / P1 `_or_empty`.
|
|
76
|
-
- Public API: có `get_row_count()`, `get_all_rows()` thay vì test gọi `_private()`; helper trả data là method thường (không cần bọc step).
|
|
77
|
-
|
|
78
|
-
### Phần 2 — Test file (`tests/test_<feature>.py`)
|
|
79
|
-
- Đủ class `TestFeatureUI` / `TestFeatureFunctional` / `TestFeatureNegative`; fixture scope `function`, base `logged_in_page`.
|
|
80
|
-
- KHÔNG Allure: phân loại/độ ưu tiên qua pytest markers (`smoke`/`regression`/domain); docstring/`__doc__` ghi `TC_FEATURE_NNN – …`; Priority khớp marker (P0→smoke, P1/P2→regression).
|
|
81
|
-
- Marker: ≥1 category (`smoke`/`regression`) + 1 domain (`ui`/`filter`/`search`/`pagination`/`action`/`negative`); đã đăng ký `pytest.ini`.
|
|
82
|
-
- Step: bọc bước bằng `with step("…")` (`from utils.steps import step`) rõ Action/Verify; KHÔNG step rỗng `: pass`.
|
|
83
|
-
- Isolation: độc lập thứ tự; không global state; không gọi `_private()` từ test.
|
|
84
|
-
- Logic nghiệp vụ nghi ngờ → `@pytest.mark.xfail(strict=False, reason=...)` giải thích rõ.
|
|
85
|
-
|
|
86
|
-
### Phần 4 — Tổng quát
|
|
87
|
-
- Compile & collect bắt buộc trước submit:
|
|
88
|
-
`python3 -m py_compile pages/<f>_page.py tests/test_<f>.py` · `pytest tests/test_<f>.py --collect-only -q`
|
|
89
|
-
- Số test collect = số TC trong `.md`; không warning marker chưa đăng ký.
|
|
90
|
-
- Naming: class `PascalCase`+`Page`; method `test_TC<NNN>_<snake>`; constant `UPPER_SNAKE`; locator `_snake()`; action `verb_noun()`; assert `assert_condition()`.
|
|
91
|
-
|
|
92
|
-
### Lỗi phổ biến (TC_TRUCLOP)
|
|
93
|
-
empty step `:pass` · test gọi `_private()` · Counter≠Pagination → xfail · "ordered" không verify thứ tự · magic `cells[7]` · silent fail → raise · Reset thiếu domain marker · `wait_for_timeout` thừa sau networkidle · orphan selector constant.
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## Output
|
|
98
|
-
|
|
99
|
-
Mỗi issue: file:line | severity | mô tả | suggestion fix.
|
|
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
|
-
**Đ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-design-script`.
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Review Test Script — Integration
|
|
8
|
-
|
|
9
|
-
Review Python pytest script cho test tích hợp (GUI↔Backend, API, DB) và đánh giá chất lượng code.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- "review script integration cho [Feature]" / "check code tích hợp"
|
|
13
|
-
- Sau khi qa-runner sinh script integration, trước khi merge
|
|
14
|
-
|
|
15
|
-
## Khi KHÔNG trigger
|
|
16
|
-
- Review script functional 1 màn/endpoint → `script/functional`
|
|
17
|
-
- Review script E2E xuyên nhiều module → `script/e2e`
|
|
18
|
-
- Review session note → `script/exploratory`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Phase 1 — Clarify
|
|
23
|
-
|
|
24
|
-
1. Đọc file Python test integration được chỉ định
|
|
25
|
-
2. Đọc Page Object và API/DB utility liên quan
|
|
26
|
-
3. Đọc TC integration Markdown gốc để so sánh coverage
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Phase 2 — Review
|
|
31
|
-
|
|
32
|
-
Đánh giá theo 6 tiêu chí:
|
|
33
|
-
|
|
34
|
-
A. NO MOCK ON INTEGRATION:
|
|
35
|
-
- Không mock API/DB trong integration test (mock → đây là unit test, không phải integration)?
|
|
36
|
-
- Dùng real network call / real DB query / `page.expect_response()` để capture API thật?
|
|
37
|
-
- Network interception chỉ dùng để **observe** (verify request), không để **stub** response?
|
|
38
|
-
|
|
39
|
-
B. BACKEND STATE VERIFICATION:
|
|
40
|
-
- Sau action UI, có verify trạng thái backend không (DB query / API GET để re-fetch)?
|
|
41
|
-
- **GUI↔Backend:** verify cả request gửi đúng (method/URL/payload) lẫn render UI đúng?
|
|
42
|
-
- **DB:** dùng trực tiếp DB fixture/util để query `bảng.cột = giá trị`; không chỉ verify qua UI?
|
|
43
|
-
- **API:** verify response schema + status code + downstream effect (DB/event)?
|
|
44
|
-
|
|
45
|
-
C. ERROR STATE COVERAGE:
|
|
46
|
-
- Có test 4xx/5xx response → UI hiển thị message đúng?
|
|
47
|
-
- Có test empty state / loading state / timeout state?
|
|
48
|
-
- Concurrency test: mô tả rõ số request đồng thời; assert không race condition (vd unique constraint giữ)?
|
|
49
|
-
|
|
50
|
-
D. DATA SETUP & CLEANUP:
|
|
51
|
-
- Data test được tạo qua fixture (không hardcode ID)?
|
|
52
|
-
- Fixture `yield` + teardown xóa/rollback data sau mỗi test?
|
|
53
|
-
- Không dùng data production hoặc shared data giữa các test?
|
|
54
|
-
|
|
55
|
-
E. WAIT & TIMING:
|
|
56
|
-
- Không `time.sleep()`; chờ API response bằng `page.expect_response()` hoặc `wait_for_response()`?
|
|
57
|
-
- Sau action có side-effect backend, chờ đủ trước khi assert state (vd `wait_for_load_state("networkidle")`)?
|
|
58
|
-
- Timeout đủ cho network round-trip (≥10s)?
|
|
59
|
-
|
|
60
|
-
F. CONVENTION:
|
|
61
|
-
- Marker `@pytest.mark.integration` + sub-domain (`gui`, `api`, `db`)?
|
|
62
|
-
- Marker phân loại = loại tích hợp; docstring = TC ID + điểm tích hợp?
|
|
63
|
-
- `with step(...)` (`from utils.steps`) rõ hành động → API call → verify response/DB?
|
|
64
|
-
- Helper DB/API truy cập trong `utils/`, không rải trong test file?
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Checklist chi tiết
|
|
69
|
-
|
|
70
|
-
### GUI↔Backend
|
|
71
|
-
- Dùng `page.expect_response("**/api/endpoint")` để capture và assert request/response.
|
|
72
|
-
- Assert: status code + response payload + UI change sau response.
|
|
73
|
-
|
|
74
|
-
### API integration
|
|
75
|
-
- Dùng `requests` hoặc Playwright API context; không dùng UI để trigger API call.
|
|
76
|
-
- Assert schema với JSON schema validator hoặc `assert key in response.json()`.
|
|
77
|
-
|
|
78
|
-
### DB integration
|
|
79
|
-
- DB fixture trả connection/cursor; cleanup `DELETE WHERE id = created_id`.
|
|
80
|
-
- `assert cursor.fetchone()["column"] == expected_value`; không hardcode row position.
|
|
81
|
-
|
|
82
|
-
### Compile & collect
|
|
83
|
-
`python3 -m py_compile` + `pytest --collect-only -q`; số test collect = số TC integration `.md`.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## Output
|
|
88
|
-
|
|
89
|
-
Mỗi issue: `file:line` | severity | mô tả | suggestion fix.
|
|
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
|
-
**Đ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-design-script`.
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Review Test Script — Non-Functional
|
|
8
|
-
|
|
9
|
-
Review Python pytest script cho test phi chức năng (performance, security, accessibility, compatibility) và đánh giá chất lượng code.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- "review script non-functional cho [Feature]" / "check code performance/security/accessibility"
|
|
13
|
-
- Sau khi qa-runner sinh script non-functional, trước khi merge
|
|
14
|
-
|
|
15
|
-
## Khi KHÔNG trigger
|
|
16
|
-
- Review script functional → `script/functional`
|
|
17
|
-
- Review script integration → `script/integration`
|
|
18
|
-
- Review session note → `script/exploratory`
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Phase 1 — Clarify
|
|
23
|
-
|
|
24
|
-
1. Đọc file Python test non-functional được chỉ định
|
|
25
|
-
2. Xác định loại: performance / security / accessibility / compatibility
|
|
26
|
-
3. Đọc TC non-functional Markdown gốc để đối chiếu ngưỡng + công cụ đo
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Phase 2 — Review
|
|
31
|
-
|
|
32
|
-
Đánh giá theo 6 tiêu chí:
|
|
33
|
-
|
|
34
|
-
A. THRESHOLD ASSERTION — tiêu chí quan trọng nhất:
|
|
35
|
-
- Assertion có dùng **giá trị ngưỡng cụ thể** không? (`assert elapsed < 2.0`, `assert violations == []`)
|
|
36
|
-
- Không dùng assertion mơ hồ: `assert response` / `assert "ok" in text` / `assert True`?
|
|
37
|
-
- Ngưỡng khớp với TC Markdown gốc (không tự đặt giá trị khác)?
|
|
38
|
-
|
|
39
|
-
B. THEO LOẠI:
|
|
40
|
-
- **Performance:**
|
|
41
|
-
- Đo thời gian bằng `page.wait_for_load_state` + `performance.timing` hoặc `time.perf_counter()` (không `time.sleep()`)?
|
|
42
|
-
- Có parametrize tải mục tiêu (concurrent users / data volume)?
|
|
43
|
-
- `pytest-benchmark` hoặc custom fixture đo rõ ràng?
|
|
44
|
-
- Margin hợp lý (không `assert elapsed < 0.001` quá strict)?
|
|
45
|
-
- **Security:**
|
|
46
|
-
- Payload injection được lưu trong fixture/constant, không inline magic string?
|
|
47
|
-
- Test không thực sự tấn công server production; dùng môi trường test?
|
|
48
|
-
- Assert bị chặn đúng: status 4xx, message lỗi, KHÔNG tạo được record?
|
|
49
|
-
- PII test: assert response KHÔNG chứa SĐT/email raw?
|
|
50
|
-
- **Accessibility:**
|
|
51
|
-
- Dùng `axe-playwright` (`AxeBuilder`) hoặc `pytest-axe`?
|
|
52
|
-
- Assert `violations == []` hoặc filter đúng WCAG level (`wcag2a`, `wcag2aa`)?
|
|
53
|
-
- Không assert bằng element count / class name (không liên quan accessibility)?
|
|
54
|
-
- **Compatibility:**
|
|
55
|
-
- Parametrize `@pytest.mark.parametrize` trên browser/device/viewport?
|
|
56
|
-
- Mỗi parameter = 1 target trong TC Markdown?
|
|
57
|
-
- Dùng `playwright_browser_type` fixture, không hardcode `chromium`?
|
|
58
|
-
|
|
59
|
-
C. ENVIRONMENT GUARD:
|
|
60
|
-
- Test cần môi trường đặc biệt (load server, scanner) có `@pytest.mark.skipif` nếu env không đủ?
|
|
61
|
-
- Credentials/endpoint load test không hardcode → `Env.*` / `CONFIG`?
|
|
62
|
-
- Test security không gọi endpoint production?
|
|
63
|
-
|
|
64
|
-
D. DATA SETUP & TEARDOWN:
|
|
65
|
-
- Data lớn (performance) có fixture tạo trước, teardown sau?
|
|
66
|
-
- Không để lại data/artifact sau test (security test không tạo record rác)?
|
|
67
|
-
|
|
68
|
-
E. WAIT & TIMING:
|
|
69
|
-
- Không `time.sleep()` cho wait UI; dùng Playwright auto-wait?
|
|
70
|
-
- Đo elapsed time chính xác: bắt đầu/kết thúc đo rõ ràng, không bao gồm fixture setup?
|
|
71
|
-
|
|
72
|
-
F. CONVENTION:
|
|
73
|
-
- Marker `@pytest.mark.non_functional` + sub-domain (`performance`/`security`/`accessibility`/`compatibility`)?
|
|
74
|
-
- **KHÔNG Allure** (đã gỡ): không `@allure.*`; bọc bước bằng `with step("…")` (`from utils.steps import step`)?
|
|
75
|
-
- `with step(...)` rõ: setup tải → trigger → measure → assert ngưỡng?
|
|
76
|
-
- Docstring ghi TC ID + ngưỡng mục tiêu + công cụ đo?
|
|
77
|
-
- Report = Playwright Trace (`test-results/<nodeid>/trace.zip`, `playwright show-trace`) + pytest-html (`--html=… --self-contained-html`); không tham chiếu report tự viết/Allure?
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## Checklist chi tiết
|
|
82
|
-
|
|
83
|
-
### Performance
|
|
84
|
-
```python
|
|
85
|
-
# ✅ Đúng
|
|
86
|
-
start = time.perf_counter()
|
|
87
|
-
page.goto(Env.BASE_URL + "/list")
|
|
88
|
-
page.wait_for_load_state("networkidle")
|
|
89
|
-
elapsed = time.perf_counter() - start
|
|
90
|
-
assert elapsed < 2.0, f"Load time {elapsed:.2f}s > 2.0s threshold"
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Security
|
|
94
|
-
```python
|
|
95
|
-
# ✅ Đúng — payload trong constant, assert bị block
|
|
96
|
-
INJECTION_PAYLOADS = ["<script>alert(1)</script>", "' OR 1=1--"]
|
|
97
|
-
# assert response.status == 400 hoặc record không tồn tại
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Accessibility
|
|
101
|
-
```python
|
|
102
|
-
# ✅ Đúng — axe-playwright
|
|
103
|
-
from axe_playwright_python.sync_playwright import Axe
|
|
104
|
-
results = Axe().run(page)
|
|
105
|
-
assert results.violations_count == 0, results.generate_report()
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Compatibility
|
|
109
|
-
```python
|
|
110
|
-
# ✅ Đúng — parametrize browser
|
|
111
|
-
@pytest.mark.parametrize("browser_name", ["chromium", "firefox", "webkit"])
|
|
112
|
-
def test_compatibility(browser_name, playwright):
|
|
113
|
-
browser = getattr(playwright, browser_name).launch()
|
|
114
|
-
...
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Compile & collect
|
|
118
|
-
`python3 -m py_compile` + `pytest --collect-only -q`; số test collect = số TC non-functional `.md`.
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Output
|
|
123
|
-
|
|
124
|
-
Mỗi issue: `file:line` | severity | mô tả | suggestion fix.
|
|
125
|
-
Severity: 🔴 fix ngay (assertion không có ngưỡng, gọi production endpoint, hardcode credential) · 🟠 quan trọng (ngưỡng không khớp TC, thiếu parametrize, không teardown data) · 🟡 nhỏ (style, marker thiếu sub-domain, docstring thiếu ngưỡng).
|
|
126
|
-
**Điểm `XX/100`** — ánh xạ mức độ sang điểm trừ: 🔴 = `FAIL` (−5đ) · 🟠 = `WARN` (−2đ) ·
|
|
127
|
-
🟡 = ghi nhận, không trừ. ≥80 đạt · 60–79 cần cải thiện · <60 không đạt.
|
|
128
|
-
**Verdict:** `≥80` VÀ không còn 🔴 → **`APPROVED`**; ngược lại **`NEEDS_FIX`**.
|
|
129
|
-
|
|
130
|
-
**Ghi vào `{qc_artifact_dir}test-cases/REVIEW_<FEATURE>.md`** — thêm một hàng vào bảng Tổng quan
|
|
131
|
-
(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).
|
|
132
|
-
Khuôn + quy tắc ghi: `../shared/review-file-template.md`.
|
|
133
|
-
|
|
134
|
-
**KHÔNG tự sửa code** — chỉ nêu `file:line` + cách sửa. Người sửa là `/qc-design-script`.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Gen Script — E2E Journey
|
|
8
|
-
|
|
9
|
-
Skill **tự chứa**: convert journey `.Test.md` → Python pytest + Playwright đầu→cuối xuyên nhiều màn/module. Chỉ cần load file này.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- Convert TC E2E journey (output qa-designer e2e/journey) sang script; TC đã Reviewed
|
|
13
|
-
|
|
14
|
-
## Khi KHÔNG trigger
|
|
15
|
-
- Test 1 màn/field → `functional/*` · 1 điểm tích hợp → `integration.md`
|
|
16
|
-
|
|
17
|
-
## Quy ước script (bám CLAUDE.md)
|
|
18
|
-
- Tiền đề: `.Test.md` đã Reviewed. KHÔNG hardcode → `Env.*`/`CONFIG`; KHÔNG `time.sleep()` → `expect()`.
|
|
19
|
-
- Dùng chuỗi Page Object xuyên các màn; verify points (V1…Vn) thành các `assert_*()` rõ ràng.
|
|
20
|
-
- **Tiền điều kiện qua fixture** (tài khoản role, dữ liệu lớp/buổi); **cleanup** sau journey; mỗi journey độc lập.
|
|
21
|
-
- Cần verify hệ thống ngoài (DB/CRM) → client/fixture riêng. Bọc mỗi chặng `with step("…")` (`from utils.steps import step`, **KHÔNG Allure**); assertion `expect()`; marker `@pytest.mark.e2e`.
|
|
22
|
-
- Naming: class `TestFeatureE2E`, method `test_E2E_<NN>_<snake>`.
|
|
23
|
-
|
|
24
|
-
## Phase 1 — Clarify
|
|
25
|
-
Đọc journey `.Test.md` · các màn/PO + hệ thống verify · tài khoản role & data cần dựng · điểm cleanup.
|
|
26
|
-
|
|
27
|
-
## Phase 2 — Generate
|
|
28
|
-
Mỗi journey → 1 test; bọc từng bước `with step("…")`; cuối journey verify đủ V1…Vn (tạo/mã/định tuyến/đồng bộ/danh sách).
|
|
29
|
-
Journey còn phụ thuộc gap → tạo test `@pytest.mark.skip(reason="GAP-UC{N}-{nnn}")` hoặc xfail.
|
|
30
|
-
|
|
31
|
-
## Phase 3 — Verify
|
|
32
|
-
`py_compile` + `pytest --collect-only -q` · chạy (môi trường staging + CRM) · cập nhật Status TC.
|
|
33
|
-
**Phân loại FAIL — 3 nhãn, luật ở `/qc-run-script` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại luật ở đây**). Đặc thù E2E: journey fail vì 1 bước feature chưa wire = `product-gap` (giữ FAIL/skip + bằng chứng), không phải lỗi script; sai selector/state → `script-bug`. Journey dài qua nhiều bước **dễ ra `flaky` hơn test đơn lẻ** — một bước chậm bất thường là đủ; nên đừng vội gọi `product-gap` khi chưa chạy lại.
|
|
34
|
-
|
|
35
|
-
## Output
|
|
36
|
-
Script `tests/<project>/e2e/test_<feature>.py` + Page Object/client tái dùng. Bàn giao `qa-reviewer`.
|
|
37
|
-
|
|
38
|
-
## Phase 4 — Report (bắt buộc sau khi chạy test)
|
|
39
|
-
Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashboard tự viết).
|
|
40
|
-
|
|
41
|
-
1. Chạy test kèm pytest-html (trace đã bật sẵn ở conftest → mỗi test có `test-results/<nodeid>/trace.zip`):
|
|
42
|
-
```bash
|
|
43
|
-
pytest tests/<project>/e2e/test_<feature>.py --html=reports/<feature>/report.html --self-contained-html
|
|
44
|
-
```
|
|
45
|
-
2. Gửi cho người dùng:
|
|
46
|
-
- HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp).
|
|
47
|
-
- Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
|
|
48
|
-
- Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
|
|
49
|
-
3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Gen Script — Functional API
|
|
8
|
-
|
|
9
|
-
Skill **tự chứa**: convert `.Test.md` API → Python pytest (requests/httpx), không qua UI. Chỉ cần load file này.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- Convert TC API (output qa-designer functional/api) sang script; TC đã Reviewed
|
|
13
|
-
|
|
14
|
-
## Khi KHÔNG trigger
|
|
15
|
-
- Test qua UI → `functional/gui-screen.md` · tích hợp đa thành phần → `integration.md`
|
|
16
|
-
|
|
17
|
-
## Quy ước script (bám CLAUDE.md)
|
|
18
|
-
- Tiền đề: `.Test.md` đã Reviewed. KHÔNG hardcode base URL/token → `Env.*`/`CONFIG`.
|
|
19
|
-
- Client API gói trong helper/fixture (base url, auth header); KHÔNG rải request rời rạc trong test.
|
|
20
|
-
- Assertion: `assert` cho status code + field response (jsonpath); `with step(...)` (`from utils.steps`) cho mỗi call.
|
|
21
|
-
- Marker `@pytest.mark.api` + category; fixture `function`; test độc lập (tạo→cleanup data qua API/teardown).
|
|
22
|
-
- Naming: class `TestFeatureAPI`, method `test_TC<NNN>_<snake>`.
|
|
23
|
-
|
|
24
|
-
## Phase 1 — Clarify
|
|
25
|
-
Đọc `.Test.md` · base url/auth/role · client/fixture đã có chưa · data setup/cleanup.
|
|
26
|
-
|
|
27
|
-
## Phase 2 — Generate
|
|
28
|
-
Mỗi TC → 1 test gọi endpoint với request từ Test Data; assert **status code + field body** theo Expected.
|
|
29
|
-
Nhóm happy/validation/auth/not-found/edge. Data từ `test_data/`.
|
|
30
|
-
|
|
31
|
-
## Phase 3 — Verify
|
|
32
|
-
`py_compile` + `pytest --collect-only -q` · chạy · cập nhật Status TC · in mapping.
|
|
33
|
-
|
|
34
|
-
## Output
|
|
35
|
-
Script `tests/<project>/functional/api/test_<feature>.py` + API client/fixture nếu mới. Bàn giao `qa-reviewer`.
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ui-automation-testing
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Gen Script — Functional GUI Feature (đa màn hình)
|
|
8
|
-
|
|
9
|
-
Skill **tự chứa**: convert `.Test.md` feature span ≥2 màn → Python pytest + Playwright. Chỉ cần load file này.
|
|
10
|
-
|
|
11
|
-
## Khi nào trigger
|
|
12
|
-
- Convert TC feature đa màn (output qa-designer gui-feature) sang script; TC đã Reviewed
|
|
13
|
-
|
|
14
|
-
## Khi KHÔNG trigger
|
|
15
|
-
- Gọn 1 màn → `functional/gui-screen.md` · API → `functional/api.md` · đầu-cuối + đồng bộ → `e2e.md`
|
|
16
|
-
|
|
17
|
-
## Quy ước script (bám CLAUDE.md)
|
|
18
|
-
- Tiền đề: `.Test.md` đã Reviewed. KHÔNG `time.sleep()` → `expect()`/auto-wait; KHÔNG hardcode → `Env.*`/`CONFIG`.
|
|
19
|
-
- **Một Page Object / màn**; điều hướng giữa màn là action trả về PO màn kế (`return NextPage(self.page)`).
|
|
20
|
-
- PO 3 lớp (kế thừa slim `BasePage`, **KHÔNG Allure**) + bọc bước `with step("…")` (`from utils.steps import step`); assertion `expect()`; mọi interaction qua PO; selector constants `UPPER_SNAKE`.
|
|
21
|
-
- Marker + fixture pytest-playwright từ root `tests/conftest.py` (`page`/`logged_in_page`/`logged_in_page_gv`/`login_page`/`dashboard`); test độc lập + cleanup; naming `Test*{...}` / `test_TC<NNN>_<snake>`.
|
|
22
|
-
|
|
23
|
-
## Phase 1 — Clarify
|
|
24
|
-
Đọc `.Test.md` · liệt kê các màn/PO cần · state truyền giữa màn · fixture dựng tiền điều kiện (data qua nhiều bước).
|
|
25
|
-
**Locator: đọc hợp đồng TRƯỚC, dò DOM là bước cuối.** Thứ tự bắt buộc (luật đầy đủ + lý do ở `/qc-design-script` §Role & stack — **không chép lại ở đây**):
|
|
26
|
-
|
|
27
|
-
1. **Test-id contract** — bảng *Test Selectors* §4.5.6 của tech-doc gộp, lọc theo cột "Serves SC" khớp SC của UC này. TÊN thuộc tính đọc từ `@trace.testid_attr` ở header tech-doc (đừng suy từ platform). Feature đa màn: một UC chạm nhiều màn nhưng **vẫn một bảng §4.5.6** cho cả platform — lọc theo SC, không theo màn.
|
|
28
|
-
2. **Role + accessible name** — cho element có action mà §4.5.6 chưa phủ.
|
|
29
|
-
3. **Dò DOM** — CHỈ khi 1 và 2 đều không định vị được. Dump class/`aria-label`/role, rồi nhìn kết quả:
|
|
30
|
-
- **3a. Element ĐÃ mang test-id trong code** → **DỪNG, đừng tự dùng id nhặt được.** Đây là ca *code đi trước hợp đồng*: chạy `/map-testids {UC-ID}` để đưa id đó vào §4.5.6 (nhánh `existing` — reverse-document), rồi quay lại bậc 1.
|
|
31
|
-
- **3b. Element KHÔNG có test-id nào** (chỉ class/role) → mới dùng class/role: BEM `feature__el`; carousel dot thường `role="tab"` + class `--active` (không `aria-selected`). **VÀ ghi một GAP**: element nào, màn nào, thiếu test-id → đề nghị dev gắn rồi chạy `/map-testids` lại. Đừng im lặng sống với selector giòn.
|
|
32
|
-
|
|
33
|
-
## Phase 2 — Generate
|
|
34
|
-
**PHỦ HẾT 100%**: 1 test cho **MỌI** TC trong file (`grep -cE "^#{2,4} *TC_"` = số test phải sinh), KHÔNG chọn tập đại diện, KHÔNG để TC nào Draft; TC bất khả thi → `pytest.skip`/`xfail` + lý do.
|
|
35
|
-
Bọc mỗi chặng bằng `with step("…")`; dùng chuỗi PO theo điều hướng.
|
|
36
|
-
Phủ TC điều hướng forward/back/giữ-reset state. Data từ `test_data/`. Marker mới (`bva ep e2e`…) đăng ký `pytest.ini`.
|
|
37
|
-
|
|
38
|
-
## Phase 3 — Verify
|
|
39
|
-
`py_compile` + `pytest --collect-only -q` (**số collect = tổng TC**; thiếu → sinh nốt) · chạy · cập nhật Status TC (verify KHÔNG còn Draft) · in mapping.
|
|
40
|
-
**Gom nhóm role/account** tự áp qua `utils/test_ordering.py` (root conftest); fixture auth mới → `register_auth_fixtures([...])`. ⚠️ Run dài bị **WSL suspend** có thể gây flaky login/timeout → re-run TC đó + merge report.
|
|
41
|
-
**Phân loại FAIL — 3 nhãn, luật ở `/qc-run-script` §Chạy lại trước khi kết luận** (chạy lại ×2 trước, rồi người xác nhận; **không chép lại ở đây**). Đặc thù đa màn: sai selector/logic → `script-bug`, sửa & chạy lại; feature chưa wire/defect **đỏ nhất quán** → `product-gap`, giữ FAIL + ghi bằng chứng vào khối "Kết quả thực thi" đầu `.Test.md`, không fake-pass. **State truyền giữa màn là nguồn `flaky` phổ biến** — điều hướng nhanh hơn/chậm hơn một nhịp là đủ đổi kết quả; ghi nghi vấn đó vào phần nguyên nhân.
|
|
42
|
-
|
|
43
|
-
## Output
|
|
44
|
-
Script + nhiều Page Object (mỗi màn) trong `pages/<project>/...`. Bàn giao `qa-reviewer` (script).
|
|
45
|
-
|
|
46
|
-
## Phase 4 — Report (bắt buộc sau khi chạy test)
|
|
47
|
-
Report = **Playwright Trace viewer + pytest-html** (KHÔNG Allure, KHÔNG dashboard tự viết).
|
|
48
|
-
|
|
49
|
-
1. Chạy test kèm pytest-html (trace đã bật sẵn ở conftest → mỗi test có `test-results/<nodeid>/trace.zip`):
|
|
50
|
-
```bash
|
|
51
|
-
pytest tests/<project>/.../test_<feature>.py --html=reports/<feature>/report.html --self-contained-html
|
|
52
|
-
```
|
|
53
|
-
2. Gửi cho người dùng:
|
|
54
|
-
- HTML report: `reports/<feature>/report.html` (self-contained, mở trực tiếp).
|
|
55
|
-
- Trace từng test (debug step-by-step): `python3 -m playwright show-trace test-results/<nodeid>/trace.zip`.
|
|
56
|
-
- Tóm tắt: **TOTAL / PASS / FAIL / SKIP** + duration.
|
|
57
|
-
3. TC Fail → mở trace tương ứng để xem timeline/DOM snapshot/network, phân loại theo **3 nhãn** (`script-bug` · `product-gap` · `flaky`) — luật đầy đủ + bước chạy lại ×2 ở `/qc-run-script` §Chạy lại trước khi kết luận, **không chép lại ở đây**; ghi mô tả lỗi tiếng Việt dễ hiểu vào Status/khối kết quả của `.Test.md`.
|