@nhonh/qabot 1.1.0 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nhonh/qabot",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "AI-powered universal QA automation tool. Import any project, AI analyzes and runs tests across all layers.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -153,11 +153,22 @@ async function runTest(feature, options) {
153
153
 
154
154
  const route = featureConfig?.route || guessRoute(feature);
155
155
 
156
+ let routesContext = "";
157
+ const routeFiles = await findFiles(
158
+ projectDir,
159
+ "src/routes/*.{js,jsx,ts,tsx}",
160
+ );
161
+ if (routeFiles.length > 0) {
162
+ const routeContent = await safeReadFile(routeFiles[0]);
163
+ if (routeContent) routesContext = routeContent.slice(0, 3000);
164
+ }
165
+
156
166
  try {
157
167
  const spec = await generateE2ESpec(ai, feature, {
158
168
  baseUrl,
159
169
  sourceCode,
160
170
  route,
171
+ routes: routesContext,
161
172
  authProvider: config.auth?.provider || "none",
162
173
  useCases,
163
174
  });
@@ -1,4 +1,4 @@
1
- export const VERSION = "1.1.0";
1
+ export const VERSION = "1.2.0";
2
2
  export const TOOL_NAME = "qabot";
3
3
 
4
4
  export const PROJECT_TYPES = [
@@ -33,17 +33,21 @@ ${code}
33
33
  ## CRITICAL: Architecture rules (DO NOT CHANGE)
34
34
  1. MUST use \`test.describe.serial\` — all tests share ONE browser session
35
35
  2. MUST use \`let page\` at describe scope — shared across all tests
36
- 3. \`test.beforeAll\` creates page + login + navigate ONCE
36
+ 3. \`test.beforeAll\` creates page via \`browser.newPage()\` ONLY
37
37
  4. \`test.afterAll\` closes page ONCE
38
38
  5. Each \`test()\` does NOT take \`{ page }\` argument — uses shared \`page\`
39
+ 6. Tests are SEQUENTIAL JOURNEY — TC-01 opens landing, TC-02 logs in, TC-03+ navigate and test
40
+ 7. Login happens inside a test (TC-02), NOT in beforeAll
39
41
 
40
42
  ## Common fixes
41
- 1. Wrong selector — use getByRole, getByText, getByTestId
42
- 2. Timing — add waitForLoadState("networkidle") or waitForTimeout(2000)
43
- 3. Element not visible — add .first() for multiple matches, or more specific selector
44
- 4. Navigation — use full URL with baseURL prefix
45
- 5. Auth — ensure login completes before assertions
46
- 6. Timeout — increase timeout for slow elements: { timeout: 15000 }
43
+ 1. Wrong selector — use getByRole, getByText, getByTestId, or .first() for multiple matches
44
+ 2. Timing — add waitForLoadState("networkidle") or waitForTimeout(2000) after navigation
45
+ 3. Element not visible — scroll into view, wait for animation, check if inside modal/iframe
46
+ 4. Navigation — use FULL URL (e.g. "${context.baseUrl}/refer-a-friend") not relative paths
47
+ 5. Auth — if login fails, wrap in try/catch and skip dependent tests gracefully
48
+ 6. Timeout — increase to { timeout: 15000 } or { timeout: 30000 } for slow pages
49
+ 7. Multiple matches — use .first() or more specific parent: page.locator(".section").getByText()
50
+ 8. Page changed — after clicking navigation links, await page.waitForURL() before assertions
47
51
 
48
52
  Return the COMPLETE fixed test file. No markdown fences.`;
49
53
 
@@ -1,11 +1,13 @@
1
1
  export function buildE2EPrompt(featureName, context) {
2
2
  const sourceSection = context.sourceCode
3
- ? `\n## Source Code Analysis\n\`\`\`\n${context.sourceCode.slice(0, 8000)}\n\`\`\`\n`
3
+ ? `\n## Source Code (analyze navigation, hooks, API calls, user actions, conditions)\n\`\`\`\n${context.sourceCode.slice(0, 10000)}\n\`\`\`\n`
4
4
  : "";
5
5
 
6
- const routeSection = context.route
7
- ? `\n## Page Route: ${context.route}\n`
8
- : "";
6
+ const routeSection = context.routes
7
+ ? `\n## All Application Routes\n${context.routes}\n`
8
+ : context.route
9
+ ? `\n## Feature Route: ${context.route}\n`
10
+ : "";
9
11
 
10
12
  const useCaseSection = context.useCases?.length
11
13
  ? `\n## QA Use Cases\n${context.useCases.map((uc) => `### ${uc.scenario}\n${uc.steps.map((s, i) => `${i + 1}. ${s}`).join("\n")}`).join("\n\n")}\n`
@@ -14,81 +16,102 @@ export function buildE2EPrompt(featureName, context) {
14
16
  const baseUrl = context.baseUrl || "http://localhost:3000";
15
17
  const route = context.route || "/" + featureName;
16
18
 
17
- return `You are an expert Playwright E2E automation engineer.
19
+ return `You are an expert QA automation engineer designing REAL user journey tests.
18
20
 
19
21
  ## Feature: ${featureName}
20
22
  ## Base URL: ${baseUrl}
21
- ## Page Route: ${route}
22
23
  ## Auth: ${context.authProvider || "none"}
23
- ${sourceSection}${useCaseSection}
24
+ ${routeSection}${sourceSection}${useCaseSection}
24
25
 
25
- ## CRITICAL ARCHITECTURE ONE BROWSER SESSION
26
+ ## CRITICAL: This is a JOURNEY-BASED test, not a page screenshot test.
26
27
 
27
- All tests run in a SINGLE browser session. The browser opens ONCE, logs in ONCE, then navigates between tests WITHOUT closing.
28
+ You MUST test REAL USER FLOWS across multiple pages. A user does NOT just open one page they:
29
+ 1. Land on the app → see landing/home page
30
+ 2. Sign in or are already signed in
31
+ 3. Navigate to the feature via menu/link/URL
32
+ 4. Interact with the feature (click buttons, fill forms, read data)
33
+ 5. Feature may redirect them to other pages (FAQ, account, modals)
34
+ 6. Come back, verify state changed
28
35
 
29
- Use this EXACT structure:
36
+ ## ARCHITECTURE Single Browser, Serial Tests
30
37
 
31
- \`\`\`
38
+ \`\`\`javascript
32
39
  const { test, expect } = require("@playwright/test");
33
40
  const { login } = require("../helpers/auth.js");
34
41
 
35
- test.describe.serial("${featureName}", () => {
42
+ test.describe.serial("${featureName} - User Journey", () => {
36
43
  let page;
37
44
 
38
45
  test.beforeAll(async ({ browser }) => {
39
46
  page = await browser.newPage();
40
- await login(page, "${baseUrl}");
41
- await page.goto("${baseUrl}${route}");
42
- await page.waitForLoadState("networkidle");
43
- await page.screenshot({ path: "e2e/screenshots/${featureName}-00-initial.png", fullPage: true });
44
47
  });
45
48
 
46
49
  test.afterAll(async () => {
47
- await page.close();
48
- });
49
-
50
- test("TC-01: page loads and displays main content", async () => {
51
- // use the shared 'page' variable — NOT the argument
52
- await expect(page).toHaveURL(/${featureName.replace(/-/g, "[-/]")}/i);
53
- // verify main content visible
54
- await page.screenshot({ path: "e2e/screenshots/${featureName}-01-loaded.png", fullPage: true });
50
+ if (page) await page.close();
55
51
  });
56
52
 
57
- test("TC-02: next test case...", async () => {
58
- // continue using shared 'page' same browser, same session
59
- });
53
+ // Tests use shared 'page' — same browser, same session, same cookies
54
+ // Each test() does NOT take { page } argument
60
55
  });
61
56
  \`\`\`
62
57
 
63
- ## IMPORTANT RULES:
64
- 1. Use \`test.describe.serial\` — tests run IN ORDER on the SAME page
65
- 2. Use \`let page\` declared at describe level — shared across ALL tests
66
- 3. \`test.beforeAll\` creates page + login + navigate ONCE
67
- 4. \`test.afterAll\` closes page ONCE
68
- 5. Each \`test()\` does NOT take \`{ page }\` argument — uses the shared \`page\` variable
69
- 6. Take screenshot in EVERY test with path: \`e2e/screenshots/${featureName}-{number}-{name}.png\`
70
- 7. Use \`page.getByRole()\`, \`page.getByText()\`, \`page.getByTestId()\` selectors
71
- 8. After navigation within tests: \`await page.waitForLoadState("networkidle")\`
72
- 9. Use \`{ timeout: 15000 }\` for slow-loading elements
73
- 10. Prefix each test name with TC-XX: for tracking
74
-
75
- ## GENERATE 8-12 TEST CASES:
76
-
77
- ### P0 Critical (must have):
78
- - TC-01: Page loads, main content visible, URL correct
79
- - TC-02: Key data displays correctly (lists, cards, amounts)
80
- - TC-03: Primary user action (main button/form/interaction)
81
- - TC-04: Navigation within the feature works
82
-
83
- ### P1 Important:
84
- - TC-05: Secondary actions (links, toggles, modals)
85
- - TC-06: Different UI states (loading, empty, error)
86
- - TC-07: Form validation if applicable
87
- - TC-08: Responsive check (viewport resize)
88
-
89
- ### P2 Edge cases:
90
- - TC-09: Edge cases relevant to the feature
91
- - TC-10: Back navigation / breadcrumbs
92
-
93
- Return ONLY JavaScript code. No markdown fences. No explanation.`;
58
+ ## GENERATE 10-15 TEST CASES as a SEQUENTIAL USER JOURNEY:
59
+
60
+ ### Phase 1: Entry & Authentication (TC-01 to TC-03)
61
+ - TC-01: Open app landing page verify it loads → screenshot
62
+ - TC-02: Sign in flow → click sign in → fill credentials → submit → verify redirect to lobby/home
63
+ - TC-03: Verify authenticated state user menu visible, correct username/avatar
64
+
65
+ ### Phase 2: Navigation to Feature (TC-04 to TC-05)
66
+ - TC-04: Navigate to "${featureName}" via menu, link, or direct URL "${route}" → verify page loads
67
+ - TC-05: Verify feature page layout key sections, headers, data loaded (not empty/loading)
68
+
69
+ ### Phase 3: Core Feature Interactions (TC-06 to TC-10)
70
+ READ THE SOURCE CODE and generate tests for the ACTUAL user interactions:
71
+ - What buttons does the page have? Test clicking them.
72
+ - What data does the page display? Verify it shows correctly.
73
+ - What actions can the user take? (share, copy, claim, submit, toggle, select)
74
+ - What modals/popups appear? Verify they open and close.
75
+ - What state changes happen? (loading → loaded, button text changes, counters update)
76
+
77
+ ### Phase 4: Cross-Page Navigation (TC-11 to TC-12)
78
+ - Does the feature link to other pages? (FAQ, account, game details, etc.)
79
+ - Test navigating AWAY and coming BACK — verify state is preserved or reset correctly
80
+ - Test browser back button behavior
81
+
82
+ ### Phase 5: Edge Cases & Cleanup (TC-13 to TC-15)
83
+ - Test with different viewport (mobile: 375x667)
84
+ - Test error states if possible (disconnect, slow network)
85
+ - Verify page after refresh (F5) does state persist?
86
+
87
+ ## PLAYWRIGHT RULES:
88
+ 1. Use \`test.describe.serial\` all tests share ONE page
89
+ 2. \`let page\` at describe scope — shared across ALL tests
90
+ 3. \`test.beforeAll\` → \`browser.newPage()\` ONLY (login happens in TC-02)
91
+ 4. Each \`test()\` does NOT take \`{ page }\` argument
92
+ 5. Use \`page.goto("${baseUrl}${route}")\` with FULL URL for navigation
93
+ 6. After navigation: \`await page.waitForLoadState("networkidle")\`
94
+ 7. Screenshot EVERY test: \`await page.screenshot({ path: "e2e/screenshots/${featureName}-TC{XX}.png", fullPage: true })\`
95
+ 8. Selectors priority: \`getByRole()\` > \`getByText()\` > \`getByTestId()\` > \`locator()\`
96
+ 9. For slow elements: \`{ timeout: 15000 }\`
97
+ 10. For navigation between pages, always verify URL changed: \`expect(page).toHaveURL()\`
98
+ 11. After clicking links/buttons that navigate: \`await page.waitForLoadState("networkidle")\`
99
+ 12. For modals: \`await expect(page.getByRole("dialog")).toBeVisible()\`
100
+ 13. Use \`try/catch\` for optional elements that may not exist (feature flags, A/B tests)
101
+ 14. If auth is "${context.authProvider}":
102
+ \`\`\`
103
+ const { login } = require("../helpers/auth.js");
104
+ // In TC-02:
105
+ await login(page, "${baseUrl}");
106
+ \`\`\`
107
+
108
+ ## IMPORTANT:
109
+ - Tests are SEQUENTIAL — TC-02 login result carries to TC-03, TC-04, etc.
110
+ - Do NOT navigate to "${route}" in beforeAll — let TC-01 to TC-04 handle the journey
111
+ - TC-01 starts at "${baseUrl}/" (landing page)
112
+ - Generate MEANINGFUL assertions, not just "page exists"
113
+ - Each test must VERIFY something specific with expect()
114
+
115
+ Return ONLY JavaScript code. No markdown fences. No explanation.
116
+ Generate a COMPLETE spec file with 10-15 tests.`;
94
117
  }
@@ -70,8 +70,8 @@ module.exports = defineConfig({
70
70
  fullyParallel: false,
71
71
  retries: 0,
72
72
  workers: 1,
73
- timeout: 60000,
74
- expect: { timeout: 10000 },
73
+ timeout: 90000,
74
+ expect: { timeout: 15000 },
75
75
  reporter: [
76
76
  ["line"],
77
77
  ["json", { outputFile: "../qabot-reports/playwright/results.json" }],