@relipa/ai-flow-kit 0.1.2 → 0.1.4-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -0
- package/bin/aiflow.js +89 -2
- package/custom/harness/playwright/.env.example +10 -0
- package/custom/harness/playwright/playwright.config.ts +34 -0
- package/custom/harness/playwright/tests/e2e/auth.setup.ts +25 -0
- package/custom/harness/playwright/tests/e2e/fixtures/test.ts +6 -0
- package/custom/harness/playwright/tests/e2e/pages/BasePage.ts +9 -0
- package/custom/harness/playwright/tests/e2e/support/auth.ts +5 -0
- package/custom/mcp-presets/playwright.json +8 -0
- package/custom/rules/test-patterns.md +70 -0
- package/custom/skills/automation-testing/SKILL.md +239 -0
- package/custom/skills/automation-testing/templates/BasePage.ts +29 -0
- package/custom/skills/automation-testing/templates/PageObject.example.ts +29 -0
- package/custom/skills/automation-testing/templates/playwright.config.ts +39 -0
- package/custom/skills/automation-testing/templates/spec.example.ts +29 -0
- package/custom/skills/ba-skills/skill-ba-phan-tich-ban-dau-v1.md +44 -0
- package/custom/skills/ba-skills/skill-ba-prototype-v1.md +35 -0
- package/custom/skills/ba-skills/skill-ba-qa-template-v1.md +21 -0
- package/custom/skills/ba-skills/skill-ba-qa-v1.md +35 -0
- package/custom/skills/ba-skills/skill-ba-template-phan-tich-ban-dau-v1.md +30 -0
- package/custom/skills/ba-skills/skill-ba-template-uc-v1.md +83 -0
- package/custom/skills/ba-skills/skill-ba-ve-luong-mermaid-v1.md +35 -0
- package/custom/skills/ba-skills/skill-ba-viet-spec-uc-v1.md +38 -0
- package/custom/skills/ba-skills/skill-ba-xay-dung-business-rules-v1.md +39 -0
- package/custom/skills/coverage-check/SKILL.md +202 -0
- package/custom/skills/evidence-aggregation/SKILL.md +246 -0
- package/custom/skills/execute-flow/SKILL.md +499 -0
- package/custom/skills/execute-flow/templates/playwright.config.ts +39 -0
- package/custom/skills/gate-review/SKILL.md +195 -0
- package/custom/skills/generate-test-report/SKILL.md +99 -0
- package/custom/skills/generate-test-report/templates/test-report.md +58 -0
- package/custom/skills/generate-testcase/SKILL.md +350 -0
- package/custom/skills/generate-testcase/templates/testcase.md +88 -0
- package/custom/skills/log-bug/SKILL.md +131 -0
- package/custom/skills/pr-impact-analysis/SKILL.md +180 -0
- package/custom/skills/retest-orchestration/SKILL.md +191 -0
- package/custom/skills/script-sync/SKILL.md +208 -0
- package/custom/skills/test-analysis/SKILL.md +300 -0
- package/custom/skills/test-skills/categories/00-core/00.01.requirement-analysis.md +111 -0
- package/custom/skills/test-skills/categories/00-core/00.02.risk-analysis.md +24 -0
- package/custom/skills/test-skills/categories/00-core/00.03.test-scenario-builder.md +90 -0
- package/custom/skills/test-skills/categories/00-core/00.04.testcase-review.md +68 -0
- package/custom/skills/test-skills/categories/01-test-design/01.01.boundary-value-analysis.md +30 -0
- package/custom/skills/test-skills/categories/01-test-design/01.02.equivalence.partitioning.md +27 -0
- package/custom/skills/test-skills/categories/01-test-design/01.03.decision-table.md +26 -0
- package/custom/skills/test-skills/categories/01-test-design/01.04.state.transition.md +26 -0
- package/custom/skills/test-skills/categories/01-test-design/01.05.pairwise.md +25 -0
- package/custom/skills/test-skills/categories/01-test-design/01.06.error-guessing.md +28 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.01.UI-layout.md +29 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.02.form-validation.md +57 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.03.navigation.md +27 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.04.localization.md +27 -0
- package/custom/skills/test-skills/categories/02-ui-testing/02.05.accessibility.md +27 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.01.CRUD-testing.md +51 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.02.workflow-testing.md +44 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.03.permission-testing.md +41 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.04.dependency-validation.md +40 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.05.notification-testing.md +43 -0
- package/custom/skills/test-skills/categories/03-business-testing/03.06.calculation.testing.md +44 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.01.database-testing.md +43 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.02.import-export-testing.md +43 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.03.data-mapping.md +39 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.04.duplicate-handling.md +39 -0
- package/custom/skills/test-skills/categories/04-data-testing/04.05.migration.md +42 -0
- package/custom/skills/test-skills/categories/05-integration/05.01.API-testing.md +37 -0
- package/custom/skills/test-skills/categories/05-integration/05.02.third-party-integration.md +36 -0
- package/custom/skills/test-skills/categories/05-integration/05.03.batch-processing.md +38 -0
- package/custom/skills/test-skills/categories/05-integration/05.04.file-upload-download.md +40 -0
- package/custom/skills/test-skills/categories/08-domain-skills/CMS.md +34 -0
- package/custom/skills/test-skills/categories/08-domain-skills/Ecommerce.md +35 -0
- package/custom/skills/test-skills/categories/99-review/99.01.coverage-review.md +35 -0
- package/custom/skills/test-skills/categories/99-review/99.02.knowledge-learning.md +34 -0
- package/custom/skills/test-skills/categories/99-review/99.03.repository-update.md +33 -0
- package/custom/skills/test-skills/categories/99-review/99.04.change-history.md +38 -0
- package/custom/skills/test-skills/rules/Directory_and_Naming_Convention.md +257 -0
- package/custom/skills/test-skills/rules/QA_Writing_Standards.md +49 -0
- package/custom/skills/test-skills/template/template_testcase.md +92 -0
- package/custom/templates/shared/create-spec-workflow.md +441 -0
- package/custom/templates/shared/create-testcase-workflow.md +470 -0
- package/custom/templates/shared/gate-workflow.md +421 -11
- package/docs/common/CHANGELOG.md +52 -0
- package/docs/common/QUICK_START.md +30 -0
- package/docs/common/cli-reference.md +48 -7
- package/package.json +2 -2
- package/scripts/create-score-excel.js +37 -14
- package/scripts/detect.js +10 -0
- package/scripts/guide.js +9 -0
- package/scripts/init.js +48 -1
- package/scripts/prompt.js +36 -0
- package/scripts/review.js +91 -0
- package/scripts/scaffold-playwright.js +106 -0
- package/scripts/task.js +21 -7
- package/scripts/update.js +127 -124
- package/scripts/use.js +36 -12
package/README.md
CHANGED
|
@@ -70,6 +70,82 @@ PM writes ticket on Backlog/Jira
|
|
|
70
70
|
|
|
71
71
|
---
|
|
72
72
|
|
|
73
|
+
## Execute Test Flow
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
aiflow execute PROJ-44 (or ./testcases.md or aiflow execute)
|
|
77
|
+
│
|
|
78
|
+
▼
|
|
79
|
+
⛩️ GATE 1 — Pre-flight & Work Plan [AI + QA]
|
|
80
|
+
Parse TC file → verify ak-test/{repo}/ exists
|
|
81
|
+
Check BASE_URL env var + playwright.config.ts
|
|
82
|
+
Create execution work plan
|
|
83
|
+
│ Ready
|
|
84
|
+
▼
|
|
85
|
+
⛩️ GATE 2 — Script Sync [AI]
|
|
86
|
+
Hash-based TC↔script sync
|
|
87
|
+
Generate new / update changed / skip unchanged
|
|
88
|
+
Uses Playwright MCP for selectors — never fabricates
|
|
89
|
+
│ Scripts synced
|
|
90
|
+
▼
|
|
91
|
+
⛩️ GATE 3 — Execute & Evidence [AI]
|
|
92
|
+
Run: npx playwright test
|
|
93
|
+
Organize evidence per run-{N}/: screenshots, trace.zip, result.md
|
|
94
|
+
Auto-draft bug files for failed TCs
|
|
95
|
+
Support RETEST: [TC_ID] loop
|
|
96
|
+
│ Tests done
|
|
97
|
+
▼
|
|
98
|
+
⛩️ GATE 4 — Report & Bug Logging [AI + QA]
|
|
99
|
+
Generate testreport.md with Go/No-Go recommendation
|
|
100
|
+
Log each failed TC to Jira/Backlog — interactive confirm per bug
|
|
101
|
+
│
|
|
102
|
+
▼
|
|
103
|
+
DONE
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Execute Test Flow
|
|
109
|
+
|
|
110
|
+
Flow độc lập cho QA — không cần chạy lại phân tích (Gates 1–2 của Development Flow).
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
QA nhận TC file (từ ticket hoặc file)
|
|
114
|
+
│
|
|
115
|
+
▼
|
|
116
|
+
⛩️ GATE 1 — Context & Work Plan [AI + QA]
|
|
117
|
+
aiflow execute PROJ-44 → claude
|
|
118
|
+
AI kiểm tra: MCP Playwright, ak-test/, BASE_URL, playwright.config.ts
|
|
119
|
+
AI parse TC file → extract TCs, phân loại Auto / Manual
|
|
120
|
+
AI xuất work plan + danh sách TCs cần thực thi
|
|
121
|
+
│ Work Plan ready
|
|
122
|
+
▼
|
|
123
|
+
⛩️ GATE 2 — Script Sync [AI]
|
|
124
|
+
Hash-based TC ↔ script sync
|
|
125
|
+
Gen mới TC chưa có script (Playwright MCP → selector DOM thật)
|
|
126
|
+
Cập nhật script đã thay đổi, bỏ qua script không đổi
|
|
127
|
+
Không fabricate selector — luôn lấy từ DOM thật
|
|
128
|
+
│ Scripts synced
|
|
129
|
+
▼
|
|
130
|
+
⛩️ GATE 3 — Execute & Evidence [AI]
|
|
131
|
+
Chạy Playwright, tổ chức evidence theo run-{N}/
|
|
132
|
+
Cập nhật cột R1/R2 trong TC file
|
|
133
|
+
Tổng hợp kết quả pass/fail per TC
|
|
134
|
+
│ Tests done
|
|
135
|
+
▼
|
|
136
|
+
⛩️ GATE 4 — Report & Bug Logging [AI + QA]
|
|
137
|
+
AI tạo: testreport.md
|
|
138
|
+
AI hỏi từng bug → QA xác nhận log lên Jira/Backlog
|
|
139
|
+
QA review → DONE
|
|
140
|
+
│
|
|
141
|
+
▼
|
|
142
|
+
DONE
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
> **Entry points:** `aiflow execute PROJ-44` (từ ticket) · `aiflow execute ./testcases/AD10.md` (từ file) · `aiflow execute` (manual — AI hỏi TC file path)
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
73
149
|
## Installation
|
|
74
150
|
|
|
75
151
|
```bash
|
|
@@ -91,6 +167,7 @@ npm uninstall -g @relipa/ai-flow-kit
|
|
|
91
167
|
|---------|-------------|
|
|
92
168
|
| `aiflow init` | Setup framework, adapters, and multi-AI rules. |
|
|
93
169
|
| `aiflow use <ticket...>` | Load context from one or more tickets/files. First target is primary; rest become supplementary. |
|
|
170
|
+
| `aiflow execute <target>` | **QA:** Execute test cases — load TC file, sync Playwright scripts, run and collect evidence. |
|
|
94
171
|
| `aiflow fetch-links <url>` | Fetch a Backlog/Jira link and print SupplementaryContext JSON (used by AI at runtime). |
|
|
95
172
|
| `aiflow task` | Manage multiple tasks — pause, switch, resume. |
|
|
96
173
|
| `aiflow task next` | Finalize gate approval and prepare for fresh session. |
|
|
@@ -141,6 +218,31 @@ aiflow init --framework spring-boot,reactjs --adapter backlog,jira
|
|
|
141
218
|
|
|
142
219
|
---
|
|
143
220
|
|
|
221
|
+
### `aiflow execute <target>`
|
|
222
|
+
|
|
223
|
+
Execute test cases from a Backlog/Jira ticket, a TC file, or manually. The AI syncs Playwright scripts, runs them, collects evidence, and generates a test report.
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# From a ticket (taskType must be "execute")
|
|
227
|
+
aiflow execute PROJ-44
|
|
228
|
+
|
|
229
|
+
# From a TC file directly
|
|
230
|
+
aiflow execute ./testcases/AD10.md
|
|
231
|
+
|
|
232
|
+
# Manual — AI asks for TC file path
|
|
233
|
+
aiflow execute
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**What happens (4-gate Execute Flow):**
|
|
237
|
+
1. **Gate 1 — Pre-flight:** Parse TC file, verify `ak-test/{repo}/` exists, check `BASE_URL` and `playwright.config.ts`
|
|
238
|
+
2. **Gate 2 — Script Sync:** Hash-based TC↔script sync — gen new, update changed, skip unchanged (never fabricates selectors — uses Playwright MCP)
|
|
239
|
+
3. **Gate 3 — Execute & Evidence:** Run Playwright, organize evidence per `run-{N}/`, update TC file R1/R2 columns
|
|
240
|
+
4. **Gate 4 — Report & Bug Logging:** Generate `testreport.md`, ask per-bug Jira confirmation
|
|
241
|
+
|
|
242
|
+
> **Multi-AI:** Works with Claude, Gemini, Cursor, Copilot — the execute-flow skill is loaded via `ak init`/`ak up`.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
144
246
|
### `aiflow sync-skills`
|
|
145
247
|
|
|
146
248
|
Synchronize AI instruction files (`CLAUDE.md`, `GEMINI.md`, etc.) and Skills without upgrading the package version.
|
|
@@ -428,6 +530,43 @@ Then run `aiflow update` or `aiflow sync-skills` to apply.
|
|
|
428
530
|
|
|
429
531
|
> Summary of major changes per version. See full details in [CHANGELOG.md](docs/common/CHANGELOG.md).
|
|
430
532
|
|
|
533
|
+
### v0.1.3 — 2026-06-18
|
|
534
|
+
- **Execute Test Flow (4-Gate):** New `aiflow execute` command + `execute-flow` skill — Pre-flight → Script Sync → Execute & Evidence → Report & Bug Logging.
|
|
535
|
+
- **`script-sync` skill:** Hash-based TC↔Playwright script sync — gen new, update changed, skip unchanged. Uses MCP browser tools for selectors, never fabricates.
|
|
536
|
+
- **`ak execute` command** (`ak ex` alias): Standalone QA entry point — accepts ticket ID, TC file path, or interactive mode.
|
|
537
|
+
- **▶️ Execute Test** added to `ak use` type selector; `taskType: "execute"` routes AI to execute-flow skill automatically.
|
|
538
|
+
- **Playwright harness scaffold** (`ak scaffold playwright`): Creates full `ak-test/{repo}/` structure with config, fixtures, and page objects.
|
|
539
|
+
- Fixes: `screenId` casing ambiguity, `--reporter` flag overriding config reporters, Gate 1 missing `playwright.config.ts` check.
|
|
540
|
+
|
|
541
|
+
### v0.1.2 — 2026-06-13
|
|
542
|
+
- **Testing Workflow (4-Gate):** New `taskType: "testing"` — Test Analysis → Test Planning → Test Execution → Test Report. AI auto-routes skill per gate.
|
|
543
|
+
- **`python-ml` framework:** Supports scikit-learn / PyTorch / TensorFlow / MLflow / Wandb. Auto-detected from `requirements.txt` / `pyproject.toml`.
|
|
544
|
+
- **Task type selector in `ak use`:** Interactive list after loading ticket — auto-detects and pre-selects task type.
|
|
545
|
+
- **Critical fix — `update`/`init` not updating CLAUDE.md/GEMINI.md:** Fixed 3 compounding causes (`framework` singular vs. plural, missing `force: true`, per-file confirm dialogs).
|
|
546
|
+
- **Backup before overwrite:** AI instruction files backed up to `.aiflow/bk/YYYY-MM-DD_HH-MM_<filename>` before any overwrite.
|
|
547
|
+
- **`aiflow update` no longer wipes `.claude/`:** Now clears only `.claude/skills/`, preserving `settings.json` and hooks.
|
|
548
|
+
|
|
549
|
+
### v0.1.1 — 2026-06-08
|
|
550
|
+
- **Ubuntu/Linux clipboard in `ak prompt`:** Auto-detects display server (Wayland/X11) and package manager — offers to install clipboard tool if missing.
|
|
551
|
+
- **`figma-to-component` image detection & export:** Scans node tree for image nodes, exports to `public/assets/figma/`, renders with `<Image>`/`<img>`.
|
|
552
|
+
- **`figma-to-component` MCP pre-check (Step 0):** Verifies MCP connected before running; stops with setup instructions if not.
|
|
553
|
+
- **`figma-to-component` CSS tooling detection:** Branches on Tailwind / CSS Modules / styled-components / vanilla CSS; maps Figma Styles/Variables to existing tokens.
|
|
554
|
+
- **Critical fix — `figma-to-component` source/installed divergence:** Synced both copies to canonical version with correct tool names and 4-tier framework detection.
|
|
555
|
+
|
|
556
|
+
### v0.1.3 — 2026-06-22
|
|
557
|
+
|
|
558
|
+
**QA Automation Suite — End-to-end test execution với Playwright MCP**
|
|
559
|
+
|
|
560
|
+
- New `aiflow execute` command with full 4-gate Execute Flow (pre-flight → script sync → run → report).
|
|
561
|
+
- New skill suite for QA: `execute-flow`, `automation-testing`, `script-sync`, `generate-testcase`, `generate-test-report`, `log-bug`, `test-analysis`, `evidence-aggregation`, `retest-orchestration`, `coverage-check`.
|
|
562
|
+
- Playwright harness template (`custom/harness/playwright/`) — pre-wired `playwright.config.ts`, `BasePage`, fixtures, và auth setup.
|
|
563
|
+
- New `aiflow scaffold` command (`ak sc`) — tự động tạo cấu trúc `ak-test/{repo}/` từ template.
|
|
564
|
+
- Hash-based TC↔script sync: chỉ gen/update script khi TC thay đổi, bỏ qua TC không đổi — không mất thời gian re-gen.
|
|
565
|
+
- Selector lấy từ DOM thật qua Playwright MCP — không fabricate, không đoán.
|
|
566
|
+
- ML framework support: `python-ml` template + 7 ML skills (`frame-ml-problem`, `explore-data`, `design-experiment`, `train-model`, `evaluate-model`, `improve-algorithm`, `deploy-model`).
|
|
567
|
+
- New `pr-impact-analysis` skill — phân tích breaking changes của PR trước khi merge.
|
|
568
|
+
- Deprecated `aiflow` CLI alias — dùng `ak` thay thế (warning hiện khi dùng `aiflow`).
|
|
569
|
+
|
|
431
570
|
### v0.1.0 — 2026-05-28
|
|
432
571
|
- Multi-target `ak use` — load multiple tickets/files in a single call (primary + supplementary).
|
|
433
572
|
- Auto link resolution — auto-fetch Backlog/Jira URLs found in the ticket description (capped at 5 links).
|
package/bin/aiflow.js
CHANGED
|
@@ -19,6 +19,7 @@ const taskCommand = require('../scripts/task');
|
|
|
19
19
|
const checkpointCommand = require('../scripts/checkpoint');
|
|
20
20
|
const { record } = require('../scripts/telemetry/record');
|
|
21
21
|
const { updateTaskGateState } = require('../scripts/task');
|
|
22
|
+
const scaffoldPlaywrightCommand = require('../scripts/scaffold-playwright');
|
|
22
23
|
const semver = require('semver');
|
|
23
24
|
const { execSync: execSyncChild, spawnSync } = require('child_process');
|
|
24
25
|
|
|
@@ -63,7 +64,8 @@ program
|
|
|
63
64
|
'up': 'update',
|
|
64
65
|
'sync': 'sync-skills',
|
|
65
66
|
'dr': 'doctor',
|
|
66
|
-
'tel': 'telemetry'
|
|
67
|
+
'tel': 'telemetry',
|
|
68
|
+
'sc': 'scaffold'
|
|
67
69
|
};
|
|
68
70
|
if (aliases[first]) {
|
|
69
71
|
first = aliases[first];
|
|
@@ -501,6 +503,53 @@ program
|
|
|
501
503
|
}
|
|
502
504
|
});
|
|
503
505
|
|
|
506
|
+
// ── review ────────────────────────────────────────────────────
|
|
507
|
+
const reviewCmd = program.command('review').description('Gate review file operations');
|
|
508
|
+
|
|
509
|
+
reviewCmd
|
|
510
|
+
.command('check')
|
|
511
|
+
.description('Check review file state — called by AI before accepting APPROVED')
|
|
512
|
+
.requiredOption('-g, --gate <n>', 'gate number (string — supports sub-phases like 2a, 2b)')
|
|
513
|
+
.requiredOption('-t, --ticket <id>', 'ticket ID')
|
|
514
|
+
.action(async (opts) => {
|
|
515
|
+
const { checkReviewFile } = require('../scripts/review');
|
|
516
|
+
const result = await checkReviewFile(opts.gate, opts.ticket);
|
|
517
|
+
|
|
518
|
+
if (!result.exists) {
|
|
519
|
+
console.log(chalk.red(`\n ✗ Review file not found for gate ${opts.gate}, ticket ${opts.ticket}`));
|
|
520
|
+
console.log(chalk.gray(` Expected: .aiflow/review/gate-${opts.gate}-${opts.ticket}.md`));
|
|
521
|
+
console.log(chalk.yellow(' → Re-generate the review file before accepting APPROVED.\n'));
|
|
522
|
+
process.exit(1);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (result.passed) {
|
|
526
|
+
console.log(chalk.green(`\n ✅ All ${result.total} items checked — gate can proceed\n`));
|
|
527
|
+
process.exit(0);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const pendingCount = result.unchecked.length + result.commented.length;
|
|
531
|
+
console.log(chalk.red(`\n ❌ Review incomplete — ${pendingCount} item(s) pending:\n`));
|
|
532
|
+
|
|
533
|
+
if (result.commented.length > 0) {
|
|
534
|
+
console.log(chalk.yellow(' Items with comments (need AI revision):'));
|
|
535
|
+
result.commented.forEach(({ item, comment }) => {
|
|
536
|
+
console.log(chalk.yellow(` • ${item}`));
|
|
537
|
+
console.log(chalk.gray(` Comment: "${comment}"`));
|
|
538
|
+
});
|
|
539
|
+
if (result.unchecked.length > 0) console.log('');
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (result.unchecked.length > 0) {
|
|
543
|
+
console.log(chalk.red(' Items unchecked (no comment — please check or add a comment):'));
|
|
544
|
+
result.unchecked.forEach(item => {
|
|
545
|
+
console.log(chalk.red(` • ${item}`));
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
console.log(chalk.gray('\n → Check all items in the review file, then type APPROVED again.\n'));
|
|
550
|
+
process.exit(1);
|
|
551
|
+
});
|
|
552
|
+
|
|
504
553
|
// ── remove ────────────────────────────────────────────────────
|
|
505
554
|
program
|
|
506
555
|
.command('remove')
|
|
@@ -529,7 +578,7 @@ program
|
|
|
529
578
|
.description('Manually synchronize AI Instruction files with local custom skills')
|
|
530
579
|
.action(async () => {
|
|
531
580
|
const projectDir = process.cwd();
|
|
532
|
-
const { setupFramework, AI_TOOL_FILES, ensureAiflowGitignored } = require('../scripts/init');
|
|
581
|
+
const { setupFramework, AI_TOOL_FILES, ensureAiflowGitignored, setupClaudeCommands } = require('../scripts/init');
|
|
533
582
|
const fs = require('fs-extra');
|
|
534
583
|
const path = require('path');
|
|
535
584
|
const chalk = require('chalk');
|
|
@@ -549,6 +598,7 @@ program
|
|
|
549
598
|
for (const fw of frameworks) {
|
|
550
599
|
await setupFramework(projectDir, fw, frameworks.length > 1, selectedTools, { force: true });
|
|
551
600
|
}
|
|
601
|
+
await setupClaudeCommands(projectDir);
|
|
552
602
|
await ensureAiflowGitignored(projectDir);
|
|
553
603
|
console.log(chalk.green('✨ Sync completed!'));
|
|
554
604
|
});
|
|
@@ -575,4 +625,41 @@ program
|
|
|
575
625
|
telemetryCommand(action || 'status', options);
|
|
576
626
|
});
|
|
577
627
|
|
|
628
|
+
// ── scaffold ──────────────────────────────────────────────────
|
|
629
|
+
const scaffoldCmd = program.command('scaffold').alias('sc').description('Scaffold project harness files');
|
|
630
|
+
|
|
631
|
+
scaffoldCmd
|
|
632
|
+
.command('playwright')
|
|
633
|
+
.alias('pw')
|
|
634
|
+
.description('Scaffold Playwright E2E harness (playwright.config.ts, BasePage, fixtures, auth, .mcp.json)')
|
|
635
|
+
.option('-f, --force', 'overwrite existing files')
|
|
636
|
+
.option('-d, --dir <path>', 'target directory (default: current directory)')
|
|
637
|
+
.addHelpText('after', `
|
|
638
|
+
Examples:
|
|
639
|
+
$ ak scaffold playwright Scaffold into current directory
|
|
640
|
+
$ ak scaffold playwright --force Overwrite existing files
|
|
641
|
+
$ ak scaffold playwright --dir ./my-app Scaffold into ./my-app
|
|
642
|
+
|
|
643
|
+
Next steps after scaffolding:
|
|
644
|
+
1. npm install --save-dev @playwright/test
|
|
645
|
+
2. npx playwright install chromium
|
|
646
|
+
3. cp .env.example .env # then fill in BASE_URL
|
|
647
|
+
4. npx playwright test
|
|
648
|
+
`)
|
|
649
|
+
.action(async (options) => {
|
|
650
|
+
const targetDir = options.dir ? require('path').resolve(options.dir) : process.cwd();
|
|
651
|
+
console.log(chalk.cyan('\n⟳ Scaffolding Playwright E2E harness...\n'));
|
|
652
|
+
const result = await scaffoldPlaywrightCommand.scaffoldPlaywright(targetDir, { force: !!options.force });
|
|
653
|
+
console.log(chalk.cyan('\n📦 Next steps:'));
|
|
654
|
+
console.log(chalk.gray(' 1. npm install --save-dev @playwright/test'));
|
|
655
|
+
console.log(chalk.gray(' 2. npx playwright install chromium'));
|
|
656
|
+
console.log(chalk.gray(' 3. cp .env.example .env # then fill in BASE_URL'));
|
|
657
|
+
console.log(chalk.gray(' 4. npx playwright test'));
|
|
658
|
+
if (result.copied.length === 0 && result.skipped.length > 0) {
|
|
659
|
+
console.log(chalk.yellow('\n ⚠ All files already exist. Use --force to overwrite.\n'));
|
|
660
|
+
} else {
|
|
661
|
+
console.log(chalk.green('\n✨ Scaffold complete!\n'));
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
|
|
578
665
|
program.parse(process.argv);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Sao chép thành .env rồi điền giá trị. KHÔNG commit .env (đã .gitignore).
|
|
2
|
+
|
|
3
|
+
BASE_URL=http://localhost:3000
|
|
4
|
+
|
|
5
|
+
# --- Đăng nhập — chỉ cần khi app yêu cầu login ---
|
|
6
|
+
# Có E2E_USER → auth tự bật: đăng nhập 1 lần, lưu phiên, các test tái dùng.
|
|
7
|
+
E2E_USER=
|
|
8
|
+
E2E_PASSWORD=
|
|
9
|
+
E2E_LOGIN_PATH=/login
|
|
10
|
+
E2E_POST_LOGIN_PATH=/dashboard
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
try { require('dotenv').config(); } catch (_) {}
|
|
4
|
+
|
|
5
|
+
const baseURL = process.env.BASE_URL || 'http://localhost:3000';
|
|
6
|
+
const authFile = 'tests/e2e/.auth/user.json';
|
|
7
|
+
const useAuth = Boolean(process.env.E2E_USER);
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
testDir: './tests/e2e/specs',
|
|
11
|
+
fullyParallel: false,
|
|
12
|
+
forbidOnly: !!process.env.CI,
|
|
13
|
+
retries: process.env.CI ? 2 : 0,
|
|
14
|
+
reporter: [
|
|
15
|
+
['html', { outputFolder: 'playwright-report', open: 'never' }],
|
|
16
|
+
['list'],
|
|
17
|
+
],
|
|
18
|
+
use: {
|
|
19
|
+
baseURL,
|
|
20
|
+
screenshot: 'only-on-failure',
|
|
21
|
+
video: 'on-first-retry',
|
|
22
|
+
trace: 'on-first-retry',
|
|
23
|
+
},
|
|
24
|
+
projects: useAuth
|
|
25
|
+
? [
|
|
26
|
+
{ name: 'setup', testMatch: /auth\.setup\.ts/ },
|
|
27
|
+
{
|
|
28
|
+
name: 'chromium',
|
|
29
|
+
use: { ...devices['Desktop Chrome'], storageState: authFile },
|
|
30
|
+
dependencies: ['setup'],
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
: [{ name: 'chromium', use: devices['Desktop Chrome'] }],
|
|
34
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { test as setup, expect } from '@playwright/test';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
const authFile = path.join('tests', 'e2e', '.auth', 'user.json');
|
|
5
|
+
|
|
6
|
+
setup('xác thực', async ({ page }) => {
|
|
7
|
+
const user = process.env.E2E_USER;
|
|
8
|
+
const password = process.env.E2E_PASSWORD;
|
|
9
|
+
const loginPath = process.env.E2E_LOGIN_PATH || '/login';
|
|
10
|
+
const postLoginPath = process.env.E2E_POST_LOGIN_PATH || '/dashboard';
|
|
11
|
+
|
|
12
|
+
if (!user || !password) {
|
|
13
|
+
throw new Error('E2E_USER và E2E_PASSWORD phải được thiết lập trong .env');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
await page.goto(loginPath);
|
|
17
|
+
// Cập nhật các locator bên dưới bằng selector thật từ app (dùng automation-testing skill)
|
|
18
|
+
await page.getByRole('textbox', { name: 'Email' }).fill(user);
|
|
19
|
+
await page.getByLabel('Mật khẩu').fill(password);
|
|
20
|
+
await page.getByRole('button', { name: 'Đăng nhập' }).click();
|
|
21
|
+
|
|
22
|
+
const escaped = postLoginPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
23
|
+
await expect(page).toHaveURL(new RegExp(escaped));
|
|
24
|
+
await page.context().storageState({ path: authFile });
|
|
25
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Test Patterns — Quy ước chung cho automation-testing
|
|
2
|
+
|
|
3
|
+
Tài liệu này được skill `automation-testing` đọc ở Phase 1 và áp dụng khi sinh test.
|
|
4
|
+
Mục tiêu: test ổn định, dễ đọc, ít vỡ khi UI đổi.
|
|
5
|
+
|
|
6
|
+
## Nguyên tắc chọn locator (ưu tiên từ trên xuống)
|
|
7
|
+
|
|
8
|
+
1. `getByRole(role, { name })` — bám theo accessibility, bền nhất.
|
|
9
|
+
2. `getByLabel(text)` — cho input có `<label>`.
|
|
10
|
+
3. `getByPlaceholder(text)` — khi không có label.
|
|
11
|
+
4. `getByText(text)` — cho message, nội dung tĩnh.
|
|
12
|
+
5. `getByTestId(id)` — khi dev đã gắn `data-testid`.
|
|
13
|
+
6. CSS / XPath — **chỉ khi bất đắc dĩ**, kèm comment lý do.
|
|
14
|
+
|
|
15
|
+
> Locator phải lấy từ DOM thật (Phase 3 qua Playwright MCP), không tự bịa tên.
|
|
16
|
+
|
|
17
|
+
## Quy ước chung
|
|
18
|
+
|
|
19
|
+
- Mỗi test độc lập: tự `navigate` tới trang cần test, không phụ thuộc test trước.
|
|
20
|
+
- Page Object: 1 file / 1 màn hình; locator khai báo ở constructor; action là method.
|
|
21
|
+
- Spec import `{ test, expect }` từ `tests/e2e/fixtures/test.ts`.
|
|
22
|
+
- ID test (`TC01`, `TC02`...) khớp bảng test case đã chốt ở Phase 2.
|
|
23
|
+
- Tên test, comment viết tiếng Việt.
|
|
24
|
+
- Không hardcode tài khoản/dữ liệu thật; dùng dữ liệu test do tester cung cấp.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Pattern 1 — Login
|
|
29
|
+
|
|
30
|
+
Steps điển hình: vào trang login → nhập email/password → submit.
|
|
31
|
+
- Thành công: `await expect(page).toHaveURL(/dashboard/)`.
|
|
32
|
+
- Sai thông tin: `await expect(errorMessage).toBeVisible()`.
|
|
33
|
+
- Validation rỗng: submit ngay → `await expect(page.getByText('... bắt buộc')).toBeVisible()`.
|
|
34
|
+
|
|
35
|
+
## Pattern 2 — Form validation
|
|
36
|
+
|
|
37
|
+
- Submit khi field rỗng → kiểm tra message bắt buộc của từng field.
|
|
38
|
+
- Nhập sai định dạng (email, số điện thoại) → kiểm tra message định dạng.
|
|
39
|
+
- Nhập hợp lệ → submit thành công (toast / redirect / record mới xuất hiện).
|
|
40
|
+
|
|
41
|
+
## Pattern 3 — CRUD (Create / Read / Update / Delete)
|
|
42
|
+
|
|
43
|
+
- **Create**: mở form → điền → submit → khẳng định record xuất hiện trong list.
|
|
44
|
+
- **Read**: tìm/lọc → khẳng định kết quả đúng.
|
|
45
|
+
- **Update**: mở record → sửa → lưu → khẳng định giá trị mới hiển thị.
|
|
46
|
+
- **Delete**: xóa → xác nhận → khẳng định record biến mất.
|
|
47
|
+
- Mẹo: tạo dữ liệu có hậu tố thời gian/ngẫu nhiên để tránh trùng giữa các lần chạy.
|
|
48
|
+
|
|
49
|
+
## Pattern 4 — Modal / Dialog
|
|
50
|
+
|
|
51
|
+
- Mở modal → `await expect(dialog).toBeVisible()`.
|
|
52
|
+
- Thao tác trong modal dùng locator scope trong dialog: `dialog.getByRole(...)`.
|
|
53
|
+
- Đóng/confirm → khẳng định modal đóng (`toBeHidden`) và side-effect đúng.
|
|
54
|
+
|
|
55
|
+
## Pattern 5 — Table / Pagination / Search
|
|
56
|
+
|
|
57
|
+
- Search: nhập từ khóa → khẳng định hàng khớp xuất hiện, hàng không khớp biến mất.
|
|
58
|
+
- Pagination: sang trang → khẳng định nội dung trang đổi.
|
|
59
|
+
- Dùng `getByRole('row')`, `getByRole('cell')` để bám bảng theo accessibility.
|
|
60
|
+
|
|
61
|
+
## Pattern 6 — Auth-gated pages (storageState)
|
|
62
|
+
|
|
63
|
+
Cơ chế có sẵn trong repo — **ưu tiên dùng**, đừng đăng nhập lại trong từng test:
|
|
64
|
+
|
|
65
|
+
- Đăng nhập **1 lần** ở `tests/e2e/auth.setup.ts`, lưu phiên vào `.auth/user.json`.
|
|
66
|
+
- Bật bằng env `E2E_USER` (+ `E2E_PASSWORD`, `E2E_LOGIN_PATH`, `E2E_POST_LOGIN_PATH`).
|
|
67
|
+
- Khi bật, mọi test chạy ở trạng thái **đã đăng nhập** sẵn — không cần `beforeEach` login.
|
|
68
|
+
- Test cần **chưa đăng nhập** (test login/logout): `test.use({ storageState: LOGGED_OUT })`
|
|
69
|
+
ở đầu spec (`LOGGED_OUT` import từ `../../fixtures/test`).
|
|
70
|
+
- Selector trong `auth.setup.ts` phải là selector THẬT của trang login (lấy ở Phase 3).
|