Skip to content

DO NOT MERGE: native iOS coverage setup (local harness fork)#247

Draft
mfazekas wants to merge 1 commit into
feat/rive-ios-experimentalfrom
setup/native-ios-coverage
Draft

DO NOT MERGE: native iOS coverage setup (local harness fork)#247
mfazekas wants to merge 1 commit into
feat/rive-ios-experimentalfrom
setup/native-ios-coverage

Conversation

@mfazekas
Copy link
Copy Markdown
Collaborator

@mfazekas mfazekas commented May 8, 2026

Do not merge — this PR contains local file: and portal: references to the react-native-harness fork.

What this does

Sets up native iOS code coverage collection using @react-native-harness/coverage-ios from the mfazekas/react-native-harness fork (feat/native-ios-coverage branch).

How to use

Prerequisites: clone the harness fork at /Users/boga/Work/Margelo/react-native-harness and check out feat/native-ios-coverage.

1. Fix harness fork (one-time setup)

The packages/cli package is used as the portal target for react-native-harness, but it's missing three things that Jest/Metro/npx need. Apply these fixes in the harness fork:

a) Add jest-preset.cjs — Jest requires react-native-harness/jest-preset at the package root:

cat > packages/cli/jest-preset.cjs << 'SHIM'
module.exports = {
    runner: '@react-native-harness/jest',
};
SHIM

b) Add metro.cjs — Metro config imports react-native-harness/metro. Uses realpathSync to handle --preserve-symlinks:

cat > packages/cli/metro.cjs << 'SHIM'
const path = require('path');
const fs = require('fs');
const realDir = path.dirname(fs.realpathSync(__filename));
module.exports = require(path.join(realDir, '..', 'metro', 'dist', 'index.js'));
SHIM

c) Add bin.cjs — Without a bin entry, npx downloads a fresh copy from npm instead of using the local portal:

cat > packages/cli/bin.cjs << 'SHIM'
#!/usr/bin/env node
import('./dist/index.js');
SHIM
chmod +x packages/cli/bin.cjs

d) Update packages/cli/package.json — add the exports and bin fields:

{
  "bin": {
    "react-native-harness": "./bin.cjs",
    "harness": "./bin.cjs"
  },
  "exports": {
    ...existing exports...,
    "./jest-preset": "./jest-preset.cjs",
    "./metro": "./metro.cjs"
  }
}

e) Fix packages/coverage-ios/package.json — add missing fields that cause pod validation errors:

{
  "homepage": "https://github.com/callstackincubator/react-native-harness",
  "author": "React Native Harness contributors"
}

2. Build and run coverage

yarn install
cd example/ios && pod install  # should print [HarnessCoverage] Instrumenting pods
cd ..

# Build with Xcode 16.4 (not Xcode 26 beta)
DEVELOPER_DIR=/Applications/Xcode16.4.app/Contents/Developer xcodebuild build \
  -workspace ios/RiveExample.xcworkspace -scheme RiveExample \
  -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.6" \
  -derivedDataPath ios/build

# Install on the correct simulator
xcrun simctl install "iPhone 16 Pro" ios/build/Build/Products/Debug-iphonesimulator/RiveExample.app

# Run tests with coverage
NODE_OPTIONS="--preserve-symlinks" npx react-native-harness --harnessRunner ios --coverage

3. Collect native coverage

The debug dylib path depends on where the app is installed. Find it with:

APP_PATH=$(xcrun simctl get_app_container "iPhone 16 Pro" rive.example)

Then merge and export:

xcrun llvm-profdata merge -sparse /tmp/harness-coverage/*.profraw -o coverage/native-ios.profdata
xcrun llvm-cov export --format=lcov \
  --instr-profile=coverage/native-ios.profdata \
  "$APP_PATH/RiveExample.debug.dylib" \
  > coverage/native-ios.lcov

# HTML report
genhtml coverage/native-ios.lcov -o coverage/native-ios-html \
  --ignore-errors inconsistent,corrupt,unsupported
open coverage/native-ios-html/index.html

Why these fixes are needed

The portal resolution "react-native-harness": "portal:.../packages/cli" maps the package to the CLI sub-package, but Jest expects react-native-harness/jest-preset, Metro expects react-native-harness/metro, and npx needs a bin entry — none of which exist in the CLI package. The correct package (packages/react-native-harness) can't be used as a portal target because yarn refuses to write into a different monorepo root. These shims bridge the gap.

Known issue

The resolve-coverage-pods.mjs script needs NODE_OPTIONS="--preserve-symlinks" when using portal resolutions. After yarn install, manually patch node_modules/@react-native-harness/coverage-ios/scripts/harness_coverage_hook.rb line 19 to add this. This will be fixed upstream.

Adds coverage-ios dependency and portal resolutions pointing to the local
react-native-harness fork (feat/native-ios-coverage branch).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant