Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 243 additions & 0 deletions .github/workflows/native-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
name: native-tests

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: native-tests-${{ github.ref }}
cancel-in-progress: true

jobs:
android-unit:
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24.x'
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v4
- name: Install and generate native bindings
run: |
corepack enable
yarn install --immutable
# shellcheck disable=SC2016
find native-modules native-views -mindepth 2 -maxdepth 2 -name nitro.json -print0 |
xargs -0 -n1 -P4 bash -c 'cd "$(dirname "$0")" && yarn nitrogen > /dev/null'
- name: Run nine Android unit test suites
working-directory: example/react-native/android
run: |
./gradlew --continue --no-daemon --max-workers=2 --console=plain \
:onekeyfe_react-native-app-update:testDebugUnitTest \
:onekeyfe_react-native-bundle-crypto:testDebugUnitTest \
:onekeyfe_react-native-network-throttle:testDebugUnitTest \
:onekeyfe_react-native-range-downloader:testDebugUnitTest \
:onekeyfe_react-native-sni-connect:testDebugUnitTest \
:onekeyfe_react-native-auto-size-input:testDebugUnitTest \
:onekeyfe_react-native-image:testDebugUnitTest \
:onekeyfe_react-native-native-list:testDebugUnitTest \
:onekeyfe_react-native-text-input:testDebugUnitTest
- name: Verify every Android suite executed tests
if: always()
run: |
python3 - <<'PY'
from pathlib import Path
import xml.etree.ElementTree as ET

packages = {
'native-modules/react-native-app-update',
'native-modules/react-native-bundle-crypto',
'native-modules/react-native-network-throttle',
'native-modules/react-native-range-downloader',
'native-modules/react-native-sni-connect',
'native-views/react-native-auto-size-input',
'native-views/react-native-image',
'native-views/react-native-native-list',
'native-views/react-native-text-input',
}
total = 0
for package in sorted(packages):
reports = list((Path(package) / 'android/build/test-results/testDebugUnitTest').glob('TEST-*.xml'))
count = sum(int(ET.parse(report).getroot().attrib['tests']) for report in reports)
print(f'{package}: {count} tests in {len(reports)} reports')
if count == 0:
raise SystemExit(f'No executed tests for {package}')
total += count
print(f'Android unit tests executed: {total}')
PY
- name: Upload Android test reports on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: android-native-test-reports
path: |
native-modules/*/android/build/test-results/testDebugUnitTest/*.xml
native-views/*/android/build/test-results/testDebugUnitTest/*.xml
example/react-native/android/build/reports/problems/
if-no-files-found: warn

kotlin-cli:
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Install verified Kotlin 2.3.21 compiler
run: |
curl -fsSLo kotlin-compiler.zip https://github.com/JetBrains/kotlin/releases/download/v2.3.21/kotlin-compiler-2.3.21.zip
curl -fsSLo kotlin-compiler.sha256 https://github.com/JetBrains/kotlin/releases/download/v2.3.21/kotlin-compiler-2.3.21.zip.sha256
echo "$(cat kotlin-compiler.sha256) kotlin-compiler.zip" | sha256sum --check
unzip -q kotlin-compiler.zip -d "$RUNNER_TEMP"
"$RUNNER_TEMP/kotlinc/bin/kotlinc" -version 2>&1 | grep -F '2.3.21'
- name: Run bundle-update Kotlin policy tests
working-directory: native-modules/react-native-bundle-update
run: |
"$RUNNER_TEMP/kotlinc/bin/kotlinc" \
android/src/main/java/com/margelo/nitro/reactnativebundleupdate/BundleStorageSchemaPolicy.kt \
tests/kotlin/BundleStorageSchemaPolicyTest.kt \
-include-runtime -d "$RUNNER_TEMP/bundle-storage-schema-tests.jar"
java -jar "$RUNNER_TEMP/bundle-storage-schema-tests.jar" | tee "$RUNNER_TEMP/kotlin-tests.log"
grep -Eq 'BundleStorageSchemaPolicy: [1-9][0-9]* assertions passed' "$RUNNER_TEMP/kotlin-tests.log"

swiftpm:
runs-on: macos-26
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- name: Select and verify Xcode 26.6
run: |
sudo xcode-select -s /Applications/Xcode_26.6.app/Contents/Developer
xcodebuild -version
xcodebuild -version | grep -F 'Xcode 26.6'
- name: Run three SwiftPM suites and verify execution
shell: bash
run: |
set -euo pipefail
mkdir -p artifacts/swiftpm
packages=(
native-modules/react-native-sni-connect
native-modules/react-native-bundle-update
native-modules/react-native-range-downloader/tests/swiftpm
)
for package in "${packages[@]}"; do
name=$(basename "$package")
if [[ "$package" == *range-downloader* ]]; then name=range-downloader; fi
swift test --package-path "$package" --scratch-path "$RUNNER_TEMP/swift-$name" \
2>&1 | tee "artifacts/swiftpm/$name.log"
if ! grep -Eq 'Executed [1-9][0-9]* tests?|Test run with [1-9][0-9]* tests?' "artifacts/swiftpm/$name.log"; then
echo "No executed Swift tests for $package" >&2
exit 1
fi
done
- name: Upload SwiftPM logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: swiftpm-native-test-logs
path: artifacts/swiftpm/*.log
if-no-files-found: warn

ios-xctest:
runs-on: macos-26
timeout-minutes: 90
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24.x'
- uses: ruby/setup-ruby@v1
with:
working-directory: example/react-native
ruby-version: '3.4.4'
bundler-cache: true
- name: Select and verify Xcode and simulator
run: |
sudo xcode-select -s /Applications/Xcode_26.6.app/Contents/Developer
xcodebuild -version | grep -F 'Xcode 26.6'
xcrun simctl list devices available | grep -F 'iOS 26.5'
xcrun simctl list devices available | grep -F 'iPhone 17 Pro ('
df -h .
- name: Install and generate native bindings
run: |
corepack enable
yarn install --immutable
# shellcheck disable=SC2016
find native-modules native-views -mindepth 2 -maxdepth 2 -name nitro.json -print0 |
xargs -0 -n1 -P4 bash -c 'cd "$(dirname "$0")" && yarn nitrogen > /dev/null'
- name: Install CocoaPods test specs and verify lockfile
working-directory: example/react-native/ios
run: |
bundle exec pod install
ruby - <<'RUBY'
require 'yaml'

def normalized_lockfile(text)
lockfile = YAML.safe_load(text, permitted_classes: [Symbol], aliases: true)
checksums = lockfile.fetch('SPEC CHECKSUMS')
checksum = checksums.fetch('hermes-engine')
abort 'Invalid Hermes podspec checksum' unless checksum.match?(/\A[0-9a-f]{40}\z/)
checksums['hermes-engine'] = '<host-path-dependent>'

# CocoaPods may retain the previous Specs Git URL in the lockfile
# even when the Podfile now resolves the same specs through trunk CDN.
repos = lockfile.fetch('SPEC REPOS')
git_specs = repos.delete('https://github.com/CocoaPods/Specs.git')
if git_specs
repos['trunk'] = ((repos['trunk'] || []) + git_specs).sort
end
lockfile
end

committed = IO.popen(
['git', 'show', 'HEAD:example/react-native/ios/Podfile.lock'], &:read
)
installed = File.read('Podfile.lock')
unless normalized_lockfile(committed) == normalized_lockfile(installed)
abort 'CocoaPods changed the locked dependencies or checksums'
end
puts 'Podfile.lock matches: only the Hermes checksum and Specs CDN URL may differ'
RUBY
- name: Run six pod XCTest suites on iOS Simulator
shell: bash
run: |
set -euo pipefail
mkdir -p artifacts/ios
workspace=example/react-native/ios/example.xcworkspace
schemes=(NativeSheet-Unit-Tests react-native-pager-view-Unit-Tests OneKeyTextInput-Unit-Tests OneKeyImage-Unit-Tests react-native-native-list-Unit-Tests ReactNativeBundleCrypto-Unit-Tests)
xcodebuild -list -workspace "$workspace" > artifacts/ios/schemes.log
for scheme in "${schemes[@]}"; do
grep -Fxq " $scheme" artifacts/ios/schemes.log
# shellcheck disable=SC2016
xcodebuild test -workspace "$workspace" -scheme "$scheme" \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=26.5' \
-derivedDataPath "$RUNNER_TEMP/native-tests-derived-data" \
-resultBundlePath "$PWD/artifacts/ios/$scheme.xcresult" \
-parallel-testing-enabled NO -jobs 2 CODE_SIGNING_ALLOWED=NO \
IPHONEOS_DEPLOYMENT_TARGET=16.4 \
'OTHER_LDFLAGS=$(inherited) -lc++' \
2>&1 | tee "artifacts/ios/$scheme.log"
xcrun xcresulttool get test-results summary \
--path "artifacts/ios/$scheme.xcresult" \
> "artifacts/ios/$scheme-summary.json"
jq -e '.totalTestCount > 0' "artifacts/ios/$scheme-summary.json"
done
df -h .
- name: Upload iOS result bundles and logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ios-native-test-results
path: artifacts/ios/
if-no-files-found: warn
4 changes: 4 additions & 0 deletions example/react-native/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
rootProject.name = 'example'
include ':app'

// This package is not an example app dependency, but its unit tests use the same Gradle host.
include ':onekeyfe_react-native-network-throttle'
project(':onekeyfe_react-native-network-throttle').projectDir = file('../../../native-modules/react-native-network-throttle/android')

def reactNativeGradlePlugin = new File(
providers.exec {
workingDir(rootDir)
Expand Down
10 changes: 9 additions & 1 deletion example/react-native/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Spec sources. The default CDN plus Aliyun's repo, which hosts EMASCurl
# (a transitive native dependency of @onekeyfe/react-native-sni-connect).
source 'https://github.com/CocoaPods/Specs.git'
source 'https://cdn.cocoapods.org/'
source 'https://github.com/aliyun/aliyun-specs.git'

# Resolve react_native_pods.rb with node to allow for hoisting
Expand Down Expand Up @@ -41,6 +41,14 @@ target 'example' do
pod 'SDWebImageSVGCoder', '1.7.0', :modular_headers => true
pod 'SDWebImageWebPCoder', '0.14.6', :modular_headers => true

# CocoaPods does not install test specs unless they are requested explicitly.
pod 'OneKeyImage', :path => '../../../node_modules/@onekeyfe/react-native-image', :testspecs => ['Tests']
pod 'NativeSheet', :path => '../../../node_modules/@onekeyfe/react-native-native-sheet', :testspecs => ['Tests']
pod 'react-native-pager-view', :path => '../../../node_modules/@onekeyfe/react-native-pager-view', :testspecs => ['Tests']
pod 'OneKeyTextInput', :path => '../../../node_modules/@onekeyfe/react-native-text-input', :testspecs => ['Tests']
pod 'react-native-native-list', :path => '../../../node_modules/@onekeyfe/react-native-native-list', :testspecs => ['Tests']
pod 'ReactNativeBundleCrypto', :path => '../../../node_modules/@onekeyfe/react-native-bundle-crypto', :testspecs => ['Tests']

# Copy optional offline TradingView chart material into the app bundle as
# `tradingview-assets/`, preserving the
# directory tree so react-native-chart-webview's WKURLSchemeHandler can serve it.
Expand Down
Loading
Loading