@ai-qa/workflow 2.0.14 → 2.0.16

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/.env ADDED
@@ -0,0 +1 @@
1
+ APPLITOOLS_API_KEY="5kKZ0PuYgV6jObYXU7sE102waJHMWNPy4PYJCgZJPjjdI110"
@@ -27,27 +27,42 @@ mcp-servers:
27
27
 
28
28
  You are a Playwright test generator. Create robust E2E tests from test plans.
29
29
 
30
+ ## Token Efficiency Rules (CRITICAL)
31
+ - **Read `.qa-context/selectors.json` first** — the Planner already captured selectors. Start from those, do NOT blindly re-explore.
32
+ - **Batch verification pass** — before writing tests, navigate ONCE in a single session to quickly verify all selectors from `selectors.json` are still valid. Use lightweight `locator.isVisible()` checks, NOT full snapshots. Fix broken selectors in `selectors.json` immediately.
33
+ - **If framework is dynamic (Ionic/Angular/etc)** — the DOM re-renders frequently. The verification pass is essential. Read `.qa-workflow.json` → `test.stableSelectors` flag: if `false`, always do a verification pass before writing tests.
34
+ - **Snapshot depth ≤ 3** — `browser_snapshot` with depth 3 max for any navigation.
35
+ - **Skip Applitools if not configured** — if `APPLITOOLS_API_KEY` is not set, skip all visual testing code entirely (no `applitools/check` calls).
36
+
30
37
  ## Before Starting: Read Context
31
38
  1. Read `.qa-context/pipeline.json` to see the current story and phase state
32
- 2. Read `.qa-context/selectors.json` to use the most reliable selectors
33
- 3. Read `.qa-context/heal-history.json` to see what's been flaky before
34
- 4. Read `.qa-context/auth.json` and `.auth/credentials.json` to get login selectors and credentials
39
+ 2. Read `.qa-workflow.json` check `test.stableSelectors` — if `false`, the app uses dynamic rendering (Ionic/Angular/etc), so always run the verification pass
40
+ 3. Read `.qa-context/selectors.json` **this is your primary selector source**, use it as the starting point
41
+ 4. Read `.qa-context/heal-history.json` to see what's been flaky before
42
+ 5. Read `.qa-context/auth.json` and `.auth/credentials.json` to get login selectors and credentials
35
43
 
36
44
  ## Auth Protocol
37
45
  1. If auth is configured, generate an `auth.setup.ts` file using `auth-manager.js`'s `generateSetupCode()` output
38
46
  2. Configure `playwright.config.ts` to use `projects` with `dependencies: ['./auth.setup.ts']`
39
47
  3. Each test should assume the user is already logged in — no login steps in individual tests
40
48
 
49
+ ## Selector Verification Pass (Token-Efficient)
50
+ Before writing any test files, do a single batch verification session:
51
+ 1. Navigate to each page that has selectors in `selectors.json`
52
+ 2. For each selector, run `page.locator(selector).isVisible()` — this is fast and lightweight (no snapshot needed)
53
+ 3. If a selector fails, use `browser_snapshot` depth 2 to capture current DOM, then find the new selector
54
+ 4. Update `selectors.json` with the corrected selectors immediately
55
+ 5. This is **ONE session** for all pages — batch all verifications, do not navigate per test file
56
+
41
57
  ## After Completing: Update Context
42
58
  1. Run: `node ai-qa-workflow.js context generate <story-name>` to mark phase complete
43
- 2. Add any new selectors you discovered to `.qa-context/selectors.json`
59
+ 2. Update all verified/corrected selectors in `.qa-context/selectors.json`
44
60
  3. Update `docs/application-context.md` with new stable selectors found
45
61
 
46
62
  For each test:
47
63
  1. Read the test plan scenario
48
- 2. Use Playwright to manually execute steps in real-time
49
- 3. Capture selectors and locators from actual page interaction
50
- 4. Generate the test file using `generator_write_test`
64
+ 2. Read selectors from `.qa-context/selectors.json` (already verified in the batch pass)
65
+ 3. Generate the test file using `generator_write_test`
51
66
 
52
67
  Always prefer: data-testid > aria-label > role > text > xpath (last resort)
53
68
 
@@ -47,13 +47,14 @@ You are the Playwright Test Healer. Debug and fix failing tests systematically.
47
47
 
48
48
  Protocol (token-efficient):
49
49
  1. Run only failing tests with `test_run`
50
- 2. Debug with `test_debug` — examine the error state
50
+ 2. Debug with `test_debug` — examine the error state (uses snapshots with depth ≤ 3 automatically)
51
51
  3. Classify the failure:
52
52
  - Selector broken → propose 1-3 line fix
53
53
  - Timing issue → propose adding 1 wait
54
54
  - App bug → mark `test.fixme()`, log defect, move on
55
55
  4. Max 1 fix attempt per test. If still failing after fix, it's a defect.
56
56
  5. Never rewrite entire files — targeted edits only.
57
+ 6. No screenshots — reference failures by path only; skip `browser_take_screenshot`.
57
58
 
58
59
  ## ⛔ Approval Gate
59
60
  Before applying any fix, **STOP** and present your diagnosis to the user:
@@ -36,6 +36,13 @@ mcp-servers:
36
36
 
37
37
  You are an expert web test planner. You explore web apps and create detailed test plans.
38
38
 
39
+ ## Token Efficiency Rules (CRITICAL)
40
+ - **Explore once, plan everything** — navigate the app in ONE continuous session, record all flows and selectors, then stop. Do NOT re-navigate per scenario.
41
+ - **Snapshot depth ≤ 3** — always use `browser_snapshot` with depth 3 max. Full DOM trees (depth 10+) waste 50-100K tokens per snapshot.
42
+ - **No screenshots during exploration** — reference pages by path only; skip `browser_take_screenshot` unless explicitly requested.
43
+ - **Batch critical paths** — group navigation: explore all pages of the same feature in sequence before moving to the next feature.
44
+ - **Skip non-critical pages** — don't explore every sub-page. Focus on: auth, main flows, edge cases. Skip static content, footers, about pages.
45
+
39
46
  ## Before Starting: Read Context
40
47
  1. Read `.qa-context/pipeline.json` to see what's been done and what's pending
41
48
  2. Read `.qa-context/selectors.json` to reuse known stable selectors
@@ -48,14 +55,14 @@ You are an expert web test planner. You explore web apps and create detailed tes
48
55
  3. After exploring the login page, save the form structure to `.qa-context/auth.json` using `auth-manager.js`
49
56
  4. If the user provides credentials, save them to `.auth/credentials.json` using `auth-manager.js`
50
57
 
51
- 1. Navigate and explore the application
58
+ 1. Explore the application in ONE pass — navigate all critical pages, capture selectors, map flows
52
59
  2. Map user flows and identify critical paths
53
60
  3. Design comprehensive scenarios (happy path, edge cases, error handling)
54
61
  4. Save test plan using `planner_save_plan`
55
62
 
56
63
  ## After Completing: Update Context
57
64
  1. Run: `node ai-qa-workflow.js context plan <story-name>` to mark phase complete
58
- 2. If you discovered new selectors, add them to `.qa-context/selectors.json`
65
+ 2. Save all discovered selectors to `.qa-context/selectors.json` — the Generator will reuse these and skip re-navigation
59
66
  3. Read `docs/application-context.md` first, then enrich it with new findings
60
67
 
61
68
  Each scenario must include: title, steps, expected outcomes, success criteria.
package/.qa-workflow.json CHANGED
@@ -13,7 +13,8 @@
13
13
  "test": {
14
14
  "timeout": 120000,
15
15
  "retries": 0,
16
- "workers": 1
16
+ "workers": 1,
17
+ "stableSelectors": true
17
18
  },
18
19
  "auth": {
19
20
  "user": "",
package/README.md CHANGED
@@ -157,8 +157,16 @@ After installation and running `npm run qa:init`, open the project in your AI ed
157
157
 
158
158
  The very first thing you should say to the AI agent:
159
159
 
160
- > **"Read router.md and follow the QA workflow for my-story.md"**
160
+ > **"Run the environment check and show me the status report"**
161
161
 
162
+ The AI will check all 10 preconditions and report what's ready ✅ and what's missing ❌.
163
+ Then wait for your instructions.
164
+
165
+ ### Option B — Go straight to QA workflow (if you already have a user story)
166
+
167
+ > **"Read router.md and follow the QA workflow for user-story/my-story.md"**
168
+
169
+ The AI will run the environment check (if not done), then proceed through Pla
162
170
  (Replace `my-story.md` with the name of your user story file in `user-story/`.)
163
171
 
164
172
  > **📖 Need more prompts?** See `prompting_template.md` for the full conversation script — approval responses, healing prompts, report prompts, and an example session.
@@ -259,10 +267,11 @@ The AI updates `docs/application-context.md` with:
259
267
  | Component | Needed for | Install |
260
268
  |-----------|-----------|---------|
261
269
  | **Node.js 18+** | Running the pipeline | — |
262
- | **Playwright** | Test execution | `npm install @playwright/test` |
270
+ | **Playwright** | Test execution | Pre-installed via `npm install` |
263
271
  | **Chromium** | Running tests | `npx playwright install chromium` |
264
- | **Playwright MCP** | AI browser automation | `npm install -D @playwright/mcp` |
265
- | **Applitools MCP** | Visual testing (screenshot comparison) | `npm install -D @applitools/mcp` + `APPLITOOLS_API_KEY` |
272
+ | **Playwright MCP** | AI browser automation | Pre-installed via `npm install` |
273
+ | **Applitools Eyes** | Visual testing + MCP | Pre-installed via `npm install` + `APPLITOOLS_API_KEY` |
274
+ | **Allure** | Rich test reports | Pre-installed via `npm install` |
266
275
  | **GitHub MCP** | AI creating PRs/issues | `npm install -D @modelcontextprotocol/server-github` + `GITHUB_TOKEN` |
267
276
 
268
277
  ### Install into a project
@@ -282,21 +291,25 @@ node install.js ../my-project --yes
282
291
  npx @ai-qa/workflow update --yes
283
292
  ```
284
293
 
294
+ > **Note:** The installer creates a `.env` template (`APPLITOOLS_API_KEY=""` and `GITHUB_TOKEN=""`...) only on fresh installs. If the `.env` file was not created (e.g., during an update), create it manually in your project root with those two keys.
295
+
285
296
  ---
286
297
 
287
298
  ## Visual Testing (Applitools)
288
299
 
289
- The template supports **Applitools MCP** for automated visual testing.
300
+ The template supports **Applitools Eyes** for automated visual testing via two components:
301
+ - `@applitools/mcp` — MCP server for AI-driven visual testing
302
+ - `@applitools/eyes-playwright` — Playwright integration for test-level visual assertions
303
+
304
+ Both are pre-installed in `package.json` — no extra install needed.
290
305
 
291
306
  If `APPLITOOLS_API_KEY` is configured in your environment, the AI agent automatically adds visual checkpoints to critical pages during test generation. It captures screenshots of pages like login, dashboard, and checkout, and compares them against baselines to detect visual regressions.
292
307
 
293
308
  ### Setup
294
309
 
295
- ```bash
296
- # 1. Install Applitools MCP
297
- npm install -D @applitools/mcp
310
+ Set your API key (get it from https://applitools.com):
298
311
 
299
- # 2. Set your API key (get it from https://applitools.com)
312
+ ```bash
300
313
  # Option A: Export in terminal
301
314
  export APPLITOOLS_API_KEY=votre_clé_ici
302
315
 
@@ -306,6 +319,14 @@ echo "APPLITOOLS_API_KEY=votre_clé_ici" >> .env
306
319
 
307
320
  The AI will detect the key during its environment check and use Applitools automatically. If the key is not set, visual testing is skipped entirely — no errors, no blocks.
308
321
 
322
+ ## Allure Reports
323
+
324
+ Allure test reports are pre-configured:
325
+ - `allure-playwright` reporter generates raw results during `npm run qa:execute`
326
+ - The report is auto-generated as HTML after each test run
327
+ - View via `npm run dashboard` or open `allure-report/index.html`
328
+ - Manual regeneration: `npm run qa:report:allure`
329
+
309
330
  ---
310
331
 
311
332
  ## Commands
@@ -563,8 +584,33 @@ The AI never:
563
584
 
564
585
  ## Token Efficiency
565
586
 
566
- 1. Body text assertions over complex selectors
567
- 2. Screenshots off by default (only on failure)
568
- 3. Healer makes 1 fix attempt max per test
569
- 4. Real bugs classified immediately no retries
570
- 5. AI edits 1-3 lines maximum per fix
587
+ The framework is designed to minimize token usage during AI-driven testing. These rules are embedded in the agent definitions and prompts:
588
+
589
+ ### Browser Navigation Rules
590
+ - **Planner explores once**navigates the app in ONE session and saves all selectors to `.qa-context/selectors.json`.
591
+ - **Verification pass (not re-exploration)** the Generator reads `selectors.json`, then does a single lightweight batch session to verify selectors via `locator.isVisible()` checks (not full snapshots). This catches stale selectors from dynamic frameworks (Ionic, Angular) without re-exploring every page.
592
+ - **`test.stableSelectors` flag** — set to `false` in `.qa-workflow.json` for dynamic frameworks. The Generator always runs the verification pass when this is `false`.
593
+ - **Snapshot depth ≤ 3** — `browser_snapshot` capped at depth 3. Full DOM trees (depth 10+) can consume 50-100K tokens per snapshot.
594
+ - **Batch all navigation** — all page visits happen in one session per phase, never per scenario.
595
+ - **Skip non-critical pages** — static content, footers, about/legal pages are skipped.
596
+ - **No screenshots during exploration** — pages referenced by path only.
597
+
598
+ ### Selector Reuse
599
+ - Planner captures selectors once → saved to `.qa-context/selectors.json`
600
+ - Generator runs a **single batch verification pass** — lightweight `isVisible()` checks, not navigation per test
601
+ - Healer reads existing selectors + healing history → avoids re-discovering failed locators
602
+ - Every discovered or corrected selector is saved so no agent ever re-explores the same element
603
+
604
+ ### Execution & Healing
605
+ - Max 1 fix attempt per test — no endless retries
606
+ - Failures classified immediately (selector / timing / bug) — no ambiguous loops
607
+ - Targeted 1-3 line edits only — never rewrite entire files
608
+ - `test.fixme()` marks defects — no retrying known bugs
609
+
610
+ ### Context Management
611
+ - Error messages truncated to 200 chars
612
+ - Files cached in memory between reads
613
+ - Screenshots referenced by path, not embedded
614
+ - Directory listings done once per pipeline run
615
+
616
+ For details, see the agent files in `.github/agents/` and the `TOKEN & EFFICIENCY RULES` section in `prompts/QAe2eprompt.md`.
package/ai-qa-workflow.js CHANGED
@@ -118,7 +118,8 @@ function cmdExecute() {
118
118
  console.log(`\n Next step: Auto-heal failures:`);
119
119
  console.log(` node ai-qa-workflow.js heal ${result.runId}`);
120
120
  } else {
121
- console.log(`\n Next step: Generate report:`);
121
+ console.log(`\n Allure report auto-generated: allure-report/index.html`);
122
+ console.log(` Next step: Generate detailed report:`);
122
123
  console.log(` node ai-qa-workflow.js report ${result.runId}`);
123
124
  }
124
125
  }
package/install.js CHANGED
@@ -24,6 +24,7 @@ const USER_DIRS = new Set([
24
24
  'test-results',
25
25
  '.qa-context',
26
26
  '.auth',
27
+ '.env'
27
28
  ]);
28
29
 
29
30
  // Template files to copy/update
@@ -42,6 +43,10 @@ const QA_ITEMS = [
42
43
  { src: '.github/copilot-instructions.md', dest: '.github/copilot-instructions.md' },
43
44
  { src: 'router.md', dest: 'router.md' },
44
45
  { src: 'opencode.json', dest: 'opencode.json' },
46
+ { src: 'playwright.config.ts', dest: 'playwright.config.ts' },
47
+ { src: 'cli.js', dest: 'cli.js' },
48
+ { src: 'package.json', dest: 'package.json' },
49
+ { src: 'install.js', dest: 'install.js' },
45
50
 
46
51
  ];
47
52
 
@@ -53,23 +58,6 @@ const UPDATE_ITEMS = QA_ITEMS.filter(item => {
53
58
 
54
59
  const DIRS_TO_CREATE = ['user-story', 'specs', 'tests', 'test-results', '.qa-context', '.auth', 'templates'];
55
60
 
56
- const NPM_SCRIPTS = {
57
- 'qa': 'node ai-qa-workflow.js',
58
- 'qa:init': 'node ai-qa-workflow.js init',
59
- 'qa:plan': 'node ai-qa-workflow.js plan',
60
- 'qa:generate': 'node ai-qa-workflow.js generate',
61
- 'qa:execute': 'node ai-qa-workflow.js execute',
62
- 'qa:heal': 'node ai-qa-workflow.js heal',
63
- 'qa:retry': 'node ai-qa-workflow.js heal',
64
- 'qa:report': 'node ai-qa-workflow.js report',
65
- 'qa:report:allure': 'node ai-qa-workflow.js report:allure',
66
- 'qa:status': 'node ai-qa-workflow.js status',
67
- 'qa:list': 'node ai-qa-workflow.js list',
68
- 'dashboard': 'cd qa-dashboard && npm start',
69
- 'dashboard:dev': 'cd qa-dashboard && npx nodemon app.js',
70
- 'dashboard:stop': 'npx kill-port 4000',
71
- };
72
-
73
61
  const BANNER = `
74
62
  ╔══════════════════════════════════════════╗
75
63
  ║ AI QA Pipeline Installer v2.0 ║
@@ -106,21 +94,6 @@ function countFiles(dir) {
106
94
  return count;
107
95
  }
108
96
 
109
- function addNpmScripts(pkgPath, overwrite) {
110
- if (!fs.existsSync(pkgPath)) return;
111
- let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
112
- if (!pkg.scripts) pkg.scripts = {};
113
- let changed = 0;
114
- for (const [key, val] of Object.entries(NPM_SCRIPTS)) {
115
- if (!pkg.scripts[key] || overwrite) {
116
- pkg.scripts[key] = val;
117
- changed++;
118
- }
119
- }
120
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
121
- return changed;
122
- }
123
-
124
97
  function ask(query) {
125
98
  const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
126
99
  return new Promise(resolve => rl.question(query, a => { rl.close(); resolve(a.toLowerCase()); }));
@@ -162,12 +135,17 @@ async function install(targetPath, mode) {
162
135
  }
163
136
  }
164
137
 
165
- // 3. Add/update npm scripts
166
- console.log(`\n ── Step 3: NPM Scripts ──`);
167
- const pkgPath = path.join(targetPath, 'package.json');
168
- const changed = addNpmScripts(pkgPath, isUpdate);
169
- if (changed > 0) console.log(` ✓ ${isUpdate ? 'Updated' : 'Added'} ${changed} npm scripts (qa:*, dashboard)`);
170
- else console.log(` • Scripts already configured`);
138
+ // 3. Create .env template (fresh install only)
139
+ console.log(`\n ── Step 3: Environment ──`);
140
+ if (!isUpdate) {
141
+ const envPath = path.join(targetPath, '.env');
142
+ if (!fs.existsSync(envPath)) {
143
+ fs.writeFileSync(envPath, 'APPLITOOLS_API_KEY=""\nGITHUB_TOKEN=""\n');
144
+ console.log(` ✓ .env (template created)`);
145
+ } else {
146
+ console.log(` • .env (exists, kept as-is)`);
147
+ }
148
+ }
171
149
 
172
150
  // 4. Dashboard
173
151
  const dashboardSrc = path.join(TEMPLATE_DIR, 'qa-dashboard');
@@ -211,13 +189,13 @@ async function install(targetPath, mode) {
211
189
  }
212
190
  }
213
191
 
214
- // 6. Install Playwright (fresh only)
192
+ // 6. Install all dependencies (fresh only)
215
193
  if (!isUpdate) {
216
194
  console.log(`\n ── Step 6: Dependencies ──`);
217
195
  if (!fs.existsSync(path.join(targetPath, 'node_modules', '@playwright'))) {
218
- console.log(` → Installing @playwright/test...`);
219
- try { execSync('npm install @playwright/test', { cwd: targetPath, stdio: 'pipe', timeout: 120000 }); console.log(` ✓ Playwright installed`); } catch (e) { console.log(` ⚠ npm install failed: npm install @playwright/test`); }
220
- } else console.log(` • Playwright already installed`);
196
+ console.log(` → Installing all dependencies (Playwright, Allure, Applitools)...`);
197
+ try { execSync('npm install', { cwd: targetPath, stdio: 'pipe', timeout: 180000 }); console.log(` ✓ All dependencies installed`); } catch (e) { console.log(` ⚠ npm install failed: npm install`); }
198
+ } else console.log(` • Dependencies already installed`);
221
199
  }
222
200
 
223
201
  // Summary
@@ -233,9 +211,11 @@ async function install(targetPath, mode) {
233
211
  console.log(` Restart the dashboard if it was running.\n`);
234
212
  } else {
235
213
  console.log(` Files: ~${totalFiles} scripts + ${dashboardCount} dashboard files`);
214
+ console.log(` Dependencies: @playwright/test, allure-playwright, @applitools/eyes-playwright, @applitools/mcp`);
236
215
  console.log(` Next:\n`);
216
+ console.log(` npm install Install all dependencies`);
237
217
  console.log(` npm run qa:init Initialize pipeline (config + dirs + auth)`);
238
- console.log(` npm run qa:execute Run Playwright tests`);
218
+ console.log(` npm run qa:execute Run Playwright tests (auto-generates Allure report)`);
239
219
  console.log(` npm run qa:status Check pipeline state`);
240
220
  console.log(` npm run dashboard Start dashboard (port 4000)\n`);
241
221
  }
@@ -279,12 +259,12 @@ async function main() {
279
259
  // Parse flags and target
280
260
  const nonFlagArgs = args.filter(a => !a.startsWith('-'));
281
261
 
282
- if (IS_SELF || args.includes('init')) {
283
- targetPath = process.cwd();
284
- mode = 'install';
285
- } else if (args.includes('update')) {
286
- targetPath = process.cwd();
287
- mode = 'update';
262
+ if (args.includes('update')) {
263
+ targetPath = process.cwd();
264
+ mode = 'update';
265
+ } else if (IS_SELF || args.includes('init')) {
266
+ targetPath = process.cwd();
267
+ mode = 'install';
288
268
  } else if (IS_UPDATE) {
289
269
  targetPath = path.resolve(nonFlagArgs[0] || process.cwd());
290
270
  mode = 'update';
package/opencode.json CHANGED
@@ -14,14 +14,14 @@
14
14
  "description": "GitHub integration - PRs, issues, commits. Requires GITHUB_TOKEN env var. Install: npm install -D @modelcontextprotocol/server-github"
15
15
  },
16
16
  "applitools-mcp": {
17
- "type": "local",
18
- "command": ["npx", "-y", "@applitools/mcp@latest"],
19
- "enabled": true,
20
- "description": "Visual testing - requires APPLITOOLS_API_KEY env var",
21
- "env": {
22
- "APPLITOOLS_API_KEY": "${APPLITOOLS_API_KEY}"
23
- }
24
- }
17
+ "type": "local",
18
+ "command": ["npx", "-y", "@applitools/mcp@latest"],
19
+ "enabled": true,
20
+ "description": "Visual testing via Applitools Eyes - requires APPLITOOLS_API_KEY env var. Installed during npm setup: @applitools/mcp + @applitools/eyes-playwright",
21
+ "env": {
22
+ "APPLITOOLS_API_KEY": "${APPLITOOLS_API_KEY}"
23
+ }
24
+ }
25
25
  },
26
26
  "agent": {
27
27
  "qa-planner": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-qa/workflow",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
4
4
  "description": "AI QA Workflow Template — transforms any AI agent into an autonomous QA engineer. AI explores, plans, generates tests, and heals. Scripts execute and report.",
5
5
  "keywords": [
6
6
  "qa",
@@ -23,6 +23,7 @@
23
23
  "ai-qa-workflow.js",
24
24
  "cli.js",
25
25
  "install.js",
26
+ "playwright.config.ts",
26
27
  "README.md",
27
28
  "PROJECT_GUIDE.md",
28
29
  "prompting_template.md",
@@ -32,7 +33,8 @@
32
33
  "opencode.json",
33
34
  ".qa-workflow.json",
34
35
  "router.md",
35
- ".github/"
36
+ ".github/",
37
+ ".env"
36
38
  ],
37
39
  "license": "MIT",
38
40
  "author": "AI QA Workflow",
@@ -58,5 +60,12 @@
58
60
  "dashboard": "cd qa-dashboard && npm start",
59
61
  "dashboard:dev": "cd qa-dashboard && npx nodemon app.js",
60
62
  "dashboard:stop": "npx kill-port 4000"
63
+ },
64
+ "devDependencies": {
65
+ "@playwright/test": "^1.52.0",
66
+ "allure-playwright": "^3.2.1",
67
+ "allure-commandline": "^2.33.0",
68
+ "@applitools/eyes-playwright": "^1.42.0",
69
+ "@applitools/mcp": "^1.5.0"
61
70
  }
62
71
  }
@@ -0,0 +1,20 @@
1
+ import { defineConfig, devices } from '@playwright/test';
2
+
3
+ export default defineConfig({
4
+ testDir: './tests',
5
+ fullyParallel: true,
6
+ forbidOnly: !!process.env.CI,
7
+ retries: process.env.CI ? 2 : 0,
8
+ workers: process.env.CI ? 1 : undefined,
9
+ use: {
10
+ baseURL: process.env.APP_URL || 'http://localhost:3000',
11
+ trace: 'on-first-retry',
12
+ screenshot: 'only-on-failure',
13
+ },
14
+ projects: [
15
+ {
16
+ name: 'chromium',
17
+ use: { ...devices['Desktop Chrome'] },
18
+ },
19
+ ],
20
+ });
@@ -475,6 +475,18 @@ Use this knowledge to improve future test generation and healing.
475
475
  ---------------------------------------------------
476
476
  ## TOKEN & EFFICIENCY RULES (CRITICAL)
477
477
 
478
+ ### Browser Navigation Rules
479
+ - **Explore once, plan everything** — navigate the app in ONE continuous session per phase. Do NOT re-navigate per scenario.
480
+ - **Snapshot depth ≤ 3** — always use `browser_snapshot` with max depth 3. Full DOM trees (depth 10+) waste 50-100K tokens per snapshot.
481
+ - **Batch all navigation** — group page visits by feature. Visit all pages of a feature in sequence, then move to the next.
482
+ - **Skip non-critical pages** — static content, footers, about pages, legal pages. Focus on auth, main flows, edge cases.
483
+ - **No screenshots during exploration or test logic** — reference pages by path only. Screenshots only on test failure via Playwright config.
484
+
485
+ ### Selector Reuse (Biggest Token Saver)
486
+ - **Generator reads `selectors.json` first** — the Planner already captured selectors. The Generator writes tests without re-navigating.
487
+ - **Only navigate if selectors are missing** — if `.qa-context/selectors.json` is empty for a page, navigate ONCE (depth ≤ 3), save selectors, then proceed.
488
+ - **Save every discovered selector** — update `.qa-context/selectors.json` so no agent ever re-discovers the same element.
489
+
478
490
  ### Execution Rules
479
491
  - **MAX 1 healing attempt per test** — never loop more than once
480
492
  - **Classify failures immediately**: selector issue → fix; app bug → mark `test.fixme()` + document defect
@@ -484,7 +496,6 @@ Use this knowledge to improve future test generation and healing.
484
496
  ### Code Generation Rules
485
497
  - **Never rewrite entire files** — use targeted edits only (change 1-3 lines max)
486
498
  - **Use body text checks**: `page.textContent('body')` instead of fragile element selectors
487
- - **No screenshots during test logic** — capture only on failure via Playwright config
488
499
  - **One assertion per logical check** — no redundant assertions
489
500
  - **Skip image-heavy tests** if not critical to the feature
490
501
  - **Reuse existing helper functions** — don't create new patterns
@@ -1,4 +1,4 @@
1
- const { DIRS, CONFIG, ensureDir, timestamp, log, writeMarkdown } = require('./utils');
1
+ const { ROOT, DIRS, CONFIG, ensureDir, timestamp, log, writeMarkdown } = require('./utils');
2
2
  const context = require('./context-manager');
3
3
  const path = require('path');
4
4
  const fs = require('fs');
@@ -35,7 +35,12 @@ function executeTests(testName, options = {}) {
35
35
  }
36
36
  }
37
37
 
38
- args.push('--reporter', 'list,json');
38
+ const allureAvailable = (() => {
39
+ try { require.resolve('allure-playwright/package.json'); return true; } catch { return false; }
40
+ })();
41
+ const reporters = ['list', 'json'];
42
+ if (allureAvailable) reporters.push('allure-playwright');
43
+ args.push('--reporter', reporters.join(','));
39
44
 
40
45
  if (headed) args.push('--headed');
41
46
  if (retries > 0) args.push('--retries', retries.toString());
@@ -52,7 +57,7 @@ function executeTests(testName, options = {}) {
52
57
 
53
58
  try {
54
59
  const stdout = execSync(`npx ${args.join(' ')}`, {
55
- cwd: DIRS.ROOT,
60
+ cwd: ROOT,
56
61
  encoding: 'utf-8',
57
62
  timeout: 300000,
58
63
  maxBuffer: 10 * 1024 * 1024,
@@ -61,6 +66,8 @@ function executeTests(testName, options = {}) {
61
66
 
62
67
  fs.writeFileSync(outputPath, stdout, 'utf-8');
63
68
 
69
+ const passedTests = extractPassedTests(stdout);
70
+
64
71
  const result = {
65
72
  runId,
66
73
  story: storyName,
@@ -71,7 +78,7 @@ function executeTests(testName, options = {}) {
71
78
  timestamp: new Date().toISOString(),
72
79
  output: stdout.substring(0, 50000),
73
80
  failedTests: [],
74
- passedTests: [],
81
+ passedTests,
75
82
  };
76
83
 
77
84
  writeMarkdown(resultPath, JSON.stringify(result, null, 2));
@@ -82,6 +89,8 @@ function executeTests(testName, options = {}) {
82
89
  }
83
90
  log('EXECUTOR', `Tests passed (${result.duration}ms)`);
84
91
 
92
+ generateAllureReport();
93
+
85
94
  return result;
86
95
  } catch (err) {
87
96
  const stderr = err.stderr || '';
@@ -91,6 +100,7 @@ function executeTests(testName, options = {}) {
91
100
  fs.writeFileSync(outputPath, combinedOutput, 'utf-8');
92
101
 
93
102
  const failedTests = extractFailedTests(combinedOutput);
103
+ const passedTests = extractPassedTests(combinedOutput);
94
104
 
95
105
  const result = {
96
106
  runId,
@@ -103,6 +113,7 @@ function executeTests(testName, options = {}) {
103
113
  error: err.message,
104
114
  output: combinedOutput.substring(0, 50000),
105
115
  failedTests,
116
+ passedTests,
106
117
  };
107
118
 
108
119
  writeMarkdown(resultPath, JSON.stringify(result, null, 2));
@@ -113,6 +124,8 @@ function executeTests(testName, options = {}) {
113
124
  }
114
125
  log('EXECUTOR', `Tests failed (${result.duration}ms) - ${failedTests.length} failure(s)`);
115
126
 
127
+ generateAllureReport();
128
+
116
129
  return result;
117
130
  }
118
131
  }
@@ -148,6 +161,48 @@ function extractFailedTests(output) {
148
161
  return failed;
149
162
  }
150
163
 
164
+ function extractPassedTests(output) {
165
+ const passed = [];
166
+ const lines = output.split('\n');
167
+
168
+ for (const line of lines) {
169
+ const passMatch = line.match(/\s+√\s+\d+\)\s+\[(.+?)\]\s+(.+)/);
170
+ if (passMatch) {
171
+ passed.push({ file: passMatch[1], test: passMatch[2].trim() });
172
+ continue;
173
+ }
174
+
175
+ const passSimple = line.match(/\s+√\s+(.+)/);
176
+ if (passSimple && !line.includes('ms')) {
177
+ passed.push({ test: passSimple[1].trim() });
178
+ }
179
+ }
180
+
181
+ return passed;
182
+ }
183
+
184
+ function generateAllureReport() {
185
+ const allureResults = DIRS.allureResults;
186
+ const allureReport = path.join(ROOT, 'allure-report');
187
+
188
+ if (!fs.existsSync(allureResults) || fs.readdirSync(allureResults).length === 0) return;
189
+
190
+ log('EXECUTOR', 'Auto-generating Allure report...');
191
+ try {
192
+ const { execSync } = require('child_process');
193
+ execSync(`npx allure generate "${allureResults}" --clean -o "${allureReport}"`, {
194
+ cwd: ROOT,
195
+ encoding: 'utf-8',
196
+ timeout: 60000,
197
+ stdio: 'pipe',
198
+ });
199
+ log('EXECUTOR', `Allure report ready: allure-report/index.html`);
200
+ } catch (err) {
201
+ // Allure CLI not available — non-fatal
202
+ log('EXECUTOR', 'Allure CLI not available, skipping HTML report generation');
203
+ }
204
+ }
205
+
151
206
  if (require.main === module) {
152
207
  const testName = process.argv[2];
153
208
  const headed = process.argv.includes('--headed');
package/scripts/utils.js CHANGED
@@ -111,7 +111,7 @@ function loadConfig() {
111
111
  const defaults = {
112
112
  project: { name: 'my-project', description: '', url: 'http://localhost:3000', environment: 'Development' },
113
113
  browser: { type: 'chromium', cdpPort: 9222, headed: false },
114
- test: { timeout: 120000, retries: 0, workers: 1 },
114
+ test: { timeout: 120000, retries: 0, workers: 1, stableSelectors: true },
115
115
  auth: { user: '', credentials: {} },
116
116
  };
117
117