Skip to content

Commit 922b103

Browse files
Merge 05dac0e into 8ba5377
2 parents 8ba5377 + 05dac0e commit 922b103

File tree

14 files changed

+910
-20
lines changed

14 files changed

+910
-20
lines changed

.github/workflows/sample-application.yml

Lines changed: 167 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ concurrency:
1414
env:
1515
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
1616
RN_SENTRY_POD_NAME: RNSentry
17+
IOS_APP_ARCHIVE_PATH: sentry-react-native-sample.app.zip
18+
ANDROID_APP_ARCHIVE_PATH: sentry-react-native-sample.apk.zip
19+
REACT_NATIVE_SAMPLE_PATH: samples/react-native
20+
IOS_DEVICE: 'iPhone 16'
21+
IOS_VERSION: '18.1'
22+
ANDROID_API_LEVEL: '30'
1723

1824
jobs:
1925
diff_check:
@@ -66,7 +72,7 @@ jobs:
6672
- uses: ruby/setup-ruby@v1
6773
if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }}
6874
with:
69-
working-directory: ${{ matrix.platform == 'ios' && ' samples/react-native' || ' samples/react-native-macos' }}
75+
working-directory: ${{ matrix.platform == 'ios' && env.REACT_NATIVE_SAMPLE_PATH || ' samples/react-native-macos' }}
7076
ruby-version: '3.3.0' # based on what is used in the sample
7177
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
7278
cache-version: 1 # cache the installed gems
@@ -106,7 +112,7 @@ jobs:
106112
107113
- name: Build Android App
108114
if: ${{ matrix.platform == 'android' }}
109-
working-directory: samples/react-native/android
115+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}/android
110116
run: |
111117
if [[ ${{ matrix.rn-architecture }} == 'new' ]]; then
112118
perl -i -pe's/newArchEnabled=false/newArchEnabled=true/g' gradle.properties
@@ -119,11 +125,14 @@ jobs:
119125
fi
120126
[[ "${{ matrix.build-type }}" == "production" ]] && CONFIG='Release' || CONFIG='Debug'
121127
echo "Building $CONFIG"
122-
./gradlew ":app:assemble$CONFIG" -PreactNativeArchitectures=x86
128+
[[ "${{ matrix.build-type }}" == "production" ]] && TEST_TYPE='release' || TEST_TYPE='debug'
129+
echo "Building $TEST_TYPE"
130+
131+
./gradlew ":app:assemble$CONFIG" app:assembleAndroidTest -DtestBuildType=$TEST_TYPE -PreactNativeArchitectures=x86
123132
124133
- name: Build iOS App
125134
if: ${{ matrix.platform == 'ios' }}
126-
working-directory: samples/react-native/ios
135+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}/ios
127136
run: |
128137
[[ "${{ matrix.build-type }}" == "production" ]] && CONFIG='Release' || CONFIG='Debug'
129138
echo "Building $CONFIG"
@@ -160,9 +169,162 @@ jobs:
160169
| tee xcodebuild.log \
161170
| xcbeautify --quieter --is-ci --disable-colored-output
162171
172+
- name: Archive iOS App
173+
if: ${{ matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }}
174+
run: |
175+
cd ${{ env.REACT_NATIVE_SAMPLE_PATH }}/ios/DerivedData/Build/Products/Release-iphonesimulator
176+
zip -r \
177+
${{ github.workspace }}/${{ env.IOS_APP_ARCHIVE_PATH }} \
178+
sentryreactnativesample.app
179+
180+
- name: Archive Android App
181+
if: ${{ matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }}
182+
run: |
183+
mv ${{ env.REACT_NATIVE_SAMPLE_PATH }}/android/app/build/outputs/apk/release/app-release.apk app.apk
184+
mv ${{ env.REACT_NATIVE_SAMPLE_PATH }}/android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk app-androidTest.apk
185+
zip -j \
186+
${{ env.ANDROID_APP_ARCHIVE_PATH }} \
187+
app.apk \
188+
app-androidTest.apk
189+
190+
- name: Upload iOS APP
191+
if: ${{ matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }}
192+
uses: actions/upload-artifact@v4
193+
with:
194+
name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-${{ matrix.platform }}
195+
path: ${{ env.IOS_APP_ARCHIVE_PATH }}
196+
retention-days: 1
197+
198+
- name: Upload Android APK
199+
if: ${{ matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }}
200+
uses: actions/upload-artifact@v4
201+
with:
202+
name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.platform }}
203+
path: ${{ env.ANDROID_APP_ARCHIVE_PATH }}
204+
retention-days: 1
205+
163206
- name: Upload logs
164207
if: ${{ always() }}
165208
uses: actions/upload-artifact@v4
166209
with:
167210
name: build-sample-${{ matrix.rn-architecture }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-logs
168-
path: samples/react-native/${{ matrix.platform }}/*.log
211+
path: ${{ env.REACT_NATIVE_SAMPLE_PATH }}/${{ matrix.platform }}/*.log
212+
213+
test:
214+
name: Test ${{ matrix.platform }} ${{ matrix.build-type }}
215+
runs-on: ${{ matrix.runs-on }}
216+
needs: [diff_check, build]
217+
if: ${{ needs.diff_check.outputs.skip_ci != 'true' }}
218+
strategy:
219+
# we want that the matrix keeps running, default is to cancel them if it fails.
220+
fail-fast: false
221+
matrix:
222+
include:
223+
- platform: ios
224+
runs-on: macos-15
225+
rn-architecture: 'new'
226+
ios-use-frameworks: 'no-frameworks'
227+
build-type: 'production'
228+
229+
- platform: android
230+
runs-on: ubuntu-latest
231+
rn-architecture: 'new'
232+
build-type: 'production'
233+
234+
steps:
235+
- uses: actions/checkout@v4
236+
237+
- name: Download iOS App Archive
238+
if: ${{ matrix.platform == 'ios' }}
239+
uses: actions/download-artifact@v4
240+
with:
241+
name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-${{ matrix.platform }}
242+
path: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
243+
244+
- name: Download Android APK
245+
if: ${{ matrix.platform == 'android' }}
246+
uses: actions/download-artifact@v4
247+
with:
248+
name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.platform }}
249+
path: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
250+
251+
- name: Unzip iOS App Archive
252+
if: ${{ matrix.platform == 'ios' }}
253+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
254+
run: unzip ${{ env.IOS_APP_ARCHIVE_PATH }}
255+
256+
- name: Unzip Android APK
257+
if: ${{ matrix.platform == 'android' }}
258+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
259+
run: unzip ${{ env.ANDROID_APP_ARCHIVE_PATH }}
260+
261+
- name: Enable Corepack
262+
run: |
263+
npm install -g corepack@0.29.4
264+
corepack enable
265+
- uses: actions/setup-node@v4
266+
with:
267+
node-version: 18
268+
cache: 'yarn'
269+
cache-dependency-path: yarn.lock
270+
271+
- name: Install JS Dependencies
272+
run: yarn install
273+
274+
- name: Install Detox
275+
run: npm install -g detox-cli@20.0.0
276+
277+
- name: Install Apple Simulator Utilities
278+
if: ${{ matrix.platform == 'ios' }}
279+
run: |
280+
brew tap wix/brew
281+
brew install applesimutils
282+
283+
- name: Setup KVM
284+
if: ${{ matrix.platform == 'android' }}
285+
shell: bash
286+
run: |
287+
# check if virtualization is supported...
288+
sudo apt install -y --no-install-recommends cpu-checker coreutils && echo "CPUs=$(nproc --all)" && kvm-ok
289+
# allow access to KVM to run the emulator
290+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
291+
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
292+
sudo udevadm control --reload-rules
293+
sudo udevadm trigger --name-match=kvm
294+
295+
- uses: futureware-tech/simulator-action@dab10d813144ef59b48d401cd95da151222ef8cd # pin@v4
296+
if: ${{ matrix.platform == 'ios' }}
297+
with:
298+
# the same envs are used by Detox ci.sim configuration
299+
model: ${{ env.IOS_DEVICE }}
300+
os_version: ${{ env.IOS_VERSION }}
301+
302+
- name: Run Detox iOS Tests
303+
if: ${{ matrix.platform == 'ios' }}
304+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
305+
run: detox test --configuration ci.sim
306+
307+
- name: Run tests on Android
308+
if: ${{ matrix.platform == 'android' }}
309+
env:
310+
# used by Detox ci.android configuration
311+
ANDROID_AVD_NAME: 'test' # test is default reactivecircus/android-emulator-runner name
312+
uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # pin@v2.33.0
313+
with:
314+
api-level: ${{ env.ANDROID_API_LEVEL }}
315+
force-avd-creation: false
316+
disable-animations: true
317+
disable-spellchecker: true
318+
target: 'aosp_atd'
319+
channel: canary # Necessary for ATDs
320+
emulator-options: >
321+
-no-window
322+
-no-snapshot-save
323+
-gpu swiftshader_indirect
324+
-noaudio
325+
-no-boot-anim
326+
-camera-back none
327+
-camera-front none
328+
-timezone US/Pacific
329+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
330+
script: detox test --configuration ci.android

samples/react-native/.detoxrc.js

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
const process = require('process');
2+
3+
/** @type {Detox.DetoxConfig} */
4+
module.exports = {
5+
testRunner: {
6+
args: {
7+
$0: 'jest',
8+
config: 'e2e/jest.config.js',
9+
},
10+
jest: {
11+
setupTimeout: 120000,
12+
},
13+
},
14+
apps: {
15+
'ios.debug': {
16+
type: 'ios.app',
17+
binaryPath:
18+
'ios/build/Build/Products/Debug-iphonesimulator/sentryreactnativesample.app',
19+
build:
20+
'xcodebuild -workspace ios/sentryreactnativesample.xcworkspace -scheme sentryreactnativesample -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
21+
},
22+
'ios.release': {
23+
type: 'ios.app',
24+
binaryPath:
25+
'ios/build/Build/Products/Release-iphonesimulator/sentryreactnativesample.app',
26+
build:
27+
'xcodebuild -workspace ios/sentryreactnativesample.xcworkspace -scheme sentryreactnativesample -configuration Release -sdk iphonesimulator -derivedDataPath ios/build',
28+
},
29+
'android.debug': {
30+
type: 'android.apk',
31+
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
32+
build:
33+
'cd android && ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug',
34+
reversePorts: [8081],
35+
},
36+
'android.release': {
37+
type: 'android.apk',
38+
binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
39+
build:
40+
'cd android && ./gradlew app:assembleRelease app:assembleAndroidTest -DtestBuildType=release',
41+
},
42+
'ci.android': {
43+
type: 'android.apk',
44+
binaryPath: 'app.apk',
45+
testBinaryPath: 'app-androidTest.apk',
46+
},
47+
'ci.ios': {
48+
type: 'ios.app',
49+
binaryPath: 'sentryreactnativesample.app',
50+
},
51+
},
52+
devices: {
53+
simulator: {
54+
type: 'ios.simulator',
55+
device: {
56+
type: 'iPhone 16',
57+
},
58+
},
59+
attached: {
60+
type: 'android.attached',
61+
device: {
62+
adbName: '.*',
63+
},
64+
},
65+
emulator: {
66+
type: 'android.emulator',
67+
device: {
68+
avdName: 'Pixel_9_API_35',
69+
},
70+
},
71+
'ci.emulator': {
72+
type: 'android.emulator',
73+
device: {
74+
avdName: process.env.ANDROID_AVD_NAME,
75+
},
76+
},
77+
'ci.simulator': {
78+
type: 'ios.simulator',
79+
device: {
80+
type: process.env.IOS_DEVICE,
81+
os: process.env.IOS_VERSION,
82+
},
83+
},
84+
},
85+
configurations: {
86+
'ios.sim.debug': {
87+
device: 'simulator',
88+
app: 'ios.debug',
89+
},
90+
'ios.sim.release': {
91+
device: 'simulator',
92+
app: 'ios.release',
93+
},
94+
'android.att.debug': {
95+
device: 'attached',
96+
app: 'android.debug',
97+
},
98+
'android.att.release': {
99+
device: 'attached',
100+
app: 'android.release',
101+
},
102+
'android.emu.debug': {
103+
device: 'emulator',
104+
app: 'android.debug',
105+
},
106+
'android.emu.release': {
107+
device: 'emulator',
108+
app: 'android.release',
109+
},
110+
'ci.android': {
111+
device: 'ci.emulator',
112+
app: 'ci.android',
113+
},
114+
'ci.sim': {
115+
device: 'ci.simulator',
116+
app: 'ci.ios',
117+
},
118+
},
119+
};

samples/react-native/android/app/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ android {
138138
targetSdkVersion rootProject.ext.targetSdkVersion
139139
versionCode 41
140140
versionName "6.9.0"
141+
142+
// Detox
143+
testBuildType System.getProperty('testBuildType', 'debug')
144+
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
141145
}
142146

143147
signingConfigs {
@@ -192,11 +196,15 @@ android {
192196
signingConfig signingConfigs.debug
193197
minifyEnabled enableProguardInReleaseBuilds
194198
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
199+
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
195200
}
196201
}
197202
}
198203

199204
dependencies {
205+
androidTestImplementation('com.wix:detox:+')
206+
implementation 'androidx.appcompat:appcompat:1.7.0'
207+
200208
// The version of react-native is set by the React Native Gradle Plugin
201209
implementation("com.facebook.react:react-android")
202210

samples/react-native/android/app/proguard-rules.pro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@
88
# http://developer.android.com/guide/developing/tools/proguard.html
99

1010
# Add any project specific keep options here:
11+
12+
# Detox Release tests were failing on missing kotlin.Result
13+
# It should be covered by node_modules/detox/android/detox/proguard-rules-app.pro but it seems missing
14+
-keep class kotlin.** { *; }
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.sentry.reactnative.sample;
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4;
4+
import androidx.test.filters.LargeTest;
5+
import androidx.test.rule.ActivityTestRule;
6+
import com.wix.detox.Detox;
7+
import com.wix.detox.config.DetoxConfig;
8+
import org.junit.Rule;
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
12+
@RunWith(AndroidJUnit4.class)
13+
@LargeTest
14+
public class DetoxTest {
15+
@Rule
16+
public ActivityTestRule<MainActivity> mActivityRule =
17+
new ActivityTestRule<>(MainActivity.class, false, false);
18+
19+
@Test
20+
public void runDetoxTests() {
21+
DetoxConfig detoxConfig = new DetoxConfig();
22+
detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
23+
detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60;
24+
detoxConfig.rnContextLoadTimeoutSec = (BuildConfig.DEBUG ? 180 : 60);
25+
26+
Detox.runTests(mActivityRule, detoxConfig);
27+
}
28+
}

0 commit comments

Comments
 (0)