Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: Detox E2E Tests

on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:

concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true

jobs:
ios:
name: iOS E2E
runs-on: macos-15
timeout-minutes: 60
env:
DEVELOPER_DIR: /Applications/Xcode_16.4.app/Contents/Developer

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: |
package-lock.json
example/package-lock.json

- name: Install root dependencies
run: npm install

- name: Build and pack library
run: |
npm run build
npm pack
VERSION=$(node -p "require('./package.json').version")
mv "react-native-launch-arguments-${VERSION}.tgz" "example/react-native-launch-arguments-${VERSION}.tgz"

- name: Install example dependencies
working-directory: example
run: |
VERSION=$(node -p "require('../package.json').version")
npm install "./react-native-launch-arguments-${VERSION}.tgz" --legacy-peer-deps

- name: Install applesimutils
run: |
brew tap wix/brew
brew install applesimutils
env:
HOMEBREW_NO_AUTO_UPDATE: 1

- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: ~/.cocoapods
key: cocoapods-${{ runner.os }}

- name: Build iOS app
working-directory: example
run: npx detox build -c ios.ci

- name: Test iOS
working-directory: example
run: npx detox test -c ios.ci --headless --cleanup

- name: Upload artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: detox-ios-artifacts
path: example/artifacts/
retention-days: 7

android:
name: Android E2E
runs-on: ubuntu-latest
timeout-minutes: 60
env:
API_LEVEL: 34
ARCH: x86_64

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: |
package-lock.json
example/package-lock.json

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Gradle cache
uses: gradle/actions/setup-gradle@v4

- name: Install root dependencies
run: npm ci

- name: Build and pack library
run: |
npm run build
npm pack
VERSION=$(node -p "require('./package.json').version")
mv "react-native-launch-arguments-${VERSION}.tgz" "example/react-native-launch-arguments-${VERSION}.tgz"

- name: Install example dependencies
working-directory: example
run: |
VERSION=$(node -p "require('../package.json').version")
npm install "./react-native-launch-arguments-${VERSION}.tgz" --legacy-peer-deps

- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ env.API_LEVEL }}

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ env.API_LEVEL }}
arch: ${{ env.ARCH }}
disable-animations: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
force-avd-creation: false
script: echo 'Generated AVD snapshot for caching.'

- name: Build Android app
working-directory: example
run: npx detox build -c android.ci

- name: Test Android
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ env.API_LEVEL }}
arch: ${{ env.ARCH }}
avd-name: test
disable-animations: true
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
force-avd-creation: false
script: cd example && npx detox test -c android.ci --headless

- name: Upload artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: detox-android-artifacts
path: example/artifacts/
retention-days: 7
15 changes: 9 additions & 6 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ buildscript {
}
}

plugins {
id('com.android.library')
id('maven-publish')
}

def DEFAULT_COMPILE_SDK_VERSION = 28
def DEFAULT_BUILD_TOOLS_VERSION = '28.0.3'
def DEFAULT_MIN_SDK_VERSION = 18
Expand All @@ -40,9 +35,16 @@ def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'com.facebook.react'

android {
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION)

namespace "com.reactnativelauncharguments"

defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
Expand All @@ -66,6 +68,7 @@ repositories {
url "$rootDir/../node_modules/jsc-android/dist"
}
google()
mavenCentral()
}

dependencies {
Expand Down Expand Up @@ -130,4 +133,4 @@ afterEvaluate { project ->
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,14 @@
import android.content.Intent;
import android.os.Bundle;

import com.facebook.fbreact.specs.NativeLaunchArgumentsSpec;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class LaunchArgumentsModule extends ReactContextBaseJavaModule {
public class LaunchArgumentsModule extends NativeLaunchArgumentsSpec {

private static final long ACTIVITY_WAIT_INTERVAL = 100L;
private static final int ACTIVITY_WAIT_TRIES = 200;
Expand All @@ -29,15 +24,8 @@ public class LaunchArgumentsModule extends ReactContextBaseJavaModule {
super(context);
}

@NonNull
@Override
public String getName() {
return "LaunchArguments";
}

@Nullable
@Override
public Map<String, Object> getConstants() {
protected Map<String, Object> getTypedExportedConstants() {
// When the app is killed, it doesn't start the activity so no need to wait for it
if (!isAppKilled()) {
// This is work-around for the RN problem described here:
Expand All @@ -52,13 +40,6 @@ public Map<String, Object> getConstants() {
}};
}

/**
* Looks like a bug in RN, without it this module is invisible
* in NativeModules.
*/
@ReactMethod
public void foo() {}

private void waitForActivity() {
for (int tries = 0; tries < ACTIVITY_WAIT_TRIES && !isActivityReady(); tries++) {
sleep(ACTIVITY_WAIT_INTERVAL);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
package com.reactnativelauncharguments;

import com.facebook.react.ReactPackage;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;

import java.util.HashMap;
import java.util.Map;

import java.util.Collections;
import java.util.List;
public class LaunchArgumentsPackage extends TurboReactPackage {

public class LaunchArgumentsPackage implements ReactPackage {

@Nullable
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactContext) {
if (name.equals(LaunchArgumentsModule.NAME)) {
return new LaunchArgumentsModule(reactContext);
} else {
return null;
}
}

@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
final NativeModule nativeModule = new LaunchArgumentsModule(reactContext);
return Collections.singletonList(nativeModule);
public ReactModuleInfoProvider getReactModuleInfoProvider() {
return () -> {
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
moduleInfos.put(
LaunchArgumentsModule.NAME,
new ReactModuleInfo(
LaunchArgumentsModule.NAME,
LaunchArgumentsModule.NAME,
false, // canOverrideExistingModule
false, // needsEagerInit
true, // hasConstants
false, // isCxxModule
true // isTurboModule
));
return moduleInfos;
};
}
}
6 changes: 0 additions & 6 deletions example/.buckconfig

This file was deleted.

Loading