-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathaction.yml
More file actions
236 lines (231 loc) · 10.3 KB
/
action.yml
File metadata and controls
236 lines (231 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
name: React Native Harness
description: Run React Native Harness tests on iOS, Android or Web
inputs:
runner:
description: The runner to use (must match a runner name defined in your harness config)
required: true
type: string
app:
description: The path to the app (.app for iOS, .apk for Android). Not required for web.
required: false
type: string
projectRoot:
description: The project root directory
required: false
type: string
uploadVisualTestArtifacts:
description: Whether to upload visual test diff and actual images as artifacts
required: false
type: boolean
default: 'true'
harnessArgs:
description: Additional arguments to pass to the Harness CLI
required: false
type: string
default: ''
packageManager:
description: Package manager to use instead of auto-detection (npm, yarn, pnpm, bun, or deno)
required: false
type: string
default: ''
cacheAvd:
description: Whether to cache the AVD
required: false
type: boolean
default: 'true'
preRunHook:
description: Shell script to run in bash immediately before Harness starts
required: false
type: string
default: ''
afterRunHook:
description: Shell script to run in bash immediately after Harness finishes
required: false
type: string
default: ''
runs:
using: 'composite'
steps:
- name: Load React Native Harness configuration
id: load-config
shell: bash
env:
INPUT_RUNNER: ${{ inputs.runner }}
INPUT_PROJECTROOT: ${{ inputs.projectRoot }}
HARNESS_AVD_CACHING: ${{ inputs.cacheAvd }}
run: |
node ${{ github.action_path }}/actions/shared/index.cjs
- name: Verify native app input
if: fromJson(steps.load-config.outputs.config).platformId != 'web'
shell: bash
run: |
if [ -z "${{ inputs.app }}" ]; then
echo "Error: app input is required for native runners"
echo "Please provide the path to the built app (.apk for Android, .app for iOS)"
exit 1
fi
- name: Metro cache
uses: actions/cache@v4
with:
path: ${{ steps.load-config.outputs.projectRoot }}/.harness/metro-cache
key: ${{ runner.os }}-metro-cache-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/metro.config.js', '**/metro.config.cjs', '**/metro.config.mjs', '**/metro.config.ts', '**/babel.config.js', '**/babel.config.cjs', '**/babel.config.mjs', '**/babel.config.ts', '**/babel.config.json') }}
restore-keys: |
${{ runner.os }}-metro-cache-
# ── iOS ──────────────────────────────────────────────────────────────────
# iOS simulator boot and app installation are handled by Harness itself.
# ── Android ──────────────────────────────────────────────────────────────
- name: Verify Android config
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' }}
shell: bash
run: |
if [ '${{ fromJson(steps.load-config.outputs.config).config.device.avd }}' = 'null' ]; then
echo "Error: AVD config is required for Android emulators"
echo "Please define the 'avd' property in the runner config"
exit 1
fi
- name: Get architecture of the runner
id: arch
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' }}
shell: bash
run: |
case "${{ runner.arch }}" in
X64)
echo "arch=x86_64" >> $GITHUB_OUTPUT
;;
ARM64)
echo "arch=arm64-v8a" >> $GITHUB_OUTPUT
;;
ARM32)
echo "arch=armeabi-v7a" >> $GITHUB_OUTPUT
;;
*)
echo "arch=x86_64" >> $GITHUB_OUTPUT
;;
esac
- name: Enable KVM group perms
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' }}
shell: bash
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
ls /dev/kvm
- name: Compute AVD cache key
id: avd-key
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' && fromJson(steps.load-config.outputs.config).action.avdCachingEnabled }}
shell: bash
run: |
CACHE_CONFIG='${{ toJson(fromJson(steps.load-config.outputs.config).action.avdCacheConfig) }}'
AVD_CONFIG_HASH=$(printf '%s' "$CACHE_CONFIG" | sha256sum | cut -d' ' -f1)
AVD_NAME='${{ fromJson(steps.load-config.outputs.config).config.device.name }}'
ARCH="${{ steps.arch.outputs.arch }}"
CACHE_KEY="avd-$AVD_NAME-$ARCH-$AVD_CONFIG_HASH"
echo "key=$CACHE_KEY" >> $GITHUB_OUTPUT
- name: Restore AVD cache
uses: actions/cache/restore@v4
id: avd-cache
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' && fromJson(steps.load-config.outputs.config).action.avdCachingEnabled }}
with:
path: |
~/.android/avd
~/.android/adb*
key: ${{ steps.avd-key.outputs.key }}
# ── Web ──────────────────────────────────────────────────────────────────
- name: Install Playwright Browsers
if: fromJson(steps.load-config.outputs.config).platformId == 'web'
shell: bash
run: npx playwright install --with-deps chromium
# ── Shared ───────────────────────────────────────────────────────────────
- name: Detect Package Manager
id: detect-pm
shell: bash
working-directory: ${{ steps.load-config.outputs.projectRoot }}
run: |
if [ -n "${{ inputs.packageManager }}" ]; then
case "${{ inputs.packageManager }}" in
pnpm)
echo "manager=pnpm" >> $GITHUB_OUTPUT
echo "runner=pnpm exec " >> $GITHUB_OUTPUT
;;
yarn)
echo "manager=yarn" >> $GITHUB_OUTPUT
echo "runner=yarn " >> $GITHUB_OUTPUT
;;
bun)
echo "manager=bun" >> $GITHUB_OUTPUT
echo "runner=bunx " >> $GITHUB_OUTPUT
;;
deno)
echo "manager=deno" >> $GITHUB_OUTPUT
echo "runner=deno run -A npm:" >> $GITHUB_OUTPUT
;;
npm)
echo "manager=npm" >> $GITHUB_OUTPUT
echo "runner=npx " >> $GITHUB_OUTPUT
;;
*)
echo "Error: Unsupported packageManager '${{ inputs.packageManager }}'"
echo "Supported values: npm, yarn, pnpm, bun, deno"
exit 1
;;
esac
elif [ -f "pnpm-lock.yaml" ]; then
echo "manager=pnpm" >> $GITHUB_OUTPUT
echo "runner=pnpm exec " >> $GITHUB_OUTPUT
elif [ -f "yarn.lock" ]; then
echo "manager=yarn" >> $GITHUB_OUTPUT
echo "runner=yarn " >> $GITHUB_OUTPUT
elif [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
echo "manager=bun" >> $GITHUB_OUTPUT
echo "runner=bunx " >> $GITHUB_OUTPUT
elif [ -f "deno.lock" ]; then
echo "manager=deno" >> $GITHUB_OUTPUT
echo "runner=deno run -A npm:" >> $GITHUB_OUTPUT
else
echo "manager=npm" >> $GITHUB_OUTPUT
echo "runner=npx " >> $GITHUB_OUTPUT
fi
- name: Run E2E tests
id: run-tests
shell: bash
working-directory: ${{ steps.load-config.outputs.projectRoot }}
env:
PRE_RUN_HOOK: ${{ inputs.preRunHook }}
AFTER_RUN_HOOK: ${{ inputs.afterRunHook }}
HARNESS_RUNNER: ${{ inputs.runner }}
HARNESS_APP_PATH: ${{ inputs.app }}
HARNESS_AVD_CACHING: ${{ inputs.cacheAvd }}
run: |
export HARNESS_PROJECT_ROOT="$PWD"
set +e
${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner ${{ inputs.runner }} ${{ inputs.harnessArgs }}
harness_exit_code=$?
set -e
echo "harness_exit_code=$harness_exit_code" >> "$GITHUB_OUTPUT"
if [ "$harness_exit_code" -ne 0 ]; then
exit "$harness_exit_code"
fi
- name: Upload visual test artifacts
if: always() && inputs.uploadVisualTestArtifacts == 'true'
uses: actions/upload-artifact@v4
with:
name: visual-test-diffs-${{ fromJson(steps.load-config.outputs.config).platformId }}
path: |
${{ steps.load-config.outputs.projectRoot }}/**/__image_snapshots__/**/*-diff.png
${{ steps.load-config.outputs.projectRoot }}/**/__image_snapshots__/**/*-actual.png
if-no-files-found: ignore
- name: Save AVD cache
if: ${{ always() && fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' && fromJson(steps.load-config.outputs.config).action.avdCachingEnabled && steps.avd-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: |
~/.android/avd
~/.android/adb*
key: ${{ steps.avd-key.outputs.key }}
- name: Upload crash report artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: harness-crash-reports-${{ fromJson(steps.load-config.outputs.config).platformId }}
path: ${{ steps.load-config.outputs.projectRoot }}/.harness/crash-reports/**/*
if-no-files-found: ignore