E2E Testing Mobile (Detox) — Mobile

End-to-End Testing di Mobile E2E testing di mobile lebih kompleks dari web karena perlu berinteraksi dengan native UI, permissions, gestures, dan…

End-to-End Testing di Mobile

E2E testing di mobile lebih kompleks dari web karena perlu berinteraksi dengan native UI, permissions, gestures, dan platform-specific behavior. Detox dari Wix adalah framework E2E testing paling populer untuk React Native.

Kenapa E2E Testing di Mobile?

Setup Detox

# Install
npm install detox --save-dev
npm install jest-circus --save-dev

# iOS: install applesimutils
brew tap wix/brew
brew install applesimutils

# Init Detox config
npx detox init

// .detoxrc.js
module.exports = {
  testRunner: {
    args: { $0: 'jest', config: 'e2e/jest.config.js' },
    jest: { setupTimeout: 120000 },
  },
  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',
    },
  },
  devices: {
    simulator: { type: 'ios.simulator', device: { type: 'iPhone 15' } },
    emulator: { type: 'android.emulator', device: { avdName: 'Pixel_7' } },
  },
  configurations: {
    'ios.sim.debug': { device: 'simulator', app: 'ios.debug' },
    'android.emu.debug': { device: 'emulator', app: 'android.debug' },
  },
};

Menulis Test

// e2e/login.test.js
describe('Login Flow', () => {
  beforeAll(async () => {
    await device.launchApp();
  });

  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('should login with valid credentials', async () => {
    // Ketik email
    await element(by.id('email-input')).typeText('[email protected]');
    // Ketik password
    await element(by.id('password-input')).typeText('password123');
    // Tap login button
    await element(by.id('login-button')).tap();
    // Verify navigasi ke home
    await expect(element(by.id('home-screen'))).toBeVisible();
  });

  it('should show error for invalid credentials', async () => {
    await element(by.id('email-input')).typeText('[email protected]');
    await element(by.id('password-input')).typeText('wrong');
    await element(by.id('login-button')).tap();
    await expect(element(by.text('Invalid credentials'))).toBeVisible();
  });
});

Test Matchers & Actions

// Matchers
element(by.id('testID'));           // testID prop
element(by.text('Hello'));          // Exact text
element(by.label('Submit'));        // Accessibility label

// Actions
await element(by.id('input')).typeText('hello');
await element(by.id('button')).tap();
await element(by.id('scroll')).scroll(200, 'down');
await element(by.id('item')).swipe('left', 'fast');
await element(by.id('input')).clearText();

// Assertions
await expect(element(by.id('title'))).toBeVisible();
await expect(element(by.id('error'))).not.toExist();
await expect(element(by.id('input'))).toHaveText('expected');

Running Tests

# Build app for testing
npx detox build --configuration ios.sim.debug

# Run tests
npx detox test --configuration ios.sim.debug

# Run specific test file
npx detox test --configuration ios.sim.debug e2e/login.test.js

Tips

Yang akan kamu pelajari