agentsclimarketplace

Detox skill

Skill Pyfagorass/bookofspells/skills/lambdatest/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

Install
npx -y skills add Pyfagorass/bookofspells --skill detox-skill

Assembled 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

BadGoodWhy
waitFor().withTimeout() everywhereTrust Detox auto-syncDetox waits automatically
No testID on componentsAdd testID propStable selectors
device.launchApp() in every testdevice.reloadReactNative()Faster
Manual delaysDetox synchronizationBuilt-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

TaskCommand
Build iOSdetox build --configuration ios.sim.debug
Test iOSdetox test --configuration ios.sim.debug
Build Androiddetox build --configuration android.emu.debug
Test Androiddetox test --configuration android.emu.debug
Specific testdetox test --configuration ios.sim.debug e2e/login.test.js
Record videodetox test --record-videos all
Take screenshotawait 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/

Keep looking

Skills are one crate of 326,834. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.