Skip to content

Commit 07ed7f1

Browse files
committed
harness patch to naturally specify external xctest run, but not sure if AWS accepts a test spec file when its XCUITest …
1 parent 5edf2a9 commit 07ed7f1

5 files changed

Lines changed: 323 additions & 39 deletions

File tree

.github/workflows/harness-aws-device.yml

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ env:
6565
HARNESS_IOS_IPA_ARTIFACT_NAME: harness-ios-ipa
6666
HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_ARTIFACT_NAME: harness-xctest-agent-ipa
6767
HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_PATH: apps/simple-camera/ios/build/devicefarm/HarnessXCTestAgentUITests.ipa
68+
HARNESS_IOS_XCTEST_UI_TEST_PACKAGE_OUTPUT: apps/simple-camera/ios/build/devicefarm/HarnessXCTestUITestPackage.zip
69+
HARNESS_DEVICE_FARM_REPO_ARCHIVE_NAME: react-native-vision-camera.zip
6870
HARNESS_DEVICE_FARM_TEST_PACKAGE_OUTPUT: devicefarm-test-package.zip
6971
HARNESS_ANDROID_BUNDLE_ID: com.margelo.nitro.camera.example.simple
7072
HARNESS_ANDROID_DEVICE_ARCH: ${{ github.event.inputs.device_arch || 'arm64-v8a' }}
@@ -185,7 +187,7 @@ jobs:
185187
project-arn: ${{ env.HARNESS_DEVICE_FARM_PROJECT_ARN }}
186188
aws-region: ${{ env.HARNESS_AWS_REGION }}
187189
file-path: apps/simple-camera/device-farm-tests/AwsTestSpecIOS.yml
188-
upload-type: APPIUM_NODE_TEST_SPEC
190+
upload-type: XCTEST_UI_TEST_SPEC
189191
content-type: application/octet-stream
190192
upload-name: AwsTestSpecIOS-${{ github.run_id }}-${{ github.run_attempt }}.yml
191193

@@ -295,16 +297,6 @@ jobs:
295297
platform: android
296298
test-step-outcome: ${{ steps.run-test.outcome }}
297299

298-
# iOS testing on AWS Device Farm is temporarily disabled.
299-
# Device Farm has no UI operator to tap through runtime permission dialogs
300-
# (Camera, Microphone, Location, etc.), so the app hangs on first launch.
301-
# Unlike Android, there is no equivalent to `adb shell pm grant` for iOS, so
302-
# we depend on an upcoming React Native Harness feature to pre-grant iOS
303-
# permissions. Until that ships, we still build the iOS app here as a
304-
# compile-only smoke test (and to keep the DerivedData/Pods caches warm), but
305-
# we do NOT schedule any Device Farm run.
306-
# TODO: Re-enable iOS Device Farm testing once Harness ships iOS permission
307-
# pre-granting.
308300
build-ios:
309301
name: Build iOS
310302
runs-on: macos-latest
@@ -510,6 +502,38 @@ jobs:
510502
- name: Verify Harness XCTest UI runner IPA artifact
511503
run: test -f ${{ env.HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_PATH }}
512504

505+
- name: Create XCTest UI test package
506+
run: |
507+
set -euo pipefail
508+
509+
PACKAGE_PATH="${{ env.HARNESS_IOS_XCTEST_UI_TEST_PACKAGE_OUTPUT }}"
510+
PACKAGE_ROOT="$(mktemp -d)"
511+
REPO_ARCHIVE="$PACKAGE_ROOT/${{ env.HARNESS_DEVICE_FARM_REPO_ARCHIVE_NAME }}"
512+
RUNNER_IPA="$PACKAGE_ROOT/$(basename "${{ env.HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_PATH }}")"
513+
514+
rm -f "$PACKAGE_PATH"
515+
mkdir -p "$(dirname "$PACKAGE_PATH")"
516+
517+
git archive \
518+
--format=zip \
519+
--output "$REPO_ARCHIVE" \
520+
HEAD
521+
522+
cp "${{ env.HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_PATH }}" "$RUNNER_IPA"
523+
524+
(
525+
cd "$PACKAGE_ROOT"
526+
zip -qry "$GITHUB_WORKSPACE/$PACKAGE_PATH" \
527+
"$(basename "$RUNNER_IPA")" \
528+
"${{ env.HARNESS_DEVICE_FARM_REPO_ARCHIVE_NAME }}"
529+
)
530+
531+
unzip -tq "$PACKAGE_PATH"
532+
unzip -l "$PACKAGE_PATH"
533+
534+
- name: Verify XCTest UI test package
535+
run: test -f ${{ env.HARNESS_IOS_XCTEST_UI_TEST_PACKAGE_OUTPUT }}
536+
513537
- name: Configure AWS credentials
514538
uses: aws-actions/configure-aws-credentials@v6
515539
with:
@@ -527,16 +551,16 @@ jobs:
527551
content-type: application/octet-stream
528552
upload-name: simple-camera-${{ github.run_id }}-${{ github.run_attempt }}.ipa
529553

530-
- name: Upload Harness XCTest UI runner IPA to AWS Device Farm
531-
id: upload-xctest-runner
554+
- name: Upload XCTest UI test package to AWS Device Farm
555+
id: upload-xctest-ui-package
532556
uses: ./.github/actions/upload-devicefarm-artifact
533557
with:
534558
project-arn: ${{ env.HARNESS_DEVICE_FARM_PROJECT_ARN }}
535559
aws-region: ${{ env.HARNESS_AWS_REGION }}
536-
file-path: ${{ env.HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_PATH }}
537-
upload-type: IOS_APP
538-
content-type: application/octet-stream
539-
upload-name: ${{ env.HARNESS_IOS_HARNESS_XCTEST_RUNNER_IPA_ARTIFACT_NAME }}-${{ github.run_id }}-${{ github.run_attempt }}.ipa
560+
file-path: ${{ env.HARNESS_IOS_XCTEST_UI_TEST_PACKAGE_OUTPUT }}
561+
upload-type: XCTEST_UI_TEST_PACKAGE
562+
content-type: application/zip
563+
upload-name: harness-xctest-ui-package-${{ github.run_id }}-${{ github.run_attempt }}.zip
540564

541565
- name: Schedule Device Farm iOS Automated Test
542566
id: run-test
@@ -548,14 +572,9 @@ jobs:
548572
"projectArn": "${{ env.HARNESS_DEVICE_FARM_PROJECT_ARN }}",
549573
"appArn": "${{ steps.upload-ipa.outputs['upload-arn'] }}",
550574
"devicePoolArn": "${{ env.HARNESS_DEVICE_FARM_IOS_DEVICE_POOL_ARN }}",
551-
"configuration": {
552-
"auxiliaryApps": [
553-
"${{ steps.upload-xctest-runner.outputs['upload-arn'] }}"
554-
]
555-
},
556575
"test": {
557-
"type": "APPIUM_NODE",
558-
"testPackageArn": "${{ needs.prepare-devicefarm-assets.outputs.test_package_arn }}",
576+
"type": "XCTEST_UI",
577+
"testPackageArn": "${{ steps.upload-xctest-ui-package.outputs['upload-arn'] }}",
559578
"testSpecArn": "${{ needs.prepare-devicefarm-assets.outputs.ios_test_spec_arn }}"
560579
}
561580
}

apps/simple-camera/device-farm-tests/AwsTestSpecIOS.yml

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,115 @@ phases:
77
commands:
88
- devicefarm-cli use node 20
99
- node -v
10+
- xcodebuild -version
1011
- curl -fsSL https://bun.com/install | bash
11-
- ~/.bun/bin/bun install
1212
- xcrun devicectl list devices
1313

14+
# The XCTEST_UI package contains the Harness XCTest runner IPA and a
15+
# repo archive. Unpack the repo so the Node/Bun Harness tests can run.
16+
- |
17+
set -euo pipefail
18+
19+
REPO_ARCHIVE="$DEVICEFARM_XCTEST_BUILD_DIRECTORY/react-native-vision-camera.zip"
20+
HARNESS_REPO_ROOT="$WORKING_DIRECTORY/react-native-vision-camera"
21+
22+
test -f "$REPO_ARCHIVE"
23+
rm -rf "$HARNESS_REPO_ROOT"
24+
mkdir -p "$HARNESS_REPO_ROOT"
25+
unzip -q "$REPO_ARCHIVE" -d "$HARNESS_REPO_ROOT"
26+
27+
cd "$HARNESS_REPO_ROOT"
28+
~/.bun/bin/bun install --frozen-lockfile
29+
1430
test:
1531
commands:
1632
- HARNESS_JUNIT="$WORKING_DIRECTORY/harness-results.junit.xml"
1733
- HARNESS_LOG="$WORKING_DIRECTORY/harness-output.log"
1834

19-
# Resolve host IPv6 for Metro. On macOS runners ipv4 won't work, as confirmed by AWS support.
20-
# AWS specifically recommends using the utun interfaces for this, which is what we do here.
21-
# If we fail to resolve an IP address, we error out, as without this the tests won't be able to connect to Metro at all.
35+
# Resolve host IPv6 for Metro. On macOS runners IPv4 won't work, as
36+
# confirmed by AWS support. AWS recommends utun interfaces for this.
2237
- |
38+
set -euo pipefail
39+
2340
METRO_HOST_IP="$(ifconfig utun1 2>/dev/null | awk '/inet6 / {ip=$2} END {print ip}')"
2441
if [ -z "$METRO_HOST_IP" ]; then
2542
METRO_HOST_IP="$(ifconfig utun0 2>/dev/null | awk '/inet6 / {ip=$2} END {print ip}')"
2643
fi
44+
2745
METRO_HOST_IP="${METRO_HOST_IP%%%*}"
28-
[ -n "$METRO_HOST_IP" ] || { echo "Failed to resolve Metro host IPv6." >&2; exit 1; }
46+
if [ -z "$METRO_HOST_IP" ]; then
47+
echo "Failed to resolve Metro host IPv6." >&2
48+
exit 1
49+
fi
50+
2951
echo "Using Metro host IPv6 for iOS harness: ${METRO_HOST_IP}"
3052
echo "$METRO_HOST_IP" > "$WORKING_DIRECTORY/metro-host-ip.txt"
3153
32-
# Find the physical device connected to this runner we want to run the test on:
33-
- IOS_DEVICE_UDID="${DEVICEFARM_DEVICE_UDID:-${DEVICEFARM_DEVICE_NAME:-}}"
34-
- IOS_DEVICES_JSON="$(mktemp)"
35-
- xcrun devicectl list devices --json-output "$IOS_DEVICES_JSON"
36-
- IOS_DEVICE_NAME="$(node -e "const fs=require('node:fs');const payload=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));const devices=payload?.result?.devices ?? [];const udid=process.env.IOS_DEVICE_UDID || '';const matchedByUdid=devices.find((d)=>d?.identifier===udid);const selected=matchedByUdid ?? devices[0] ?? null;const name=selected?.deviceProperties?.name ?? '';if(!name){process.exit(1)};process.stdout.write(name);" "$IOS_DEVICES_JSON")"
37-
- 'echo "Resolved Device Farm iOS device for harness: ${IOS_DEVICE_NAME} (${IOS_DEVICE_UDID:-unknown-udid})"'
54+
# Find the physical device connected to this runner.
55+
- |
56+
set -euo pipefail
57+
58+
IOS_DEVICE_UDID="${DEVICEFARM_DEVICE_UDID:-${DEVICEFARM_DEVICE_NAME:-}}"
59+
IOS_DEVICES_JSON="$(mktemp)"
60+
xcrun devicectl list devices --json-output "$IOS_DEVICES_JSON"
61+
62+
IOS_DEVICE_NAME="$(
63+
IOS_DEVICE_UDID="$IOS_DEVICE_UDID" node - "$IOS_DEVICES_JSON" <<'NODE'
64+
const fs = require('node:fs')
65+
66+
const jsonPath = process.argv[2]
67+
const rawJson = fs.readFileSync(jsonPath, 'utf8')
68+
const payload = JSON.parse(rawJson)
69+
const devices = payload.result.devices
70+
const udid = process.env.IOS_DEVICE_UDID || ''
71+
72+
let selected = null
73+
for (const device of devices) {
74+
if (device.identifier === udid) {
75+
selected = device
76+
break
77+
}
78+
}
79+
80+
if (selected == null && devices.length > 0) {
81+
selected = devices[0]
82+
}
83+
84+
if (selected == null) {
85+
process.exit(1)
86+
}
87+
88+
const name = selected.deviceProperties.name
89+
if (!name) {
90+
process.exit(1)
91+
}
92+
93+
process.stdout.write(name)
94+
NODE
95+
)"
96+
97+
echo "$IOS_DEVICE_NAME" > "$WORKING_DIRECTORY/ios-device-name.txt"
98+
echo "Resolved Device Farm iOS device for harness: ${IOS_DEVICE_NAME} (${IOS_DEVICE_UDID:-unknown-udid})"
99+
100+
# Actually run the JS Harness tests. Harness owns the XCTest agent
101+
# lifecycle, but uses AWS's generated .xctestrun instead of building one.
102+
- |
103+
set -o pipefail
104+
105+
cd "$WORKING_DIRECTORY/react-native-vision-camera/apps/simple-camera"
38106
39-
# Actually run the test:
40-
- cd apps/simple-camera
41-
- set -o pipefail; HARNESS_METRO_BIND_HOST="::" HARNESS_IOS_METRO_HOST="$(cat "$WORKING_DIRECTORY/metro-host-ip.txt")" HARNESS_IOS_DEVICE_NAME="$IOS_DEVICE_NAME" HARNESS_DETECT_NATIVE_CRASHES=false CI=true JEST_JUNIT_OUTPUT_FILE="$HARNESS_JUNIT" ~/.bun/bin/bun run test:harness -- --harnessRunner ios --reporters=default --reporters=jest-junit 2>&1 | tee "$HARNESS_LOG"
107+
HARNESS_IOS_XCTESTRUN_FILE="$DEVICEFARM_XCUITESTRUN_FILE" \
108+
HARNESS_IOS_XCTEST_DERIVED_DATA_PATH="$DEVICEFARM_DERIVED_DATA_PATH" \
109+
HARNESS_METRO_BIND_HOST="::" \
110+
HARNESS_IOS_METRO_HOST="$(cat "$WORKING_DIRECTORY/metro-host-ip.txt")" \
111+
HARNESS_IOS_DEVICE_NAME="$(cat "$WORKING_DIRECTORY/ios-device-name.txt")" \
112+
HARNESS_DETECT_NATIVE_CRASHES=false \
113+
CI=true \
114+
JEST_JUNIT_OUTPUT_FILE="$HARNESS_JUNIT" \
115+
~/.bun/bin/bun run test:harness -- \
116+
--harnessRunner ios \
117+
--reporters=default \
118+
--reporters=jest-junit 2>&1 | tee "$HARNESS_LOG"
42119
43120
artifacts:
44121
- $WORKING_DIRECTORY

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@
126126
}
127127
},
128128
"patchedDependencies": {
129-
"react-native@0.84.0": "patches/react-native@0.84.0.patch"
129+
"react-native@0.84.0": "patches/react-native@0.84.0.patch",
130+
"@react-native-harness/platform-apple@1.2.0-rc.1": "patches/@react-native-harness%2Fplatform-apple@1.2.0-rc.1.patch"
130131
},
131132
"version": "5.0.9"
132133
}

0 commit comments

Comments
 (0)