@educa-corp/sdd-framework 0.9.6 → 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/lint-trace.js +4 -4
- package/bin/qc-base-map.json +13 -11
- package/bin/self-check.js +497 -16
- package/bin/trace-schema.json +3226 -2656
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/amend-prd.md +7 -1
- package/core/commands/debug.md +8 -2
- package/core/commands/define-product.md +38 -1
- package/core/commands/dev-gen-test.md +9 -3
- package/core/commands/dev-run-test.md +8 -2
- package/core/commands/dev-smoke-test.md +7 -1
- package/core/commands/extend-prd.md +7 -1
- package/core/commands/fix-bug.md +11 -5
- package/core/commands/generate-architecture.md +9 -1
- package/core/commands/generate-bdd.md +45 -5
- package/core/commands/generate-code.md +43 -4
- package/core/commands/generate-design-spec.md +7 -1
- package/core/commands/generate-prd.md +9 -1
- package/core/commands/generate-spec-manifest.md +7 -1
- package/core/commands/generate-tech-docs.md +41 -1
- package/core/commands/learn.md +7 -1
- package/core/commands/map-testids.md +11 -5
- package/core/commands/propose-scenario.md +7 -1
- package/core/commands/qc-analyze.md +12 -6
- package/core/commands/qc-automation-assess.md +356 -0
- package/core/commands/qc-design-script.md +430 -0
- package/core/commands/qc-design-test.md +98 -20
- package/core/commands/qc-plan.md +9 -3
- package/core/commands/qc-report.md +92 -77
- package/core/commands/qc-review-script.md +342 -0
- package/core/commands/{qc-review.md → qc-review-testcase.md} +86 -54
- package/core/commands/qc-run-manualtest.md +401 -0
- package/core/commands/qc-run-script.md +421 -0
- package/core/commands/refine-prd.md +7 -1
- package/core/commands/report-bug.md +9 -3
- package/core/commands/review-code.md +9 -3
- package/core/commands/review-context.md +11 -3
- package/core/commands/review-tech-docs.md +11 -3
- package/core/commands/setup-ai-first.md +7 -1
- package/core/commands/validate-traces.md +10 -4
- 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/rules/workflow.md +2 -2
- package/core/skills/qc/_shared/self-review-principles.md +2 -2
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +1 -1
- package/core/skills/qc/qa-analyst/data-flow.md +1 -1
- package/core/skills/qc/qa-analyst/spec-issue-reporter.md +1 -1
- package/core/skills/qc/qa-automation-assess/matrix.md +123 -0
- package/core/skills/qc/qa-designer/e2e/journey.md +1 -1
- package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +1 -1
- package/core/skills/qc/{qa-runner → qa-designer}/exploratory/session.md +8 -2
- package/core/skills/qc/qa-designer/functional/api.md +2 -2
- package/core/skills/qc/qa-designer/functional/gui-feature.md +1 -1
- package/core/skills/qc/qa-designer/functional/gui-screen.md +1 -1
- package/core/skills/qc/qa-designer/functional/job.md +128 -0
- package/core/skills/qc/qa-designer/integration/api.md +2 -2
- package/core/skills/qc/qa-designer/integration/db.md +2 -2
- package/core/skills/qc/qa-designer/integration/gui.md +1 -1
- package/core/skills/qc/qa-designer/integration/{kafka.md → queue.md} +21 -5
- package/core/skills/qc/qa-designer/non-functional.md +1 -1
- package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +17 -0
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +28 -6
- 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 +3 -3
- 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 +29 -10
- package/core/skills/qc/qa-reviewer/test-case/e2e.md +2 -2
- package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/functional.md +2 -2
- package/core/skills/qc/qa-reviewer/test-case/integration.md +2 -2
- package/core/skills/qc/qa-reviewer/test-case/non-functional.md +2 -2
- 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/context-loader.md +1 -1
- package/core/steps/gate.md +7 -1
- package/core/steps/qc-scope.md +45 -2
- package/core/steps/qc-stamp.md +4 -4
- package/core/steps/report-footer.md +10 -9
- package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +1 -1
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +13 -12
- package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +3 -3
- package/docs/02-concepts/traceability.md +1 -1
- package/docs/03-guides/developer.md +1 -1
- package/docs/03-guides/tester-qa.md +40 -11
- package/docs/04-reference/commands.md +4 -2
- package/docs/04-reference/modules.md +2 -1
- package/docs/04-reference/trace-schema.md +4 -4
- package/docs/explain/17-qc-design-test.md +5 -5
- package/docs/explain/18-qc-review.md +42 -20
- package/docs/explain/19-qc-run-test.md +13 -10
- package/docs/explain/20-qc-report.md +3 -3
- package/docs/explain/23-fix-bug.md +2 -2
- package/docs/explain/README.md +2 -2
- package/docs/plans/qc-surgery/01-checklist.md +86 -21
- 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/commands/qc-run-test.md +0 -561
- 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
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
source: upstream/qc-base-new/Automation-Standards.md §4 §6 §7 §8 §9 §10 §11 (Approved)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Web Automation Conventions — TypeScript + Playwright Test
|
|
8
|
+
|
|
9
|
+
Skill **tự chứa**: quy ước bắt buộc khi sinh automation script web bằng `@playwright/test` +
|
|
10
|
+
TypeScript. Mọi file layer trong `qa-script-designer/web/*` đọc file này trước — không lặp
|
|
11
|
+
lại các quy tắc ở đây, chỉ có phần logic sinh-script riêng của layer.
|
|
12
|
+
|
|
13
|
+
## 1. Locator Strategy — thứ tự ưu tiên (bắt buộc)
|
|
14
|
+
|
|
15
|
+
Đây là nguồn lỗi automation phổ biến nhất: locator giòn (fragile) làm script fail không phải
|
|
16
|
+
vì bug sản phẩm mà vì UI đổi CSS/text/thứ tự DOM. Luôn theo đúng thứ tự ưu tiên sau, **dừng ở
|
|
17
|
+
mức đầu tiên khả dụng** — không nhảy xuống mức thấp hơn "cho nhanh":
|
|
18
|
+
|
|
19
|
+
| # | Locator | Khi dùng | Ví dụ |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| 1 | **Test-ID contract** | Luôn ưu tiên nếu tech-doc có `@trace.testid_attr` + bảng §4.5.6 | `page.getByTestId('login-submit-btn')` |
|
|
22
|
+
| 2 | **Role + Accessible Name** | Không có test-id nhưng element có role/aria chuẩn (button/link/textbox/checkbox…) | `page.getByRole('button', { name: 'Đăng nhập' })` |
|
|
23
|
+
| 3 | **Label** (cho form field) | Input có `<label for>` hoặc `aria-label` | `page.getByLabel('Email')` |
|
|
24
|
+
| 4 | **Text** (chỉ cho element tĩnh, không lặp lại nhiều lần trên trang) | Heading, thông báo, tiêu đề duy nhất | `page.getByText('Đăng nhập thành công')` |
|
|
25
|
+
| 5 | **CSS/XPath theo cấu trúc ổn định** (BEM class, không phải class utility sinh tự động) | Bất khả kháng — không có gì ở trên | `page.locator('.login-form__submit')` |
|
|
26
|
+
|
|
27
|
+
**Không bao giờ dùng làm mức đầu tiên** (chỉ là fallback bất đắc dĩ, luôn kèm ghi chú
|
|
28
|
+
`// FIXME: cần test-id, xem IMPROVE-xxx`):
|
|
29
|
+
- Class do bundler/CSS-in-JS sinh tự động (`css-1a2b3c`, `sc-hGRVom`, các hash động) — đổi mỗi
|
|
30
|
+
lần build, **không ổn định giữa các lần deploy**.
|
|
31
|
+
- XPath tuyệt đối/theo vị trí (`/html/body/div[3]/div[2]/button`) — vỡ ngay khi DOM chèn thêm 1
|
|
32
|
+
node.
|
|
33
|
+
- Index không có điều kiện đi kèm (`.first()`, `nth(2)`) khi danh sách có thể thay đổi thứ tự.
|
|
34
|
+
- Text tiếng Việt cho element có thể đổi copy/đa ngôn ngữ.
|
|
35
|
+
|
|
36
|
+
**Locator cho danh sách/bảng động:** dùng `locator().filter({ hasText })` hoặc lọc theo
|
|
37
|
+
test-id của row thay vì đếm index cố định; nếu cần verify thứ tự thật (sort/paging), so sánh
|
|
38
|
+
mảng giá trị thay vì giả định vị trí.
|
|
39
|
+
|
|
40
|
+
### 1.1 Cấu hình test-id attribute (bắt buộc trước khi dùng `getByTestId`)
|
|
41
|
+
|
|
42
|
+
Đọc `@trace.testid_attr` từ header tech-doc gộp:
|
|
43
|
+
|
|
44
|
+
| Đọc được | Làm gì |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `data-testid` (mặc định Playwright) | Dùng thẳng `getByTestId()`. |
|
|
47
|
+
| Khác `data-testid` (vd `data-test`, `data-qa`) | **Bắt buộc** cấu hình trước: `playwright.config.ts` → `use: { testIdAttribute: 'data-test' }`. Bỏ bước này → `getByTestId()` luôn tìm `data-testid` mặc định → **locator trượt 100%**, trông giống bug sản phẩm nhưng thực ra là script-bug. |
|
|
48
|
+
| Không có field | Cảnh báo mềm, fallback Role/Text, và ghi `IMPROVE-xxx` đề nghị dev bổ sung field. |
|
|
49
|
+
|
|
50
|
+
## 2. Page Object Model — 3 lớp (bắt buộc)
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// pages/login.page.ts
|
|
54
|
+
import { type Page, type Locator, expect } from '@playwright/test';
|
|
55
|
+
import { BasePage } from './base.page';
|
|
56
|
+
|
|
57
|
+
export class LoginPage extends BasePage {
|
|
58
|
+
// ── Lớp 1: Locators — chỉ khai báo, KHÔNG hành động ──
|
|
59
|
+
private readonly emailInput: Locator;
|
|
60
|
+
private readonly passwordInput: Locator;
|
|
61
|
+
private readonly submitBtn: Locator;
|
|
62
|
+
|
|
63
|
+
constructor(page: Page) {
|
|
64
|
+
super(page);
|
|
65
|
+
this.emailInput = page.getByTestId('login-email-input');
|
|
66
|
+
this.passwordInput = page.getByTestId('login-password-input');
|
|
67
|
+
this.submitBtn = page.getByTestId('login-submit-btn');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── Lớp 2: Actions — verb_noun(), trả về Page kế tiếp nếu điều hướng ──
|
|
71
|
+
async login(email: string, password: string): Promise<DashboardPage> {
|
|
72
|
+
await this.emailInput.fill(email);
|
|
73
|
+
await this.passwordInput.fill(password);
|
|
74
|
+
await this.submitBtn.click();
|
|
75
|
+
return new DashboardPage(this.page);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Lớp 3: Assertions — expect(), không bare assert ──
|
|
79
|
+
async assertValidationError(message: string): Promise<void> {
|
|
80
|
+
await expect(this.page.getByTestId('login-error')).toHaveText(message);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- Kế thừa `BasePage` gọn (chứa `page`, helper chung như `screenshot()`), **không** framework
|
|
86
|
+
report riêng (Allure…) — reporter là của Playwright Test.
|
|
87
|
+
- Điều hướng giữa màn: action trả về Page Object màn kế tiếp (`return new NextPage(this.page)`)
|
|
88
|
+
— test chuỗi được `const dashboard = await loginPage.login(...)`.
|
|
89
|
+
- Selector khai báo tập trung ở constructor/đầu class — không rải trong action method.
|
|
90
|
+
- Test **không bao giờ** gọi `page.click()`/`page.fill()` trực tiếp — luôn qua method của PO.
|
|
91
|
+
|
|
92
|
+
## 3. Report Readability — `test.step()` (bắt buộc)
|
|
93
|
+
|
|
94
|
+
Playwright Test có `test.step()` built-in — report/trace viewer hiển thị từng step rõ ràng,
|
|
95
|
+
thu gọn được, giúp đọc lại 1 test dài dễ hơn nhiều so với đọc thẳng code:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
test('TC_LOGIN_001 — đăng nhập thành công', async ({ page }) => {
|
|
99
|
+
const loginPage = new LoginPage(page);
|
|
100
|
+
|
|
101
|
+
await test.step('Nhập thông tin đăng nhập hợp lệ', async () => {
|
|
102
|
+
await loginPage.login('user@test.com', 'Password123');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await test.step('Xác nhận vào được Dashboard', async () => {
|
|
106
|
+
await expect(page).toHaveURL(/\/dashboard/);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Bọc **mỗi chặng có ý nghĩa nghiệp vụ** (không phải mỗi dòng code) bằng `test.step()` — đặc
|
|
112
|
+
biệt quan trọng cho test đa bước (feature đa-màn, E2E journey) nơi report cần chỉ đúng bước
|
|
113
|
+
nào fail thay vì chỉ báo cả `test()` fail chung chung.
|
|
114
|
+
|
|
115
|
+
## 4. Wait & Timing (bắt buộc)
|
|
116
|
+
|
|
117
|
+
- **Không bao giờ** `page.waitForTimeout(N)` cố định để "chờ cho chắc" — dùng auto-wait của
|
|
118
|
+
`expect()`/action locator (Playwright tự retry tới khi actionable hoặc timeout).
|
|
119
|
+
- Sau navigation/submit cần chờ mạng ổn định: `page.waitForLoadState('networkidle')` — nhưng
|
|
120
|
+
**không** gọi `waitForTimeout` ngay sau đó (thừa, che giấu race condition thật).
|
|
121
|
+
networkidle không tương thích tốt hoặc app poll liên tục.
|
|
122
|
+
- Verify network call thật: `page.waitForResponse(url => ...)` — không mock trong integration
|
|
123
|
+
test (mock = unit test, không phải test tích hợp).
|
|
124
|
+
|
|
125
|
+
## 5. Assertion (bắt buộc)
|
|
126
|
+
|
|
127
|
+
- Dùng `expect(locator).toHaveText/toBeVisible/toHaveValue(...)` — auto-retry, thông báo lỗi rõ.
|
|
128
|
+
- **Không** `assert someCondition` trần trụi không thông điệp; **không** `assert response` mơ hồ.
|
|
129
|
+
- Mỗi test **assert nội dung thật**, không chỉ assert URL sau điều hướng.
|
|
130
|
+
- Negative case: assert đúng thông báo lỗi cụ thể, không chỉ "có lỗi xuất hiện".
|
|
131
|
+
- **`expect.soft()`** khi cần assert nhiều điều độc lập trong 1 test mà không muốn dừng ngay ở
|
|
132
|
+
assert đầu tiên fail (vd: kiểm tra đồng thời 5 field hiển thị đúng trên 1 form) — Playwright
|
|
133
|
+
gom hết soft-assertion fail rồi báo 1 lần cuối test, đọc report đỡ mất công chạy lại từng cái
|
|
134
|
+
một. **Không lạm dụng**: assertion mang tính điều kiện tiên quyết cho bước sau (vd "đã login
|
|
135
|
+
chưa") vẫn phải dùng `expect()` thường để dừng ngay, tránh test tiếp tục chạy trên state sai.
|
|
136
|
+
|
|
137
|
+
## 6. Test Independence & Data
|
|
138
|
+
|
|
139
|
+
- Không hard-code URL/credential/timeout → `process.env.*` hoặc file `config/env.ts`.
|
|
140
|
+
- Mỗi test độc lập: dữ liệu từ `TEST_DATA_PLAN.md` (factory/fixture), cleanup sau khi tạo.
|
|
141
|
+
- Không global state chia sẻ giữa test; gom test theo (role, account) nếu auth tốn chi phí,
|
|
142
|
+
qua Playwright `test.describe.serial` có chủ đích — không phải mặc định.
|
|
143
|
+
|
|
144
|
+
### 6.1 Auth reuse — `storageState` (bắt buộc khi feature cần login)
|
|
145
|
+
|
|
146
|
+
Login qua UI ở **mỗi** test (điền form, submit, chờ redirect) là nguồn chậm + flaky lớn nhất
|
|
147
|
+
của một suite Playwright — mỗi lần login là một chuỗi network call thật. Best practice chuẩn
|
|
148
|
+
của Playwright: **login một lần trong global setup, lưu lại session, mọi test tái sử dụng**:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// auth.setup.ts — chạy 1 lần trước cả suite (khai trong playwright.config.ts: projects: [{ name: 'setup', testMatch: /auth\.setup\.ts/ }])
|
|
152
|
+
import { test as setup } from '@playwright/test';
|
|
153
|
+
|
|
154
|
+
setup('authenticate as teacher', async ({ page }) => {
|
|
155
|
+
await page.goto('/login');
|
|
156
|
+
await page.getByTestId('login-email-input').fill(process.env.TEACHER_EMAIL!);
|
|
157
|
+
await page.getByTestId('login-password-input').fill(process.env.TEACHER_PASSWORD!);
|
|
158
|
+
await page.getByTestId('login-submit-btn').click();
|
|
159
|
+
await page.waitForURL(/\/dashboard/);
|
|
160
|
+
await page.context().storageState({ path: 'playwright/.auth/teacher.json' });
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// playwright.config.ts (trích) — project phụ thuộc setup, dùng lại storageState
|
|
166
|
+
projects: [
|
|
167
|
+
{ name: 'setup', testMatch: /auth\.setup\.ts/ },
|
|
168
|
+
{ name: 'teacher-tests', use: { storageState: 'playwright/.auth/teacher.json' }, dependencies: ['setup'] },
|
|
169
|
+
],
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- Mỗi role cần 1 file storageState riêng (`teacher.json`, `admin.json`…) — khớp `Account` trong
|
|
173
|
+
`TEST_DATA_PLAN.md`.
|
|
174
|
+
- TC **về chính hành vi login** (validate lỗi sai mật khẩu, khoá tài khoản…) **không** dùng
|
|
175
|
+
storageState — đó là TC test luôn chính flow login qua UI, không phải TC cần login xong mới
|
|
176
|
+
test cái khác.
|
|
177
|
+
- File storageState chứa session thật → thêm vào `.gitignore`, không commit.
|
|
178
|
+
|
|
179
|
+
## 7. Retry & Flaky Quarantine (bắt buộc cấu hình)
|
|
180
|
+
|
|
181
|
+
Test automation **luôn** có một tỷ lệ flaky nền do timing/network/môi trường CI — coi đó là
|
|
182
|
+
bình thường và có quy trình xử lý có hệ thống, thay vì coi mọi lần fail là product-gap hoặc
|
|
183
|
+
mọi lần pass-sau-retry là "không sao":
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// playwright.config.ts (trích)
|
|
187
|
+
export default defineConfig({
|
|
188
|
+
retries: process.env.CI ? 2 : 0, // CI retry tối đa 2 lần; local KHÔNG retry (fail phải hiện ngay để debug)
|
|
189
|
+
reporter: [['html'], ['list']],
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
- **Retry chỉ để hấp thụ nhiễu môi trường CI, không phải để che giấu bug.** Test pass sau
|
|
194
|
+
retry vẫn hiện trong report là "flaky" (Playwright HTML Report tự đánh dấu `flaky` khác với
|
|
195
|
+
`passed`) — **không coi là pass sạch**. Đây là tín hiệu `qc-run-script` phải đọc để đưa vào
|
|
196
|
+
nhóm cần điều tra riêng (xem gate phân loại Fail của `/qc-run-script`), không tự động lờ đi.
|
|
197
|
+
- **Quarantine**: một test flaky lặp lại ≥3 lần chạy gần nhất → tách khỏi suite chính
|
|
198
|
+
(`test.skip` tạm + tag `@flaky`, hoặc project riêng `flaky-tests` không chặn CI), mở
|
|
199
|
+
`IMPROVE-xxx`/ghi chú kỹ thuật để điều tra root cause (thường là thiếu `storageState`, thiếu
|
|
200
|
+
cách ly data, hoặc race condition thật trong sản phẩm) — không để một test flaky nằm mãi
|
|
201
|
+
trong suite chính làm nhiễu tín hiệu của tất cả lần chạy sau.
|
|
202
|
+
|
|
203
|
+
## 8. Naming & Structure
|
|
204
|
+
|
|
205
|
+
Vị trí file + quy tắc slug (`<feature>` từ `TC_<FEATURE>.md`, kiểm tra tồn tại trước khi tạo
|
|
206
|
+
mới khi nhiều UC cùng chạm 1 màn) — xem **`_shared/file-naming-and-folders.md`** (nguồn chuẩn
|
|
207
|
+
duy nhất, không lặp lại bảng path ở đây nữa). Quy ước còn lại riêng cho code:
|
|
208
|
+
|
|
209
|
+
| Gì | Convention |
|
|
210
|
+
|---|---|
|
|
211
|
+
| Test title | `test('TC_xxx — <mô tả ngắn>', async ({ page }) => {...})` — TC_ID **trong title**, không chỉ comment |
|
|
212
|
+
| Tag | Suy **tự động** từ `Priority` của TC gốc — xem §8.1, không tự chọn tuỳ ý |
|
|
213
|
+
| Comment trace | `// @trace.verifies={UC-ID}-SC{N}` ngay trên mỗi `test(...)` |
|
|
214
|
+
|
|
215
|
+
### 8.1 Mapping `Priority` (TC) → tag (script) — bắt buộc, suy tự động
|
|
216
|
+
|
|
217
|
+
`qc-design-script` đọc field `Priority` (`P0`/`P1`/`P2`) đã có sẵn trong `TC_<FEATURE>.md` —
|
|
218
|
+
**không tự đặt tag theo cảm tính**:
|
|
219
|
+
|
|
220
|
+
| Priority (TC) | Tag gắn vào `test()` | Lý do |
|
|
221
|
+
|:---:|---|---|
|
|
222
|
+
| `P0` | `{ tag: ['@smoke', '@regression'] }` | P0 = tính năng lõi/luồng chính — vừa chạy trong smoke suite (nhanh, mỗi build) vừa nằm trong regression đầy đủ |
|
|
223
|
+
| `P1` | `{ tag: ['@regression'] }` | Quan trọng nhưng không phải lõi — không cần chặn mỗi build, chạy ở regression đầy đủ |
|
|
224
|
+
| `P2` | `{ tag: ['@regression'] }` | Biên/phụ — cùng regression, không vào smoke |
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
test('TC_LOGIN_001 — đăng nhập thành công', { tag: ['@smoke', '@regression'] }, async ({ page }) => {
|
|
228
|
+
// ...
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Chạy riêng smoke suite** (xem `/qc-smoke-test`): `npx playwright test --grep @smoke`.
|
|
233
|
+
Review script (`/qc-review`, `qa-reviewer/script/web/*`) đối chiếu đúng mapping này — tag lệch
|
|
234
|
+
Priority (vd P0 nhưng thiếu `@smoke`) là lỗi 🟠 cần sửa, vì nó khiến smoke suite bỏ sót tính
|
|
235
|
+
năng lõi.
|
|
236
|
+
|
|
237
|
+
## 9. Common Pitfalls — lỗi thường gặp cần tránh (checklist self-review)
|
|
238
|
+
|
|
239
|
+
| # | Lỗi | Tại sao sai | Sửa |
|
|
240
|
+
|---|---|---|---|
|
|
241
|
+
| 1 | `await page.waitForTimeout(3000)` để "chờ load" | Chậm, flaky (mạng chậm hơn 3s vẫn fail; nhanh hơn thì lãng phí) | `expect(locator).toBeVisible()` / `waitForLoadState` |
|
|
242
|
+
| 2 | Locator theo class hash (`'.css-1x2y3z'`) | Vỡ mỗi lần build lại CSS-in-JS | Test-id contract, hoặc Role/Label |
|
|
243
|
+
| 3 | `test.skip()` không lý do | Không biết TC bị bỏ vì gì, dễ quên xử lý | `test.skip(true, 'GAP-03 — chưa có API reset state')` |
|
|
244
|
+
| 4 | Assertion chỉ ở bước cuối cùng của journey dài | Bug ở giữa flow bị che bởi state cuối đúng "tình cờ" | Assert sau mỗi bước có side-effect quan trọng |
|
|
245
|
+
| 5 | Test phụ thuộc thứ tự chạy (`test B` cần `test A` chạy trước) | Playwright chạy song song mặc định — sinh flaky ngẫu nhiên | Fixture độc lập cho mỗi test, không biến global |
|
|
246
|
+
| 6 | Hard-code data đã tồn tại sẵn trên môi trường (`userId: 42`) | Vỡ khi seed data đổi, không chạy song song được | Tạo qua API/fixture trong `beforeEach`, cleanup `afterEach` |
|
|
247
|
+
| 7 | Bắt exception rồi bỏ qua (`try { ... } catch {}`) để test "luôn xanh" | Che giấu lỗi thật, fake-pass | Không catch; để test fail đúng bản chất |
|
|
248
|
+
| 8 | Dùng `.first()`/`.nth(N)` không kèm filter | Thứ tự phần tử có thể đổi (server-side sort, feature flag) | `.filter({ hasText })`, hoặc locator theo test-id của item |
|
|
249
|
+
| 9 | Test gọi trực tiếp `page.locator(...)` thay vì qua Page Object | Trùng lặp selector nhiều nơi, khó bảo trì khi UI đổi | Mọi interaction qua method PO |
|
|
250
|
+
| 10 | So sánh screenshot toàn trang cho mọi test (visual regression tràn lan) | Flaky theo font/OS/timing render, chi phí review cao | Chỉ dùng visual assertion cho component cụ thể cần, có mask vùng động |
|
|
251
|
+
|
|
252
|
+
## 10. Compile & Lint (bắt buộc trước khi báo Human approve)
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
npx tsc --noEmit # type-check toàn bộ, không build ra file
|
|
256
|
+
npx playwright test --list # liệt kê test sẽ chạy — đếm phải khớp số TC Automatable=Y
|
|
257
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-17
|
|
4
|
+
source: upstream/qc-base-new/API-Testing-Standards.md §5.5 §9.1 · AGT-010 (Approved)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Sinh script — API xác thực & phân quyền
|
|
8
|
+
|
|
9
|
+
**Đọc `_shared/api-conventions.md` rồi `endpoint.md` trước.** Đây là phần thêm.
|
|
10
|
+
|
|
11
|
+
## Khi nào trigger
|
|
12
|
+
- TC kiểm đăng nhập, vòng đời token, hoặc **quyền truy cập theo vai** lên endpoint.
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Clarify
|
|
15
|
+
Liệt kê **mọi endpoint được bảo vệ** trong phạm vi, và **mọi vai** có trong hợp đồng. Bảng
|
|
16
|
+
vai × endpoint là đầu vào của Phase 2.
|
|
17
|
+
|
|
18
|
+
## Phase 2 — Generate
|
|
19
|
+
|
|
20
|
+
**Fixture token theo vai** *(§5.5)* — `fixtures/api.fixture.ts` cấp một context cho mỗi vai.
|
|
21
|
+
Không đăng nhập lại trong từng test: chậm, và dễ chạm rate-limit.
|
|
22
|
+
|
|
23
|
+
**Mỗi endpoint được bảo vệ sinh đủ ba ca** *(§9.1)*:
|
|
24
|
+
|
|
25
|
+
| Ca | Mong đợi |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Không token | `401` |
|
|
28
|
+
| Token sai / hết hạn | `401` |
|
|
29
|
+
| Token đúng nhưng **sai vai** | `403` |
|
|
30
|
+
|
|
31
|
+
Không gộp `401` với `403` — hai lỗi khác nhau: *chưa biết anh là ai* vs *biết rồi nhưng anh
|
|
32
|
+
không được phép*. Gộp là mất khả năng phân biệt lỗi cấu hình xác thực với lỗi phân quyền.
|
|
33
|
+
|
|
34
|
+
**Assert phải là "bị chặn", không phải "không lỗi":** assert đúng mã, **và** assert body không
|
|
35
|
+
rò dữ liệu của tài nguyên bị cấm.
|
|
36
|
+
|
|
37
|
+
## Phase 3 — Trace tag + cột `Script file`
|
|
38
|
+
Như `endpoint.md` Phase 3 và Phase 4, `@trace.test_type=functional`.
|
|
39
|
+
|
|
40
|
+
## Self-review
|
|
41
|
+
- Mỗi endpoint được bảo vệ có đủ 3 ca?
|
|
42
|
+
- Fixture phân biệt **theo vai**, không dùng một token cho mọi test?
|
|
43
|
+
- Không token thật nào nằm trong code?
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-17
|
|
4
|
+
source: upstream/qc-base-new/API-Testing-Standards.md §4 §5 §6 §8 · AGT-010 (Approved)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Sinh script — API endpoint *(CRUD, mã trạng thái, cấu trúc response)*
|
|
8
|
+
|
|
9
|
+
**Đọc `_shared/api-conventions.md` trước.** File này chỉ có phần sinh-script riêng của tầng
|
|
10
|
+
endpoint. Lane này dùng khi `active_platform = system`.
|
|
11
|
+
|
|
12
|
+
## Khi nào trigger
|
|
13
|
+
- Chuyển TC `Automatable: Y` của một endpoint *(từ `AUTOMATION_ASSESSMENT.md`)* thành spec,
|
|
14
|
+
sau khi `TC_<FEATURE>.Test.md` đã qua `/qc-review-testcase`.
|
|
15
|
+
|
|
16
|
+
## Khi KHÔNG trigger
|
|
17
|
+
- Xác thực / phân quyền → `auth.md` · biên đầu vào & injection → `security.md`
|
|
18
|
+
- API gọi phụ trợ **bên trong** dự án web *(setup/teardown)* → `web/functional/api.md`
|
|
19
|
+
|
|
20
|
+
## Phase 1 — Clarify
|
|
21
|
+
|
|
22
|
+
Đọc `TC_<FEATURE>.Test.md` **chỉ các TC `Automatable: Y`** + `TEST_DATA_PLAN.md`. API Object cho
|
|
23
|
+
resource này đã có chưa → tạo mới nếu chưa. Đọc hợp đồng endpoint từ tech-doc: path · method ·
|
|
24
|
+
payload · mã trạng thái · cấu trúc response.
|
|
25
|
+
|
|
26
|
+
## Phase 2 — Generate
|
|
27
|
+
|
|
28
|
+
**Phủ đúng số TC `Automatable: Y`** — đếm trong `AUTOMATION_ASSESSMENT.md` = số `test(...)` phải
|
|
29
|
+
sinh, **không hơn không kém**. TC `Y` mà gặp rào cản kỹ thuật lúc viết → `test.fixme('TC-API-xxx — {lý do}')`
|
|
30
|
+
+ ghi `IMPROVE-xxx`, **không âm thầm bỏ qua**.
|
|
31
|
+
|
|
32
|
+
Gom bằng `test.describe` theo **resource → method**. Mỗi TC một `test()`, tiêu đề mang `TC-API-ID`.
|
|
33
|
+
|
|
34
|
+
Sinh đủ ba lớp:
|
|
35
|
+
|
|
36
|
+
| Lớp | File |
|
|
37
|
+
|---|---|
|
|
38
|
+
| API Object | `api-automation/api/<resource>.api.ts` — 1 method = 1 endpoint action |
|
|
39
|
+
| Test data | `api-automation/data/<resource>.data.ts` |
|
|
40
|
+
| Spec | `api-automation/tests/{TICKET-ID}/<feature>-<scenario>.spec.ts` |
|
|
41
|
+
|
|
42
|
+
## Phase 3 — Trace tag bắt buộc
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// @trace.verifies={UC-ID}-SC{N}
|
|
46
|
+
// @trace.source=specs/{domain}/{prd-slug}/bdd/system/{UC-ID}-{slug}.feature
|
|
47
|
+
// @trace.test_type=functional
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Phase 4 — Điền cột `Script file`
|
|
51
|
+
|
|
52
|
+
Sau khi sinh, **điền đường dẫn thật** vào cột `Script file` của từng TC `Y` trong
|
|
53
|
+
`AUTOMATION_ASSESSMENT.md`. Đây là chỉ mục ngược duy nhất TC → file code; `/qc-run-script` đọc
|
|
54
|
+
đúng cột này để biết chạy file nào.
|
|
55
|
+
|
|
56
|
+
## Self-review trước khi báo xong
|
|
57
|
+
|
|
58
|
+
- Số `test()` = số TC `Automatable: Y`?
|
|
59
|
+
- Mọi request đi qua API Object, **không** `request.*` thô trong spec?
|
|
60
|
+
- Mọi test assert **mã trạng thái** + ít nhất một assert về nội dung?
|
|
61
|
+
- `npx tsc --noEmit` sạch và `--list` collect đúng số?
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-17
|
|
4
|
+
source: upstream/qc-base-new/API-Testing-Standards.md §8 §9.2 · AGT-010 (Approved)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Sinh script — API biên đầu vào & injection
|
|
8
|
+
|
|
9
|
+
**Đọc `_shared/api-conventions.md` rồi `endpoint.md` trước.** Đây là phần thêm.
|
|
10
|
+
|
|
11
|
+
## Khi nào trigger
|
|
12
|
+
- TC kiểm **biên của đầu vào** hoặc các mẫu injection lên endpoint.
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Clarify
|
|
15
|
+
Với mỗi trường đầu vào, lấy từ hợp đồng: kiểu · bắt buộc/không · giới hạn min–max · tập giá trị
|
|
16
|
+
hợp lệ. Thiếu ràng buộc trong hợp đồng → ghi `IMPROVE-xxx`, **không tự bịa ngưỡng**.
|
|
17
|
+
|
|
18
|
+
## Phase 2 — Generate
|
|
19
|
+
|
|
20
|
+
**Ba kỹ thuật phải thấy được trong code** *(§8)*:
|
|
21
|
+
|
|
22
|
+
| Kỹ thuật | Sinh gì |
|
|
23
|
+
|---|---|
|
|
24
|
+
| **Phân lớp tương đương** | mỗi lớp ít nhất một ca — không chỉ ca hợp lệ |
|
|
25
|
+
| **Giá trị biên** | với trường có giới hạn: `min-1` · `min` · `max` · `max+1` |
|
|
26
|
+
| **Phủ HTTP method** | gọi method không hỗ trợ → mong đợi `405` |
|
|
27
|
+
|
|
28
|
+
**Payload injection** *(§9.2)* — gom vào `data/<resource>.data.ts` thành **một bộ dùng lại**,
|
|
29
|
+
không rải trong spec. Phủ đủ các họ: SQL · NoSQL · command · path traversal · XSS lưu trữ.
|
|
30
|
+
|
|
31
|
+
**Mong đợi phải cụ thể:** `400`/`422` + thông điệp lỗi có cấu trúc, hoặc dữ liệu được làm sạch.
|
|
32
|
+
**Không** assert kiểu *"không sập"* — một endpoint trả `200` kèm dữ liệu đã bị nhiễm vẫn "không sập".
|
|
33
|
+
|
|
34
|
+
Thêm một assert: thông điệp lỗi **không rò** stack trace, tên bảng, hay phiên bản thư viện.
|
|
35
|
+
|
|
36
|
+
## Phase 3 — Trace tag + cột `Script file`
|
|
37
|
+
Như `endpoint.md`, `@trace.test_type=non-functional`.
|
|
38
|
+
|
|
39
|
+
## Ranh giới
|
|
40
|
+
Đây **không** phải kiểm thâm nhập. Sinh script theo TC đã duyệt; **không** tự mở rộng sang dò
|
|
41
|
+
quét lỗ hổng, và **không** kết luận gì về mức an toàn của hệ thống.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gen Script — Mobile E2E Journey (Flutter)
|
|
7
|
+
|
|
8
|
+
**Đọc `_shared/mobile-conventions.md` trước.**
|
|
9
|
+
|
|
10
|
+
## Khi nào trigger
|
|
11
|
+
- Convert TC E2E journey (output `qa-designer/e2e/journey.md`, platform `app`), TC Automatable=Y.
|
|
12
|
+
|
|
13
|
+
## Khi KHÔNG trigger
|
|
14
|
+
- Test 1 màn/field → `functional/*` · 1 điểm tích hợp → `integration.md`
|
|
15
|
+
|
|
16
|
+
## Quy ước riêng
|
|
17
|
+
- Chuỗi Page Object xuyên các màn; verify V1…Vn sau mỗi chặng.
|
|
18
|
+
- Journey dài trên thiết bị thật/emulator chậm hơn web đáng kể — timeout cho mỗi bước chờ nên
|
|
19
|
+
rộng hơn mặc định (cold start, animation transition Flutter).
|
|
20
|
+
- Tiền điều kiện (tài khoản, data) qua fixture riêng (`beforeEach`), reset app state
|
|
21
|
+
(`driver.reset()`) trước mỗi journey — không dựa vào journey trước "dọn" giúp.
|
|
22
|
+
|
|
23
|
+
## Phase 1 — Clarify
|
|
24
|
+
Các màn/PO + hệ thống verify ngoài (nếu có); tài khoản/data cần dựng.
|
|
25
|
+
|
|
26
|
+
## Phase 2 — Generate
|
|
27
|
+
Mỗi journey → 1 test; verify đủ V1…Vn. Journey phụ thuộc gap → `it.skip('...GAP-xx')`.
|
|
28
|
+
|
|
29
|
+
## Phase 3 — Self-Verify
|
|
30
|
+
```bash
|
|
31
|
+
npx tsc --noEmit
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Output
|
|
35
|
+
`mobile-automation/test/specs/{TICKET-ID}/e2e/<feature>-<scenario>.spec.ts` + Page Object tái dùng.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gen Script — Mobile Functional Feature (đa màn hình, Flutter)
|
|
7
|
+
|
|
8
|
+
**Đọc `_shared/mobile-conventions.md` trước.**
|
|
9
|
+
|
|
10
|
+
## Khi nào trigger
|
|
11
|
+
- Convert TC feature đa-màn (output `qa-designer/functional/gui-feature.md`, platform `app`),
|
|
12
|
+
TC Automatable=Y.
|
|
13
|
+
|
|
14
|
+
## Khi KHÔNG trigger
|
|
15
|
+
- Gọn 1 màn → `functional/screen.md` · đầu-cuối xuyên hệ thống ngoài → `e2e.md`
|
|
16
|
+
|
|
17
|
+
## Phase 1 — Clarify
|
|
18
|
+
Liệt kê các màn/Page Object cần; state truyền giữa màn (đặc biệt qua navigation Flutter —
|
|
19
|
+
argument truyền route, không phải chỉ URL như web).
|
|
20
|
+
|
|
21
|
+
## Phase 2 — Generate
|
|
22
|
+
Điều hướng giữa Page Object: test tự import Page Object màn kế tiếp sau action điều hướng
|
|
23
|
+
(singleton pattern WDIO — khác Playwright là PO theo instance `page`). Phủ đúng TC
|
|
24
|
+
Automatable=Y. Assert sau mỗi chặng có side-effect, không dồn về cuối.
|
|
25
|
+
|
|
26
|
+
## Phase 3 — Self-Verify
|
|
27
|
+
```bash
|
|
28
|
+
npx tsc --noEmit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Output
|
|
32
|
+
Script + nhiều Page Object (mỗi màn) trong `mobile-automation/pageobjects/{TICKET-ID}/...`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gen Script — Mobile Functional Screen (1 màn hình, Flutter)
|
|
7
|
+
|
|
8
|
+
**Đọc `_shared/mobile-conventions.md` trước** (Locator Strategy — vì sao cần
|
|
9
|
+
`FlutterIntegration`, Page Object, Wait/Assertion, Common Pitfalls).
|
|
10
|
+
|
|
11
|
+
## Khi nào trigger
|
|
12
|
+
- Convert TC functional 1 màn (output `qa-designer/functional/gui-screen.md`, platform `app`),
|
|
13
|
+
TC Automatable=Y, `TC_<FEATURE>.md` đã approve.
|
|
14
|
+
|
|
15
|
+
## Khi KHÔNG trigger
|
|
16
|
+
- Feature đa-màn → `functional/feature.md` · web → dùng bộ `qa-script-designer/web/*`
|
|
17
|
+
|
|
18
|
+
## Phase 1 — Clarify
|
|
19
|
+
Đọc `TC_<FEATURE>.md` + `TEST_DATA_PLAN.md`. Page Object cho màn này đã có chưa. Đọc contract
|
|
20
|
+
`ValueKey` §4.5.6 tech-doc gộp cho màn này (xem `_shared/mobile-conventions.md` §1.1).
|
|
21
|
+
**§4.5.6 không đủ/không có** → probe widget tree thật bằng Appium Inspector/Flutter DevTools
|
|
22
|
+
trước khi viết locator (xem `_shared/mobile-conventions.md` §1.2) — không đoán `ValueKey` từ
|
|
23
|
+
ảnh chụp màn hình.
|
|
24
|
+
|
|
25
|
+
## Phase 2 — Generate
|
|
26
|
+
Phủ đúng TC Automatable=Y của màn này (đếm khớp `AUTOMATION_ASSESSMENT.md`). Rào cản kỹ
|
|
27
|
+
thuật (thiếu `ValueKey`, permission dialog chặn) → viết test tốt nhất có thể + đánh dấu
|
|
28
|
+
`it.skip` có lý do + ghi `IMPROVE-xxx`, không bỏ sót TC.
|
|
29
|
+
|
|
30
|
+
Nhóm `describe`: GUI (hiển thị/enable-disable) → Functional (input/validation/action). Data từ
|
|
31
|
+
`TEST_DATA_PLAN.md`.
|
|
32
|
+
|
|
33
|
+
## Phase 3 — Self-Verify
|
|
34
|
+
```bash
|
|
35
|
+
npx tsc --noEmit
|
|
36
|
+
```
|
|
37
|
+
Đối chiếu thủ công số `it(...)` sinh ra = số TC Automatable=Y của màn này.
|
|
38
|
+
|
|
39
|
+
## Output
|
|
40
|
+
`mobile-automation/test/specs/{TICKET-ID}/<screen-slug>.spec.ts` +
|
|
41
|
+
`mobile-automation/pageobjects/{TICKET-ID}/<screen-slug>.page.ts`
|
|
42
|
+
(xem quy tắc slug/kiểm tra tồn tại trước khi tạo ở `_shared/file-naming-and-folders.md`).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gen Script — Mobile Integration (App↔Backend)
|
|
7
|
+
|
|
8
|
+
**Đọc `_shared/mobile-conventions.md` trước.** Phần backend (DB/Kafka/API thuần) dùng lại
|
|
9
|
+
đúng client/fixture của `qa-script-designer/web/integration.md` — chỉ khác **phía trigger**
|
|
10
|
+
là thao tác trên app qua WebdriverIO thay vì Playwright.
|
|
11
|
+
|
|
12
|
+
## Khi nào trigger
|
|
13
|
+
- TC integration app↔backend (output `qa-designer/integration/gui.md` cho platform `app`),
|
|
14
|
+
TC Automatable=Y.
|
|
15
|
+
|
|
16
|
+
## Quy ước riêng — không mock
|
|
17
|
+
Giống nguyên tắc web: gọi API/DB thật trên môi trường test, không mock response. Khác biệt
|
|
18
|
+
mobile: capture network request từ app khó hơn web (không có `page.waitForResponse()`) —
|
|
19
|
+
dùng 1 trong 2 cách:
|
|
20
|
+
- **Proxy chặn network của thiết bị/emulator** (mitmproxy hoặc tương đương) để verify request
|
|
21
|
+
thật gửi đi — cần setup riêng trong `wdio.conf.ts`.
|
|
22
|
+
- **Verify gián tiếp qua backend**: sau action trên app, query API/DB để xác nhận state đã
|
|
23
|
+
đổi đúng — đơn giản hơn, đủ dùng cho phần lớn TC integration.
|
|
24
|
+
|
|
25
|
+
## Phase 1 — Clarify
|
|
26
|
+
Chuỗi tích hợp & chặng cần verify; client/fixture backend đã có chưa (tái dùng từ web nếu đã
|
|
27
|
+
tồn tại trong cùng project).
|
|
28
|
+
|
|
29
|
+
## Phase 2 — Generate
|
|
30
|
+
Mỗi TC → 1 test: action trên app → verify chặng backend (API/DB). Nhóm happy → contract-negative
|
|
31
|
+
→ concurrency (nếu áp dụng).
|
|
32
|
+
|
|
33
|
+
## Phase 3 — Self-Verify
|
|
34
|
+
```bash
|
|
35
|
+
npx tsc --noEmit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Output
|
|
39
|
+
Script trong `mobile-automation/test/specs/{TICKET-ID}/integration/` + client/fixture backend tái dùng.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gen Script — Mobile Non-Functional (Performance/Security/Compatibility)
|
|
7
|
+
|
|
8
|
+
**Đọc `_shared/mobile-conventions.md` trước.**
|
|
9
|
+
|
|
10
|
+
## Công cụ theo loại
|
|
11
|
+
|
|
12
|
+
| Loại | Công cụ | Assert |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| **Performance** | Thời gian cold start (`driver.startActivity`/launch time), thời gian render màn hình đo qua timestamp trước/sau `waitForDisplayed` | Ngưỡng cụ thể (vd cold start < 3s) |
|
|
15
|
+
| **Security** | Test lưu trữ local không mã hoá (kiểm tra file app data qua ADB/`driver.execute('mobile: shell', ...)`), test deep-link injection | Assert dữ liệu nhạy cảm không tồn tại dạng plaintext |
|
|
16
|
+
| **Compatibility** | `capabilities` parametrize theo OS version/device profile trong `wdio.conf.ts`; dùng Device Farm (BrowserStack/Sauce Labs/Firebase Test Lab, xem `_shared/mobile-conventions.md` §5.2) khi cần phủ device thật ngoài máy sẵn có | Mỗi profile = 1 target trong TC |
|
|
17
|
+
|
|
18
|
+
Mobile **không có** hạng mục accessibility qua axe-core (đó là công cụ web); nếu TC yêu cầu
|
|
19
|
+
accessibility mobile, dùng công cụ nền tảng riêng (Android Accessibility Scanner API/iOS
|
|
20
|
+
Accessibility Inspector) — thường vẫn cần một phần thao tác thủ công, đánh dấu rõ trong TC
|
|
21
|
+
gốc thay vì cố automate 100%.
|
|
22
|
+
|
|
23
|
+
## Quy ước riêng
|
|
24
|
+
- Ngưỡng cụ thể khớp TC gốc; đo elapsed không gồm thời gian setup fixture/app install.
|
|
25
|
+
- Test cần thiết bị/profile đặc biệt → `it.skip(!deviceReady, 'lý do')`.
|
|
26
|
+
|
|
27
|
+
## Phase 1 — Clarify
|
|
28
|
+
Loại + ngưỡng + công cụ; profile thiết bị cần test.
|
|
29
|
+
|
|
30
|
+
## Phase 2 — Generate
|
|
31
|
+
Mỗi TC → 1 test đo + assert ngưỡng.
|
|
32
|
+
|
|
33
|
+
## Phase 3 — Self-Verify
|
|
34
|
+
```bash
|
|
35
|
+
npx tsc --noEmit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Output
|
|
39
|
+
`mobile-automation/test/specs/{TICKET-ID}/non-functional/<feature>-<scenario>.spec.ts` + helper đo (`utils/measure.ts`).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-09-09
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gen Script — Web E2E Journey
|
|
7
|
+
|
|
8
|
+
**Đọc `_shared/web-conventions.md` trước.**
|
|
9
|
+
|
|
10
|
+
## Khi nào trigger
|
|
11
|
+
- Convert TC E2E journey (output `qa-designer/e2e/journey.md`), TC Automatable=Y.
|
|
12
|
+
|
|
13
|
+
## Khi KHÔNG trigger
|
|
14
|
+
- Test 1 màn/field → `functional/*` · 1 điểm tích hợp → `integration.md`
|
|
15
|
+
|
|
16
|
+
## Quy ước riêng
|
|
17
|
+
- Chuỗi Page Object xuyên các màn; verify points (V1…Vn của journey) thành `expect()` rõ ràng
|
|
18
|
+
**sau mỗi chặng**, không dồn hết về cuối (Common Pitfall #4).
|
|
19
|
+
- Tiền điều kiện phức tạp (tài khoản role, dữ liệu buổi/lớp) qua fixture Playwright riêng,
|
|
20
|
+
không inline trong test; cleanup sau journey.
|
|
21
|
+
- Cần verify hệ thống ngoài (DB/CRM) → client/fixture riêng, giống `integration.md`.
|
|
22
|
+
|
|
23
|
+
## Phase 1 — Clarify
|
|
24
|
+
Các màn/PO + hệ thống verify; tài khoản/data cần dựng; điểm cleanup.
|
|
25
|
+
|
|
26
|
+
## Phase 2 — Generate
|
|
27
|
+
Mỗi journey → 1 test; verify đủ V1…Vn. Journey phụ thuộc gap → `test.fixme('...GAP-xx')`.
|
|
28
|
+
|
|
29
|
+
## Phase 3 — Self-Verify
|
|
30
|
+
```bash
|
|
31
|
+
npx tsc --noEmit
|
|
32
|
+
npx playwright test automation/tests/{TICKET-ID}/e2e/<feature>-<scenario>.spec.ts --list
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Output
|
|
36
|
+
`automation/tests/{TICKET-ID}/e2e/<feature>-<scenario>.spec.ts` + Page Object/client tái dùng.
|