@torus-engineering/tas-kit 1.10.0 → 1.12.0
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/.tas/README.md +70 -70
- package/{.claude → .tas/_platform/claude-code}/settings.json +0 -12
- package/{.claude → .tas/_platform}/hooks/code-quality.js +1 -1
- package/{.claude → .tas/_platform}/hooks/session-end.js +20 -25
- package/.tas/commands/ado-create.md +28 -0
- package/.tas/commands/ado-delete.md +22 -0
- package/.tas/commands/ado-get.md +20 -0
- package/.tas/commands/ado-status.md +18 -0
- package/.tas/commands/ado-update.md +27 -0
- package/.tas/commands/tas-adr.md +33 -0
- package/.tas/commands/tas-apitest-plan.md +173 -0
- package/.tas/commands/tas-apitest.md +143 -0
- package/.tas/commands/tas-brainstorm.md +19 -0
- package/.tas/commands/tas-bug.md +113 -0
- package/.tas/commands/tas-design.md +37 -0
- package/.tas/commands/tas-dev.md +125 -0
- package/{.claude → .tas}/commands/tas-e2e-mobile.md +155 -155
- package/{.claude → .tas}/commands/tas-e2e-web.md +163 -163
- package/.tas/commands/tas-e2e.md +102 -0
- package/.tas/commands/tas-epic.md +35 -0
- package/.tas/commands/tas-feature.md +47 -0
- package/.tas/commands/tas-fix.md +51 -0
- package/.tas/commands/tas-functest-mobile.md +144 -0
- package/{.claude → .tas}/commands/tas-functest-web.md +192 -192
- package/.tas/commands/tas-functest.md +76 -0
- package/.tas/commands/tas-init.md +17 -0
- package/.tas/commands/tas-plan.md +198 -0
- package/.tas/commands/tas-prd.md +37 -0
- package/.tas/commands/tas-review.md +113 -0
- package/.tas/commands/tas-sad.md +43 -0
- package/.tas/commands/tas-security.md +87 -0
- package/.tas/commands/tas-spec.md +50 -0
- package/.tas/commands/tas-status.md +16 -0
- package/.tas/commands/tas-story.md +91 -0
- package/.tas/platforms.json +5 -0
- package/.tas/project-status-example.yaml +17 -17
- package/.tas/rules/ado-integration.md +65 -0
- package/{.claude/skills/api-design/SKILL.md → .tas/rules/common/api-design.md} +517 -530
- package/{.claude → .tas}/rules/common/code-review.md +30 -6
- package/.tas/rules/common/post-implementation-review.md +51 -0
- package/{.claude → .tas}/rules/common/project-status.md +80 -80
- package/.tas/rules/common/stack-detection.md +29 -0
- package/.tas/rules/common/story-done.md +30 -0
- package/.tas/rules/common/tdd.md +89 -0
- package/{.claude → .tas}/rules/common/testing.md +3 -8
- package/.tas/rules/common/token-logging.md +36 -0
- package/{.claude → .tas}/rules/csharp/api-testing.md +20 -20
- package/{.claude → .tas}/rules/csharp/coding-style.md +0 -2
- package/{.claude → .tas}/rules/csharp/security.md +10 -0
- package/{.claude → .tas}/rules/python/coding-style.md +0 -2
- package/{.claude → .tas}/rules/typescript/coding-style.md +0 -2
- package/.tas/rules/typescript/patterns.md +142 -0
- package/.tas/rules/typescript/security.md +88 -0
- package/{.claude → .tas}/rules/typescript/testing.md +0 -4
- package/{.claude → .tas}/rules/web/coding-style.md +0 -2
- package/.tas/tas-example.yaml +10 -11
- package/.tas/templates/ADR.md +47 -47
- package/.tas/templates/AGENTS.md +37 -0
- package/.tas/templates/API-Test-Spec.md +3 -3
- package/.tas/templates/Bug.md +67 -67
- package/.tas/templates/Design-Spec.md +36 -36
- package/.tas/templates/E2E-Execution-Report.md +1 -1
- package/.tas/templates/Epic.md +46 -46
- package/.tas/templates/Feature.md +10 -10
- package/.tas/templates/Func-Test-Spec.md +3 -3
- package/.tas/templates/SAD.md +106 -106
- package/.tas/templates/Security-Report.md +27 -27
- package/.tas/templates/Story.md +9 -9
- package/.tas/tools/tas-ado-readme.md +68 -68
- package/.tas/tools/tas-ado.py +621 -621
- package/README.md +78 -78
- package/bin/cli.js +91 -73
- package/lib/adapters/antigravity.js +137 -0
- package/lib/adapters/claude-code.js +35 -0
- package/lib/adapters/codex.js +163 -0
- package/lib/adapters/cursor.js +80 -0
- package/lib/adapters/index.js +20 -0
- package/lib/adapters/utils.js +81 -0
- package/lib/deleted-files.json +99 -0
- package/lib/install.js +403 -327
- package/package.json +4 -3
- package/.claude/agents/code-reviewer.md +0 -41
- package/.claude/agents/e2e-runner.md +0 -61
- package/.claude/agents/planner.md +0 -82
- package/.claude/agents/tdd-guide.md +0 -84
- package/.claude/commands/ado-create.md +0 -27
- package/.claude/commands/ado-delete.md +0 -21
- package/.claude/commands/ado-get.md +0 -20
- package/.claude/commands/ado-status.md +0 -18
- package/.claude/commands/ado-update.md +0 -26
- package/.claude/commands/tas-adr.md +0 -33
- package/.claude/commands/tas-apitest-plan.md +0 -173
- package/.claude/commands/tas-apitest.md +0 -143
- package/.claude/commands/tas-brainstorm.md +0 -19
- package/.claude/commands/tas-bug.md +0 -113
- package/.claude/commands/tas-design.md +0 -37
- package/.claude/commands/tas-dev.md +0 -128
- package/.claude/commands/tas-e2e.md +0 -102
- package/.claude/commands/tas-epic.md +0 -35
- package/.claude/commands/tas-feature.md +0 -47
- package/.claude/commands/tas-fix.md +0 -51
- package/.claude/commands/tas-functest-mobile.md +0 -144
- package/.claude/commands/tas-functest.md +0 -76
- package/.claude/commands/tas-init.md +0 -17
- package/.claude/commands/tas-plan.md +0 -200
- package/.claude/commands/tas-prd.md +0 -37
- package/.claude/commands/tas-review.md +0 -111
- package/.claude/commands/tas-sad.md +0 -43
- package/.claude/commands/tas-security.md +0 -87
- package/.claude/commands/tas-spec.md +0 -50
- package/.claude/commands/tas-status.md +0 -16
- package/.claude/commands/tas-story.md +0 -91
- package/.claude/commands/tas-verify.md +0 -51
- package/.claude/rules/common/post-review-agent.md +0 -49
- package/.claude/rules/common/stack-detection.md +0 -29
- package/.claude/rules/common/token-logging.md +0 -27
- package/.claude/rules/typescript/patterns.md +0 -62
- package/.claude/rules/typescript/security.md +0 -28
- package/.claude/settings.local.json +0 -38
- package/.claude/skills/ado-integration/SKILL.md +0 -75
- package/.claude/skills/ai-regression-testing/SKILL.md +0 -364
- package/.claude/skills/architecture-decision-records/SKILL.md +0 -184
- package/.claude/skills/benchmark/SKILL.md +0 -98
- package/.claude/skills/browser-qa/SKILL.md +0 -92
- package/.claude/skills/canary-watch/SKILL.md +0 -104
- package/.claude/skills/js-backend-patterns/SKILL.md +0 -603
- package/.claude/skills/tas-conventions/SKILL.md +0 -65
- package/.claude/skills/tas-implementation-complete/SKILL.md +0 -99
- package/.claude/skills/tas-tdd/SKILL.md +0 -123
- package/.claude/skills/token-logger/SKILL.md +0 -19
- package/.tas/checklists/code-review.md +0 -29
- package/.tas/checklists/security.md +0 -21
- package/.tas/checklists/story-done.md +0 -23
- package/CLAUDE-Example.md +0 -61
- /package/{.claude → .tas}/agents/architect.md +0 -0
- /package/{.claude → .tas}/agents/aws-reviewer.md +0 -0
- /package/{.claude → .tas}/agents/build-resolver.md +0 -0
- /package/{.claude → .tas}/agents/code-explorer.md +0 -0
- /package/{.claude → .tas}/agents/csharp-reviewer.md +0 -0
- /package/{.claude → .tas}/agents/database-reviewer.md +0 -0
- /package/{.claude → .tas}/agents/doc-updater.md +0 -0
- /package/{.claude → .tas}/agents/python-reviewer.md +0 -0
- /package/{.claude → .tas}/agents/security-reviewer.md +0 -0
- /package/{.claude → .tas}/agents/typescript-reviewer.md +0 -0
- /package/{.claude → .tas}/rules/.gitkeep +0 -0
- /package/{.claude → .tas}/rules/common/hooks.md +0 -0
- /package/{.claude → .tas}/rules/common/patterns.md +0 -0
- /package/{.claude → .tas}/rules/common/security.md +0 -0
- /package/{.claude → .tas}/rules/csharp/hooks.md +0 -0
- /package/{.claude → .tas}/rules/csharp/patterns.md +0 -0
- /package/{.claude → .tas}/rules/csharp/testing.md +0 -0
- /package/{.claude → .tas}/rules/python/hooks.md +0 -0
- /package/{.claude → .tas}/rules/python/patterns.md +0 -0
- /package/{.claude → .tas}/rules/python/security.md +0 -0
- /package/{.claude → .tas}/rules/python/testing.md +0 -0
- /package/{.claude → .tas}/rules/typescript/hooks.md +0 -0
- /package/{.claude → .tas}/rules/web/design-quality.md +0 -0
- /package/{.claude → .tas}/rules/web/hooks.md +0 -0
- /package/{.claude → .tas}/rules/web/patterns.md +0 -0
- /package/{.claude → .tas}/rules/web/performance.md +0 -0
- /package/{.claude → .tas}/rules/web/security.md +0 -0
- /package/{.claude → .tas}/rules/web/testing.md +0 -0
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
# /tas-e2e-mobile $ARGUMENTS
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Generate Detox E2E test scripts
|
|
5
|
-
|
|
6
|
-
##
|
|
7
|
-
-
|
|
8
|
-
- Scripts
|
|
9
|
-
- REUSE helpers
|
|
10
|
-
- Chain functional test steps
|
|
11
|
-
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
###
|
|
15
|
-
1. $ARGUMENTS
|
|
16
|
-
2.
|
|
17
|
-
3. List scenarios
|
|
18
|
-
|
|
19
|
-
###
|
|
20
|
-
1.
|
|
21
|
-
2.
|
|
22
|
-
- Scenario steps
|
|
23
|
-
- FT ID references (
|
|
24
|
-
- FT Reuse Map (section
|
|
25
|
-
- Test data per environment
|
|
26
|
-
- Scenario type (single-epic / cross-epic)
|
|
27
|
-
|
|
28
|
-
###
|
|
29
|
-
|
|
30
|
-
1.
|
|
31
|
-
2. Verify helper functions
|
|
32
|
-
3.
|
|
33
|
-
4. Import map: FT ID → file path → function name
|
|
34
|
-
|
|
35
|
-
###
|
|
36
|
-
|
|
37
|
-
**File output**: `apps/mobile/e2e/flows/{scenario-slug}.e2e.ts`
|
|
38
|
-
|
|
39
|
-
**Structure**:
|
|
40
|
-
```typescript
|
|
41
|
-
/**
|
|
42
|
-
* E2E Flow: {Scenario Name}
|
|
43
|
-
* Scenario: {Scenario_ID}
|
|
44
|
-
* Epic(s): {Epic_ID(s)}
|
|
45
|
-
* Type: {single-epic | cross-epic}
|
|
46
|
-
*
|
|
47
|
-
* Generated by /tas-e2e-mobile
|
|
48
|
-
* Spec: {path to E2E-Scenario-*.md}
|
|
49
|
-
*/
|
|
50
|
-
|
|
51
|
-
import { device, element, expect, by, waitFor } from 'detox';
|
|
52
|
-
import { TEST_IDS } from '../test-ids';
|
|
53
|
-
import { loadTestData, getCredentials } from '../helpers/data-loader';
|
|
54
|
-
import { login, logout, navigateToTab } from '../helpers/test-utils';
|
|
55
|
-
|
|
56
|
-
// Layer 2 helpers (reuse from functional tests)
|
|
57
|
-
import { fillLoginForm, verifyLoginSuccess } from '../features/{epic}/{feature}/helpers';
|
|
58
|
-
import { viewAllergenList } from '../features/{epic2}/{feature2}/helpers';
|
|
59
|
-
|
|
60
|
-
const testData = loadTestData();
|
|
61
|
-
|
|
62
|
-
describe('E2E Flow: {Scenario Name}', () => {
|
|
63
|
-
beforeAll(async () => {
|
|
64
|
-
await device.launchApp({ newInstance: true });
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Main Flow
|
|
68
|
-
describe('{PROJECT}_E{EPIC}_E2E_001_H: {Flow Title}', () => {
|
|
69
|
-
it('Step 1: {Action}', async () => {
|
|
70
|
-
// Reuses: AL_E002_F002_S001_FT_001_H
|
|
71
|
-
const creds = getCredentials();
|
|
72
|
-
await fillLoginForm(creds.email, creds.password);
|
|
73
|
-
await verifyLoginSuccess();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('Step 2: {Action}', async () => {
|
|
77
|
-
// Reuses: AL_E003_F001_S001_FT_001_H
|
|
78
|
-
await viewAllergenList();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('Step 3: {New logic - no FT reference}', async () => {
|
|
82
|
-
// New step: no functional test helper exists
|
|
83
|
-
await element(by.id(TEST_IDS.SCAN.SCREEN.CAMERA)).tap();
|
|
84
|
-
// ...
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Alternate Flow (if defined in scenario)
|
|
89
|
-
describe('{PROJECT}_E{EPIC}_E2E_002_N: {Alternate Flow}', () => {
|
|
90
|
-
it('should handle {error condition}', async () => {
|
|
91
|
-
// ...
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
###
|
|
98
|
-
|
|
99
|
-
```json
|
|
100
|
-
"e2e:flow:{scenario-slug}": "detox test --configuration ios.sim.debug --testPathPattern='e2e/flows/{scenario-slug}'"
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
###
|
|
104
|
-
|
|
105
|
-
- Summary metrics (passed/failed/skipped)
|
|
106
|
-
- Results by test ID
|
|
107
|
-
- Failed test details
|
|
108
|
-
- Performance metrics
|
|
109
|
-
- AC coverage analysis
|
|
110
|
-
|
|
111
|
-
## File Structure Output
|
|
112
|
-
```
|
|
113
|
-
apps/mobile/e2e/flows/
|
|
114
|
-
├── {scenario-1-slug}.e2e.ts
|
|
115
|
-
├── {scenario-2-slug}.e2e.ts
|
|
116
|
-
└── ...
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Reuse Strategy
|
|
120
|
-
```
|
|
121
|
-
Layer 2 (features/) Layer 3 (flows/)
|
|
122
|
-
┌───────────────────┐ ┌──────────────────────┐
|
|
123
|
-
│ helpers.ts │──────>│ {scenario}.e2e.ts │
|
|
124
|
-
│ - fillLoginForm()│ │ import { fillLogin } │
|
|
125
|
-
│ - verifyLogin() │ │ import { viewList } │
|
|
126
|
-
└───────────────────┘ │ │
|
|
127
|
-
┌───────────────────┐ │ Step 1: fillLogin() │
|
|
128
|
-
│ helpers.ts │──────>│ Step 2: viewList() │
|
|
129
|
-
│ - viewList() │ │ Step 3: new logic │
|
|
130
|
-
└───────────────────┘ └──────────────────────┘
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
##
|
|
134
|
-
```bash
|
|
135
|
-
#
|
|
136
|
-
yarn e2e:flow:{scenario-slug}
|
|
137
|
-
|
|
138
|
-
#
|
|
139
|
-
npx detox test --configuration ios.sim.debug --testPathPattern='e2e/flows/'
|
|
140
|
-
|
|
141
|
-
#
|
|
142
|
-
npx detox test --configuration android.emu.debug --testPathPattern='e2e/flows/{scenario}'
|
|
143
|
-
|
|
144
|
-
#
|
|
145
|
-
npx detox test --configuration ios.sim.debug --testPathPattern='e2e/flows/{scenario}' --reporters=jest-junit
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
##
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
- Steps
|
|
152
|
-
- Scripts
|
|
153
|
-
-
|
|
154
|
-
- describe block
|
|
155
|
-
- import paths: relative
|
|
1
|
+
# /tas-e2e-mobile $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Role: SE / QA
|
|
4
|
+
Generate Detox E2E test scripts from an E2E Scenario markdown file.
|
|
5
|
+
|
|
6
|
+
## IMPORTANT - Layer 3: Mobile E2E Scripts
|
|
7
|
+
- Create Detox test scripts from E2E-Scenario (markdown)
|
|
8
|
+
- Scripts located in `apps/mobile/e2e/flows/`
|
|
9
|
+
- REUSE helpers from Layer 2 functional tests (features/)
|
|
10
|
+
- Chain functional test steps into end-to-end flows
|
|
11
|
+
|
|
12
|
+
## Actions
|
|
13
|
+
|
|
14
|
+
### Step 1: Identify Scenario
|
|
15
|
+
1. $ARGUMENTS is path to E2E-Scenario-*.md file
|
|
16
|
+
2. If not provided: scan `docs/epics/**/E2E-Scenario-*.md` and `docs/e2e-scenarios/E2E-Scenario-*.md`
|
|
17
|
+
3. List scenarios and ask user to choose
|
|
18
|
+
|
|
19
|
+
### Step 2: Check Prerequisites
|
|
20
|
+
1. Check `apps/mobile/` exists. If not → graceful error
|
|
21
|
+
2. Read scenario file to get:
|
|
22
|
+
- Scenario steps and flow
|
|
23
|
+
- FT ID references ("Builds on FT IDs" column)
|
|
24
|
+
- FT Reuse Map (section at end)
|
|
25
|
+
- Test data per environment
|
|
26
|
+
- Scenario type (single-epic / cross-epic)
|
|
27
|
+
|
|
28
|
+
### Step 3: Find Functional Test Helpers
|
|
29
|
+
From FT Reuse Map in scenario:
|
|
30
|
+
1. Find each source file in `apps/mobile/e2e/features/`
|
|
31
|
+
2. Verify helper functions exist
|
|
32
|
+
3. If helper doesn't exist → create stub and note "TODO: implement helper"
|
|
33
|
+
4. Import map: FT ID → file path → function name
|
|
34
|
+
|
|
35
|
+
### Step 4: Generate E2E Script
|
|
36
|
+
|
|
37
|
+
**File output**: `apps/mobile/e2e/flows/{scenario-slug}.e2e.ts`
|
|
38
|
+
|
|
39
|
+
**Structure**:
|
|
40
|
+
```typescript
|
|
41
|
+
/**
|
|
42
|
+
* E2E Flow: {Scenario Name}
|
|
43
|
+
* Scenario: {Scenario_ID}
|
|
44
|
+
* Epic(s): {Epic_ID(s)}
|
|
45
|
+
* Type: {single-epic | cross-epic}
|
|
46
|
+
*
|
|
47
|
+
* Generated by /tas-e2e-mobile
|
|
48
|
+
* Spec: {path to E2E-Scenario-*.md}
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
import { device, element, expect, by, waitFor } from 'detox';
|
|
52
|
+
import { TEST_IDS } from '../test-ids';
|
|
53
|
+
import { loadTestData, getCredentials } from '../helpers/data-loader';
|
|
54
|
+
import { login, logout, navigateToTab } from '../helpers/test-utils';
|
|
55
|
+
|
|
56
|
+
// Layer 2 helpers (reuse from functional tests)
|
|
57
|
+
import { fillLoginForm, verifyLoginSuccess } from '../features/{epic}/{feature}/helpers';
|
|
58
|
+
import { viewAllergenList } from '../features/{epic2}/{feature2}/helpers';
|
|
59
|
+
|
|
60
|
+
const testData = loadTestData();
|
|
61
|
+
|
|
62
|
+
describe('E2E Flow: {Scenario Name}', () => {
|
|
63
|
+
beforeAll(async () => {
|
|
64
|
+
await device.launchApp({ newInstance: true });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Main Flow
|
|
68
|
+
describe('{PROJECT}_E{EPIC}_E2E_001_H: {Flow Title}', () => {
|
|
69
|
+
it('Step 1: {Action}', async () => {
|
|
70
|
+
// Reuses: AL_E002_F002_S001_FT_001_H
|
|
71
|
+
const creds = getCredentials();
|
|
72
|
+
await fillLoginForm(creds.email, creds.password);
|
|
73
|
+
await verifyLoginSuccess();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('Step 2: {Action}', async () => {
|
|
77
|
+
// Reuses: AL_E003_F001_S001_FT_001_H
|
|
78
|
+
await viewAllergenList();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('Step 3: {New logic - no FT reference}', async () => {
|
|
82
|
+
// New step: no functional test helper exists
|
|
83
|
+
await element(by.id(TEST_IDS.SCAN.SCREEN.CAMERA)).tap();
|
|
84
|
+
// ...
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Alternate Flow (if defined in scenario)
|
|
89
|
+
describe('{PROJECT}_E{EPIC}_E2E_002_N: {Alternate Flow}', () => {
|
|
90
|
+
it('should handle {error condition}', async () => {
|
|
91
|
+
// ...
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Step 5: Update package.json Script
|
|
98
|
+
Add or update script in `apps/mobile/package.json`:
|
|
99
|
+
```json
|
|
100
|
+
"e2e:flow:{scenario-slug}": "detox test --configuration ios.sim.debug --testPathPattern='e2e/flows/{scenario-slug}'"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Step 6: Generate Execution Report (Optional)
|
|
104
|
+
After running tests, generate report from `.tas/templates/E2E-Execution-Report.md`:
|
|
105
|
+
- Summary metrics (passed/failed/skipped)
|
|
106
|
+
- Results by test ID
|
|
107
|
+
- Failed test details
|
|
108
|
+
- Performance metrics
|
|
109
|
+
- AC coverage analysis
|
|
110
|
+
|
|
111
|
+
## File Structure Output
|
|
112
|
+
```
|
|
113
|
+
apps/mobile/e2e/flows/
|
|
114
|
+
├── {scenario-1-slug}.e2e.ts
|
|
115
|
+
├── {scenario-2-slug}.e2e.ts
|
|
116
|
+
└── ...
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Reuse Strategy
|
|
120
|
+
```
|
|
121
|
+
Layer 2 (features/) Layer 3 (flows/)
|
|
122
|
+
┌───────────────────┐ ┌──────────────────────┐
|
|
123
|
+
│ helpers.ts │──────>│ {scenario}.e2e.ts │
|
|
124
|
+
│ - fillLoginForm()│ │ import { fillLogin } │
|
|
125
|
+
│ - verifyLogin() │ │ import { viewList } │
|
|
126
|
+
└───────────────────┘ │ │
|
|
127
|
+
┌───────────────────┐ │ Step 1: fillLogin() │
|
|
128
|
+
│ helpers.ts │──────>│ Step 2: viewList() │
|
|
129
|
+
│ - viewList() │ │ Step 3: new logic │
|
|
130
|
+
└───────────────────┘ └──────────────────────┘
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Run Tests
|
|
134
|
+
```bash
|
|
135
|
+
# Run specific E2E flow
|
|
136
|
+
yarn e2e:flow:{scenario-slug}
|
|
137
|
+
|
|
138
|
+
# Run all E2E flows
|
|
139
|
+
npx detox test --configuration ios.sim.debug --testPathPattern='e2e/flows/'
|
|
140
|
+
|
|
141
|
+
# Run with Android
|
|
142
|
+
npx detox test --configuration android.emu.debug --testPathPattern='e2e/flows/{scenario}'
|
|
143
|
+
|
|
144
|
+
# Run and generate report
|
|
145
|
+
npx detox test --configuration ios.sim.debug --testPathPattern='e2e/flows/{scenario}' --reporters=jest-junit
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Principles
|
|
149
|
+
- MUST reuse helpers from Layer 2 when possible, DO NOT rewrite existing logic
|
|
150
|
+
- Each step in E2E flow should correspond to 1 functional test helper
|
|
151
|
+
- Steps without FT reference → write new logic in flow file
|
|
152
|
+
- Scripts MUST be runnable from CLI, WITHOUT Claude window
|
|
153
|
+
- If apps/mobile/ doesn't exist → graceful error
|
|
154
|
+
- describe block uses full E2E ID for grep-ability
|
|
155
|
+
- import paths: relative from flows/ up to features/
|
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
# /tas-e2e-web $ARGUMENTS
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Generate Playwright E2E test scripts
|
|
5
|
-
|
|
6
|
-
##
|
|
7
|
-
-
|
|
8
|
-
- Scripts
|
|
9
|
-
- REUSE helpers
|
|
10
|
-
- Cross-browser testing (Chromium, Firefox, WebKit)
|
|
11
|
-
- Chain functional test steps
|
|
12
|
-
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
###
|
|
16
|
-
1. $ARGUMENTS
|
|
17
|
-
2.
|
|
18
|
-
3. List scenarios
|
|
19
|
-
|
|
20
|
-
###
|
|
21
|
-
1.
|
|
22
|
-
> "Web app
|
|
23
|
-
>
|
|
24
|
-
2.
|
|
25
|
-
- Scenario steps
|
|
26
|
-
- FT ID references
|
|
27
|
-
- FT Reuse Map
|
|
28
|
-
- Test data per environment
|
|
29
|
-
3.
|
|
30
|
-
|
|
31
|
-
###
|
|
32
|
-
|
|
33
|
-
1.
|
|
34
|
-
2. Verify helper functions
|
|
35
|
-
3.
|
|
36
|
-
4. Import map: FT ID → file path → function name
|
|
37
|
-
|
|
38
|
-
###
|
|
39
|
-
|
|
40
|
-
**File output**: `apps/web/e2e/flows/{scenario-slug}.spec.ts`
|
|
41
|
-
|
|
42
|
-
**Structure**:
|
|
43
|
-
```typescript
|
|
44
|
-
/**
|
|
45
|
-
* E2E Flow: {Scenario Name}
|
|
46
|
-
* Scenario: {Scenario_ID}
|
|
47
|
-
* Epic(s): {Epic_ID(s)}
|
|
48
|
-
* Type: {single-epic | cross-epic}
|
|
49
|
-
*
|
|
50
|
-
* Generated by /tas-e2e-web
|
|
51
|
-
* Spec: {path to E2E-Scenario-*.md}
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
import { test, expect, Page } from '@playwright/test';
|
|
55
|
-
import { loadTestData, getCredentials } from '../helpers/data-loader';
|
|
56
|
-
|
|
57
|
-
// Layer 2 helpers (reuse from functional tests)
|
|
58
|
-
import { fillLoginForm, verifyLoginSuccess } from '../features/{epic}/{feature}/helpers';
|
|
59
|
-
import { viewAllergenList } from '../features/{epic2}/{feature2}/helpers';
|
|
60
|
-
|
|
61
|
-
const testData = loadTestData();
|
|
62
|
-
|
|
63
|
-
test.describe('E2E Flow: {Scenario Name}', () => {
|
|
64
|
-
test.beforeEach(async ({ page }) => {
|
|
65
|
-
await page.goto(testData.baseUrl);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Main Flow
|
|
69
|
-
test.describe('{PROJECT}_E{EPIC}_E2E_001_H: {Flow Title}', () => {
|
|
70
|
-
test('Complete flow', async ({ page }) => {
|
|
71
|
-
// Step 1: Login (reuses AL_E002_F002_S001_FT_001_H)
|
|
72
|
-
const creds = getCredentials();
|
|
73
|
-
await fillLoginForm(page, creds.email, creds.password);
|
|
74
|
-
await verifyLoginSuccess(page);
|
|
75
|
-
|
|
76
|
-
// Step 2: View allergen list (reuses AL_E003_F001_S001_FT_001_H)
|
|
77
|
-
await viewAllergenList(page);
|
|
78
|
-
|
|
79
|
-
// Step 3: New logic (no FT reference)
|
|
80
|
-
await page.getByTestId('scan-button').click();
|
|
81
|
-
await expect(page.getByTestId('scan-result')).toBeVisible();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Cross-browser validation
|
|
86
|
-
test.describe('{PROJECT}_E{EPIC}_E2E_001_H - Cross-browser', () => {
|
|
87
|
-
test('should complete flow on all browsers', async ({ page, browserName }) => {
|
|
88
|
-
test.info().annotations.push({ type: 'browser', description: browserName });
|
|
89
|
-
// Same flow, validated across browsers via Playwright projects config
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Alternate/Error flows
|
|
94
|
-
test.describe('{PROJECT}_E{EPIC}_E2E_002_N: {Error Flow}', () => {
|
|
95
|
-
test('should handle {error condition}', async ({ page }) => {
|
|
96
|
-
// ...
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
###
|
|
103
|
-
|
|
104
|
-
```json
|
|
105
|
-
"e2e:flow:{scenario-slug}": "npx playwright test e2e/flows/{scenario-slug}"
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
###
|
|
109
|
-
|
|
110
|
-
-
|
|
111
|
-
- Viewport testing results
|
|
112
|
-
- Performance metrics (LCP, INP, CLS)
|
|
113
|
-
|
|
114
|
-
## File Structure Output
|
|
115
|
-
```
|
|
116
|
-
apps/web/e2e/flows/
|
|
117
|
-
├── {scenario-1-slug}.spec.ts
|
|
118
|
-
├── {scenario-2-slug}.spec.ts
|
|
119
|
-
└── ...
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Reuse Strategy
|
|
123
|
-
```
|
|
124
|
-
Layer 2 (features/) Layer 3 (flows/)
|
|
125
|
-
┌───────────────────┐ ┌──────────────────────────┐
|
|
126
|
-
│ helpers.ts │──────>│ {scenario}.spec.ts │
|
|
127
|
-
│ - fillLogin(page)│ │ import { fillLogin } │
|
|
128
|
-
│ - verify(page) │ │ import { viewList } │
|
|
129
|
-
└───────────────────┘ │ │
|
|
130
|
-
┌───────────────────┐ │ Step 1: fillLogin(page) │
|
|
131
|
-
│ helpers.ts │──────>│ Step 2: viewList(page) │
|
|
132
|
-
│ - viewList(page) │ │ Step 3: new logic │
|
|
133
|
-
└───────────────────┘ └──────────────────────────┘
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Note: Web helpers
|
|
137
|
-
|
|
138
|
-
##
|
|
139
|
-
```bash
|
|
140
|
-
#
|
|
141
|
-
yarn e2e:flow:{scenario-slug}
|
|
142
|
-
|
|
143
|
-
#
|
|
144
|
-
npx playwright test e2e/flows/
|
|
145
|
-
|
|
146
|
-
#
|
|
147
|
-
npx playwright test --project=firefox e2e/flows/{scenario}
|
|
148
|
-
|
|
149
|
-
#
|
|
150
|
-
npx playwright test --ui e2e/flows/{scenario}
|
|
151
|
-
|
|
152
|
-
#
|
|
153
|
-
npx playwright test e2e/flows/{scenario} --reporter=html
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
##
|
|
157
|
-
-
|
|
158
|
-
- Web helpers
|
|
159
|
-
- Scripts
|
|
160
|
-
-
|
|
161
|
-
- Cross-browser: Chromium, Firefox, WebKit (
|
|
162
|
-
- describe block
|
|
163
|
-
- import paths: relative
|
|
1
|
+
# /tas-e2e-web $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Role: SE / QA
|
|
4
|
+
Generate Playwright E2E test scripts from an E2E Scenario markdown file.
|
|
5
|
+
|
|
6
|
+
## IMPORTANT - Layer 3: Web E2E Scripts
|
|
7
|
+
- Create Playwright test scripts from E2E-Scenario (markdown)
|
|
8
|
+
- Scripts located in `apps/web/e2e/flows/`
|
|
9
|
+
- REUSE helpers from Layer 2 functional tests (features/)
|
|
10
|
+
- Cross-browser testing (Chromium, Firefox, WebKit)
|
|
11
|
+
- Chain functional test steps into end-to-end flows
|
|
12
|
+
|
|
13
|
+
## Actions
|
|
14
|
+
|
|
15
|
+
### Step 1: Identify Scenario
|
|
16
|
+
1. $ARGUMENTS is path to E2E-Scenario-*.md file
|
|
17
|
+
2. If not provided: scan `docs/epics/**/E2E-Scenario-*.md` and `docs/e2e-scenarios/E2E-Scenario-*.md`
|
|
18
|
+
3. List scenarios and ask user to choose
|
|
19
|
+
|
|
20
|
+
### Step 2: Check Prerequisites
|
|
21
|
+
1. Check `apps/web/` exists. If not → report:
|
|
22
|
+
> "Web app doesn't exist in this project. If project only has mobile, use /tas-e2e-mobile."
|
|
23
|
+
> STOP, DO NOT create file.
|
|
24
|
+
2. Read scenario file to get:
|
|
25
|
+
- Scenario steps and flow
|
|
26
|
+
- FT ID references
|
|
27
|
+
- FT Reuse Map
|
|
28
|
+
- Test data per environment
|
|
29
|
+
3. Read `apps/web/playwright.config.ts` (if exists)
|
|
30
|
+
|
|
31
|
+
### Step 3: Find Functional Test Helpers
|
|
32
|
+
From FT Reuse Map in scenario:
|
|
33
|
+
1. Find source files in `apps/web/e2e/features/`
|
|
34
|
+
2. Verify helper functions and page objects exist
|
|
35
|
+
3. If helper doesn't exist → create stub and note "TODO: implement helper"
|
|
36
|
+
4. Import map: FT ID → file path → function name
|
|
37
|
+
|
|
38
|
+
### Step 4: Generate E2E Script
|
|
39
|
+
|
|
40
|
+
**File output**: `apps/web/e2e/flows/{scenario-slug}.spec.ts`
|
|
41
|
+
|
|
42
|
+
**Structure**:
|
|
43
|
+
```typescript
|
|
44
|
+
/**
|
|
45
|
+
* E2E Flow: {Scenario Name}
|
|
46
|
+
* Scenario: {Scenario_ID}
|
|
47
|
+
* Epic(s): {Epic_ID(s)}
|
|
48
|
+
* Type: {single-epic | cross-epic}
|
|
49
|
+
*
|
|
50
|
+
* Generated by /tas-e2e-web
|
|
51
|
+
* Spec: {path to E2E-Scenario-*.md}
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
import { test, expect, Page } from '@playwright/test';
|
|
55
|
+
import { loadTestData, getCredentials } from '../helpers/data-loader';
|
|
56
|
+
|
|
57
|
+
// Layer 2 helpers (reuse from functional tests)
|
|
58
|
+
import { fillLoginForm, verifyLoginSuccess } from '../features/{epic}/{feature}/helpers';
|
|
59
|
+
import { viewAllergenList } from '../features/{epic2}/{feature2}/helpers';
|
|
60
|
+
|
|
61
|
+
const testData = loadTestData();
|
|
62
|
+
|
|
63
|
+
test.describe('E2E Flow: {Scenario Name}', () => {
|
|
64
|
+
test.beforeEach(async ({ page }) => {
|
|
65
|
+
await page.goto(testData.baseUrl);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Main Flow
|
|
69
|
+
test.describe('{PROJECT}_E{EPIC}_E2E_001_H: {Flow Title}', () => {
|
|
70
|
+
test('Complete flow', async ({ page }) => {
|
|
71
|
+
// Step 1: Login (reuses AL_E002_F002_S001_FT_001_H)
|
|
72
|
+
const creds = getCredentials();
|
|
73
|
+
await fillLoginForm(page, creds.email, creds.password);
|
|
74
|
+
await verifyLoginSuccess(page);
|
|
75
|
+
|
|
76
|
+
// Step 2: View allergen list (reuses AL_E003_F001_S001_FT_001_H)
|
|
77
|
+
await viewAllergenList(page);
|
|
78
|
+
|
|
79
|
+
// Step 3: New logic (no FT reference)
|
|
80
|
+
await page.getByTestId('scan-button').click();
|
|
81
|
+
await expect(page.getByTestId('scan-result')).toBeVisible();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Cross-browser validation
|
|
86
|
+
test.describe('{PROJECT}_E{EPIC}_E2E_001_H - Cross-browser', () => {
|
|
87
|
+
test('should complete flow on all browsers', async ({ page, browserName }) => {
|
|
88
|
+
test.info().annotations.push({ type: 'browser', description: browserName });
|
|
89
|
+
// Same flow, validated across browsers via Playwright projects config
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Alternate/Error flows
|
|
94
|
+
test.describe('{PROJECT}_E{EPIC}_E2E_002_N: {Error Flow}', () => {
|
|
95
|
+
test('should handle {error condition}', async ({ page }) => {
|
|
96
|
+
// ...
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Step 5: Update package.json Script
|
|
103
|
+
Add or update script in `apps/web/package.json`:
|
|
104
|
+
```json
|
|
105
|
+
"e2e:flow:{scenario-slug}": "npx playwright test e2e/flows/{scenario-slug}"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Step 6: Generate Execution Report (Optional)
|
|
109
|
+
From `.tas/templates/E2E-Execution-Report.md`:
|
|
110
|
+
- Include browser-specific results
|
|
111
|
+
- Viewport testing results
|
|
112
|
+
- Performance metrics (LCP, INP, CLS)
|
|
113
|
+
|
|
114
|
+
## File Structure Output
|
|
115
|
+
```
|
|
116
|
+
apps/web/e2e/flows/
|
|
117
|
+
├── {scenario-1-slug}.spec.ts
|
|
118
|
+
├── {scenario-2-slug}.spec.ts
|
|
119
|
+
└── ...
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Reuse Strategy
|
|
123
|
+
```
|
|
124
|
+
Layer 2 (features/) Layer 3 (flows/)
|
|
125
|
+
┌───────────────────┐ ┌──────────────────────────┐
|
|
126
|
+
│ helpers.ts │──────>│ {scenario}.spec.ts │
|
|
127
|
+
│ - fillLogin(page)│ │ import { fillLogin } │
|
|
128
|
+
│ - verify(page) │ │ import { viewList } │
|
|
129
|
+
└───────────────────┘ │ │
|
|
130
|
+
┌───────────────────┐ │ Step 1: fillLogin(page) │
|
|
131
|
+
│ helpers.ts │──────>│ Step 2: viewList(page) │
|
|
132
|
+
│ - viewList(page) │ │ Step 3: new logic │
|
|
133
|
+
└───────────────────┘ └──────────────────────────┘
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Note: Web helpers receive `page: Page` parameter (unlike mobile using global Detox API).
|
|
137
|
+
|
|
138
|
+
## Run Tests
|
|
139
|
+
```bash
|
|
140
|
+
# Run specific E2E flow
|
|
141
|
+
yarn e2e:flow:{scenario-slug}
|
|
142
|
+
|
|
143
|
+
# Run all E2E flows
|
|
144
|
+
npx playwright test e2e/flows/
|
|
145
|
+
|
|
146
|
+
# Run only on Firefox
|
|
147
|
+
npx playwright test --project=firefox e2e/flows/{scenario}
|
|
148
|
+
|
|
149
|
+
# Run with debug UI
|
|
150
|
+
npx playwright test --ui e2e/flows/{scenario}
|
|
151
|
+
|
|
152
|
+
# Run and generate HTML report
|
|
153
|
+
npx playwright test e2e/flows/{scenario} --reporter=html
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Principles
|
|
157
|
+
- MUST reuse helpers from Layer 2 when possible
|
|
158
|
+
- Web helpers MUST receive `page: Page` parameter (dependency injection)
|
|
159
|
+
- Scripts MUST be runnable from CLI
|
|
160
|
+
- If apps/web/ doesn't exist → graceful error, DO NOT create
|
|
161
|
+
- Cross-browser: Chromium, Firefox, WebKit (from playwright.config.ts)
|
|
162
|
+
- describe block uses full E2E ID
|
|
163
|
+
- import paths: relative from flows/ up to features/
|