---
model: sonnet
---

# /tas-functest-mobile $ARGUMENTS

Role: SE / QA
Generate all Detox automation test scripts for a mobile Feature.

## IMPORTANT — Layer 2: Mobile Functional Test Scripts
- Create Detox test scripts from the FuncTest spec (markdown)
- Scripts located in `apps/mobile/e2e/features/`
- Reusable helpers exported for Layer 3 (E2E) reuse
- Hardcoded data in tests, credentials from `.env`

## Actions

### Step 1: Identify Feature
1. `$ARGUMENTS` is Feature ID or file path
2. If not provided: scan `docs/features/{CODE}-Feature-*/{CODE}-Feature-*.md` for Features with status `In Development`
3. Read Feature file to get Feature ID + slug

### Step 2: Check Prerequisites
1. Check `apps/mobile/` exists. If not → report:
   > "Mobile app doesn't exist. If project only has web, use `/tas-functest-web`."
   > STOP, DO NOT create file.
2. Find the FuncTest spec in Feature directory:
   ```
   docs/features/{CODE}-Feature-{NNN}-{slug}/{CODE}-FuncTest.md
   ```
3. If missing → error:
   > "No FuncTest spec for this Feature. Run `/tas-functest {Feature-ID}` first."
4. Read the **`### Locator Map`** (App stack) from the Feature-Technical file — authoritative testid → element table. Use it for every `by.id(...)`. If a TC needs an element absent from the Map → **warn** (signals source/plan gap; `/tas-dev` should have back-filled it) and do NOT invent a testid.
5. Read `apps/mobile/e2e/test-ids.ts` to know existing testIDs (derived registry; the Locator Map is authoritative)
6. Read `apps/mobile/e2e/helpers/data-loader.ts` and `test-utils.ts` for patterns

### Step 2.5: TC ID rule (CRITICAL — chain contract)

- The FuncTest §4 **TC ID is the SSoT**: `F{NNN}_AC{N}_{CAT}_{SEQ}` (CAT ∈ `GUI|VAL|BL|EXC|SEC|INT|PERF`), e.g. `F001_AC1_BL_001`.
- Each `describe(...)` MUST reuse the §4 TC ID **verbatim** as its title. Do NOT synthesize a new ID (no `_FT_`, no `{PROJECT}` prefix, no `_H/_E/_N` modifier) — a synthesized title never maps back in `/tas-functest-report` and the result is dropped as "unmatched".
- TC ID must appear at the **start** of the title so the report can parse it: `^(F\d+_AC\d+_[A-Z]+_\d+[a-z]?)`. BVA/EP variants keep their trailing letter (`F001_AC1_VAL_001a`) — each is a separate §4 TC, one `describe` each.
- Device runs are **variants of the same TC ID**, not new tests — suffix in brackets: `F001_AC1_BL_001 [ios]`.

### Step 3: Aggregate FT Test Cases
- From the FuncTest spec, list all FT test cases grouped by AC
- Pull test data requirements from spec

### Step 4: Generate Test Scripts

**File output**: `apps/mobile/e2e/features/{feature-slug}/{feature-slug}.func.e2e.ts`

(One test file per Feature — Stories no longer exist.)

**Structure**:
```typescript
/**
 * Functional Tests: {Feature Name}
 * Feature: {Feature_ID}
 * Stack: app
 *
 * Generated by /tas-functest-mobile
 * Spec: docs/features/{feature-dir}/{CODE}-FuncTest.md
 */

import { device, element, expect, by, waitFor } from 'detox';
import { TEST_IDS } from '../../test-ids';
import { loadTestData, getCredentials } from '../../helpers/data-loader';
import { login, navigateTo } from '../../helpers/test-utils';

const testData = loadTestData();

describe('{Feature Name}', () => {
  beforeAll(async () => {
    await device.launchApp({ newInstance: true });
  });

  beforeEach(async () => {
    await device.reloadReactNative();
  });

  // AC Reference: AC-1 — title = FuncTest §4 TC ID verbatim
  describe('F001_AC1_BL_001', () => {
    it('should {description from spec}', async () => {
      // Given: {precondition}
      // When: {action} — testid from Feature-Technical ### Locator Map
      await element(by.id(TEST_IDS.AUTH.INPUT.EMAIL)).typeText(testData.email);
      await element(by.id(TEST_IDS.AUTH.INPUT.PASSWORD)).typeText(testData.password);
      await element(by.id(TEST_IDS.AUTH.BUTTON.SUBMIT)).tap();
      // Then: {expected}
      await waitFor(element(by.id(TEST_IDS.DASHBOARD.LABEL.TITLE)))
        .toBeVisible()
        .withTimeout(5000);
    });
  });
});
```

### Step 4.5: Write-back Execution Locators into the FuncTest spec

Overwrite the §4 **"Execution Locators"** column (placeholder `_Phase 3 — SE_`) in `{CODE}-FuncTest.md`. For each TC, translate its Logical Steps into the **Action DSL** from `.tas/rules/common/locator-naming.md`, using testids from the Feature-Technical `### Locator Map` (App stack). Example:

```
type:ipt_auth_email "{value}"
type:ipt_auth_password "{value}"
click:btn_auth_submit
assert:lbl_dashboard_title == visible
```

Only edit the Execution Locators cells — do not touch other columns. If a step's element is missing from the Locator Map, leave a `# TODO: testid missing in Locator Map` marker in that cell and warn (do not invent a testid).

### Step 5: Update test-ids.ts (if needed)
- Source testIDs from the Feature-Technical `### Locator Map` (App stack) — do not invent
- `/tas-dev` should already have synced them here; add any still missing
- Keep nested-object structure with dot notation

### Step 6: Generate Feature Helpers
Create `apps/mobile/e2e/features/{feature-slug}/helpers.ts`:
```typescript
/**
 * Reusable helpers for {Feature Name}
 * Exported for Layer 3 E2E scripts reuse.
 */

export async function {featureSpecificHelper}() {
  // Helper logic extracted from functional tests
}
```

### Step 7: Generate/Update Data Loader (if missing)
If `apps/mobile/e2e/helpers/data-loader.ts` does not exist, create it:
```typescript
type TestEnv = 'dev' | 'staging' | 'prod';

export function loadTestData(env?: TestEnv) {
  const targetEnv = env || (process.env.TEST_ENV as TestEnv) || 'dev';
  return require(`../data/test-data.${targetEnv}.json`);
}

export function getCredentials(userType = 'default') {
  const data = loadTestData();
  const user = data.users[userType] || data.users.default;
  return {
    email: user.email,
    password: process.env.TEST_USER_PASSWORD || '',
  };
}
```

### Step 8: Update package.json Script
```json
"functest:mobile:{feature-slug}": "detox test --configuration ios.sim.debug --testPathPattern='e2e/features/{feature-slug}'"
```

### Step 9: Generate Index
`apps/mobile/e2e/features/{feature-slug}/index.ts`:
```typescript
export * from './helpers';
```

## File Structure Output
```
apps/mobile/e2e/features/
└── {feature-slug}/
    ├── {feature-slug}.func.e2e.ts
    ├── helpers.ts
    └── index.ts
```

## Selector Strategy (Detox)
- **Source of testids**: the Feature-Technical `### Locator Map` (App stack). Never invent a testid — if one is missing there, warn (it means `/tas-dev` didn't inject/back-fill it).
- **Priority**: `testID` prop → `by.id(TEST_IDS.SECTION.TYPE.NAME)`
- **Text**: `by.text('Welcome')`
- **Label**: `by.label('Email')`
- DO NOT use `by.type()` or native class selectors unless required

## Test Data Convention
- **Hardcoded values**: Directly in test
- **Credentials**: `getCredentials()` → password from process.env
- **Environment data**: `loadTestData()` → from test-data.{env}.json
- **NEVER** hardcode passwords/tokens

## Run Tests
```bash
yarn functest:mobile:{feature-slug}
npx detox test --configuration ios.sim.debug --testPathPattern='e2e/features/{feature-slug}'
npx detox test --configuration android.emu.debug --testPathPattern='e2e/features/{feature-slug}'
```

## Principles
- Script MUST be runnable directly from CLI
- Each describe block reuses the FuncTest §4 TC ID **verbatim** (`F{NNN}_AC{N}_{CAT}_{SEQ}`) as its title — never synthesize a new ID
- Helpers MUST export for Layer 3 reuse
- DO NOT import from Layer 3 (`flows/`)
- If `apps/mobile/` doesn't exist → STOP, DO NOT create file

## References

- `.tas/rules/common/locator-naming.md` — element prefix system, action DSL, state assertions (Phase 3 mapping)
- Feature-Technical `### Locator Map` (App stack) — authoritative testid → element table (SSoT)
- `.tas/templates/Func-Test.md` — §4 table structure (input: Logical Steps + Execution Locators columns)
