driftx 0.1.0 → 0.1.2
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/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/bin.js +842 -84
- package/dist/bin.js.map +1 -1
- package/driftx-plugin/skills/driftx/SKILL.md +514 -0
- package/ios-companion/DriftxCompanion/DriftxCompanionApp.swift +10 -0
- package/ios-companion/DriftxCompanion/Info.plist +22 -0
- package/ios-companion/DriftxCompanion.xcodeproj/project.pbxproj +376 -0
- package/ios-companion/DriftxCompanion.xcodeproj/xcshareddata/xcschemes/DriftxCompanionUITests.xcscheme +109 -0
- package/ios-companion/DriftxCompanionUITests/CompanionServer.swift +176 -0
- package/ios-companion/DriftxCompanionUITests/DriftxCompanionUITests.swift +15 -0
- package/ios-companion/DriftxCompanionUITests/HierarchyEndpoint.swift +140 -0
- package/ios-companion/DriftxCompanionUITests/Info.plist +22 -0
- package/ios-companion/DriftxCompanionUITests/InteractionEndpoint.swift +142 -0
- package/ios-companion/DriftxCompanionUITests/Router.swift +47 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/DriftxCompanion +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/DriftxCompanion.debug.dylib +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/PkgInfo +1 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/__preview.dylib +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/DriftxCompanionUITests-Runner +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/Testing +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/_CodeSignature/CodeResources +168 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/XCTAutomationSupport +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/_CodeSignature/CodeResources +113 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/XCTest +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/_CodeSignature/CodeResources +817 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/XCTestCore +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/_CodeSignature/CodeResources +113 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/XCTestSupport +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/_CodeSignature/CodeResources +113 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/XCUIAutomation +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/_CodeSignature/CodeResources +432 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/Info.plist +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/XCUnit +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/_CodeSignature/CodeResources +113 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/version.plist +18 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/libXCTestSwiftSupport.dylib +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Info.plist +254 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/PkgInfo +1 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/PlugIns/DriftxCompanionUITests.xctest/DriftxCompanionUITests +0 -0
- package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/PlugIns/DriftxCompanionUITests.xctest/Info.plist +0 -0
- package/ios-companion/prebuilt/DriftxCompanionUITests.xctestrun +135 -0
- package/ios-companion/prebuilt/build-info.json +6 -0
- package/package.json +19 -4
- package/driftx-plugin/skills/driftx.md +0 -299
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: driftx
|
|
3
|
+
description: Visual comparison, accessibility audit, layout regression, and device interaction for mobile apps (Android, iOS, React Native). Use when the user asks to compare their app against a design, check accessibility, detect visual regressions, inspect the component tree, capture screenshots, or interact with a device/simulator (tap, type, swipe, navigate).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# driftx — Visual Analysis for React Native & Android
|
|
7
|
+
|
|
8
|
+
Use driftx when the user wants to:
|
|
9
|
+
- Compare their running app against a design image (Figma export, mockup, etc.)
|
|
10
|
+
- Run an accessibility audit on the component tree
|
|
11
|
+
- Detect layout regressions between builds
|
|
12
|
+
- Inspect the React Native component tree on a device
|
|
13
|
+
- Capture a screenshot from a running simulator/emulator
|
|
14
|
+
- Interact with the app — tap buttons, type text, swipe, navigate back, open deep links
|
|
15
|
+
- Test a user flow end-to-end (navigate, interact, then verify visually)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g driftx
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The iOS companion ships pre-built — no Xcode build step required on install.
|
|
24
|
+
driftx will notify you when a newer version is available.
|
|
25
|
+
|
|
26
|
+
## Prerequisites
|
|
27
|
+
|
|
28
|
+
Run `driftx doctor` to verify the environment is set up correctly.
|
|
29
|
+
|
|
30
|
+
**Requirements:**
|
|
31
|
+
- **Metro bundler** must be running (`npx react-native start`) for tree inspection, tap resolution, and bundle ID auto-detection
|
|
32
|
+
- **Android**: `adb` available, emulator booted
|
|
33
|
+
- **iOS**: `xcrun simctl` available, simulator booted. The XCUITest companion auto-launches when needed.
|
|
34
|
+
|
|
35
|
+
## Platform Support
|
|
36
|
+
|
|
37
|
+
driftx currently supports **simulators and emulators only**:
|
|
38
|
+
- **Android**: Emulators via `adb`
|
|
39
|
+
- **iOS**: Simulators via `xcrun simctl` + XCUITest companion
|
|
40
|
+
|
|
41
|
+
Physical device support is not yet available (requires code signing for XCUITest companion deployment and alternative screenshot tooling).
|
|
42
|
+
|
|
43
|
+
## Global Flags
|
|
44
|
+
|
|
45
|
+
| Flag | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `-d, --device <id>` | Device ID or name. If omitted and multiple devices are booted, driftx shows a picker. |
|
|
48
|
+
| `--bundle-id <id>` | iOS app bundle identifier. Optional — auto-detected from Metro CDP target when Metro is running. |
|
|
49
|
+
| `--verbose` | Enable debug logging. Useful for diagnosing tap resolution, companion issues, or CDP connection problems. |
|
|
50
|
+
| `--format <type>` | Output format: `terminal`, `markdown`, `json` (default: `terminal`). |
|
|
51
|
+
| `--copy` | Copy output to clipboard. |
|
|
52
|
+
|
|
53
|
+
## Commands Reference
|
|
54
|
+
|
|
55
|
+
### `driftx compare` — Run visual analysis
|
|
56
|
+
|
|
57
|
+
The primary command. Compares a screenshot from a running device against a design image or baseline.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Compare against a design image
|
|
61
|
+
npx driftx compare --design path/to/design.png --format json
|
|
62
|
+
|
|
63
|
+
# Compare with specific device
|
|
64
|
+
npx driftx compare --design path/to/design.png --device "iPhone 16 Pro" --format json
|
|
65
|
+
|
|
66
|
+
# Use an existing screenshot instead of capturing
|
|
67
|
+
npx driftx compare --design path/to/design.png --screenshot path/to/screenshot.png --format json
|
|
68
|
+
|
|
69
|
+
# Run only specific analyses
|
|
70
|
+
npx driftx compare --design path/to/design.png --with pixel,a11y --format json
|
|
71
|
+
|
|
72
|
+
# Exclude specific analyses
|
|
73
|
+
npx driftx compare --design path/to/design.png --without pixel --format json
|
|
74
|
+
|
|
75
|
+
# Regression mode — compare against previous run (no design needed)
|
|
76
|
+
npx driftx compare --baseline --format json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Flags:**
|
|
80
|
+
| Flag | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| `--design <path>` | Path to design image (PNG). Required unless `--baseline`. |
|
|
83
|
+
| `--screenshot <path>` | Use existing screenshot instead of capturing from device. |
|
|
84
|
+
| `--threshold <n>` | Pixel sensitivity threshold (0-1, default 0.1). |
|
|
85
|
+
| `--with <analyses>` | Comma-separated analyses to run (e.g., `pixel,a11y,regression`). |
|
|
86
|
+
| `--without <analyses>` | Analyses to exclude. |
|
|
87
|
+
| `--baseline` | Compare against previous run's screenshot. |
|
|
88
|
+
| `--format json` | **Always use this** for structured output. |
|
|
89
|
+
|
|
90
|
+
**Available analyses:**
|
|
91
|
+
| Analysis | What it does | Auto-enabled when |
|
|
92
|
+
|----------|-------------|-------------------|
|
|
93
|
+
| `pixel` | Pixel-level diff between screenshot and design | Design image provided |
|
|
94
|
+
| `a11y` | Accessibility audit — missing labels, small tap targets, images without alt text | Component tree available (device connected) |
|
|
95
|
+
| `regression` | Layout regression — diff against previous run | `--baseline` flag used |
|
|
96
|
+
|
|
97
|
+
**Smart defaults:** When no `--with`/`--without` is specified, analyses auto-enable based on available inputs. You don't need to specify `--with` unless you want to override.
|
|
98
|
+
|
|
99
|
+
### `driftx inspect` — Inspect component tree
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx driftx inspect --format json
|
|
103
|
+
npx driftx inspect --json # shorthand for --format json
|
|
104
|
+
npx driftx inspect --device "Pixel 8" --format json
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Returns the React Native component tree with component names, testIDs, text content, and bounds. Use this to discover tap targets before interacting — the tree shows all visible text, testIDs, and component names that `driftx tap` can target.
|
|
108
|
+
|
|
109
|
+
### `driftx devices` — List connected devices
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npx driftx devices --format json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Returns available simulators/emulators and their state (booted/offline). When multiple devices are booted and no `-d` flag is provided, driftx shows an interactive picker.
|
|
116
|
+
|
|
117
|
+
### `driftx capture` — Capture screenshot
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx driftx capture --output screenshot.png
|
|
121
|
+
npx driftx capture --device "iPhone 16 Pro" --output screenshot.png
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Captures a screenshot from the device and saves it to the specified path.
|
|
125
|
+
|
|
126
|
+
### `driftx doctor` — Check prerequisites
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx driftx doctor --format json
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Checks that adb, xcrun, Metro, etc. are available.
|
|
133
|
+
|
|
134
|
+
### `driftx setup-claude` — Register as Claude Code plugin
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npx driftx setup-claude
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Registers driftx as a Claude Code plugin so the skill is available in all projects.
|
|
141
|
+
|
|
142
|
+
## Output Interpretation
|
|
143
|
+
|
|
144
|
+
### JSON format (CompareReport)
|
|
145
|
+
|
|
146
|
+
When using `--format json`, `driftx compare` outputs a `CompareReport`:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"report": {
|
|
151
|
+
"runId": "abc123",
|
|
152
|
+
"analyses": [
|
|
153
|
+
{
|
|
154
|
+
"analysisName": "pixel",
|
|
155
|
+
"findings": [...],
|
|
156
|
+
"summary": "Pixel diff: 2.100% — 3 regions (fail)",
|
|
157
|
+
"metadata": {
|
|
158
|
+
"diffPercentage": 2.1,
|
|
159
|
+
"diffPixels": 5000,
|
|
160
|
+
"totalPixels": 238000,
|
|
161
|
+
"regions": [...],
|
|
162
|
+
"passed": false
|
|
163
|
+
},
|
|
164
|
+
"durationMs": 450
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"analysisName": "a11y",
|
|
168
|
+
"findings": [...],
|
|
169
|
+
"summary": "2 accessibility issues found",
|
|
170
|
+
"metadata": {
|
|
171
|
+
"totalChecked": 15,
|
|
172
|
+
"issuesByType": { "label": 1, "tapTarget": 1, "image": 0, "emptyText": 0 }
|
|
173
|
+
},
|
|
174
|
+
"durationMs": 5
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"findings": [...],
|
|
178
|
+
"summary": "...",
|
|
179
|
+
"durationMs": 460
|
|
180
|
+
},
|
|
181
|
+
"artifactDir": ".driftx/runs/abc123"
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Key fields to check:
|
|
186
|
+
- `report.analyses[].metadata.passed` — `false` means the analysis failed its threshold
|
|
187
|
+
- `report.analyses[].findings` — individual issues found
|
|
188
|
+
- `report.findings` — all findings merged across analyses
|
|
189
|
+
- `artifactDir` — where screenshots, diff masks, and region crops are saved
|
|
190
|
+
|
|
191
|
+
### Artifacts
|
|
192
|
+
|
|
193
|
+
After a compare run, artifacts are saved to `.driftx/runs/<runId>/`:
|
|
194
|
+
|
|
195
|
+
| File | Description |
|
|
196
|
+
|------|-------------|
|
|
197
|
+
| `screenshot.png` | Captured screenshot |
|
|
198
|
+
| `design.png` | Copy of the design image |
|
|
199
|
+
| `diff-mask.png` | Visual overlay showing pixel differences |
|
|
200
|
+
| `regions/<id>.png` | Cropped images of each diff region |
|
|
201
|
+
| `regression-diff-mask.png` | Diff mask for regression analysis |
|
|
202
|
+
| `result.json` | Full CompareReport as JSON |
|
|
203
|
+
| `report.md` | Human-readable markdown report |
|
|
204
|
+
|
|
205
|
+
Read `report.md` for a formatted summary. Read `result.json` for structured data. View diff mask and region crops to understand what changed visually.
|
|
206
|
+
|
|
207
|
+
### Finding categories
|
|
208
|
+
|
|
209
|
+
| Category | Source | Meaning |
|
|
210
|
+
|----------|--------|---------|
|
|
211
|
+
| `spacing`, `color`, `font`, `alignment`, `size`, `content`, `missing`, `extra` | pixel analysis | Visual differences between design and screenshot |
|
|
212
|
+
| `accessibility` | a11y analysis | Missing labels, small tap targets, images without alt text |
|
|
213
|
+
| `regression` | regression analysis | Layout changed from previous baseline |
|
|
214
|
+
|
|
215
|
+
### Finding severity
|
|
216
|
+
|
|
217
|
+
- `critical` — major visual breakage
|
|
218
|
+
- `major` — noticeable difference (missing labels, significant pixel diff)
|
|
219
|
+
- `minor` — small issues (slightly small tap targets)
|
|
220
|
+
- `info` — informational (empty text nodes)
|
|
221
|
+
|
|
222
|
+
## Interpreting Visual Differences
|
|
223
|
+
|
|
224
|
+
When comparing a design against a live app, **distinguish between structural issues and dynamic data**. Not every pixel difference is a bug.
|
|
225
|
+
|
|
226
|
+
### Dynamic data (NOT issues)
|
|
227
|
+
|
|
228
|
+
These are expected to differ between a design mockup and a live app — do NOT report them as mismatches:
|
|
229
|
+
|
|
230
|
+
- **Counts and numbers** — "12 stops" vs "243 stops", "97" vs "99+", timestamps, dates
|
|
231
|
+
- **User-specific text** — names, email addresses, avatars, profile data
|
|
232
|
+
- **API-driven content** — store names, product titles, list items, map labels, notification badges
|
|
233
|
+
- **Images from a server** — map tiles, avatars, product images, thumbnails
|
|
234
|
+
|
|
235
|
+
### Structural issues (REAL issues)
|
|
236
|
+
|
|
237
|
+
These are actual design deviations that should be reported:
|
|
238
|
+
|
|
239
|
+
- **Missing or extra UI elements** — buttons, cards, banners not in the design
|
|
240
|
+
- **Different labels/icons** — tab bar says "Settings" but design says "Account", wrong icon
|
|
241
|
+
- **Layout differences** — spacing, alignment, sizing that doesn't match the design
|
|
242
|
+
- **Typography changes** — bold vs regular, different font size, wrong color
|
|
243
|
+
- **Style differences** — wrong background color, border radius, shadows
|
|
244
|
+
|
|
245
|
+
### How to present comparison results
|
|
246
|
+
|
|
247
|
+
When showing a design-vs-app comparison table, add a **Type** column:
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
| Area | Design | App | Type | Match? |
|
|
251
|
+
|------|--------|-----|------|--------|
|
|
252
|
+
| Stop count | "12 stops" | "243 stops" | Dynamic data | OK |
|
|
253
|
+
| Tab labels | "Account" | "Settings" | Structural | Mismatch |
|
|
254
|
+
| Alert badge | 97 | 99+ | Dynamic data | OK |
|
|
255
|
+
| Action buttons | None | "View stops..." | Structural | Mismatch — extra element |
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Mark dynamic data rows as **OK** even if the values differ. Only flag structural differences as mismatches. Summarize by counting only structural mismatches, not dynamic data differences.
|
|
259
|
+
|
|
260
|
+
## Workflow Patterns
|
|
261
|
+
|
|
262
|
+
### Compare against a Figma design
|
|
263
|
+
|
|
264
|
+
If the user has a Figma MCP server connected, use it to export the frame as an image first, then run driftx:
|
|
265
|
+
|
|
266
|
+
1. Use Figma MCP to get the design frame → save as PNG
|
|
267
|
+
2. Run `npx driftx compare --design <saved-image-path> --format json`
|
|
268
|
+
3. Read the JSON output to understand differences
|
|
269
|
+
4. Read artifact files (diff mask, report.md) for visual context
|
|
270
|
+
5. **Classify each difference** as dynamic data or structural issue
|
|
271
|
+
6. Only suggest code fixes for structural issues
|
|
272
|
+
|
|
273
|
+
If no Figma MCP, ask the user to provide the design image path.
|
|
274
|
+
|
|
275
|
+
### Accessibility audit
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
npx driftx compare --design <path> --with a11y --format json
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Or without a design image (a11y only needs the component tree):
|
|
282
|
+
```bash
|
|
283
|
+
npx driftx compare --baseline --with a11y --format json
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Review findings with `category: 'accessibility'` and suggest fixes (add accessibilityLabel, increase tap target size, etc.).
|
|
287
|
+
|
|
288
|
+
### Regression detection
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
npx driftx compare --baseline --format json
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Compares current app state against the most recent previous run. No design file needed. Useful after code changes to verify nothing broke visually.
|
|
295
|
+
|
|
296
|
+
### Full audit (all analyses)
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npx driftx compare --design <path> --with pixel,a11y --format json
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Runs pixel diff and accessibility audit together.
|
|
303
|
+
|
|
304
|
+
## Device Interaction
|
|
305
|
+
|
|
306
|
+
driftx can interact with the running app — tap buttons, type text, swipe, navigate.
|
|
307
|
+
|
|
308
|
+
**Critical rule: always verify interactions visually.** Before any interaction, capture a screenshot to understand the current screen state. After any interaction, capture another screenshot to verify it worked. Never assume an interaction succeeded without visual confirmation.
|
|
309
|
+
|
|
310
|
+
### Recommended interaction pattern
|
|
311
|
+
|
|
312
|
+
1. `npx driftx capture -o /tmp/before.png` — see what's on screen
|
|
313
|
+
2. `npx driftx inspect --json` — find tap targets (text, testIDs, component names)
|
|
314
|
+
3. `npx driftx tap "Submit"` — interact
|
|
315
|
+
4. `npx driftx capture -o /tmp/after.png` — verify the result
|
|
316
|
+
|
|
317
|
+
### How tap resolution works
|
|
318
|
+
|
|
319
|
+
When you run `driftx tap "Submit"`, the tool resolves the target through multiple strategies in order:
|
|
320
|
+
|
|
321
|
+
1. **CDP tree** (React Native) — finds components by testID, name, or text with bounds
|
|
322
|
+
2. **XCUITest companion hierarchy** (iOS) — accessibility elements with real screen bounds, fuzzy text matching (e.g., "Trips" matches "Trips, tab, 2 of 6")
|
|
323
|
+
3. **XCUITest element query** (iOS) — searches staticTexts, buttons, links by label
|
|
324
|
+
4. **CDP fiber measurement** — finds the React fiber by text, then calls `stateNode.measureInWindow()` to get actual screen coordinates
|
|
325
|
+
|
|
326
|
+
This means `driftx tap "Submit"` works even for React Native elements that have no accessibility label — the CDP fiber measurement will find and measure it directly.
|
|
327
|
+
|
|
328
|
+
### `driftx tap <target>` — Tap a component
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# By testID, component name, or visible text
|
|
332
|
+
npx driftx tap login-btn
|
|
333
|
+
npx driftx tap LoginButton
|
|
334
|
+
npx driftx tap "Submit"
|
|
335
|
+
|
|
336
|
+
# By exact coordinates
|
|
337
|
+
npx driftx tap 150,300 --xy
|
|
338
|
+
|
|
339
|
+
# Target a specific device
|
|
340
|
+
npx driftx tap "Submit" --device "iPhone 16 Pro"
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The `--bundle-id` flag is optional — driftx auto-detects the app's bundle ID from the Metro CDP target when Metro is running.
|
|
344
|
+
|
|
345
|
+
### `driftx type <target> <text>` — Type text into a field
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
npx driftx type email-input "user@example.com"
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Taps the target first to focus it, then types.
|
|
352
|
+
|
|
353
|
+
### `driftx swipe <direction>` — Swipe gesture
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
npx driftx swipe up
|
|
357
|
+
npx driftx swipe down
|
|
358
|
+
npx driftx swipe left
|
|
359
|
+
npx driftx swipe right
|
|
360
|
+
|
|
361
|
+
# Custom distance (default: 300pt iOS, 600pt Android)
|
|
362
|
+
npx driftx swipe up --distance 200
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Default distance is 300pt on iOS and 600pt on Android. Always capture a screenshot before swiping to understand the screen layout and choose an appropriate distance, and after swiping to verify the result. If a swipe dismisses the app or triggers the home gesture, reduce the distance (e.g., `--distance 150`).
|
|
366
|
+
|
|
367
|
+
### `driftx go-back` — Press back button
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
npx driftx go-back
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### `driftx open-url <url>` — Open a deep link
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
npx driftx open-url "myapp://profile/123"
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Interaction Workflow
|
|
380
|
+
|
|
381
|
+
**Simple navigation test:**
|
|
382
|
+
1. `npx driftx capture -o /tmp/start.png` — capture starting state
|
|
383
|
+
2. `npx driftx inspect --json` — find available tap targets
|
|
384
|
+
3. `npx driftx tap "Login"` — navigate
|
|
385
|
+
4. `npx driftx capture -o /tmp/after-login.png` — verify navigation happened
|
|
386
|
+
5. `npx driftx compare --design mockup.png --format json` — compare against design
|
|
387
|
+
|
|
388
|
+
**Form testing:**
|
|
389
|
+
1. `npx driftx capture -o /tmp/form.png` — see the form
|
|
390
|
+
2. `npx driftx type email-input "test@example.com"`
|
|
391
|
+
3. `npx driftx type password-input "password123"`
|
|
392
|
+
4. `npx driftx tap "Submit"`
|
|
393
|
+
5. `npx driftx capture -o /tmp/after-submit.png` — verify submission result
|
|
394
|
+
|
|
395
|
+
**Scrolling to find content:**
|
|
396
|
+
1. `npx driftx capture -o /tmp/before-scroll.png` — see what's visible
|
|
397
|
+
2. `npx driftx swipe up` — scroll down
|
|
398
|
+
3. `npx driftx capture -o /tmp/after-scroll.png` — verify new content is visible
|
|
399
|
+
4. `npx driftx tap "Load More"` — tap newly visible element
|
|
400
|
+
|
|
401
|
+
## Configuration
|
|
402
|
+
|
|
403
|
+
driftx uses `.driftxrc.json` in the project root. Run `npx driftx init` to create one. Key settings:
|
|
404
|
+
|
|
405
|
+
- `platform`: `"android"` or `"ios"`
|
|
406
|
+
- `metroPort`: Metro bundler port (default 8081)
|
|
407
|
+
- `threshold`: Pixel sensitivity (default 0.1)
|
|
408
|
+
- `diffThreshold`: Pass/fail percentage threshold (default 0.01)
|
|
409
|
+
- `analyses.default`: Default analyses to run
|
|
410
|
+
- `analyses.disabled`: Analyses to never run
|
|
411
|
+
|
|
412
|
+
## Output Formatting Rules
|
|
413
|
+
|
|
414
|
+
**Always present results in a consistent, structured format.** Follow these rules strictly:
|
|
415
|
+
|
|
416
|
+
### Results Table
|
|
417
|
+
|
|
418
|
+
Every analysis result — whether it has issues or not — must be shown in a table. Use this format for **each device**:
|
|
419
|
+
|
|
420
|
+
**When issues are found:**
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
### <Device Name> (<Platform>)
|
|
424
|
+
|
|
425
|
+
<N> components checked — <M> issues found.
|
|
426
|
+
|
|
427
|
+
| Severity | Issue | Component | Location |
|
|
428
|
+
|----------|-------|-----------|----------|
|
|
429
|
+
| Major | Missing accessibilityLabel | android.widget.Button | x:954 y:164 (105x105px) |
|
|
430
|
+
| Minor | Small tap target (36x36) | RCTText | x:10 y:200 (36x36px) |
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**When no issues are found:**
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
### <Device Name> (<Platform>)
|
|
437
|
+
|
|
438
|
+
<N> components checked — no issues found.
|
|
439
|
+
|
|
440
|
+
| Category | Count |
|
|
441
|
+
|----------|-------|
|
|
442
|
+
| Missing labels | 0 |
|
|
443
|
+
| Small tap targets | 0 |
|
|
444
|
+
| Images without alt text | 0 |
|
|
445
|
+
| Empty text nodes | 0 |
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**For pixel diff results:**
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
### <Device Name> (<Platform>)
|
|
452
|
+
|
|
453
|
+
| Metric | Value |
|
|
454
|
+
|--------|-------|
|
|
455
|
+
| Diff | 2.10% (5000 / 238000 pixels) |
|
|
456
|
+
| Regions | 3 |
|
|
457
|
+
| Duration | 450ms |
|
|
458
|
+
| Result | FAIL |
|
|
459
|
+
|
|
460
|
+
| # | Severity | Category | Component | Region |
|
|
461
|
+
|---|----------|----------|-----------|--------|
|
|
462
|
+
| 1 | Critical | spacing | LoginButton [login-btn] | (10,20) 100x50 |
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Next Actions
|
|
466
|
+
|
|
467
|
+
After presenting results, **always offer next actions using the AskUserQuestion tool with `options`**. This renders as a radio-button selection menu. Never present choices as plain numbered text.
|
|
468
|
+
|
|
469
|
+
Example — after a11y audit with issues:
|
|
470
|
+
```
|
|
471
|
+
AskUserQuestion(
|
|
472
|
+
question: "What would you like to do next?",
|
|
473
|
+
options: [
|
|
474
|
+
"Capture a screenshot to visually identify the issue",
|
|
475
|
+
"Inspect the component tree to find the source component",
|
|
476
|
+
"Fix the issue (add accessibilityLabel)",
|
|
477
|
+
"Run the audit again after changes",
|
|
478
|
+
"Run on another device"
|
|
479
|
+
]
|
|
480
|
+
)
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
Example — after clean results (no issues):
|
|
484
|
+
```
|
|
485
|
+
AskUserQuestion(
|
|
486
|
+
question: "What would you like to do next?",
|
|
487
|
+
options: [
|
|
488
|
+
"Run pixel diff against a design",
|
|
489
|
+
"Run regression test against previous baseline",
|
|
490
|
+
"Check another device",
|
|
491
|
+
"Inspect the component tree",
|
|
492
|
+
"Capture a screenshot"
|
|
493
|
+
]
|
|
494
|
+
)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Tailor the options to the context. Always use AskUserQuestion with options — never plain text lists.
|
|
498
|
+
|
|
499
|
+
### General Rules
|
|
500
|
+
|
|
501
|
+
- **Consistent style across all devices** — if you show a table for one device, show a table for all
|
|
502
|
+
- **Always include the device name and platform** as a header
|
|
503
|
+
- **Always include component count** (from `metadata.totalChecked`)
|
|
504
|
+
- **Always offer next actions** as a numbered list
|
|
505
|
+
- **Read artifact files** (`report.md`, `result.json`) when you need more detail about findings
|
|
506
|
+
|
|
507
|
+
## Error Handling
|
|
508
|
+
|
|
509
|
+
- If no booted device is found, suggest the user start a simulator/emulator
|
|
510
|
+
- If Metro is not running, suggest `npx react-native start` — Metro is required for tree inspection, tap-by-text, and bundle ID auto-detection
|
|
511
|
+
- If `driftx doctor` shows missing prerequisites, show the user which tools to install
|
|
512
|
+
- If compare fails with "Either --design or --baseline must be provided", one of those flags is required
|
|
513
|
+
- If tap returns `"Target not found"`, run `npx driftx inspect --json` to see available targets, or use `--xy` with coordinates from a screenshot
|
|
514
|
+
- If interactions fail with timeout, add `--verbose` to see debug logs for the companion and CDP connection
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>en</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>APPL</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>1.0</string>
|
|
19
|
+
<key>CFBundleVersion</key>
|
|
20
|
+
<string>1</string>
|
|
21
|
+
</dict>
|
|
22
|
+
</plist>
|