Detox skill
Generates Detox E2E tests for React Native apps in JavaScript. Gray-box testing framework with automatic synchronization. Supports local simulators/emulators and TestMu AI cloud. Use when user mentions "Detox", "React Native test", "element(by.id())", "device.launchApp". Triggers on: "Detox", "React Native E2E", "React Native test", "element(by.id)", "device.launchApp".From its SKILL.md
npx -y skills add Pyfagorass/bookofspells --skill detox-skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
7.8 KB, ~2.0k tokens by cl100k_base, as published. Nobody here has run it
Detox Automation Skill
You are a senior React Native QA engineer specializing in Detox.
Core Patterns
Basic Test
describe('Login', () => {
beforeAll(async () => {
await device.launchApp();
});
beforeEach(async () => {
await device.reloadReactNative();
});
it('should login with valid credentials', async () => {
await element(by.id('emailInput')).typeText('[email protected]');
await element(by.id('passwordInput')).typeText('password123');
await element(by.id('loginButton')).tap();
await expect(element(by.id('dashboardTitle'))).toBeVisible();
await expect(element(by.text('Welcome'))).toBeVisible();
});
it('should show error for invalid credentials', async () => {
await element(by.id('emailInput')).typeText('[email protected]');
await element(by.id('passwordInput')).typeText('wrong');
await element(by.id('loginButton')).tap();
await expect(element(by.id('errorMessage'))).toBeVisible();
});
});
Matchers (Finding Elements)
element(by.id('uniqueId')) // testID prop (best)
element(by.text('Login')) // Text content
element(by.label('Submit')) // Accessibility label
element(by.type('RCTTextInput')) // Native type
element(by.traits(['button'])) // iOS traits
// Combined
element(by.id('list').withDescendant(by.text('Item 1')))
element(by.id('item').withAncestor(by.id('list')))
// At index (multiple matches)
element(by.text('Delete')).atIndex(0)
Actions
await element(by.id('btn')).tap();
await element(by.id('btn')).longPress();
await element(by.id('btn')).multiTap(3);
await element(by.id('input')).typeText('hello');
await element(by.id('input')).replaceText('new text');
await element(by.id('input')).clearText();
await element(by.id('scrollView')).scroll(200, 'down');
await element(by.id('scrollView')).scrollTo('bottom');
await element(by.id('item')).swipe('left', 'fast');
await element(by.id('input')).tapReturnKey();
Expectations
await expect(element(by.id('title'))).toBeVisible();
await expect(element(by.id('title'))).not.toBeVisible();
await expect(element(by.id('title'))).toExist();
await expect(element(by.id('title'))).toHaveText('Welcome');
await expect(element(by.id('toggle'))).toHaveToggleValue(true);
await expect(element(by.id('input'))).toHaveValue('hello');
Device Control
await device.launchApp({ newInstance: true });
await device.reloadReactNative();
await device.sendToHome();
await device.terminateApp();
await device.installApp();
await device.shake(); // Shake gesture
await device.setLocation(37.7749, -122.4194); // GPS
await device.setURLBlacklist(['.*cdn.example.*']); // Block URLs
Anti-Patterns
| Bad | Good | Why |
|---|---|---|
waitFor().withTimeout() everywhere | Trust Detox auto-sync | Detox waits automatically |
No testID on components | Add testID prop | Stable selectors |
device.launchApp() in every test | device.reloadReactNative() | Faster |
| Manual delays | Detox synchronization | Built-in waiting |
.detoxrc.js Configuration
module.exports = {
testRunner: { args: { config: 'e2e/jest.config.js' } },
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/MyApp.app',
build: 'xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
},
'android.debug': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
build: 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',
reversePorts: [8081],
},
},
devices: {
simulator: { type: 'ios.simulator', device: { type: 'iPhone 16' } },
emulator: { type: 'android.emulator', device: { avdName: 'Pixel_7_API_34' } },
},
configurations: {
'ios.sim.debug': { device: 'simulator', app: 'ios.debug' },
'android.emu.debug': { device: 'emulator', app: 'android.debug' },
},
};
Cloud Execution on TestMu AI
Detox generates native test runners (Espresso for Android, XCUITest for iOS). Run on TestMu AI cloud by uploading the built artifacts and triggering a framework build.
Android (Espresso) Cloud Run
# 1. Build the app and test APKs
detox build --configuration android.emu.debug
# 2. Upload app APK
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "appFile=@android/app/build/outputs/apk/debug/app-debug.apk" \
-F "name=DetoxApp"
# Response: {"app_url": "lt://APP_ID", ...}
# 3. Upload test APK
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "appFile=@android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" \
-F "name=DetoxTestSuite"
# Response: {"app_url": "lt://TEST_SUITE_ID", ...}
# 4. Trigger Espresso build
curl -X POST "https://mobile-api.lambdatest.com/framework/v1/espresso/build" \
-H "Authorization: Basic <BASE64_AUTH>" \
-H "Content-Type: application/json" \
-d '{
"app": "lt://APP_ID",
"testSuite": "lt://TEST_SUITE_ID",
"device": ["Galaxy S21 5G-12", "Pixel 6-12"],
"build": "Detox-Android",
"deviceLog": true,
"video": true
}'
iOS (XCUITest) Cloud Run
# 1. Build the iOS app and test runner
detox build --configuration ios.sim.release
# 2. Create .ipa from the build artifacts, then upload
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "[email protected]" -F "name=DetoxApp"
# 3. Upload test runner .ipa
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "[email protected]" -F "name=DetoxTestSuite"
# 4. Trigger XCUITest build
curl -X POST "https://mobile-api.lambdatest.com/framework/v1/xcui/build" \
-H "Authorization: Basic <BASE64_AUTH>" \
-H "Content-Type: application/json" \
-d '{
"app": "lt://APP_ID",
"testSuite": "lt://TEST_SUITE_ID",
"device": ["iPhone 14-16", "iPhone 13-15"],
"build": "Detox-iOS",
"devicelog": true,
"video": true
}'
Quick Reference
| Task | Command |
|---|---|
| Build iOS | detox build --configuration ios.sim.debug |
| Test iOS | detox test --configuration ios.sim.debug |
| Build Android | detox build --configuration android.emu.debug |
| Test Android | detox test --configuration android.emu.debug |
| Specific test | detox test --configuration ios.sim.debug e2e/login.test.js |
| Record video | detox test --record-videos all |
| Take screenshot | await device.takeScreenshot('login-page') |
Setup
npm install detox --save-dev
npm install jest jest-circus --save-dev
detox init
React Native Component Setup
// Add testID to components for Detox
<TextInput testID="emailInput" placeholder="Email" />
<TextInput testID="passwordInput" placeholder="Password" secureTextEntry />
<Button testID="loginButton" title="Login" onPress={handleLogin} />
<Text testID="errorMessage">{error}</Text>
Deep Patterns
For advanced patterns, debugging guides, CI/CD integration, and best practices,
see reference/playbook.md.
What ships with it: 2 files
16.7 KB alongside SKILL.md
reference/
- advanced-patterns.md3.5 KB
- playbook.md13.2 KB