@roopesh.yadava/qa-pack 1.6.0 → 1.6.2

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 CHANGED
@@ -92,6 +92,8 @@ and `/write-acceptance-criteria`, which are also available as explicit slash com
92
92
  | `/write-acceptance-criteria PROJ-123` | write-acceptance-criteria | Generates AC, appends to the Jira card description |
93
93
  | `/impacted-tests` / `which tests are impacted by this pull` | impacted-tests | After pulling dev changes into a test branch, reports which Cucumber feature files are at risk — report-only, no card needed |
94
94
  | `set up k6` / `scaffold performance tests` | k6-framework-scaffold | Scaffolds a `k6-performance-tests/` framework (Grafana Cloud, protocol + optional browser layers) with commented templates to fill in — no card needed |
95
+ | `set up mobile testing` / `set up mobilewright` / `scaffold mobile BDD tests` | mobilewright-setup | Scaffolds Cucumber.js + Mobilewright + a living-documentation HTML reporter into a mobile app repo (Expo, bare React Native, or native iOS/Android), plus one real smoke feature/step file — no card needed. Run once, before `mobile-automation` has anything to plug into |
96
+ | `automate mobile PROJ-123` / `write mobile automation for this card` | mobile-automation | Reuse-first Gherkin → step defs → Screen POM → real device run + self-heal for native iOS/Android apps, via Mobile MCP + Mobilewright — the mobile counterpart to `automation` (web) |
95
97
  | `roam mode` / `explore the app` | roam-testing | Card-free exploratory testing — capped breadth-first crawl, report + optional bug filing + charter |
96
98
  | `qa dashboard` / `weekly digest` / `token roi` | qa-insights | Cross-product health dashboard, weekly digest, or token-spend/ROI view — 100% script-generated, no card needed |
97
99
 
@@ -1,185 +1,11 @@
1
- You are a Jira bug reporting assistant. Follow these steps precisely and in order.
2
-
3
- ---
4
-
5
- ## Step 1 — Select a project
6
-
7
- Use the Atlassian MCP tool (`getVisibleJiraProjects`) to fetch all visible projects immediately — do not wait for user input.
8
-
9
- Display the list and ask:
10
- "Which board are you working on? You can reply with the number or the board key:
11
- 1. [KEY] — [Project Name]
12
- 2. [KEY] — [Project Name]
13
- ..."
14
-
15
- Wait for the user to select a project by number or board key. Save the selected project key for the rest of the flow.
16
-
17
- ---
18
-
19
- ## Step 1A/1B — Ask card type
20
-
21
- Ask the user:
22
- "Is this an **Exploratory Bug** (create a new card) or an **Existing Card** (add bugs to an existing one)?"
23
-
24
- Wait for the user's choice before proceeding.
25
-
26
- - If the user chooses **Exploratory Bug** → go to Step 1A
27
- - If the user chooses **Existing Card** → go to Step 1B
28
-
29
- ---
30
-
31
- ## Step 1A — Create a new Exploratory Bug card
32
-
33
- Ask the user: "Please enter a name for the Exploratory Bug card."
34
-
35
- Wait for the user's input.
36
-
37
- Use the Atlassian MCP tool (`createJiraIssue`) to create a new Jira issue in the selected project with:
38
- - **Issue Type:** Bug
39
- - **Summary:** [Card name entered by the user]
40
- - **Labels:** Exploratory
41
-
42
- After creating the issue, use `getTransitionsForJiraIssue` to fetch available transitions, then use `transitionJiraIssue` to move the card to **Backlog** status.
43
-
44
- Once created and moved to Backlog, display:
45
-
46
- > **Exploratory Bug card created:** [CARD-NUMBER] — [Card Name]
47
- > [Link to card]
48
-
49
- Save this card number as the active card for the rest of the flow. Then proceed to Step 2.
50
-
51
- ---
52
-
53
- ## Step 1B — Use an existing card
54
-
55
- Ask the user: "Please enter the card number (e.g. 123 or [KEY]-123) to attach this bug report to."
56
-
57
- Wait for the user's input.
58
-
59
- If the user enters only a number (e.g. `2446`), construct the full card number using the selected project key (e.g. QE-2446).
60
-
61
- Use the Atlassian MCP tool (`getJiraIssue`) to fetch the card details. Display:
62
-
63
- > **Card found:** [CARD-NUMBER] — [Card Summary/Title]
64
-
65
- If the fetched card's issue type is **Bug**, ask:
66
- "Do you want to add the bugs to the **Description** or as a **Comment**?"
67
-
68
- Wait for the user's choice and save it as the **save mode** (Description or Comment) for use in Step 6.
69
-
70
- Save this card number as the active card for the rest of the flow. Then proceed to Step 2.
71
-
72
- ---
73
-
74
- ## Step 2 — Collect bug details
75
-
76
- Ask the user: "Please describe the bug."
77
-
78
- Wait for the user's input. Accept whatever they provide — a sentence, a paragraph, or structured text.
79
-
80
- From the input, infer and derive all necessary fields:
81
- - **Bug Title** — extract or summarise from what was given
82
- - **Expected Outcome** — infer from context if not explicitly stated
83
- - **Actual Outcome** — extract the described problem
84
- - **Steps to Reproduce** — extract or derive from the description
85
-
86
- Do NOT ask the user for any missing fields. Use what was given and proceed.
87
-
88
1
  ---
89
-
90
- ## Step 3Display the formatted bug report
91
-
92
- Show the bug report in this exact format before posting:
93
-
94
- ### Bug No. [n]: [Bug Title]
95
-
96
- ### Expected Outcome:
97
- [Expected Outcome]
98
-
99
- ### Actual Outcome:
100
- [Actual Outcome]
101
-
102
- ### Steps to Reproduce:
103
- [Steps]
104
-
105
- After showing the report, ask:
106
- "Is this the only bug, or do you have another bug to add?"
107
-
108
- - If the user says **yes (another bug)** — go back to Step 2 and collect the next bug. Append it to the report using the same format with an incremented Bug No. Repeat until the user says no more bugs.
109
- - If the user says **no more bugs** — proceed to Step 4.
110
-
2
+ name: bug-report
3
+ description: File a bug to Jira new Exploratory Bug card or attached to an existing card.
4
+ argument-hint: "[bug description | Jira card ID]"
5
+ user-invocable: true
111
6
  ---
112
7
 
113
- ## Step 4 — Ask who to mention
114
-
115
- Before posting, ask:
116
- "Who should I notify about this bug? Please enter the person's name, or type **none** to skip."
117
-
118
- Wait for the user's input.
119
-
120
- - If the user types **none** (or says no one / skip) → set mention as empty, skip Step 5, and proceed directly to Step 6. Do NOT add any mention or "Please check this" line in the report.
121
- - Otherwise → proceed to Step 5.
122
-
123
- ---
124
-
125
- ## Step 5 — Search for the person in Jira
126
-
127
- Use the Atlassian MCP tool (`lookupJiraAccountId`) to search for the name the user entered.
128
-
129
- If multiple results are found, list them and ask:
130
- "Is this the right person? [Name — Account ID]"
131
-
132
- If only one result is found, display that person's name and ask:
133
- "Found: [Full Name]. Is this the right person? (yes / no)"
134
-
135
- Wait for confirmation before proceeding.
136
-
137
- ---
138
-
139
- ## Step 6 — Save the bug report to Jira
140
-
141
- ### If the card is an Exploratory Bug (created in Step 1A):
142
-
143
- Use the Atlassian MCP tool (`editJiraIssue`) to update the **Description** field of the card with the full bug report AND the mention at the end.
144
-
145
- The description body must follow this structure:
146
-
147
- ```
148
- h3. Bug No. [n]: [Bug Title]
149
-
150
- h3. Expected Outcome:
151
- [Expected Outcome]
152
-
153
- h3. Actual Outcome:
154
- [Actual Outcome]
155
-
156
- h3. Steps to Reproduce:
157
- [Steps]
158
-
159
- (repeat the above block for each additional bug if more than one was collected)
160
-
161
- (only include the line below if a person was confirmed in Step 5 — omit it entirely if the user chose none)
162
- @[confirmed person's display name], Please check.
163
- ```
164
-
165
- Do NOT post a comment. Write everything into the Description field of the card.
166
-
167
- ---
168
-
169
- ### If the card is an Existing Card (from Step 1B):
170
-
171
- - If the user chose **Description** → use `editJiraIssue` to update the Description field with the full bug report and mention. Do NOT post a comment.
172
- - If the user chose **Comment** → use `addCommentToJiraIssue` to post one single comment with the full bug report and mention. Do NOT post a second separate comment.
173
-
174
- In both cases the content structure is the same as above.
175
-
176
- ---
177
-
178
- ## Step 7 — Confirm completion
179
-
180
- Show a summary:
181
- - Jira card: [Card number with link]
182
- - Bug report posted: ✓
183
- - Notified: [Confirmed person's name]
8
+ Invoke the `bug-reporting` skill.
184
9
 
185
- Done.
10
+ If the user provided an argument (e.g. a bug description or a Jira card ID), pass it
11
+ directly into the skill as the initial intent so it does not re-ask for input already given.
@@ -14,8 +14,9 @@ user-invocable: true
14
14
  ## Core Workflow
15
15
 
16
16
  0. **Detect Jira card ID** — If the argument matches the pattern `[A-Z]+-[0-9]+` (e.g. `FF-420`, `AA-12`),
17
- fetch the issue using the `getJiraIssue` tool with cloudId `853e134e-6574-491a-a075-1b06f7d4b478`.
18
- Use the issue summary and description as the feature input for the next steps.
17
+ fetch the issue using the `getJiraIssue` tool. Use the issue summary and description as the
18
+ feature input for the next steps. Store the card's own URL (returned by the fetch) for the
19
+ confirmation step later — never hardcode a Jira domain.
19
20
  If the issue has no description, use the summary only and note this in the Assumptions section.
20
21
  If the argument is not a Jira card ID, treat it as a raw feature description and skip to step 1.
21
22
 
@@ -33,8 +34,8 @@ user-invocable: true
33
34
  - Fetch the current description of the issue using `getJiraIssue`
34
35
  - Preserve the full existing description exactly as-is (do NOT remove or overwrite any content, including COS or any other existing sections)
35
36
  - Append the generated acceptance criteria at the very bottom of the existing description, separated by a divider line (`---`)
36
- - Update the issue description using `editJiraIssue` with cloudId `853e134e-6574-491a-a075-1b06f7d4b478`
37
- - After updating, confirm to the user with the Jira issue URL: `https://7edge.atlassian.net/browse/<CARD-ID>`
37
+ - Update the issue description using `editJiraIssue`
38
+ - After updating, confirm to the user with the card's own URL (from the fetch in step 0) — never a hardcoded domain
38
39
 
39
40
  ---
40
41
 
@@ -125,43 +126,3 @@ If the feature description is vague:
125
126
  ---
126
127
 
127
128
  *Assumed: web-based product with a registered user model and a transactional email provider already in place. Adjust if this is a mobile or API-only context.*
128
-
129
-
130
-
131
- <!-- Created by Roopesh Yadava
132
-
133
- Generate detailed documentation for the feature: {{feature_description}}
134
-
135
- Follow these steps:
136
-
137
- 1. **Identify scenarios** — Analyze the feature description and derive all possible user flows, including standard usage and edge cases.
138
-
139
- 2. **Understand expected behavior** — Determine:
140
-
141
- * What the user is trying to achieve
142
- * System responses for valid and invalid inputs
143
- * Possible failure points or UX gaps
144
-
145
- 3. **Generate output** with the following structure:
146
-
147
- ## Acceptance Criteria
148
-
149
- (Leave this section empty — do not list or rewrite anything here.)
150
-
151
- ## Happy Paths
152
-
153
- * List all happy paths using numbered bullets.
154
- * Each step should describe one clear user action or system result.
155
- * Keep steps concise, realistic, and sequential.
156
-
157
- ## Unhappy Paths
158
-
159
- * List all unhappy paths using numbered bullets.
160
- * Include:
161
-
162
- * User errors
163
- * Validation failures
164
- * System issues
165
- * Edge cases
166
- * Missing or incorrect feedback
167
- * Be specific and practical in each scenario. -->
@@ -161,6 +161,13 @@ skill (same status as `roam-testing`/`k6-framework-scaffold`), not wired into qa
161
161
  Phase 2 dispatch, which remains web/Playwright-only via `automation`. Trigger it by name
162
162
  ("automate mobile PROJ-123", "mobile test PROJ-123") rather than through the qa-agent phase menu.
163
163
 
164
+ `mobilewright-setup` sits outside this diagram too — a one-time scaffolder (same role as
165
+ `k6-framework-scaffold`, but for a mobile app's BDD test stack instead of a perf-test stack),
166
+ not a Jira-card-driven skill and not wired into qa-agent. It's what a repo needs *before*
167
+ `mobile-automation` has anything to plug into — run it once on a repo with no existing
168
+ Cucumber/Mobilewright setup, then use `mobile-automation` for ongoing card-driven test
169
+ authoring against what it scaffolded.
170
+
164
171
  ## Skills — One-Line Summary
165
172
 
166
173
  | Skill | Input | Output | MCP Needed |
@@ -168,6 +175,7 @@ Phase 2 dispatch, which remains web/Playwright-only via `automation`. Trigger it
168
175
  | `qa-agent` | Jira card ID or menu choice | Dispatches to correct skill | Atlassian |
169
176
  | `automation` | Jira card ID | Reuse audit + Gherkin + Step Defs + POM + real run (reuse % reported) | Atlassian, Playwright |
170
177
  | `mobile-automation` | Jira card ID | Reuse audit + mobile Gherkin + Step Defs + Screen POM + real device run (reuse % reported) | Atlassian, Mobile MCP, MobileWright/mobilecli |
178
+ | `mobilewright-setup` | Nothing (a repo to scaffold into) — no card needed | Cucumber.js + Mobilewright + living-documentation HTML reporter installed and wired into `package.json`, plus one real smoke feature/step file | None — pure file scaffolding + `npx mobilewright doctor`/local test run |
171
179
  | `manual-testing` | Jira card ID + app URL | Execution report + bugs + charter | Atlassian, Playwright |
172
180
  | `ui-test-figma` | Figma URL + app URL | UI mismatch report, Jira comment | Playwright (CLI+MCP), Figma (optional) |
173
181
  | `accessibility-testing` | Full page URL + Jira card (optional) | WCAG 2.1 A/AA report + Jira bugs | Playwright (CLI+MCP), Atlassian |
@@ -318,11 +318,12 @@ Accessibility Testing Complete
318
318
 
319
319
  ---
320
320
 
321
- ## Final Step — Report to team dashboard (optional, silent)
321
+ ## Final Step — Report to team dashboard
322
322
 
323
- Always the last action of the run, after everything else has printed. This is a no-op
324
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
325
- about it, never retry, never treat a non-zero exit as a run failure.
323
+ Always run this — the last action of the run, after everything else has printed. Do not
324
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
325
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
326
+ never retry, never treat a non-zero exit as a run failure.
326
327
 
327
328
  ```
328
329
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -534,11 +534,12 @@ Selectors written to product context ({N} elements, {N} flows).
534
534
 
535
535
  ---
536
536
 
537
- ## Final Step — Report to team dashboard (optional, silent)
537
+ ## Final Step — Report to team dashboard
538
538
 
539
- Always the last action of the run, after everything else has printed. This is a no-op
540
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
541
- about it, never retry, never treat a non-zero exit as a run failure.
539
+ Always run this — the last action of the run, after everything else has printed. Do not
540
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
541
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
542
+ never retry, never treat a non-zero exit as a run failure.
542
543
 
543
544
  ```
544
545
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -295,11 +295,12 @@ Show a summary:
295
295
 
296
296
  ---
297
297
 
298
- ## Final Step — Report to team dashboard (optional, silent)
298
+ ## Final Step — Report to team dashboard
299
299
 
300
- Always the last action of the run, after everything else has printed. This is a no-op
301
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
302
- about it, never retry, never treat a non-zero exit as a run failure.
300
+ Always run this — the last action of the run, after everything else has printed. Do not
301
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
302
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
303
+ never retry, never treat a non-zero exit as a run failure.
303
304
 
304
305
  ```
305
306
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -112,11 +112,12 @@ The report is the deliverable. Do NOT run any test, do NOT ask whether to run th
112
112
 
113
113
  ---
114
114
 
115
- ## Final Step — Report to team dashboard (optional, silent)
115
+ ## Final Step — Report to team dashboard
116
116
 
117
- Run this after the report is printed and before ending the turn. This is a no-op
118
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
119
- about it, never retry, never treat a non-zero exit as a run failure.
117
+ Always run this command after the report is printed and before ending the turn do not
118
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
119
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
120
+ never retry, never treat a non-zero exit as a run failure.
120
121
 
121
122
  ```
122
123
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -59,11 +59,12 @@ After it runs, tell the tester the next steps:
59
59
 
60
60
  ---
61
61
 
62
- ## Final Step — Report to team dashboard (optional, silent)
62
+ ## Final Step — Report to team dashboard
63
63
 
64
- Always the last action of the run, after everything else has printed. This is a no-op
65
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
66
- about it, never retry, never treat a non-zero exit as a run failure.
64
+ Always run this — the last action of the run, after everything else has printed. Do not
65
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
66
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
67
+ never retry, never treat a non-zero exit as a run failure.
67
68
 
68
69
  ```
69
70
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -630,11 +630,12 @@ Do NOT stream: full charter text, all test results (save to file), full bug repo
630
630
 
631
631
  ---
632
632
 
633
- ## Final Step — Report to team dashboard (optional, silent)
633
+ ## Final Step — Report to team dashboard
634
634
 
635
- Always the last action of the run, after everything else has printed. This is a no-op
636
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
637
- about it, never retry, never treat a non-zero exit as a run failure.
635
+ Always run this — the last action of the run, after everything else has printed. Do not
636
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
637
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
638
+ never retry, never treat a non-zero exit as a run failure.
638
639
 
639
640
  ```
640
641
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -592,8 +592,9 @@ One-line confirmation either way:
592
592
  Mobile context saved → .claude/skills/qa-agent/product_context/{PRODUCT_FOLDER}/context.md ({N} elements, {N} flows).
593
593
  ```
594
594
 
595
- **Then report to the team dashboard (optional, silent)** — using the same values just
596
- written to the Runs Log row:
595
+ **Then always report to the team dashboard do not skip this** — using the same values
596
+ just written to the Runs Log row. The script itself is what decides whether anything
597
+ happens: it is a no-op unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`.
597
598
 
598
599
  ```
599
600
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -0,0 +1,365 @@
1
+ ---
2
+ name: mobilewright-setup
3
+ description: >
4
+ Scaffolds a complete BDD end-to-end test automation setup for a mobile app repo —
5
+ Cucumber.js (Gherkin feature files + step definitions), Mobilewright (a
6
+ Playwright-style device automation framework for iOS/Android, native or
7
+ React Native/Expo), and a "living documentation" HTML report generator
8
+ (multiple-cucumber-html-reporter). Works on any mobile app project: Expo,
9
+ bare React Native, native iOS (UIKit/SwiftUI), or native Android
10
+ (Views/Jetpack Compose) — it detects the project shape and adapts.
11
+ Use this skill when the user asks to "set up mobile testing", "add BDD /
12
+ Cucumber tests", "set up mobilewright", "scaffold e2e tests for the mobile
13
+ app", "add a living documentation / test report generator", "wire up
14
+ test:report / living-doc script", or generally wants end-to-end mobile UI
15
+ test automation added to a repo from scratch. Also use it as a reference
16
+ when adding new feature files or step definitions to a project that
17
+ already has this setup, so conventions stay consistent.
18
+ ---
19
+
20
+ # Mobile BDD Test Setup
21
+
22
+ Sets up a full BDD test-automation stack for a mobile app repo, end to end:
23
+ **Gherkin features → step definitions → Mobilewright device driver → Cucumber
24
+ JSON reports → an HTML "living documentation" report.** Everything is created
25
+ fresh in a single pass, adapted to whatever mobile project you're dropped into.
26
+
27
+ This skill does the scaffolding. It does not know the target app's screens —
28
+ budget time to explore the app's source (or a running build) to write the
29
+ first real feature/step files with correct locators.
30
+
31
+ ## 0. Mental model
32
+
33
+ - **Cucumber.js** runs `.feature` files (Gherkin) against step definitions in
34
+ `test/step-definitions/**/*.mjs`. It owns test discovery, execution, and
35
+ JSON report output.
36
+ - **Mobilewright** (`mobilewright` npm package) is the device driver —
37
+ Playwright's API (`getByRole`, `getByText`, `expect(...).toBeVisible()`,
38
+ auto-waiting) but pointed at a real/emulated/simulated mobile device
39
+ instead of a browser. One config file (`mobilewright.config.mjs`) declares
40
+ which platform/device/app to drive; Cucumber's `World` uses it to launch
41
+ the app before each scenario.
42
+ - **multiple-cucumber-html-reporter** turns the Cucumber JSON output into a
43
+ browsable "living documentation" HTML report — this is the `report` /
44
+ `living-doc.mjs` script.
45
+ - Nothing here is React-Native-specific. Mobilewright drives the OS
46
+ accessibility tree, so this setup works for native iOS/Android apps too —
47
+ only the locators change (see §6).
48
+
49
+ ## 1. Discover the target project
50
+
51
+ Before writing anything, gather facts. Do this with direct reads/greps, not
52
+ guesses:
53
+
54
+ 1. **Package manager & repo shape** — read `package.json`. Note the `name`
55
+ and `version` (used later for report branding). Check for `expo` in
56
+ dependencies (Expo/RN project) vs. presence of `ios/`/`android/` native
57
+ folders only (bare RN or native project).
58
+ 2. **Bundle / package identifier** — look in this order and stop at the
59
+ first match:
60
+ - `app.config.ts` / `app.config.js` / `app.json` (Expo) — read
61
+ `ios.bundleIdentifier` and `android.package`. These are sometimes
62
+ computed by a function (env-variant based, like a `getBundleIdentifier()`
63
+ helper) rather than a plain string — if so, read the function to find
64
+ the actual default value, don't just grab the string "getBundleIdentifier()".
65
+ - `ios/*/Info.plist` → `CFBundleIdentifier`, or `*.xcodeproj` → `PRODUCT_BUNDLE_IDENTIFIER`.
66
+ - `android/app/build.gradle` (or `.kts`) → `applicationId`.
67
+ - If genuinely ambiguous (multiple variants/flavors: dev/qa/preprod/prod),
68
+ ask the user which build variant to test against — don't silently pick one.
69
+ 3. **Existing test setup** — check for `test/`, `e2e/`, `cucumber.js`,
70
+ `*.feature` files, or an existing `mobilewright.config.*`. If any of this
71
+ already exists, this is an **update**, not a fresh scaffold: read what's
72
+ there and extend it rather than overwriting. Never blindly clobber an
73
+ existing `mobilewright.config.*`, `cucumber.js`, or `world.mjs`.
74
+ 4. **Testing platform** — infer if possible (e.g. only `android/` present →
75
+ android; only `ios/` → ios). If both exist and the user didn't say, ask.
76
+
77
+ Only ask the user (via a clarifying question) for facts you could not
78
+ determine from the repo: target **platform** (`ios`/`android`), a
79
+ **device** to run against (a specific simulator/emulator name, or "use
80
+ auto-discovery"), and the **bundle/app id** if it's genuinely ambiguous.
81
+ Everything else, infer and proceed — this skill runs under an
82
+ auto/no-interruption workflow by default, so don't stop for things you can
83
+ reasonably derive.
84
+
85
+ ## 2. Install dependencies
86
+
87
+ Detect the package manager from the lockfile present (`package-lock.json` →
88
+ npm, `yarn.lock` → yarn, `pnpm-lock.yaml` → pnpm, `bun.lockb` → bun) and
89
+ install as **devDependencies**:
90
+
91
+ ```bash
92
+ npm install -D @cucumber/cucumber mobilewright multiple-cucumber-html-reporter
93
+ ```
94
+
95
+ (swap `npm install -D` for the equivalent `yarn add -D` / `pnpm add -D` /
96
+ `bun add -d` as appropriate). Do not add these as runtime `dependencies`.
97
+
98
+ ## 3. Create `mobilewright.config.mjs`
99
+
100
+ Write to the project root. Fill in the platform/bundleId/device values
101
+ discovered or confirmed in step 1 — never leave placeholder text in the
102
+ committed file.
103
+
104
+ ```javascript
105
+ import { defineConfig } from 'mobilewright';
106
+
107
+ export default defineConfig({
108
+ platform: '{{PLATFORM}}', // 'android' | 'ios'
109
+ bundleId: '{{BUNDLE_ID}}', // e.g. com.example.myapp(.qa)
110
+ deviceId: '{{DEVICE_ID}}', // named emulator/simulator profile, if the user gave one — omit this line if using auto-discovery instead
111
+ deviceType: '{{DEVICE_TYPE}}', // 'emulator' | 'simulator' | 'real-device' — omit if unknown
112
+ timeout: 30_000,
113
+ });
114
+ ```
115
+
116
+ Notes:
117
+ - `deviceId`/`deviceType` are optional — Mobilewright auto-discovers the
118
+ first booted device matching `platform` if omitted. Prefer auto-discovery
119
+ unless the user specifically named a device/profile.
120
+ - If the project already targets both platforms via CI, consider the
121
+ `projects` array (Mobilewright's multi-device/platform matrix — see the
122
+ `projects` option in the mobilewright package's own `README.md` under
123
+ `node_modules/mobilewright/README.md`, or https://mobilewright.dev) instead
124
+ of a single flat config. Only do this if the user asks for multi-platform
125
+ runs; default to a single flat config otherwise.
126
+ - A one-line comment noting *why* a value was picked (e.g. "QA build shared
127
+ for testing") is fine and matches existing convention, but keep it to one
128
+ line.
129
+
130
+ ## 4. Create `cucumber.js`
131
+
132
+ Root-level Cucumber profile. This wires feature discovery, step import, and
133
+ report output:
134
+
135
+ ```javascript
136
+ module.exports = {
137
+ default: [
138
+ 'test/features/**/*.feature',
139
+ '--import test/step-definitions/**/*.mjs',
140
+ `--format json:reports/cucumber-report-${Date.now()}.json`,
141
+ '--format summary',
142
+ '--format progress-bar',
143
+ ].join(' '),
144
+ };
145
+ ```
146
+
147
+ Keep the feature/step-definition globs as-is unless the target repo already
148
+ uses a different test root (e.g. `e2e/` instead of `test/`) — match whatever
149
+ already exists rather than introducing a second convention.
150
+
151
+ ## 5. Create `test/step-definitions/support/world.mjs`
152
+
153
+ This is the Cucumber `World` — it owns the device lifecycle (launch before
154
+ each scenario, close after). This file is intentionally app-agnostic; do not
155
+ add app-specific logic here.
156
+
157
+ ```javascript
158
+ import { setWorldConstructor, setDefaultTimeout, Before, After } from '@cucumber/cucumber';
159
+ import { ios, android } from 'mobilewright';
160
+ import config from '../../../mobilewright.config.mjs';
161
+
162
+ setDefaultTimeout(config.timeout ?? 30_000);
163
+
164
+ class MobileWorld {
165
+ async launch() {
166
+ const launcher = config.platform === 'android' ? android : ios;
167
+ this.device = await launcher.launch({
168
+ bundleId: config.bundleId,
169
+ deviceId: config.deviceId,
170
+ deviceName: config.deviceName,
171
+ installApps: config.installApps,
172
+ });
173
+ this.screen = this.device.screen;
174
+ }
175
+
176
+ async teardown() {
177
+ await this.device?.close();
178
+ }
179
+ }
180
+
181
+ setWorldConstructor(MobileWorld);
182
+
183
+ Before(async function () {
184
+ await this.launch();
185
+ });
186
+
187
+ After(async function () {
188
+ await this.teardown();
189
+ });
190
+ ```
191
+
192
+ Every step definition gets `this.device` and `this.screen` from this World —
193
+ step files never construct their own device connection.
194
+
195
+ ## 6. Write the first feature + step definitions
196
+
197
+ Don't hand-wave this — a setup with zero real assertions isn't done. Find one
198
+ real, stable entry point in the app under test and write one smoke scenario
199
+ against it:
200
+
201
+ 1. **Find a locator.** Grep the app source for existing test hooks in
202
+ priority order (this matches Mobilewright's own locator priority:
203
+ `getByTestId` > `getByRole` > `getByLabel` > `getByText`):
204
+ - React Native/Expo: search for `testID=`, `accessibilityLabel=`,
205
+ `accessibilityRole=` props on the first/home screen's root and key
206
+ interactive elements.
207
+ - Native iOS: `accessibilityIdentifier` / `accessibilityLabel` in
208
+ SwiftUI/UIKit source.
209
+ - Native Android: `contentDescription` / view `id`s, or Compose
210
+ `Modifier.testTag(...)` / `semantics { }`.
211
+ - If nothing is tagged yet, don't invent testIDs blindly — either add a
212
+ minimal `testID`/`accessibilityIdentifier` to the one element you need
213
+ (small, targeted, and tell the user you did it), or fall back to
214
+ `getByText('...')` against real on-screen copy you found in source.
215
+ 2. **If you can run a booted simulator/emulator**, `npx mobilewright inspect`
216
+ opens a live element inspector against the connected device — use it to
217
+ confirm real locators instead of guessing from source alone.
218
+ 3. Write `test/features/<area>.feature`:
219
+
220
+ ```gherkin
221
+ Feature: <Screen or flow name>
222
+
223
+ Scenario: <one concrete, observable outcome>
224
+ Given <a starting state, e.g. "the app has launched">
225
+ Then <an assertion tied to a real locator>
226
+ ```
227
+
228
+ 4. Write the matching `test/step-definitions/<area>.steps.mjs`:
229
+
230
+ ```javascript
231
+ import { Given, When, Then } from '@cucumber/cucumber';
232
+ import { expect } from 'mobilewright';
233
+
234
+ Given('the app has launched', async function () {
235
+ await expect(this.screen.getByTestId('<real-test-id>')).toBeVisible();
236
+ });
237
+ ```
238
+
239
+ Step conventions to follow:
240
+ - One `Given`/`When`/`Then` per file topic; keep step text reusable across
241
+ scenarios in the same feature area rather than one-off phrasing per
242
+ scenario.
243
+ - Prefer `getByTestId` / `getByRole` over `getByText`/coordinate taps —
244
+ they're the least brittle across locale and copy changes.
245
+ - Never hardcode secrets (passwords, tokens) directly in `.feature` files if
246
+ the repo has an env/secrets convention already (`.env`, CI variable
247
+ groups, etc.) — follow that repo's existing pattern instead. If unsure, ask.
248
+
249
+ ## 7. Create `scripts/living-doc.mjs`
250
+
251
+ Generates the browsable HTML report from the Cucumber JSON output. Pull
252
+ branding from `package.json` — never hardcode a project name:
253
+
254
+ ```javascript
255
+ import { readFileSync } from 'fs';
256
+ import { generate } from 'multiple-cucumber-html-reporter';
257
+ import config from '../mobilewright.config.mjs';
258
+
259
+ const { name, version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url)));
260
+
261
+ const displayName = '{{DISPLAY_NAME}}'; // human-readable project name, e.g. derived from package.json `name`
262
+
263
+ generate({
264
+ jsonDir: 'reports/',
265
+ reportPath: 'living-documentation/',
266
+ pageTitle: displayName,
267
+ pageFooter: `<div class="created-by"><p>${displayName} QA</p></div>`,
268
+ reportName: displayName,
269
+ metadata: {
270
+ device: config.deviceName ?? config.deviceId,
271
+ platform: { name: config.platform === 'ios' ? 'iOS' : 'Android', version: '' },
272
+ app: { name, version },
273
+ },
274
+ customData: {
275
+ title: 'Run info',
276
+ data: [{ label: 'Project', value: name }],
277
+ },
278
+ });
279
+ ```
280
+
281
+ Derive `displayName` from `package.json`'s `name` (title-cased, hyphens/
282
+ underscores replaced with spaces) unless the repo already has an obvious
283
+ human-readable product name elsewhere (README title, app display name in
284
+ `app.config.*`/`app.json`) — prefer that if present.
285
+
286
+ ## 8. Wire up `package.json` scripts
287
+
288
+ Add (don't replace unrelated existing scripts):
289
+
290
+ ```json
291
+ {
292
+ "scripts": {
293
+ "test": "cucumber-js",
294
+ "test:doctor": "mobilewright doctor",
295
+ "report": "node scripts/living-doc.mjs",
296
+ "test:report": "npm run test && npm run report"
297
+ }
298
+ }
299
+ ```
300
+
301
+ If a `test` script already exists for a different test runner (unit tests,
302
+ etc.), don't clobber it — use a distinct name instead
303
+ (`test:e2e`/`test:bdd`/`test:mobile`) and say so to the user, then adjust
304
+ `test:report` to reference the new name.
305
+
306
+ ## 9. Update `.gitignore`
307
+
308
+ Ensure generated test artifacts aren't committed. Add if missing:
309
+
310
+ ```
311
+ # cucumber JSON reports + generated living documentation
312
+ reports
313
+ living-documentation
314
+
315
+ # test app binaries (built artifacts, not source)
316
+ test/app/
317
+ ```
318
+
319
+ Only add the `test/app/` line if the repo's test setup installs app binaries
320
+ locally (check whether `installApps` is used in the config); skip it
321
+ otherwise.
322
+
323
+ ## 10. Verify the environment
324
+
325
+ Run the doctor check and report its output to the user — don't just assume
326
+ success:
327
+
328
+ ```bash
329
+ npx mobilewright doctor
330
+ ```
331
+
332
+ This validates Xcode/Android SDK/emulator-simulator availability and tells
333
+ you exactly what's missing. Surface any failures verbatim; don't try to
334
+ silently work around a missing SDK/toolchain.
335
+
336
+ If a device is booted and reachable, also do a real run to confirm the
337
+ scaffold works end to end:
338
+
339
+ ```bash
340
+ npm run test:report
341
+ ```
342
+
343
+ ## 11. Summary to the user
344
+
345
+ After setup, tell the user concretely:
346
+ - What was installed and created (file list).
347
+ - Which platform/device/bundle id the config targets, and why (inferred vs.
348
+ user-provided).
349
+ - The doctor check result.
350
+ - How to run tests day to day: `npm test` (or the chosen script name),
351
+ `npm run report` / `npm run test:report`, and where the living-doc report
352
+ lands (`living-documentation/index.html`).
353
+ - That new features go in `test/features/*.feature` with matching
354
+ `test/step-definitions/*.steps.mjs`, and that `world.mjs` under
355
+ `test/step-definitions/support/` should stay app-agnostic — device
356
+ lifecycle only, no scenario-specific logic.
357
+
358
+ ## Reference
359
+
360
+ Full Mobilewright API (locators, assertions, config options, CLI commands)
361
+ is documented in the installed package at `node_modules/mobilewright/README.md`
362
+ and `node_modules/mobilewright/reference.md` once installed — read those
363
+ directly rather than relying on memory when writing non-trivial step
364
+ definitions (e.g. WebView bridging, multi-device `projects` config, role
365
+ mapping tables).
@@ -370,9 +370,10 @@ Write `context.md`, then print one line:
370
370
  Product context saved → .claude/skills/qa-agent/product_context/{PRODUCT_FOLDER}/context.md
371
371
  ```
372
372
 
373
- ### 6f — Report to team dashboard (optional, silent)
373
+ ### 6f — Report to team dashboard
374
374
 
375
- Immediately after 6e, using the same values just written to the Runs Log row, shell out:
375
+ Always run this immediately after 6e do not skip it. Using the same values just written
376
+ to the Runs Log row, shell out:
376
377
 
377
378
  ```
378
379
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -382,8 +383,9 @@ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
382
383
  --reuse {reuse % number, omit for manual-only runs}
383
384
  ```
384
385
 
385
- This is a no-op unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never
386
- print anything about it, never retry, never treat a non-zero exit as a run failure.
386
+ The script itself is what decides whether anything happens: it is a no-op unless
387
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
388
+ never retry, never treat a non-zero exit as a run failure.
387
389
 
388
390
  ---
389
391
 
@@ -188,11 +188,12 @@ If yes: `Skill: test-charter`, pre-filled with the roam report path just saved.
188
188
 
189
189
  ---
190
190
 
191
- ## Final Step — Report to team dashboard (optional, silent)
191
+ ## Final Step — Report to team dashboard
192
192
 
193
- Always the last action of the run, after everything else has printed. This is a no-op
194
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
195
- about it, never retry, never treat a non-zero exit as a run failure.
193
+ Always run this — the last action of the run, after everything else has printed. Do not
194
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
195
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
196
+ never retry, never treat a non-zero exit as a run failure.
196
197
 
197
198
  ```
198
199
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -301,11 +301,12 @@ TEST CHARTER PUBLISHED
301
301
 
302
302
  ---
303
303
 
304
- ## Final Step — Report to team dashboard (optional, silent)
304
+ ## Final Step — Report to team dashboard
305
305
 
306
- Always the last action of the run, after everything else has printed. This is a no-op
307
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
308
- about it, never retry, never treat a non-zero exit as a run failure.
306
+ Always run this — the last action of the run, after everything else has printed. Do not
307
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
308
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
309
+ never retry, never treat a non-zero exit as a run failure.
309
310
 
310
311
  ```
311
312
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
@@ -239,11 +239,12 @@ Run `end + report + session` token close-out.
239
239
 
240
240
  ---
241
241
 
242
- ## Final Step — Report to team dashboard (optional, silent)
242
+ ## Final Step — Report to team dashboard
243
243
 
244
- Always the last action of the run, after everything else has printed. This is a no-op
245
- unless `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env` never print anything
246
- about it, never retry, never treat a non-zero exit as a run failure.
244
+ Always run this — the last action of the run, after everything else has printed. Do not
245
+ skip it. The script itself is what decides whether anything happens: it is a no-op unless
246
+ `QA_DASHBOARD_REPO`/`QA_DASHBOARD_TOKEN` are set in `.env`. Never print anything about it,
247
+ never retry, never treat a non-zero exit as a run failure.
247
248
 
248
249
  ```
249
250
  node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs report-run \
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@roopesh.yadava/qa-pack",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "AI-powered QA agent skills for Claude Code — manual testing, BDD automation, accessibility, UI/Figma diff, bug reporting",
5
5
  "scripts": {
6
- "postinstall": "node bin/postinstall.js"
6
+ "postinstall": "node bin/postinstall.js",
7
+ "test": "node --test test/"
7
8
  },
8
9
  "files": [
9
10
  "bin/",