Skip to content

Commit 5d6ed16

Browse files
committed
feat: startup crash detection
1 parent 9c014a1 commit 5d6ed16

75 files changed

Lines changed: 5822 additions & 523 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e-tests.yml

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,220 @@ jobs:
237237
with:
238238
runner: chromium
239239
projectRoot: apps/playground
240+
241+
crash-validate-android:
242+
name: Crash Validation Android
243+
runs-on: ubuntu-22.04
244+
if: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'android') }}
245+
env:
246+
HARNESS_DEBUG: true
247+
248+
steps:
249+
- name: Checkout code
250+
uses: actions/checkout@v4
251+
with:
252+
ref: ${{ github.ref }}
253+
fetch-depth: 0
254+
255+
- name: Reclaim disk space
256+
uses: AdityaGarg8/remove-unwanted-software@v5
257+
with:
258+
remove-dotnet: true
259+
remove-haskell: true
260+
remove-codeql: true
261+
remove-docker-images: true
262+
263+
- name: Install pnpm
264+
uses: pnpm/action-setup@v2
265+
with:
266+
version: latest
267+
268+
- name: Setup Node.js
269+
uses: actions/setup-node@v4
270+
with:
271+
node-version: '24.10.0'
272+
cache: 'pnpm'
273+
274+
- name: Metro cache
275+
uses: actions/cache@v4
276+
with:
277+
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
278+
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
279+
restore-keys: |
280+
metro-cache
281+
282+
- name: Install dependencies
283+
run: |
284+
pnpm install
285+
286+
- name: Build packages
287+
run: |
288+
pnpm nx run-many -t build --projects="packages/*"
289+
290+
- name: Set up JDK 17
291+
uses: actions/setup-java@v3
292+
with:
293+
java-version: '17'
294+
distribution: 'temurin'
295+
296+
- name: Restore APK from cache
297+
id: cache-apk-restore
298+
uses: actions/cache/restore@v4
299+
with:
300+
path: apps/playground/android/app/build/outputs/apk/debug/app-debug.apk
301+
key: apk-playground
302+
303+
- name: Build Android app
304+
if: steps.cache-apk-restore.outputs.cache-hit != 'true'
305+
working-directory: apps/playground
306+
run: |
307+
pnpm nx run @react-native-harness/playground:build-android --tasks=assembleDebug
308+
309+
- name: Save APK to cache
310+
if: steps.cache-apk-restore.outputs.cache-hit != 'true' && success()
311+
uses: actions/cache/save@v4
312+
with:
313+
path: apps/playground/android/app/build/outputs/apk/debug/app-debug.apk
314+
key: apk-playground
315+
316+
- name: Run React Native Harness (expect crash)
317+
id: crash-test
318+
continue-on-error: true
319+
uses: ./actions/android
320+
with:
321+
app: android/app/build/outputs/apk/debug/app-debug.apk
322+
runner: android-crash-pre-rn
323+
projectRoot: apps/playground
324+
harnessArgs: --testPathPattern smoke
325+
326+
- name: Verify crash was detected
327+
shell: bash
328+
run: |
329+
if [ "${{ steps.crash-test.outcome }}" != "failure" ]; then
330+
echo "ERROR: Expected harness to fail (crash not detected)"
331+
exit 1
332+
fi
333+
echo "Crash was correctly detected by the harness"
334+
335+
- name: Verify crash artifacts exist
336+
shell: bash
337+
run: |
338+
CRASH_DIR="apps/playground/.harness/crash-reports"
339+
if [ -d "$CRASH_DIR" ] && [ "$(ls -A "$CRASH_DIR" 2>/dev/null)" ]; then
340+
echo "Crash report artifacts found:"
341+
ls -la "$CRASH_DIR"
342+
else
343+
echo "ERROR: No crash report artifacts found in $CRASH_DIR"
344+
exit 1
345+
fi
346+
347+
crash-validate-ios:
348+
name: Crash Validation iOS
349+
runs-on: macos-latest
350+
if: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios') }}
351+
352+
steps:
353+
- name: Checkout code
354+
uses: actions/checkout@v4
355+
with:
356+
ref: ${{ github.ref }}
357+
fetch-depth: 0
358+
359+
- name: Install pnpm
360+
uses: pnpm/action-setup@v2
361+
with:
362+
version: latest
363+
364+
- name: Setup Node.js
365+
uses: actions/setup-node@v4
366+
with:
367+
node-version: '24.10.0'
368+
cache: 'pnpm'
369+
370+
- name: Metro cache
371+
uses: actions/cache@v4
372+
with:
373+
path: apps/playground/node_modules/.cache/rn-harness/metro-cache
374+
key: metro-cache-${{ hashFiles('apps/playground/node_modules/.cache/rn-harness/metro-cache/**/*') }}
375+
restore-keys: |
376+
metro-cache
377+
378+
- name: Install Watchman
379+
run: brew install watchman
380+
381+
- name: Install dependencies
382+
run: |
383+
pnpm install
384+
385+
- name: Build packages
386+
run: |
387+
pnpm nx run-many -t build --projects="packages/*"
388+
389+
- name: Restore app from cache
390+
id: cache-app-restore
391+
uses: actions/cache/restore@v4
392+
with:
393+
path: ./apps/playground/ios/build/Build/Products/Debug-iphonesimulator/HarnessPlayground.app
394+
key: ios-app-playground
395+
396+
- name: CocoaPods cache
397+
if: steps.cache-app-restore.outputs.cache-hit != 'true'
398+
uses: actions/cache@v4
399+
with:
400+
path: |
401+
./apps/playground/ios/Pods
402+
~/Library/Caches/CocoaPods
403+
~/.cocoapods
404+
key: playground-${{ runner.os }}-pods-${{ hashFiles('./apps/playground/ios/Podfile.lock') }}
405+
restore-keys: |
406+
playground-${{ runner.os }}-pods-
407+
408+
- name: Install CocoaPods
409+
if: steps.cache-app-restore.outputs.cache-hit != 'true'
410+
working-directory: apps/playground/ios
411+
run: |
412+
pod install
413+
414+
- name: Build iOS app
415+
if: steps.cache-app-restore.outputs.cache-hit != 'true'
416+
working-directory: apps/playground
417+
run: |
418+
pnpm react-native build-ios --buildFolder ./build --verbose
419+
420+
- name: Save app to cache
421+
if: steps.cache-app-restore.outputs.cache-hit != 'true' && success()
422+
uses: actions/cache/save@v4
423+
with:
424+
path: ./apps/playground/ios/build/Build/Products/Debug-iphonesimulator/HarnessPlayground.app
425+
key: ios-app-playground
426+
427+
- name: Run React Native Harness (expect crash)
428+
id: crash-test
429+
continue-on-error: true
430+
uses: ./actions/ios
431+
with:
432+
app: ios/build/Build/Products/Debug-iphonesimulator/HarnessPlayground.app
433+
runner: ios-crash-pre-rn
434+
projectRoot: apps/playground
435+
harnessArgs: --testPathPattern smoke
436+
437+
- name: Verify crash was detected
438+
shell: bash
439+
run: |
440+
if [ "${{ steps.crash-test.outcome }}" != "failure" ]; then
441+
echo "ERROR: Expected harness to fail (crash not detected)"
442+
exit 1
443+
fi
444+
echo "Crash was correctly detected by the harness"
445+
446+
- name: Verify crash artifacts exist
447+
shell: bash
448+
run: |
449+
CRASH_DIR="apps/playground/.harness/crash-reports"
450+
if [ -d "$CRASH_DIR" ] && [ "$(ls -A "$CRASH_DIR" 2>/dev/null)" ]; then
451+
echo "Crash report artifacts found:"
452+
ls -la "$CRASH_DIR"
453+
else
454+
echo "ERROR: No crash report artifacts found in $CRASH_DIR"
455+
exit 1
456+
fi

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ yarn-error.log
111111

112112
# testing
113113
/coverage
114+
.harness/
114115
vite.config.*.timestamp*
115116
vitest.config.*.timestamp*
116117

@@ -128,4 +129,3 @@ npm-debug.*
128129
*.orig.*
129130
web-build/
130131
cache/
131-

actions/android/action.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ inputs:
1717
required: false
1818
type: boolean
1919
default: 'true'
20+
harnessArgs:
21+
description: Additional arguments to pass to the Harness CLI
22+
required: false
23+
type: string
24+
default: ''
2025
runs:
2126
using: 'composite'
2227
steps:
@@ -136,13 +141,20 @@ runs:
136141
script: |
137142
echo $(pwd)
138143
adb install -r ${{ inputs.app }}
139-
${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner ${{ inputs.runner }}
144+
${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner ${{ inputs.runner }} ${{ inputs.harnessArgs }}
140145
- name: Upload visual test artifacts
141146
if: always() && inputs.uploadVisualTestArtifacts == 'true'
142147
uses: actions/upload-artifact@v4
143148
with:
144-
name: visual-test-diffs-android
149+
name: visual-test-diffs-${{ inputs.runner }}
145150
path: |
146151
${{ inputs.projectRoot }}/**/__image_snapshots__/**/*-diff.png
147152
${{ inputs.projectRoot }}/**/__image_snapshots__/**/*-actual.png
148153
if-no-files-found: ignore
154+
- name: Upload crash report artifacts
155+
if: always()
156+
uses: actions/upload-artifact@v4
157+
with:
158+
name: harness-crash-reports-${{ inputs.runner }}
159+
path: ${{ inputs.projectRoot }}/.harness/crash-reports/**/*
160+
if-no-files-found: ignore

actions/ios/action.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ inputs:
1717
required: false
1818
type: boolean
1919
default: 'true'
20+
harnessArgs:
21+
description: Additional arguments to pass to the Harness CLI
22+
required: false
23+
type: string
24+
default: ''
2025
runs:
2126
using: 'composite'
2227
steps:
@@ -63,13 +68,20 @@ runs:
6368
- name: Run E2E tests
6469
shell: bash
6570
working-directory: ${{ inputs.projectRoot }}
66-
run: ${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner ${{ inputs.runner }}
71+
run: ${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner ${{ inputs.runner }} ${{ inputs.harnessArgs }}
6772
- name: Upload visual test artifacts
6873
if: always() && inputs.uploadVisualTestArtifacts == 'true'
6974
uses: actions/upload-artifact@v4
7075
with:
71-
name: visual-test-diffs-ios
76+
name: visual-test-diffs-${{ inputs.runner }}
7277
path: |
7378
${{ inputs.projectRoot }}/**/__image_snapshots__/**/*-diff.png
7479
${{ inputs.projectRoot }}/**/__image_snapshots__/**/*-actual.png
7580
if-no-files-found: ignore
81+
- name: Upload crash report artifacts
82+
if: always()
83+
uses: actions/upload-artifact@v4
84+
with:
85+
name: harness-crash-reports-${{ inputs.runner }}
86+
path: ${{ inputs.projectRoot }}/.harness/crash-reports/**/*
87+
if-no-files-found: ignore

0 commit comments

Comments
 (0)