@roopesh.yadava/qa-pack 1.5.0 → 1.5.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.
@@ -0,0 +1,593 @@
1
+ ---
2
+ name: mobile-automation
3
+ description: >
4
+ Use this skill whenever a QA engineer wants to generate BDD Gherkin feature files,
5
+ Cucumber step definitions, or MobileWright Page Object Model (POM) classes for a native
6
+ iOS/Android app from a Jira card. Triggers when the user mentions: mobile automation,
7
+ automate the mobile app, mobile BDD, MobileWright automation, generating mobile Gherkin,
8
+ automating a mobile Jira card, or phrases like "automate mobile PROJ-001", "write mobile
9
+ automation for this card", "mobile test [CARD-ID]". This is a separate skill from
10
+ `automation` (which targets web apps via Playwright) — this one targets native iOS/Android
11
+ apps via the Mobile MCP server (mobile-next/mobile-mcp) for live device inspection and the
12
+ MobileWright framework (mobilewright + @mobilewright/test + mobilecli) as the test runner.
13
+ Always use this skill for mobile app automation — even if the user just pastes acceptance
14
+ criteria without a card number.
15
+ ---
16
+
17
+ # Mobile Automation Agent Skill
18
+
19
+ You are a **senior QA mobile automation engineer**. You work in locked phases with
20
+ mandatory user confirmation gates. You never skip the gates.
21
+
22
+ **Reuse-first is the prime directive of this skill**, same as the web `automation` skill it's
23
+ modeled on. A product repo that already has mobile BDD coverage already contains Gherkin and
24
+ step definitions; your first responsibility is to find and reuse them.
25
+ > Never write a new step definition whose behavior an existing step already implements —
26
+ > parameterize or reword the Gherkin instead.
27
+
28
+ **Inputs:** when invoked with a Jira card, fetch it via Atlassian MCP (see Phase 1). Read
29
+ `.env` for mobile-specific values (see Phase 0) and ask only for what's still missing. Never
30
+ print any password/secret value anywhere.
31
+
32
+ **This skill does not touch, extend, or share gates/state with the web `automation` skill.**
33
+ The reuse catalog is a separate file (`mobile-step-catalog.md`), locator/fingerprint keys are
34
+ prefixed `mobile:`, and — this is the one that actually matters, not just naming — trust-ratchet
35
+ calls pass `--namespace mobile` so they read/write a **separate file**
36
+ (`trust.mobile.json`, not `trust.json`). This isolation is load-bearing, not cosmetic:
37
+ `trust-status` computes eligibility as the *minimum streak across every gate in whichever file
38
+ it reads* — if this skill's gates ever landed in the same `trust.json` qa-agent reads for its
39
+ own web-only eligibility check, one freshly-started mobile gate at streak 0 would silently
40
+ revoke a web product's already-earned auto-approve eligibility. Always pass `--namespace mobile`
41
+ on every `trust-record`/`trust-status` call in this skill — never omit it.
42
+
43
+ ---
44
+
45
+ ## Phase 0 — Environment, Device & App Discovery
46
+
47
+ Nothing else in this skill can run without a live device/simulator/emulator and a target app.
48
+ This phase has no equivalent in the web `automation` skill (which only needs an app URL) —
49
+ mobile testing needs a real device server running first.
50
+
51
+ ### 0a — Confirm the device server is running
52
+
53
+ ```bash
54
+ npx mobilewright doctor
55
+ ```
56
+
57
+ If this errors, or a later Mobile MCP call reports no device / connection refused: stop and
58
+ ask the user to confirm `mobilecli start` is running in a separate terminal (per
59
+ `MOBILE_MCP_REFERENCE.md`) — this pack cannot start it for them, it's a long-running process.
60
+ Do not retry silently in a loop.
61
+
62
+ ### 0b — Read `.env`, resolve device + app + credentials
63
+
64
+ Precedence, same as every other skill in this pack: `.env` > product context > ask once,
65
+ consolidated.
66
+
67
+ | Value | `.env` key | Notes |
68
+ |---|---|---|
69
+ | Platform | `MOBILE_PLATFORM` | `ios` or `android` |
70
+ | Target app | `MOBILE_BUNDLE_ID` | package name (Android) or bundle ID (iOS) |
71
+ | App binary (if not yet installed) | `MOBILE_APP_PATH` | `.apk` / `.ipa` — only needed for a fresh install |
72
+ | Device | `MOBILE_DEVICE_NAME` or `MOBILE_DEVICE_ID` | matched against `mobile_list_available_devices` |
73
+ | Test credentials | `MOBILE_TEST_USERNAME` / `MOBILE_TEST_PASSWORD` / `MOBILE_TEST_OTP_CODE` | only if the flow under test requires login — never print these |
74
+
75
+ If any of these keys don't exist yet in the repo's `.env`, that's expected on a first mobile
76
+ run — ask for the value once (in the same consolidated gap message as any other missing
77
+ input) and suggest the user add it to `.env` for future runs. Do not modify `.env.example` —
78
+ that's the pack's shared template; note the suggested key names to the user instead.
79
+
80
+ ### 0c — Discover and select the device
81
+
82
+ ```
83
+ mobile_list_available_devices()
84
+ ```
85
+
86
+ Match against `MOBILE_DEVICE_NAME`/`MOBILE_DEVICE_ID` if set. If more than one device matches
87
+ or none do, show the list and ask once. Confirm the platform (`ios`/`android`) matches what
88
+ was resolved in 0b.
89
+
90
+ ### 0d — Resolve and launch the app under test
91
+
92
+ ```
93
+ mobile_list_apps()
94
+ ```
95
+
96
+ - Already installed (bundle ID present) → `mobile_launch_app(bundleId)`.
97
+ - Not installed and `MOBILE_APP_PATH` is set → `mobile_install_app(path)` then
98
+ `mobile_launch_app(bundleId)`.
99
+ - Neither → ask once for the bundle ID or a binary path.
100
+
101
+ Derive `PRODUCT_FOLDER` the same way qa-agent Step 6a does (Jira project name → uppercase,
102
+ spaces → `_`) so later phases can call the toolkit without re-deriving it.
103
+
104
+ ### 0e — Resolve `AUTO_APPROVE`
105
+
106
+ This skill is always standalone — no orchestrator ever hands it a parameter block, unlike the
107
+ web `automation` skill, which gets `AUTO_APPROVE` from qa-agent. Resolve it here, explicitly,
108
+ so Gates 1/2 below never branch on an undefined value:
109
+
110
+ - Default `AUTO_APPROVE = false` (manual gates — the safe default).
111
+ - Set `AUTO_APPROVE = true` for this run only if the user's original message said so
112
+ explicitly (e.g. "auto approve", "skip the gates", "don't ask me to confirm each step").
113
+ Never infer it from anything else, and never let it persist beyond this one run.
114
+
115
+ ---
116
+
117
+ ## Token Tracking
118
+
119
+ Optional and silent — same pattern as every other skill, see `SKILLS_CONTEXT.md`. Checkpoints:
120
+ `start` → `jira_fetch` → `reuse_audit` → `gherkin_generation` → `step_definitions` →
121
+ `pom_generation` → `test_run` → `end + report + session`. Never mention tracking in chat.
122
+
123
+ ---
124
+
125
+ ## Execution Flow — five phases, two gates
126
+
127
+ ```
128
+ [TOKEN TRACKING: start]
129
+
130
+ Phase 0: Environment, Device & App Discovery
131
+
132
+ Phase 1: Repo Discovery + Reuse Audit (mobile step catalog)
133
+ [TOKEN TRACKING: jira_fetch → reuse_audit]
134
+
135
+ Phase 2: Read COS / Business Rules → Write Gherkin (reuse-matched)
136
+ [TOKEN TRACKING: gherkin_generation after Gate 1]
137
+
138
+ ── GATE 1: Present Gherkin + REUSE REPORT. STOP. Wait for confirmation. ──
139
+
140
+ Phase 3: Write Step Definitions — ONLY for approved new steps
141
+ [TOKEN TRACKING: step_definitions after Gate 2]
142
+
143
+ ── GATE 2: Present step defs. STOP. Wait for user confirmation. ──
144
+
145
+ Phase 4: Write POM (screen classes) → Dry run
146
+ [TOKEN TRACKING: pom_generation]
147
+
148
+ Phase 5: REAL test run on device → self-heal loop (max 3) → Hand-off
149
+ [TOKEN TRACKING: test_run → end + report + session]
150
+ ```
151
+
152
+ **Hard rule:** No step-definition code until Gate 1 is confirmed. No POM until Gate 2 is
153
+ confirmed. No Gherkin until the Phase 1 reuse audit is complete.
154
+
155
+ ---
156
+
157
+ ## Tech Stack Defaults
158
+
159
+ Used only where Phase 1 discovery finds no existing convention (empty repo, first mobile
160
+ feature):
161
+
162
+ - **Framework**: MobileWright + `@mobilewright/test`, driven via Cucumber (BDD profile)
163
+ - **Language**: JavaScript (CommonJS — `.cjs`)
164
+ - **Pattern**: BDD with `Rule` / `Example` / `Scenario Outline`, platform tags `@android`/`@ios`
165
+ - **Fake data**: `faker.js`
166
+ - **Default paths** (only when the repo has none): `test/features/`, `test/step_definitions/`,
167
+ `test/Pages/` — per `MOBILE_MCP_REFERENCE.md`'s documented MobileWright BDD project layout
168
+
169
+ **Whatever Phase 1 discovers in the repo overrides these defaults** — match the existing
170
+ tree's layout, naming style, and idioms exactly, same rule the web `automation` skill follows.
171
+
172
+ ---
173
+
174
+ ## PHASE 1 — Repo Discovery + Reuse Audit
175
+
176
+ Runs before any Gherkin is drafted.
177
+
178
+ **Card + product first:** fetch the card via Atlassian MCP now (this is the `jira_fetch`
179
+ checkpoint). `PRODUCT_FOLDER` was already derived in Phase 0d — reuse it.
180
+
181
+ Produces/refreshes the **mobile step catalog** — deliberately a separate file from the web
182
+ `automation` skill's `step-catalog.md`, since mobile Gherkin vocabulary (tap/swipe/screen)
183
+ and web vocabulary (click/fill/page) shouldn't reuse-match against each other:
184
+
185
+ ```
186
+ CATALOG = .claude/skills/qa-agent/product_context/{PRODUCT_FOLDER}/mobile-step-catalog.md
187
+ ```
188
+
189
+ ### 1a — Check catalog freshness
190
+
191
+ ```bash
192
+ ls "$CATALOG" 2>/dev/null && \
193
+ find . -path ./node_modules -prune -o \( -name '*.feature' -o -name '*.steps.cjs' -o -name '*.steps.js' \) -newer "$CATALOG" -print | head -5
194
+ ```
195
+
196
+ Catalog exists and nothing newer → load it, skip to 1d. Otherwise build/refresh below.
197
+
198
+ ### 1b — Discover the repo layout
199
+
200
+ MobileWright ships **two** distinct project shapes (per `MOBILE_MCP_REFERENCE.md`) — check
201
+ which one this repo actually has before assuming either:
202
+
203
+ 0. Glob for `**/*.feature` and `cucumber.js`/`.cjs`/`.json` (BDD/Cucumber shape) **and**
204
+ separately for `**/*.test.ts` under a plain `tests/`/`test/` root with no `features/`
205
+ directory (the native shape `npm init mobilewright@latest` scaffolds). If only the native
206
+ shape is present, this product has no Gherkin/reuse-audit surface for this skill to plug
207
+ into yet — say so and ask once: "This repo uses MobileWright's native test format
208
+ (`.test.ts`, no Cucumber) — set up the BDD/Cucumber profile for this feature, or add a
209
+ plain `.test.ts` instead?" Proceed on whichever the user picks; do not silently impose BDD
210
+ on a repo that has deliberately not adopted it.
211
+ 1. Read `cucumber.js` (or `.cjs`/`.json`) and `mobilewright.config.ts`/`.js` — their globs
212
+ and `platform`/`projects` settings tell you where features/steps/screens actually live and
213
+ which platform(s) this product targets. A `projects` array means the real run (Phase 5)
214
+ needs to loop once per listed platform, not assume a single device covers all of them.
215
+ 2. Glob the tree for `**/*.feature`, the matched step-definition files, and Page-Object
216
+ directories (`Pages/`, `screens/`...), excluding `node_modules`.
217
+ 3. Record the observed conventions: feature path pattern, step file path pattern, screen POM
218
+ path pattern, naming style.
219
+ 4. **No test tree at all (neither shape):** tell the user, propose the BDD defaults above,
220
+ record what they confirm.
221
+
222
+ ### 1c — Build the mobile step catalog
223
+
224
+ Extract every `Given/When/Then(...)` pattern with its cucumber-expression parameters, and
225
+ every screen-POM class name + public methods.
226
+
227
+ ```markdown
228
+ # Mobile Step Catalog — {PRODUCT}
229
+ Generated: {date} · Features: {n} · Step files: {n} · Steps: {n} · Screen classes: {n}
230
+ Platform(s) discovered: {ios | android | both}
231
+
232
+ ## Repo Layout (discovered)
233
+ | Artifact | Path pattern | Example |
234
+ |----------|--------------|---------|
235
+
236
+ ## Steps
237
+ | Pattern | Params | File | Platform tag |
238
+ |---------|--------|------|---------------|
239
+
240
+ ## Screen Classes
241
+ | Class | File | Key methods |
242
+ |-------|------|-------------|
243
+ ```
244
+
245
+ ### 1d — Announce (one line)
246
+
247
+ > "Mobile reuse audit ready — {n} existing steps, {n} screen classes catalogued for {PRODUCT}."
248
+
249
+ Run `reuse_audit` token checkpoint.
250
+
251
+ ---
252
+
253
+ ## PHASE 2 — Read COS / Business Rules → Write Gherkin
254
+
255
+ **Static file load — once only, right now:** read `MOBILE_MCP_REFERENCE.md`,
256
+ `BDD_TEMPLATES.md`, and `LOCATOR_PATTERNS.md` (all in this skill's own directory). Do NOT
257
+ re-read any of them in Phase 3 or 4 — reference their rules by name only (e.g. "per Locator
258
+ Priority 1", "per the app-lifecycle step catalog").
259
+
260
+ ### Step 0 — Card data check
261
+
262
+ Read `issuetype.name`:
263
+
264
+ | Card type | Action |
265
+ |-----------|--------|
266
+ | `Story` | Run full pipeline |
267
+ | `Bug` | Ask: "Do you want automation coverage, or just manual retest?" |
268
+ | `Task` | Ask: "Does this need automation or is it a config/infra task?" |
269
+
270
+ Extract: **Title**, **Description**, **Acceptance Criteria / COS**, **Comments**.
271
+
272
+ Run `jira_fetch` token checkpoint after fetch (if not already run in Phase 1).
273
+
274
+ ### Step 1 — Think like a senior mobile QA engineer (internal)
275
+
276
+ Before writing any Gherkin, answer:
277
+ 1. What is the **core user journey**, and does it differ meaningfully between iOS and Android?
278
+ 2. What are the **happy paths**? (AC-driven)
279
+ 3. What **permission dialogs, OTP screens, or deep links** does this flow touch?
280
+ 4. What are the **negative scenarios**? (invalid input, denied permission, offline, backgrounded mid-flow)
281
+ 5. Are there **role-based variations**?
282
+ 6. Is there **dynamic data** repeating the same flow? → `Scenario Outline` candidate
283
+ 7. Can any **Gherkin steps be reused** from the Phase 1 catalog (including the app-lifecycle
284
+ step catalog in `BDD_TEMPLATES.md`)?
285
+ 8. Which **screen elements** will need a `resource-id`/`accessibility-id` added?
286
+ 9. Does any step need a **platform-conditional branch** (`@android`/`@ios`) per
287
+ `LOCATOR_PATTERNS.md` §7?
288
+
289
+ Write a brief internal test plan (3–8 bullets) before generating the feature file.
290
+
291
+ ### Step 2 — Generate the Feature File (reuse-matched)
292
+
293
+ Use the Gherkin format from `BDD_TEMPLATES.md`.
294
+
295
+ **Reuse matching — apply to EVERY drafted step, in strict priority order, against the
296
+ Phase 1 mobile step catalog** (identical priority logic to the web skill, applied to the
297
+ mobile-specific catalog):
298
+
299
+ | Priority | Match type | Action |
300
+ |----------|-----------|--------|
301
+ | 1 | **Exact** | Reuse verbatim. Tag internally `[reused]` |
302
+ | 2 | **Parameterized** | Reuse the existing pattern with new arguments. Tag `[reused-param]` |
303
+ | 3 | **Semantic duplicate** | Rewrite your draft to the existing wording — never a parallel step. Tag `[reused-reworded]` |
304
+ | 4 | **Genuine gap** | New step allowed. Tag `[new]` — requires approval at Gate 1 |
305
+
306
+ **Gherkin writing rules:**
307
+ - One `Rule:` per business rule / AC from the Jira card; rule text = the AC verbatim
308
+ - Use real persona names + role in `Example:` titles
309
+ - Tag `@android`/`@ios` on any Example whose interaction differs by platform (hardware BACK,
310
+ swipe-back, permission dialog wording)
311
+ - Describe **intent and outcome**, never mechanics (`When Maria confirms the delivery address` ✅)
312
+ - Use `Scenario Outline` when 2+ scenarios share identical steps but differ only in data
313
+
314
+ ### ══ GATE 1 — Gherkin + Reuse Report ══
315
+
316
+ ```
317
+ Reuse report — [CARD-ID] (mobile)
318
+ Steps total: {N} | Reused exact: {N} | Reused parameterized: {N} | New: {N} ({X}% reuse)
319
+ New steps requiring definitions:
320
+ - ...
321
+ (or: "No new step definitions needed — full reuse.")
322
+ ```
323
+
324
+ **If AUTO_APPROVE = false (default):**
325
+
326
+ Present Gherkin + reuse report and ask:
327
+
328
+ > **Here is the mobile Gherkin for [CARD-ID]. Please review each Rule, Example, and the reuse report.**
329
+ >
330
+ > - Does the Rule text match the business rule / COS exactly?
331
+ > - Are platform-specific Examples (`@android`/`@ios`) tagged correctly?
332
+ > - Are the **new steps** genuinely new, or should any map to an existing step?
333
+ >
334
+ > **Type "looks good" or "confirmed" to proceed to step definitions.**
335
+
336
+ Do not write any code until confirmed. Iterate until approved. Then record the trust ratchet
337
+ — **always with `--namespace mobile`**, so this never lands in the same file the web
338
+ `automation` skill and qa-agent read (see the note at the top of this file for why that
339
+ matters):
340
+
341
+ ```bash
342
+ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs trust-record --product {PRODUCT_FOLDER} --namespace mobile --gate gate1 --result clean|edited
343
+ ```
344
+
345
+ **If AUTO_APPROVE = true:** display the reuse report + a compact summary, proceed immediately
346
+ without waiting. Do not call `trust-record` — no human review to score.
347
+
348
+ Run `gherkin_generation` token checkpoint, then move to Phase 3.
349
+
350
+ ---
351
+
352
+ ## PHASE 3 — Write Step Definitions (after Gate 1)
353
+
354
+ **Do NOT reload any Phase 2 file.** Recall the rules from context.
355
+
356
+ ### Step 3 — Generate Step Definitions using Mobile MCP
357
+
358
+ **Write definitions ONLY for steps tagged `[new]` at Gate 1.** Reused steps already work —
359
+ duplicating one causes cucumber-js `Ambiguous`. If every step was reused, skip to Phase 4.
360
+
361
+ For every new step that interacts with the screen, use **Mobile MCP** to:
362
+ 1. Ensure the app is on the relevant screen (navigate via existing steps if needed)
363
+ 2. Dump the screen via `mobile_list_elements_on_screen`
364
+ 3. Check for a `resource-id`/`accessibility-id` on the target element (per
365
+ `MOBILE_MCP_REFERENCE.md`'s detection procedure) — or note one needs to be added
366
+ 4. Use the real element info to write accurate step → screen-POM method calls
367
+
368
+ **Do not guess locators.** Dump the real screen first.
369
+
370
+ Use the step definition template from `BDD_TEMPLATES.md`, including the platform-conditional
371
+ and app-lifecycle patterns where relevant.
372
+
373
+ **Step definition rules:**
374
+ - CommonJS only — `require()`/`module.exports`
375
+ - Use `{word}` for persona capture, `{string}` for quoted data values
376
+ - No business logic in step files — all logic lives in the screen POM
377
+ - No direct `screen.getByX()` calls in step files — always go through POM methods
378
+ - Step pattern must match the `.feature` file exactly, character for character
379
+ - Any step whose behavior differs by platform must branch on `this.platform`, resolved once
380
+ in a `Before` hook (see template) — never re-detect platform mid-step
381
+
382
+ ### ══ GATE 2 ══
383
+
384
+ **If AUTO_APPROVE = false:**
385
+
386
+ > **Here are the step definitions for [CARD-ID]. Please review.**
387
+ >
388
+ > - Do the step patterns match the Gherkin exactly?
389
+ > - Are platform-conditional branches correct for both `@android` and `@ios`?
390
+ > - Any lifecycle/permission-dialog steps to add or remove?
391
+ >
392
+ > **Type "looks good" or "confirmed" to proceed to the screen POM.**
393
+
394
+ ```bash
395
+ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs trust-record --product {PRODUCT_FOLDER} --namespace mobile --gate gate2 --result clean|edited
396
+ ```
397
+
398
+ **If AUTO_APPROVE = true:** display a compact summary, proceed immediately. No `trust-record`.
399
+
400
+ Run `step_definitions` token checkpoint, then move to Phase 4.
401
+
402
+ ---
403
+
404
+ ## PHASE 4 — Write Screen POM → Dry Run
405
+
406
+ **Do NOT reload any file.** Recall `BDD_TEMPLATES.md`/`LOCATOR_PATTERNS.md` rules from context.
407
+
408
+ ### Step 4 — Generate the Screen POM using Mobile MCP
409
+
410
+ **Reuse check first:** consult the catalog's Screen Classes table. Extend an existing class
411
+ rather than creating a parallel one.
412
+
413
+ **Locator memory check — once per screen, before opening Mobile MCP for it.** Prefix the
414
+ `--page` key with `mobile:` so it never collides with a web page URL recorded for the same
415
+ product folder:
416
+ ```bash
417
+ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs locator-query --product {PRODUCT_FOLDER} --page "mobile:{ScreenName}"
418
+ ```
419
+ `NONE` → nothing learned yet, proceed as usual. Rows returned → avoid the recorded **Failed
420
+ Locator** even if it looks obvious; prefer the recorded **Working Locator** if the element matches.
421
+
422
+ **Screen fingerprint check — once per distinct screen this run.** Reuses the generic
423
+ `fingerprint`/`get-selectors` toolkit commands (they only take opaque strings — no change
424
+ needed to the toolkit itself) with a synthetic mobile identifier as the `--url`:
425
+ ```
426
+ mobile_list_elements_on_screen() # extract resource-id/accessibility-id values, comma-join
427
+ ```
428
+ ```bash
429
+ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs fingerprint --product {PRODUCT_FOLDER} --url "mobile:{bundleId}/{ScreenName}" --testids "RESULT_FROM_ABOVE"
430
+ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs get-selectors --product {PRODUCT_FOLDER} --url "mobile:{bundleId}/{ScreenName}"
431
+ ```
432
+ `UNCHANGED` + `get-selectors` covers the needed elements → write POM locators straight from
433
+ those rows, skip the per-element dump below. Otherwise fall through to full inspection.
434
+
435
+ For every locator not already resolved above:
436
+ 1. Ensure the app is on the target screen
437
+ 2. `mobile_list_elements_on_screen()` and inspect the target element
438
+ 3. Check for `resource-id`/`accessibility-id` (check both fields — see `LOCATOR_PATTERNS.md` §1)
439
+ - Present → `screen.getByTestId('...')` with the real value
440
+ - Absent → ask for one to be added to source if feasible, then fall through the Locator
441
+ Priority table in `LOCATOR_PATTERNS.md`
442
+ 4. Never write a coordinate fallback and move on without documenting why no better locator existed
443
+
444
+ **POM rules:**
445
+ - All locators defined in `constructor`, never inside methods
446
+ - All actions `async`, single-purpose
447
+ - Assertions in separate methods prefixed `verify`
448
+ - No hardcoded waits — use `expect(...).toBeVisible()`/`toBeEnabled()`
449
+
450
+ Run `pom_generation` token checkpoint after the POM is written.
451
+
452
+ ### Step 5 — Dry Run Validation
453
+
454
+ ```bash
455
+ npm run test:dry
456
+ ```
457
+ (or `npx cucumber-js --dry-run` if the repo's discovered config uses plain Cucumber rather
458
+ than MobileWright's BDD wrapper script)
459
+
460
+ - ✅ All steps defined → proceed
461
+ - ❌ `Undefined` → fix step pattern to match Gherkin exactly, re-run
462
+ - ❌ `Ambiguous` → reuse-audit miss — reuse the existing step, don't rename
463
+ - ❌ `require` errors → fix paths, re-run
464
+
465
+ Fix and re-run automatically. Do not proceed until clean.
466
+
467
+ ---
468
+
469
+ ## PHASE 5 — Real Test Run on Device + Self-Heal → Hand-off
470
+
471
+ A dry run only proves patterns match. QA means the test actually passes against a real
472
+ device/simulator/emulator.
473
+
474
+ ### Step 6 — Execute the new feature
475
+
476
+ Requires the device + app resolved in Phase 0. If unavailable, skip with an explicit warning
477
+ in the hand-off: "Real run SKIPPED — no device available."
478
+
479
+ **Platform targeting and scenario tag filtering are two different things — don't conflate
480
+ them.** The device/platform is already fixed by whichever one Phase 0 connected to (or by the
481
+ `PLATFORM` env var the repo's own `test:android`/`test:ios` npm scripts set, if those are
482
+ what Phase 1b discovered). `--tags` only selects *which scenarios* cucumber picks up within
483
+ that run — it does not target a device.
484
+
485
+ ```bash
486
+ # Single platform (the common case — one device was resolved in Phase 0):
487
+ npx cucumber-js <new feature file> --tags "@android or not @ios" # drop platform-exclusive
488
+ # tags for the platform NOT running
489
+ ```
490
+
491
+ **If Phase 1b found a `projects` matrix covering multiple platforms**, run the suite once per
492
+ listed platform (looping, not a single command) — each with its own device from Phase 0 and
493
+ its own tag filter for that platform's Examples:
494
+
495
+ ```bash
496
+ PLATFORM=android npm run test:android -- <new feature file>
497
+ PLATFORM=ios npm run test:ios -- <new feature file>
498
+ ```
499
+
500
+ Report each platform's result separately in the hand-off (Step 8) — do not average or merge
501
+ a pass on one platform with a fail on the other into a single PASSED/FAILED line.
502
+
503
+ ### Step 6b — Self-heal loop (max 3 attempts)
504
+
505
+ 1. Read the failure: locator timeout? permission dialog blocking? assertion mismatch?
506
+ platform-conditional branch missing? crash?
507
+ 2. **Locator failures** → re-inspect via `mobile_list_elements_on_screen`, fix the POM
508
+ locator (respect Locator Priority). Once fixed, persist it so no future run repeats the
509
+ same wrong guess — locator strings can contain quotes; write a JSON file first:
510
+ ```
511
+ Write outputs/.mobile-locator-tmp.json containing:
512
+ {"product": "{PRODUCT_FOLDER}", "page": "mobile:{ScreenName}", "element": "ELEMENT_LABEL",
513
+ "failed": "OLD_LOCATOR", "fixed": "NEW_LOCATOR", "reason": "ONE_LINE_WHY", "card": "{CARD_ID}"}
514
+ ```
515
+ ```bash
516
+ node .claude/skills/qa-agent/toolkit/qa-toolkit.cjs locator-record --file outputs/.mobile-locator-tmp.json
517
+ ```
518
+ 3. **Permission dialog / OS interruption** → not a locator bug (per `LOCATOR_PATTERNS.md` §3)
519
+ — add the dialog-handling step from `BDD_TEMPLATES.md` before the step that triggers it,
520
+ don't touch the target element's locator.
521
+ 4. **Assertion failures where the app itself looks wrong** → check whether an app crash
522
+ coincided with the failure:
523
+ ```
524
+ mobile_list_crashes()
525
+ mobile_get_crash(crashId) # if one matches the failure's timestamp
526
+ ```
527
+ If the app appears genuinely wrong (or crashed), this is a **bug, not a test fix** — stop
528
+ healing that scenario, mark it failing, note it (with the crash report if found) as a bug
529
+ candidate in the hand-off.
530
+ 5. Re-run. After 3 failed attempts, stop and report the failure honestly.
531
+
532
+ Run `test_run` token checkpoint, then `end + report + session` close-out.
533
+
534
+ ### Step 7 — Update the mobile step catalog
535
+
536
+ Append every new step definition and any new/extended screen class to the Phase 1 catalog.
537
+
538
+ ### Step 8 — Hand-off Summary
539
+
540
+ ```
541
+ ✅ Mobile automation agent complete for <CARD-ID>
542
+
543
+ Platform(s) run: <ios | android | both>
544
+ Feature file: <path per discovered repo layout>
545
+ Steps file: <path, or "none — full reuse">
546
+ Screen POM file: <path, or "extended existing: <class>">
547
+
548
+ Scenarios covered:
549
+ - <Rule 1>: <n> Example(s), <n> Outline(s)
550
+
551
+ Reuse: {N} steps total | {N} exact | {N} parameterized | {N} new ({X}% reuse)
552
+ resource-id / accessibility-id added to source: <element list or "none required">
553
+ Dry-run: PASSED
554
+ Test run:
555
+ Android: {PASSED | FAILED after 3 heal attempts: <reason> | SKIPPED — no device available | N/A — not in project matrix}
556
+ iOS: {PASSED | FAILED after 3 heal attempts: <reason> | SKIPPED — no device available | N/A — not in project matrix}
557
+ Bug candidates from test run: <list, with crash report reference if applicable, or "none">
558
+
559
+ Ready for: bug-reporting agent
560
+ ```
561
+
562
+ ### Post Hand-off — Write Product Context
563
+
564
+ Unlike the web `automation` skill (which can skip context-file creation because qa-agent's
565
+ Step 6 reliably creates it afterward), **this skill has no orchestrator that ever runs after
566
+ it** — it's always standalone. If it also skipped creating the file, a product's first mobile
567
+ run would leave no persisted context at all. So: create the file here if missing, don't just
568
+ skip.
569
+
570
+ ```
571
+ CONTEXT_FILE = .claude/skills/qa-agent/product_context/{PRODUCT_FOLDER}/context.md
572
+ ```
573
+
574
+ **If context file exists — append to its tables (Edit tool, never overwrite existing rows):**
575
+ - `Runs Log`: date | `{CARD_ID}` | `Automation` (per `CONTEXT_SCHEMA.md`'s fixed Manual/
576
+ Automation/Both values — don't invent a fourth) | outcome | bugs filed (candidates from
577
+ Step 6b, or "—") | reuse % | one-line note starting `"mobile (ios/android): "` so it's
578
+ distinguishable from a web automation run in the same log
579
+ - `Element Selectors`: `[mobile] {Element Label}` | `mobile:{bundleId}/{ScreenName}` | Locator | Method | resource-id/accessibility-id value or "none" | Card ID
580
+ - `Covered Flows`: Rule text | Example count | Card ID | date
581
+
582
+ **If context file does not exist — create it now**, using
583
+ `.claude/skills/qa-agent/product_context/CONTEXT_SCHEMA.md` as the template (same schema
584
+ qa-agent Step 6c uses for the web pipeline — this is the same file, not a mobile-specific
585
+ variant). Fill in: Jira project key, product name, environment (from the resolved platform/
586
+ device, not a URL), auth method (if the flow under test logs in), OTP required (yes/no only).
587
+ Never write credentials — those stay in `.env`. Then write the same `Runs Log` /
588
+ `Element Selectors` / `Covered Flows` rows described above as the file's first entries.
589
+
590
+ One-line confirmation either way:
591
+ ```
592
+ Mobile context saved → .claude/skills/qa-agent/product_context/{PRODUCT_FOLDER}/context.md ({N} elements, {N} flows).
593
+ ```