@sun-asterisk/sungen 3.2.28 → 3.2.29
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/dist/capabilities/discover.d.ts +29 -0
- package/dist/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +144 -10
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/capabilities/registry.d.ts +18 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +25 -0
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +9 -0
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.js +1 -1
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/dashboard/templates/index.html +1 -1
- package/dist/exporters/feature-parser.d.ts +1 -1
- package/dist/exporters/feature-parser.js +1 -1
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +14 -1
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/item-labels.d.ts +35 -0
- package/dist/exporters/matrix/item-labels.d.ts.map +1 -0
- package/dist/exporters/matrix/item-labels.js +90 -0
- package/dist/exporters/matrix/item-labels.js.map +1 -0
- package/dist/exporters/matrix/render-coverage-sheet.d.ts +14 -0
- package/dist/exporters/matrix/render-coverage-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-coverage-sheet.js +160 -0
- package/dist/exporters/matrix/render-coverage-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-overview-sheet.d.ts +20 -0
- package/dist/exporters/matrix/render-overview-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-overview-sheet.js +36 -0
- package/dist/exporters/matrix/render-overview-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-testcase-sheet.d.ts +30 -0
- package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-testcase-sheet.js +156 -0
- package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +41 -31
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +72 -425
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/testcase-summary-band.d.ts +30 -0
- package/dist/exporters/matrix/testcase-summary-band.d.ts.map +1 -0
- package/dist/exporters/matrix/testcase-summary-band.js +75 -0
- package/dist/exporters/matrix/testcase-summary-band.js.map +1 -0
- package/dist/exporters/matrix/wording.d.ts.map +1 -1
- package/dist/exporters/matrix/wording.js +13 -0
- package/dist/exporters/matrix/wording.js.map +1 -1
- package/dist/exporters/matrix/xlsx-cells.d.ts +38 -0
- package/dist/exporters/matrix/xlsx-cells.d.ts.map +1 -0
- package/dist/exporters/matrix/xlsx-cells.js +52 -0
- package/dist/exporters/matrix/xlsx-cells.js.map +1 -0
- package/dist/exporters/xlsx-report-builder.d.ts +12 -1
- package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
- package/dist/exporters/xlsx-report-builder.js +10 -2
- package/dist/exporters/xlsx-report-builder.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +7 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +3 -3
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/appium/os-support.d.ts +53 -0
- package/dist/generators/test-generator/adapters/appium/os-support.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/appium/os-support.js +200 -0
- package/dist/generators/test-generator/adapters/appium/os-support.js.map +1 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
- package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +7 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +7 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +5 -1
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +38 -2
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +37 -1
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +33 -6
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +71 -7
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +8 -0
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +40 -1
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +100 -17
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +23 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +78 -12
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/harness/audit.d.ts +3 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +51 -28
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/capability-plan.d.ts +4 -0
- package/dist/harness/capability-plan.d.ts.map +1 -1
- package/dist/harness/capability-plan.js +32 -2
- package/dist/harness/capability-plan.js.map +1 -1
- package/dist/harness/catalog/drivers.yaml +1 -1
- package/dist/harness/catalog/universal-viewpoints.yaml +145 -0
- package/dist/harness/parse.d.ts +6 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +1 -1
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/repair.d.ts.map +1 -1
- package/dist/harness/repair.js +8 -1
- package/dist/harness/repair.js.map +1 -1
- package/dist/harness/sensors.d.ts +48 -0
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +26 -1
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts +10 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +23 -2
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +48 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +18 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +11 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +10 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +58 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
- package/dist/orchestrator/templates/readme.md +1 -1
- package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
- package/dist/orchestrator/templates/wdio.conf.ts +105 -1
- package/package.json +3 -3
- package/src/capabilities/discover.ts +146 -10
- package/src/capabilities/registry.ts +30 -0
- package/src/cli/commands/audit.ts +9 -0
- package/src/cli/commands/capability.ts +1 -1
- package/src/dashboard/templates/index.html +1 -1
- package/src/exporters/feature-parser.ts +1 -1
- package/src/exporters/matrix/build.ts +13 -1
- package/src/exporters/matrix/item-labels.ts +78 -0
- package/src/exporters/matrix/render-coverage-sheet.ts +168 -0
- package/src/exporters/matrix/render-overview-sheet.ts +56 -0
- package/src/exporters/matrix/render-testcase-sheet.ts +178 -0
- package/src/exporters/matrix/render-xlsx.ts +67 -448
- package/src/exporters/matrix/testcase-summary-band.ts +79 -0
- package/src/exporters/matrix/wording.ts +13 -0
- package/src/exporters/matrix/xlsx-cells.ts +56 -0
- package/src/exporters/xlsx-report-builder.ts +16 -2
- package/src/generators/gherkin-parser/index.ts +1 -1
- package/src/generators/test-generator/adapters/appium/os-support.ts +176 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
- package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +7 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +7 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
- package/src/generators/test-generator/code-generator.ts +5 -1
- package/src/generators/test-generator/diagnostics.ts +39 -2
- package/src/generators/test-generator/patterns/index.ts +78 -8
- package/src/generators/test-generator/patterns/types.ts +8 -0
- package/src/generators/test-generator/step-mapper.ts +107 -17
- package/src/generators/test-generator/utils/selector-resolver.ts +88 -12
- package/src/harness/audit.ts +55 -30
- package/src/harness/capability-plan.ts +33 -1
- package/src/harness/catalog/drivers.yaml +1 -1
- package/src/harness/catalog/universal-viewpoints.yaml +145 -0
- package/src/harness/parse.ts +7 -1
- package/src/harness/repair.ts +8 -1
- package/src/harness/sensors.ts +75 -1
- package/src/harness/viewpoint-ledger.ts +26 -5
- package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +48 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +18 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +11 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +10 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +58 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
- package/src/orchestrator/templates/readme.md +1 -1
- package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
- package/src/orchestrator/templates/wdio.conf.ts +105 -1
|
@@ -309,7 +309,7 @@ Security: [S1 – admin only]
|
|
|
309
309
|
**Depth is a GATE dimension (harness-roadmap P1) — self-raise, never silently go shallow:**
|
|
310
310
|
- For every data-correctness theme the catalog marks `depth.requires: data-assertion`, emit its `depth.template` shape by **default** — don't wait for the repair loop. `sungen audit` measures `businessDepth` (ratio of these scenarios that assert data) against an intent threshold (functional ≥ 0.70); below it the **gate FAILs**.
|
|
311
311
|
- **Verify depth deterministically before the gate:** run `sungen depth-lint --screen <name>`. It classifies every shallow business-critical scenario into **deepen-in-place** (add the theme's value assertion — the printed `template` is a hint, fit it to the actual claim) vs **cross-screen** (route to a flow / `@manual:Mx`). Clear the `deepen` list first — this is the mechanical way to hit `businessDepth` on the first pass instead of churning repair rounds. Never fake a value assertion onto a visibility/behavior scenario the lint over-counts; leave it and note the over-count.
|
|
312
|
-
- `depth.cross_screen: true` (cart / detail / filter / brand correctness) → write the deep capture/compare shape as an **automated flow scenario** (in the flow — do NOT leave a full-step `@manual` duplicate on the screen). `@manual` is **only** for genuine judgment (M6 visual/UX · M8 not-worth · M9 human) or a missing capability (M1–M5/M7), and it **must** carry a reason code (`@manual:Mx`, or a reason comment the planner can infer). A `@manual` scenario that still has full automatable steps (a data assertion, no visual/mock/a11y judgment) is now flagged by `sungen audit` as `MANUAL-AUTOMATABLE`, and business-critical scenarios you defer to `@manual` are reported as `DEPTH-DEFERRED` (they do NOT silently inflate `businessDepth`). Deferring automatable work to `@manual` lowers quality — automate it in the flow instead.
|
|
312
|
+
- `depth.cross_screen: true` (cart / detail / filter / brand correctness) → write the deep capture/compare shape as an **automated flow scenario** (in the flow — do NOT leave a full-step `@manual` duplicate on the screen). `@manual` is **only** for genuine judgment (M6 visual/UX · M8 not-worth · M9 human), a device/OS limit on mobile (M10 OS capability · M11 real-device only), or a missing capability (M1–M5/M7), and it **must** carry a reason code (`@manual:Mx`, or a reason comment the planner can infer). A `@manual` scenario that still has full automatable steps (a data assertion, no visual/mock/a11y judgment) is now flagged by `sungen audit` as `MANUAL-AUTOMATABLE`, and business-critical scenarios you defer to `@manual` are reported as `DEPTH-DEFERRED` (they do NOT silently inflate `businessDepth`). Deferring automatable work to `@manual` lowers quality — automate it in the flow instead.
|
|
313
313
|
- **Pick the right `@manual:Mx` code — it decides which driver can later automate the case** (`sungen audit` flags a code↔reason mismatch). Tag the code that matches the **oracle the reason describes**:
|
|
314
314
|
|
|
315
315
|
| The reason needs… | Code | Unblocked by |
|
|
@@ -321,9 +321,11 @@ Security: [S1 – admin only]
|
|
|
321
321
|
| an external dependency (email, payment gateway, download) | `M5` | mail-file / contract |
|
|
322
322
|
| visual / UX / responsive / a11y judgment | `M6` | — (keep manual) |
|
|
323
323
|
| not worth automating · true human judgment | `M8` / `M9` | — (keep manual) |
|
|
324
|
+
| **mobile** — what the OS/driver will not expose (notification shade, app switcher/recents, permission variance by OS version, call interruption) | `M10` | — (keep manual) |
|
|
325
|
+
| **mobile** — what an emulator/simulator cannot be (biometrics, real camera, NFC, a real push token) | `M11` | — (keep manual) |
|
|
324
326
|
|
|
325
327
|
e.g. "submit a payload then check the subscribers **table**" is an API+DB oracle → `@manual:M2` (NOT `M1`); "seed a DB with zero products" is a data state → `M1`; "throttle the network" → `M3`.
|
|
326
|
-
- **Prefer automation-ready `@requires:<cap>` over prose `@manual`.** When you *can* write the steps for a capability-manual case (an API/DB oracle, a seeded state), write it **automation-ready** — the real `@api`/`@query`/… steps tagged `@requires:<cap>` (e.g. `@requires:db @query:subscriber_row`) — instead of a prose `@manual:M2`. It compiles to a skipped-with-reason stub until `sungen capability add <cap>`, then runs as a real test with **no rewrite**. Reserve prose `@manual:Mx` for cases whose steps genuinely can't be expressed (M6/M8/M9 judgment, or a capability with no driver). `sungen audit` reports these as `AUTOMATION-READY-PENDING` (not a gap, not manual).
|
|
328
|
+
- **Prefer automation-ready `@requires:<cap>` over prose `@manual`.** When you *can* write the steps for a capability-manual case (an API/DB oracle, a seeded state), write it **automation-ready** — the real `@api`/`@query`/… steps tagged `@requires:<cap>` (e.g. `@requires:db @query:subscriber_row`) — instead of a prose `@manual:M2`. It compiles to a skipped-with-reason stub until `sungen capability add <cap>`, then runs as a real test with **no rewrite**. Reserve prose `@manual:Mx` for cases whose steps genuinely can't be expressed (M6/M8/M9 judgment, M10/M11 device-or-OS limits on mobile, or a capability with no driver). `sungen audit` reports these as `AUTOMATION-READY-PENDING` (not a gap, not manual).
|
|
327
329
|
- **If the spec lacks the concrete value** a deep assertion needs (exact message, price, count): still write the deep shape with a `{{var}}` placeholder and leave a `# SPEC-GAP: <field> value not in spec` comment — do **not** downgrade to `see [X] section`. A visible gap is better than a silent shallow pass.
|
|
328
330
|
- **Blind-Spot Memory:** before finishing, run `sungen blindspot list --prompt` (Bash) and make sure the suite satisfies each recorded pattern (e.g. "for any Add/Create action: check success + resulting data state + duplicate/double-submit"). These are gaps QA hit before — don't repeat them.
|
|
329
331
|
|
|
@@ -478,6 +480,90 @@ And User wait for [Page Title] heading is visible
|
|
|
478
480
|
|
|
479
481
|
---
|
|
480
482
|
|
|
483
|
+
## Mobile — the two axes web has no concept of
|
|
484
|
+
|
|
485
|
+
Applies to a `@platform:mobile/android/ios` unit. Read `sungen-viewpoint` →
|
|
486
|
+
`group-f-mobile-native.md` for *what to check* per native pattern (it carries the theme↔catalog
|
|
487
|
+
map the audit scores against); this section is the two **cross-cutting** axes that multiply every
|
|
488
|
+
other scenario on a device, and that a web-shaped coverage map has no row for.
|
|
489
|
+
|
|
490
|
+
### Axis 1 — the app lifecycle state machine
|
|
491
|
+
|
|
492
|
+
A browser tab is either open or closed. An app has five states, and a screen can be wrong in any of
|
|
493
|
+
them. Generate lifecycle scenarios from the transitions, not from the states.
|
|
494
|
+
|
|
495
|
+
```
|
|
496
|
+
launch (cold)
|
|
497
|
+
│
|
|
498
|
+
▼
|
|
499
|
+
┌──────────────► FOREGROUND ──────────────┐
|
|
500
|
+
│ │ │
|
|
501
|
+
│ background N seconds restart (kill)
|
|
502
|
+
│ ▼ ▼
|
|
503
|
+
│ BACKGROUNDED RELAUNCHED ── reinstall ──► FIRST-RUN
|
|
504
|
+
│ │ (install state cleared)
|
|
505
|
+
└──── resume ─────────┤
|
|
506
|
+
▼
|
|
507
|
+
PROCESS DEATH (the OS reclaims a backgrounded app)
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
| Transition | Step | Availability |
|
|
511
|
+
|---|---|---|
|
|
512
|
+
| foreground → backgrounded → resumed | `User background the app for 5 seconds` | both OSes |
|
|
513
|
+
| foreground → killed → relaunched | `User restart the app` | both OSes — **the** persistence oracle |
|
|
514
|
+
| → first-run | `User reinstall the app` | both OSes; needs the session to have installed via `APP_APK` / `IOS_APP` |
|
|
515
|
+
| a clean state *between* scenarios | `@reset:none\|soft\|data\|full` on the Feature | a tag, never a step — a step that tries reports **SG-W023** |
|
|
516
|
+
| backgrounded → process death → resumed | *no step* | `@manual:M10` (OS capability) |
|
|
517
|
+
|
|
518
|
+
**Every lifecycle scenario needs a DATA oracle.** "The screen is still there" passes on an empty
|
|
519
|
+
shell and on a silently re-logged-in session. Assert the value that must have survived:
|
|
520
|
+
|
|
521
|
+
```gherkin
|
|
522
|
+
@high @platform:mobile
|
|
523
|
+
Scenario: VP-LOGIC-001 The session survives a cold restart
|
|
524
|
+
Given User is on [Account] screen
|
|
525
|
+
When User restart the app
|
|
526
|
+
Then User see [Account Name] text contains {{user_name}}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Minimum for any mobile unit: **one resume scenario** (the screen owes its own data back) and, when
|
|
530
|
+
the screen persists anything — a session, a setting, a dismissal, a show-once card — **one restart
|
|
531
|
+
scenario per persisted thing**. Rotation belongs here too: `User rotate to landscape` must not lose
|
|
532
|
+
entered values or fire the request twice.
|
|
533
|
+
|
|
534
|
+
### Axis 2 — permission × network decision table
|
|
535
|
+
|
|
536
|
+
These two multiply: a permission-gated feature behaves differently offline, and the honest expected
|
|
537
|
+
result is often "which message wins". Build the table, then **test only the rows with distinct
|
|
538
|
+
outcomes** — the usual decision-table discipline, not all 12 combinations.
|
|
539
|
+
|
|
540
|
+
| # | Permission | Network | Expected | How |
|
|
541
|
+
|---|---|---|---|---|
|
|
542
|
+
| 1 | granted | online | the happy path, feature content asserted | `User grant camera permission` — both OSes (iOS Simulator needs `applesimutils`) |
|
|
543
|
+
| 2 | granted | offline | the spec's cached/queued behaviour + a clear message; entered data never silently lost | `User turn wifi off` → `@platform:android` (XCUITest cannot toggle connectivity); iOS is `@manual:M10` |
|
|
544
|
+
| 3 | granted | off → on | recovers and refreshes with no manual reload | `@platform:android` |
|
|
545
|
+
| 4 | denied | online | an in-app explanation with a route to Settings — never a crash or a dead button | `@manual:M10` — no step denies a permission |
|
|
546
|
+
| 5 | denied | offline | one message wins per spec; do NOT generate this row unless the spec says which | `@manual:M10` |
|
|
547
|
+
| 6 | never-ask-again | online | no request loop; the Settings route is shown | `@manual:M10` |
|
|
548
|
+
| 7 | revoked while running | online | the app re-checks instead of trusting a stale grant | `@manual:M10` |
|
|
549
|
+
|
|
550
|
+
Row 1 is `@high` and automated. Rows 2–3 are `@high` and automated **on Android only** — tag them,
|
|
551
|
+
do not write them platform-neutral and hope. Rows 4–7 carry `@manual:M10`, which is a reason code
|
|
552
|
+
and a real oracle, not a shrug: write the steps a human follows and the value they must see.
|
|
553
|
+
|
|
554
|
+
### Two mobile traps worth naming while generating
|
|
555
|
+
|
|
556
|
+
- **A `page` assertion proves nothing on mobile.** A native app has no URL, so `Then User see [Login]
|
|
557
|
+
page` compiles to an empty comment (**SG-W022**) and the scenario passes without looking. The
|
|
558
|
+
`screen` spelling is different and is what you want: it treats the target as a plain element and
|
|
559
|
+
emits a real visibility assertion — so name a marker only that screen has (`Then User see [Login
|
|
560
|
+
Submit] button`, or `Then User see [Login] screen` against a screen-root selector), and pair it
|
|
561
|
+
with the previous screen's marker going `is hidden`.
|
|
562
|
+
- **An `open [X] page` / `navigate to` step on mobile navigates nowhere** (**SG-W026**) — the app was
|
|
563
|
+
already launched by the capabilities. Change screens with a real tap or gesture.
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
481
567
|
## Cleanup & Hooks
|
|
482
568
|
|
|
483
569
|
Add cleanup tags per the `sungen-gherkin-syntax` Cleanup table. Key rules:
|
|
@@ -84,6 +84,7 @@ Hard-fail gate. Any ✗ is a syntax error — must be fixed; do not score furthe
|
|
|
84
84
|
- [ ] A spec `Format:` line → `matches "<format>"`, NOT `with {{v}}` (an exact value pins data that changes daily; `contains` proves nothing)
|
|
85
85
|
- [ ] Correct pattern: text(`message/header/label with {{v}}`) · partial(`text contains {{v}}`) · input(`field/dropdown with {{v}}`) · state(`is …`) · attribute(`image/link with {{v}}`) · count(`row with {{count}}`) · page(`[T] page`)
|
|
86
86
|
- [ ] Table: `[Col] column in [Table] table`, `[Ref] row in [Table] table with {{v}}`, `table with {{count}}`/`is empty`, `table match data:`; row scope used correctly
|
|
87
|
+
- [ ] Table on a `<div>` list (no `<table>` / `role="row"` in the app): the table entry declares `rows:` — without it `is hidden`/`is empty` pass on 0 rows (`SG-W016`). A row label's own `type: locator` entry is ONE positioned row, never the shape
|
|
87
88
|
|
|
88
89
|
### A5. Alert / Scope / Background
|
|
89
90
|
|
|
@@ -107,6 +108,30 @@ Hard-fail gate. Any ✗ is a syntax error — must be fixed; do not score furthe
|
|
|
107
108
|
- [ ] `@parallel` is REQUIRED when a feature mixes auth groups (`@auth:user` + `@no-auth`)
|
|
108
109
|
- [ ] `@flow`: `[Screen:Element]` namespace is consistent; YAML keys quoted with the colon (`"login:submit":`)
|
|
109
110
|
|
|
111
|
+
### A8. Mobile (`@platform:mobile/android/ios` units only)
|
|
112
|
+
|
|
113
|
+
Hard-fail rules — each one is a scenario that PASSES while proving nothing, which is worse than a
|
|
114
|
+
failing one. Skip this section entirely for a web unit.
|
|
115
|
+
|
|
116
|
+
- [ ] **`Then User see [X] page` → FAIL.** A native app has no URL: the step compiles to an empty
|
|
117
|
+
comment (**SG-W022**) and the scenario goes green without looking at the app. Require a marker
|
|
118
|
+
element (`see [X] screen` against a screen-root selector, or a button/text unique to the
|
|
119
|
+
screen) plus the previous screen's marker going `is hidden`.
|
|
120
|
+
- [ ] **`When User open [X] page` / `navigate to` → FAIL.** It navigates nowhere (**SG-W026**) — the
|
|
121
|
+
app was already launched by the wdio capabilities. Require a real tap or gesture.
|
|
122
|
+
`Given User is on [X] screen` is the legitimate app-launch anchor and is NOT a violation.
|
|
123
|
+
- [ ] **A step that establishes app state → FAIL.** `Given the user is logged out` compiles to a
|
|
124
|
+
comment (**SG-W023**); auth lives in the keychain, not in cookies. Require `@reset:data|full`
|
|
125
|
+
on the Feature instead.
|
|
126
|
+
- [ ] **Android-only vocabulary without `@platform:android` → FAIL.** `turn airplane mode|wifi|mobile
|
|
127
|
+
data …`, `open notifications` and `turn device location …` throw on iOS; `hide keyboard` is
|
|
128
|
+
worse — its iOS path is guarded out with **no** throw, so the scenario passes having done
|
|
129
|
+
nothing. Cross-check `docs/spec/step-support-matrix.md` (the `iOS` column) when unsure.
|
|
130
|
+
- [ ] **A web-only step on a mobile unit → FAIL.** Tables, browser storage, tab order, `@mock`, the
|
|
131
|
+
uploader and `hover` have no native equivalent — see `sungen-gherkin-syntax` → Platform Support.
|
|
132
|
+
- [ ] No `{{variable}}` used as a coordinate in `set location to …` — the numbers are resolved at
|
|
133
|
+
compile time and a variable silently becomes `0, 0`. Literal digits only.
|
|
134
|
+
|
|
110
135
|
---
|
|
111
136
|
|
|
112
137
|
## Layer B — Coverage Matrix (against Sun Common Checklist for QA)
|
|
@@ -128,6 +153,22 @@ Build a mapping table: for each applicable group, does the feature have a matchi
|
|
|
128
153
|
| **Security** | SQL Injection; XSS; Data Integrity (edit dropdown/remove `disabled` via DevTools → server rejects). SQL on LIKE/search fields → 2 TCs per the `sungen-viewpoint` SQL 2-layer rule. | VP-SEC | `with {{xss_*}}`/`{{sql_*}}`; data-integrity usually `@manual` |
|
|
129
154
|
| **Cross-surface outcomes** | Admin action → outcome on user-facing surface (portal, mobile, widget); spec defines display condition on another URL | VP-LOGIC-CS | `@high @manual` per surface per business rule — at minimum 1 per cross-surface rule; use `@auth:role` + `@extend` if surface reachable in same test run |
|
|
130
155
|
|
|
156
|
+
**Mobile units add four categories** (`@platform:mobile/android/ios` only). Each maps to a theme the
|
|
157
|
+
`sungen audit` mobile catalog scores, so a gap here is a scored gap, not a stylistic note — the
|
|
158
|
+
per-pattern checklists are in `sungen-viewpoint` → `group-f-mobile-native.md`:
|
|
159
|
+
|
|
160
|
+
| Category | Sub-viewpoint to check | VP map | Sungen representation |
|
|
161
|
+
|---|---|---|---|
|
|
162
|
+
| **App lifecycle** | Resume after background restores the screen's data; a restart preserves what the spec says persists (session, setting, dismissal, show-once); rotation loses nothing and does not double-submit | VP-LOGIC | `background the app for N seconds` · `restart the app` · `rotate to landscape\|portrait`, each with a **value** assertion |
|
|
163
|
+
| **Permission** | Granted path works; denied path explains and routes to Settings; never-ask-again does not loop; a revoked grant is re-checked | VP-LOGIC/SEC | `grant [X] permission` for the granted row; the other three are `@manual:M10` with a real oracle |
|
|
164
|
+
| **Gesture reachability** | The target is reachable — off-screen needs `scroll to`, occluded-by-a-floating-bar needs `tap top of` (scroll is a no-op there); swipe-revealed actions are asserted, not assumed | VP-LOGIC | `swipe <dir> on [X]` · `scroll to [X]` · `tap top of [X]` · `pull to refresh [X]` |
|
|
165
|
+
| **Connectivity** | Offline banner; cached content survives; an action while offline fails clearly without losing input; recovery refreshes without a manual reload | VP-LOGIC | `turn wifi off` → `@platform:android`; iOS `@manual:M10` |
|
|
166
|
+
|
|
167
|
+
**Deduct when a mobile suite has no lifecycle, permission, or gesture oracle at all** — those are the
|
|
168
|
+
three concerns a web-shaped test set always misses, and their absence is the single strongest signal
|
|
169
|
+
that the suite was written for a browser and re-tagged. A screen that genuinely owes none of them
|
|
170
|
+
(a static read-only screen with no permissions) is not penalised — say so in the notes.
|
|
171
|
+
|
|
131
172
|
**Tier-aware**: if the suite only has `@high` (Tier 1) → do NOT penalize missing pure VP-UI (deferred to Tier 2). Require full VP coverage only on a Full review.
|
|
132
173
|
|
|
133
174
|
### EP/BVA rules when mapping
|
|
@@ -180,6 +221,18 @@ Build a mapping table: for each applicable group, does the feature have a matchi
|
|
|
180
221
|
- **error (4xx)** — the status IS the assertion; also check the error-message field when the contract defines one.
|
|
181
222
|
- **anti-pattern (counts against "Avoids anti-patterns")** — re-asserting the input just sent instead of a server-derived value.
|
|
182
223
|
|
|
224
|
+
**Mobile scenarios — depth rubric:** the mobile catalog marks most themes as needing a **data**
|
|
225
|
+
oracle, so a sighting where a value is owed fails the "Specific" check:
|
|
226
|
+
- **a lifecycle/persistence claim asserted by a sighting = fail.** "The screen is still there" after
|
|
227
|
+
`restart the app` passes on an empty shell and on a silent re-login. Require the value that had to
|
|
228
|
+
survive (`text contains {{v}}`, `field with {{v}}`).
|
|
229
|
+
- **a list claim asserted by a count or a sighting = fail.** `see all [List Item] text contains {{v}}`
|
|
230
|
+
is the oracle; a row count passes on the wrong rows.
|
|
231
|
+
- **a navigation claim asserted by one marker = weak.** Require the destination's marker AND the
|
|
232
|
+
origin's marker going `is hidden` — one marker passes when the app never moved.
|
|
233
|
+
- **`keyboard-overlap` is the exception**: its honest oracle IS a sighting (the covered element is
|
|
234
|
+
visible again). Do not deduct for the absence of a value assertion there.
|
|
235
|
+
|
|
183
236
|
### Test Data (10)
|
|
184
237
|
|
|
185
238
|
| Check | Pts |
|
|
@@ -271,6 +324,10 @@ Do NOT deduct points when a `.feature` lacks the following viewpoints (Playwrigh
|
|
|
271
324
|
15. **Mixed auth groups missing `@parallel`** → add `@parallel`.
|
|
272
325
|
16. **Missing secondary behaviors** — spec defines tiebreaker, fallback rule, or secondary sort but no scenario tests it? Add 1 `@high` TC per rule.
|
|
273
326
|
17. **Missing concurrency scenarios** — spec or test-viewpoint mentions multi-tab, multi-user, or simultaneous actions but no `@manual` scenario exists? Add 1 `@manual` TC per risk (`@normal` by default; `@high` if data integrity at risk).
|
|
327
|
+
18. **Mobile: `see [X] page` oracle** → replace with a marker element on the destination screen + the origin's marker `is hidden` (SG-W022 — the original passes having proven nothing).
|
|
328
|
+
19. **Mobile: `open [X] page` / `navigate to`** → replace with the real tap/gesture that changes screens (SG-W026).
|
|
329
|
+
20. **Mobile: Android-only step without a platform tag** → add `@platform:android`, and add the iOS counterpart as `@manual:M10` if the spec owes iOS coverage.
|
|
330
|
+
21. **Mobile: no lifecycle scenario** → add 1 resume scenario (`background the app for N seconds` + a value assertion) and 1 restart scenario per persisted thing.
|
|
274
331
|
|
|
275
332
|
---
|
|
276
333
|
|
|
@@ -338,5 +395,5 @@ If `selectors/<name>.yaml` exists, count lines matching `@needs-live-verify` (pr
|
|
|
338
395
|
|
|
339
396
|
- **When NOT to apply**: exploratory charters, performance/load scripts, pure NFR specs — this rubric grades functional test cases.
|
|
340
397
|
- **Adapting weights**: a project may rebalance the 7 dimensions (e.g. security-critical service: Security→15, Maintainability→0) as long as the total stays 100 and the PASS/CONDITIONAL/FAIL thresholds are restated. Record any change in this section.
|
|
341
|
-
- **References**: detailed syntax → `sungen-gherkin-syntax`; selector keys → `sungen-selector-keys`; VP classification → `sungen-viewpoint`; generation workflow → `sungen-tc-generation`.
|
|
398
|
+
- **References**: detailed syntax → `sungen-gherkin-syntax`; selector keys → `sungen-selector-keys`; VP classification → `sungen-viewpoint` (mobile-native patterns → its `group-f-mobile-native.md`); mobile step vocabulary → `sungen-mobile-gestures`; per-OS support → `docs/spec/step-support-matrix.md`; generation workflow → `sungen-tc-generation`.
|
|
342
399
|
- **Owner / version**: Owner: `<QA Lead>` · Version: `2.0` · Last updated: `2026-06-03`.
|
|
@@ -116,3 +116,16 @@ Scenario: VP-VAL-003 Above maximum is rejected # value = 101
|
|
|
116
116
|
- `@normal` Invalid: Completed → Draft (blocked), Pending → Completed (skip approval)
|
|
117
117
|
|
|
118
118
|
**test-data:** Use named state keys (`order_in_draft`, `order_in_pending`).
|
|
119
|
+
|
|
120
|
+
**On mobile, three state machines exist that no spec draws** — apply this technique to them even
|
|
121
|
+
when `spec.md` has no diagram, because the states are imposed by the platform rather than the
|
|
122
|
+
product:
|
|
123
|
+
|
|
124
|
+
| Machine | States | Transition steps that compile |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| App lifecycle | foreground · backgrounded · relaunched · first-run · process-death | `background the app for N seconds` · `restart the app` · `reinstall the app`; process-death is `@manual:M10` |
|
|
127
|
+
| Screen entry / exit | entered by tap · entered by deep link · left by OS back · left by in-app control | `open deep link {{url}}` · `go back` (OS/hardware) · a tap on the in-app control — **the last two are different transitions**, since system back skips the screen's own handler unless the app wires it |
|
|
128
|
+
| Connectivity | online · offline · recovering | `turn wifi off` / back on → `@platform:android` (XCUITest cannot toggle connectivity) |
|
|
129
|
+
|
|
130
|
+
Full matrices and the permission axis → `sungen-tc-generation` → "Mobile — the two axes web has no
|
|
131
|
+
concept of". Per-pattern checklists → `sungen-viewpoint` → `group-f-mobile-native.md`.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sungen-viewpoint
|
|
3
|
-
description: '
|
|
4
|
-
generation and review. Auto-loaded by create-test and review commands.'
|
|
3
|
+
description: '32 UI patterns (17 web + 15 mobile-native) x 4 viewpoints — structured
|
|
4
|
+
checklist for test case generation and review. Auto-loaded by create-test and review commands.'
|
|
5
5
|
user-invocable: false
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
## How to use this skill
|
|
9
9
|
|
|
10
|
-
This skill is a **router**. The detailed checklists live in
|
|
10
|
+
This skill is a **router**. The detailed checklists live in 6 group files — load only the ones relevant to the screen under test. Groups A–E are the 17 platform-agnostic patterns; Group F is the mobile-native layer, read IN ADDITION on a `@platform:mobile/android/ios` unit.
|
|
11
11
|
|
|
12
12
|
1. Read the **4 Viewpoints** and **Shared Checks** below (always).
|
|
13
13
|
2. Identify which UI patterns the screen contains, resolve any overlap via **Pattern selection** below, then read **only** the matching group file(s) from the routing table.
|
|
@@ -36,6 +36,22 @@ This skill is a **router**. The detailed checklists live in 5 group files — lo
|
|
|
36
36
|
| Login form / logout button | 15. Login / Logout | `group-e-identity.md` |
|
|
37
37
|
| Sign-up form / SSO | 16. Register | `group-e-identity.md` |
|
|
38
38
|
| Forgot / reset / change password | 17. Password Management | `group-e-identity.md` |
|
|
39
|
+
| **Native app screen (`@platform:mobile/android/ios`) — read Group F IN ADDITION to the patterns above** | | |
|
|
40
|
+
| Sheet sliding up from the bottom edge | 18. Bottom Sheet | `group-f-mobile-native.md` |
|
|
41
|
+
| Persistent bar of 3–5 destinations at the bottom | 19. Tab Bar / Bottom Navigation | `group-f-mobile-native.md` |
|
|
42
|
+
| Horizontal swipe on a row reveals actions | 20. Swipe-to-Delete Row | `group-f-mobile-native.md` |
|
|
43
|
+
| Field opening an OS wheel / date / dropdown picker | 21. Native Picker | `group-f-mobile-native.md` |
|
|
44
|
+
| Runtime permission — camera, location, notifications | 22. Permission Dialog | `group-f-mobile-native.md` |
|
|
45
|
+
| Fingerprint / Face ID / app lock | 23. Biometric Prompt | `group-f-mobile-native.md` |
|
|
46
|
+
| Leaves the app for the system camera or photo library | 24. Camera / Gallery Picker | `group-f-mobile-native.md` |
|
|
47
|
+
| Push messages / notification routing | 25. Push Notification | `group-f-mobile-native.md` |
|
|
48
|
+
| External link, notification payload, or QR opens a screen | 26. Deep-link Entry | `group-f-mobile-native.md` |
|
|
49
|
+
| Offline banner, cached content, retry control | 27. Offline Banner | `group-f-mobile-native.md` |
|
|
50
|
+
| First-launch intro slides / tutorial | 28. Onboarding Carousel | `group-f-mobile-native.md` |
|
|
51
|
+
| Feed reloading by drag-down, paging, Load More | 29. Pull-to-Refresh List | `group-f-mobile-native.md` |
|
|
52
|
+
| Any text field — the soft keyboard covers the screen | 30. Soft-Keyboard Overlap | `group-f-mobile-native.md` |
|
|
53
|
+
| List of switches / preferences | 31. Settings Toggle List | `group-f-mobile-native.md` |
|
|
54
|
+
| Every mobile screen (background, rotate, relaunch) | 32. App Lifecycle & Orientation | `group-f-mobile-native.md` |
|
|
39
55
|
|
|
40
56
|
## Pattern selection (precedence & inheritance)
|
|
41
57
|
|
|
@@ -54,6 +70,8 @@ A screen often matches several patterns at once — a login screen is *both* a f
|
|
|
54
70
|
| Both a keyword box and filter controls | Apply **8. Search** *and* **9. Filter** (Search = free-text match; Filter = structured narrowing) + one combined AND-logic scenario |
|
|
55
71
|
| A form rendered inside an overlay | Apply the form's pattern (1/4/5/15…) for fields/submit **and** **12. Modal/Dialog** for open/close/focus-trap/backdrop |
|
|
56
72
|
|
|
73
|
+
5. **On mobile, Group F is ADDITIVE — never a replacement.** A native screen is still whatever it functionally is: a native login screen is **15**, a native product list is **10**, and the harness routes such a screen to `auth` / `ecommerce-list` deliberately, not to a `mobile-*` page-type. Route by function first (1–17), then add the Group F patterns for the native surfaces present, and generate each check **once** — a native form is **1. Form & Inputs** *and* **30. Soft-Keyboard Overlap**, with the field rules living only in pattern 1. `group-f-mobile-native.md` carries the theme↔catalog map and the precedence detail.
|
|
74
|
+
|
|
57
75
|
## 4 Viewpoints
|
|
58
76
|
|
|
59
77
|
| VP | Focus | Tag |
|
|
@@ -90,16 +108,32 @@ The 4 viewpoints above are the *generic* axes. On a domain screen, the `VP-<CAT>
|
|
|
90
108
|
Generate **once per screen**, do not repeat for each pattern.
|
|
91
109
|
Each pattern only points back with "Shared checks applied: [name]".
|
|
92
110
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
|
99
|
-
|
|
111
|
+
The `Platform` column decides which checks a screen owes. Applying the web three to a native
|
|
112
|
+
screen is wasted work — a `<script>` payload cannot execute in a native text view and there is no
|
|
113
|
+
URL to manipulate — while the native surfaces (deep-link params, clipboard, the recents thumbnail)
|
|
114
|
+
go unchecked unless they are named here.
|
|
115
|
+
|
|
116
|
+
| Check | Condition → Expected | VP | Priority | Platform |
|
|
117
|
+
|---|---|---|---|---|
|
|
118
|
+
| **Loading State** | Data fetch in progress → spinner/skeleton shown, user cannot interact | UI | @normal | both |
|
|
119
|
+
| **Empty State** | Query returns 0 records → clear message shown, layout does not break | UI | @normal | both |
|
|
120
|
+
| **XSS** | Script tag entered into a field → rendered as literal text, not executed | SEC | @high | web |
|
|
121
|
+
| **SQL injection** | SQL payload entered into a field → DB unaffected, no data exposed | SEC | @high | web |
|
|
122
|
+
| **URL Manipulation** | URL params wrong/missing/out-of-range → fallback to default, no 500 crash | SEC | @high | web |
|
|
123
|
+
| **Deep-link param injection** | An external link carries a traversal / script / oversized param → treated as data, no crash, no privileged screen reached | SEC | @high | mobile |
|
|
124
|
+
| **Clipboard leak** | A field holding sensitive data (password, token, card) → the value cannot be copied out, or is excluded from the clipboard | SEC | @high | mobile |
|
|
125
|
+
| **Recents / screenshot leak** | Background the app on a screen showing sensitive data → the app-switcher thumbnail is masked, screenshots blocked where the spec requires it | SEC | @high | mobile |
|
|
126
|
+
| **Root / jailbreak posture** | The app runs on a rooted/jailbroken device → the spec's response (warn, degrade, or block), never a silent full-trust run | SEC | @normal | mobile |
|
|
127
|
+
| **Certificate pinning** | Traffic through an intercepting proxy with a substituted certificate → the app refuses the connection rather than transmitting | SEC | @high | mobile |
|
|
128
|
+
| **Permission over-request** | Cold launch → only the permissions the current feature needs are requested, and each is asked in context | SEC | @normal | mobile |
|
|
100
129
|
|
|
101
130
|
> **SQL injection — 2 layers for search/LIKE fields**: (1) field-level: UI blocks special chars → `@high` automated; (2) API-level: if the field reaches a LIKE query (search, partial-match), send `1 OR 1=1` straight to the API endpoint (bypassing the UI) → verify a parameterized query is used → `@high @manual`. Missing layer 2 = a real attack vector is overlooked even when field validation is correct.
|
|
102
131
|
|
|
132
|
+
> **Two mobile edges the table simplifies.** A screen rendered inside a **WebView** is web for these
|
|
133
|
+
> purposes — apply XSS there. And a native app hits the same API as the web client, so the API-level
|
|
134
|
+
> SQL-injection layer above is still owed by the *system*; it is just not a screen-unit check on a
|
|
135
|
+
> mobile unit. Record it once at the API layer (`qa/api/`), not per mobile screen.
|
|
136
|
+
|
|
103
137
|
---
|
|
104
138
|
|
|
105
139
|
## Security Tag Rules
|
|
@@ -108,6 +142,8 @@ For VP-SEC scenarios testing **unauthorized access** (no login, wrong role, dire
|
|
|
108
142
|
- Use the **`@no-auth`** tag — runs without authentication to verify the redirect/block.
|
|
109
143
|
- Do NOT use `@manual` for these — they are automatable.
|
|
110
144
|
|
|
145
|
+
On **web** the redirect target is a URL, so asserting the page is a real check:
|
|
146
|
+
|
|
111
147
|
```gherkin
|
|
112
148
|
@high @no-auth
|
|
113
149
|
Scenario: VP-SEC-001 Unauthenticated user cannot access admin page
|
|
@@ -115,4 +151,17 @@ Scenario: VP-SEC-001 Unauthenticated user cannot access admin page
|
|
|
115
151
|
Then User see [Login] page
|
|
116
152
|
```
|
|
117
153
|
|
|
154
|
+
On **mobile** that same shape is a false pass. A native app has no URL: the assertion compiles to an
|
|
155
|
+
empty comment and reports **SG-W022**, so the scenario goes green having proven nothing. Assert a
|
|
156
|
+
marker element that only exists on the login screen, plus the protected screen's own marker going
|
|
157
|
+
`is hidden`:
|
|
158
|
+
|
|
159
|
+
```gherkin
|
|
160
|
+
@high @no-auth @platform:mobile
|
|
161
|
+
Scenario: VP-SEC-001 An unauthenticated launch stops at the login screen
|
|
162
|
+
Given User is on [Login] screen
|
|
163
|
+
Then User see [Login Submit] button
|
|
164
|
+
And User see [Account Name] is hidden
|
|
165
|
+
```
|
|
166
|
+
|
|
118
167
|
Use `@manual` only when the environment truly cannot be set up automatically.
|