@roopesh.yadava/qa-pack 1.6.0 → 1.6.1
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
18
|
-
|
|
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`
|
|
37
|
-
- After updating, confirm to the user with the
|
|
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 |
|
|
@@ -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).
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roopesh.yadava/qa-pack",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.1",
|
|
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/",
|