@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.
Files changed (94) hide show
  1. package/README.md +139 -0
  2. package/bin/aiflow.js +89 -2
  3. package/custom/harness/playwright/.env.example +10 -0
  4. package/custom/harness/playwright/playwright.config.ts +34 -0
  5. package/custom/harness/playwright/tests/e2e/auth.setup.ts +25 -0
  6. package/custom/harness/playwright/tests/e2e/fixtures/test.ts +6 -0
  7. package/custom/harness/playwright/tests/e2e/pages/BasePage.ts +9 -0
  8. package/custom/harness/playwright/tests/e2e/support/auth.ts +5 -0
  9. package/custom/mcp-presets/playwright.json +8 -0
  10. package/custom/rules/test-patterns.md +70 -0
  11. package/custom/skills/automation-testing/SKILL.md +239 -0
  12. package/custom/skills/automation-testing/templates/BasePage.ts +29 -0
  13. package/custom/skills/automation-testing/templates/PageObject.example.ts +29 -0
  14. package/custom/skills/automation-testing/templates/playwright.config.ts +39 -0
  15. package/custom/skills/automation-testing/templates/spec.example.ts +29 -0
  16. package/custom/skills/ba-skills/skill-ba-phan-tich-ban-dau-v1.md +44 -0
  17. package/custom/skills/ba-skills/skill-ba-prototype-v1.md +35 -0
  18. package/custom/skills/ba-skills/skill-ba-qa-template-v1.md +21 -0
  19. package/custom/skills/ba-skills/skill-ba-qa-v1.md +35 -0
  20. package/custom/skills/ba-skills/skill-ba-template-phan-tich-ban-dau-v1.md +30 -0
  21. package/custom/skills/ba-skills/skill-ba-template-uc-v1.md +83 -0
  22. package/custom/skills/ba-skills/skill-ba-ve-luong-mermaid-v1.md +35 -0
  23. package/custom/skills/ba-skills/skill-ba-viet-spec-uc-v1.md +38 -0
  24. package/custom/skills/ba-skills/skill-ba-xay-dung-business-rules-v1.md +39 -0
  25. package/custom/skills/coverage-check/SKILL.md +202 -0
  26. package/custom/skills/evidence-aggregation/SKILL.md +246 -0
  27. package/custom/skills/execute-flow/SKILL.md +499 -0
  28. package/custom/skills/execute-flow/templates/playwright.config.ts +39 -0
  29. package/custom/skills/gate-review/SKILL.md +195 -0
  30. package/custom/skills/generate-test-report/SKILL.md +99 -0
  31. package/custom/skills/generate-test-report/templates/test-report.md +58 -0
  32. package/custom/skills/generate-testcase/SKILL.md +350 -0
  33. package/custom/skills/generate-testcase/templates/testcase.md +88 -0
  34. package/custom/skills/log-bug/SKILL.md +131 -0
  35. package/custom/skills/pr-impact-analysis/SKILL.md +180 -0
  36. package/custom/skills/retest-orchestration/SKILL.md +191 -0
  37. package/custom/skills/script-sync/SKILL.md +208 -0
  38. package/custom/skills/test-analysis/SKILL.md +300 -0
  39. package/custom/skills/test-skills/categories/00-core/00.01.requirement-analysis.md +111 -0
  40. package/custom/skills/test-skills/categories/00-core/00.02.risk-analysis.md +24 -0
  41. package/custom/skills/test-skills/categories/00-core/00.03.test-scenario-builder.md +90 -0
  42. package/custom/skills/test-skills/categories/00-core/00.04.testcase-review.md +68 -0
  43. package/custom/skills/test-skills/categories/01-test-design/01.01.boundary-value-analysis.md +30 -0
  44. package/custom/skills/test-skills/categories/01-test-design/01.02.equivalence.partitioning.md +27 -0
  45. package/custom/skills/test-skills/categories/01-test-design/01.03.decision-table.md +26 -0
  46. package/custom/skills/test-skills/categories/01-test-design/01.04.state.transition.md +26 -0
  47. package/custom/skills/test-skills/categories/01-test-design/01.05.pairwise.md +25 -0
  48. package/custom/skills/test-skills/categories/01-test-design/01.06.error-guessing.md +28 -0
  49. package/custom/skills/test-skills/categories/02-ui-testing/02.01.UI-layout.md +29 -0
  50. package/custom/skills/test-skills/categories/02-ui-testing/02.02.form-validation.md +57 -0
  51. package/custom/skills/test-skills/categories/02-ui-testing/02.03.navigation.md +27 -0
  52. package/custom/skills/test-skills/categories/02-ui-testing/02.04.localization.md +27 -0
  53. package/custom/skills/test-skills/categories/02-ui-testing/02.05.accessibility.md +27 -0
  54. package/custom/skills/test-skills/categories/03-business-testing/03.01.CRUD-testing.md +51 -0
  55. package/custom/skills/test-skills/categories/03-business-testing/03.02.workflow-testing.md +44 -0
  56. package/custom/skills/test-skills/categories/03-business-testing/03.03.permission-testing.md +41 -0
  57. package/custom/skills/test-skills/categories/03-business-testing/03.04.dependency-validation.md +40 -0
  58. package/custom/skills/test-skills/categories/03-business-testing/03.05.notification-testing.md +43 -0
  59. package/custom/skills/test-skills/categories/03-business-testing/03.06.calculation.testing.md +44 -0
  60. package/custom/skills/test-skills/categories/04-data-testing/04.01.database-testing.md +43 -0
  61. package/custom/skills/test-skills/categories/04-data-testing/04.02.import-export-testing.md +43 -0
  62. package/custom/skills/test-skills/categories/04-data-testing/04.03.data-mapping.md +39 -0
  63. package/custom/skills/test-skills/categories/04-data-testing/04.04.duplicate-handling.md +39 -0
  64. package/custom/skills/test-skills/categories/04-data-testing/04.05.migration.md +42 -0
  65. package/custom/skills/test-skills/categories/05-integration/05.01.API-testing.md +37 -0
  66. package/custom/skills/test-skills/categories/05-integration/05.02.third-party-integration.md +36 -0
  67. package/custom/skills/test-skills/categories/05-integration/05.03.batch-processing.md +38 -0
  68. package/custom/skills/test-skills/categories/05-integration/05.04.file-upload-download.md +40 -0
  69. package/custom/skills/test-skills/categories/08-domain-skills/CMS.md +34 -0
  70. package/custom/skills/test-skills/categories/08-domain-skills/Ecommerce.md +35 -0
  71. package/custom/skills/test-skills/categories/99-review/99.01.coverage-review.md +35 -0
  72. package/custom/skills/test-skills/categories/99-review/99.02.knowledge-learning.md +34 -0
  73. package/custom/skills/test-skills/categories/99-review/99.03.repository-update.md +33 -0
  74. package/custom/skills/test-skills/categories/99-review/99.04.change-history.md +38 -0
  75. package/custom/skills/test-skills/rules/Directory_and_Naming_Convention.md +257 -0
  76. package/custom/skills/test-skills/rules/QA_Writing_Standards.md +49 -0
  77. package/custom/skills/test-skills/template/template_testcase.md +92 -0
  78. package/custom/templates/shared/create-spec-workflow.md +441 -0
  79. package/custom/templates/shared/create-testcase-workflow.md +470 -0
  80. package/custom/templates/shared/gate-workflow.md +421 -11
  81. package/docs/common/CHANGELOG.md +52 -0
  82. package/docs/common/QUICK_START.md +30 -0
  83. package/docs/common/cli-reference.md +48 -7
  84. package/package.json +2 -2
  85. package/scripts/create-score-excel.js +37 -14
  86. package/scripts/detect.js +10 -0
  87. package/scripts/guide.js +9 -0
  88. package/scripts/init.js +48 -1
  89. package/scripts/prompt.js +36 -0
  90. package/scripts/review.js +91 -0
  91. package/scripts/scaffold-playwright.js +106 -0
  92. package/scripts/task.js +21 -7
  93. package/scripts/update.js +127 -124
  94. 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,6 @@
1
+ import { test as base } from '@playwright/test';
2
+
3
+ export const LOGGED_OUT = { cookies: [], origins: [] } as const;
4
+
5
+ export const test = base;
6
+ export { expect } from '@playwright/test';
@@ -0,0 +1,9 @@
1
+ import { Page } from '@playwright/test';
2
+
3
+ export class BasePage {
4
+ constructor(protected readonly page: Page) {}
5
+
6
+ async navigate(path: string): Promise<void> {
7
+ await this.page.goto(path);
8
+ }
9
+ }
@@ -0,0 +1,5 @@
1
+ export const AUTH_FILE = 'tests/e2e/.auth/user.json';
2
+
3
+ export function isAuthEnabled(): boolean {
4
+ return Boolean(process.env.E2E_USER);
5
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "playwright": {
4
+ "command": "npx",
5
+ "args": ["-y", "@playwright/mcp@latest", "--isolated", "--browser", "chromium", "--headless"]
6
+ }
7
+ }
8
+ }
@@ -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).