test(js): stop test-file module mocks leaking across files #227
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: e2e-ios | |
| on: | |
| pull_request: | |
| branches: | |
| - '**' | |
| paths: | |
| - '.github/workflows/e2e_ios.yml' | |
| - '.gitmodules' | |
| - 'package.json' | |
| - 'bun.lock' | |
| - 'react-native-update.podspec' | |
| - 'react-native.config.js' | |
| - 'expo-module.config.json' | |
| - 'src/**' | |
| - 'scripts/**' | |
| - 'ios/**' | |
| - 'cpp/**' | |
| - 'android/jni/**' | |
| - 'Example/e2etest/**' | |
| push: | |
| branches: | |
| - master | |
| paths: | |
| - '.github/workflows/e2e_ios.yml' | |
| - '.gitmodules' | |
| - 'package.json' | |
| - 'bun.lock' | |
| - 'react-native-update.podspec' | |
| - 'react-native.config.js' | |
| - 'expo-module.config.json' | |
| - 'src/**' | |
| - 'scripts/**' | |
| - 'ios/**' | |
| - 'cpp/**' | |
| - 'android/jni/**' | |
| - 'Example/e2etest/**' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| e2e-ios: | |
| runs-on: macos-26 | |
| # 绿色基线 ~16 分钟;40 分钟覆盖最坏情况:一次 --retries 1 失败重试 | |
| # (失败用例会等满各级长超时) | |
| timeout-minutes: 40 | |
| steps: | |
| - name: Checkout react-native-update | |
| uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Checkout react-native-update-cli | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: reactnativecn/react-native-update-cli | |
| path: react-native-update-cli | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Cache Bun dependencies | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: ${{ runner.os }}-bun-e2e-${{ hashFiles('Example/e2etest/bun.lock', 'react-native-update-cli/bun.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-bun-e2e- | |
| - name: Setup Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: '26.4' | |
| - name: Boot iOS simulator in background | |
| # 模拟器冷启动要 2-5 分钟,提前异步 boot,让它和依赖安装/xcodebuild | |
| # 并行。型号必须用与 .detoxrc.ts 完全同一份探测代码——此前 shell 里 | |
| # 另写一份选中了 detox 不用的设备,预热全部白费。 | |
| # 失败无害:detox 测试阶段会自己 boot。 | |
| run: | | |
| udid=$(node Example/e2etest/scripts/detect-ios-simulator-type.js --udid) | |
| if [ -n "$udid" ]; then | |
| echo "pre-booting $(node Example/e2etest/scripts/detect-ios-simulator-type.js) ($udid)" | |
| xcrun simctl boot "$udid" || true | |
| else | |
| echo "no matching simulator found, skipping pre-boot" | |
| fi | |
| - name: Cache Homebrew downloads | |
| # bottle 按 URL 内容寻址,restore-keys 前缀命中即省下载(装/链接照常) | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: ~/Library/Caches/Homebrew | |
| key: ${{ runner.os }}-brew-e2e-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-brew-e2e- | |
| - name: Install applesimutils and ccache | |
| run: brew trust wix/brew && HOMEBREW_NO_AUTO_UPDATE=1 brew install wix/brew/applesimutils ccache | |
| - name: Cache ccache | |
| # ccache 按(预处理后)内容寻址,不受 fresh checkout 的 mtime 影响—— | |
| # 这是 DerivedData 缓存在 -UseNewBuildSystem=NO 下做不到的。 | |
| # 陈旧条目不影响正确性,只影响命中率,所以 restore-keys 用前缀即可。 | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: ~/Library/Caches/ccache | |
| key: ${{ runner.os }}-ccache-e2e-xcode-26.4-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-ccache-e2e-xcode-26.4- | |
| - name: Install e2etest dependencies | |
| run: cd Example/e2etest && bun install --frozen-lockfile | |
| - name: Link local react-native-update | |
| run: | | |
| set -euo pipefail | |
| export LOCAL_RNU_VERSION="$(node -p "require('./Example/e2etest/node_modules/react-native-update/package.json').version")" | |
| LOCAL_RNU_DIR="$PWD/Example/e2etest/.e2e-artifacts/local-react-native-update" | |
| rm -rf "$LOCAL_RNU_DIR" Example/e2etest/node_modules/react-native-update | |
| mkdir -p "$LOCAL_RNU_DIR" | |
| cp package.json react-native-update.podspec react-native.config.js expo-module.config.json "$LOCAL_RNU_DIR"/ | |
| rsync -a --exclude='.git' src ios android cpp scripts "$LOCAL_RNU_DIR"/ | |
| node -e "const fs = require('fs'); const file = 'Example/e2etest/.e2e-artifacts/local-react-native-update/package.json'; const pkg = JSON.parse(fs.readFileSync(file, 'utf8')); pkg.version = process.env.LOCAL_RNU_VERSION; fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + '\n');" | |
| ln -s ../.e2e-artifacts/local-react-native-update Example/e2etest/node_modules/react-native-update | |
| - name: Install react-native-update-cli dependencies | |
| run: cd react-native-update-cli && bun install --frozen-lockfile && bun run build | |
| - name: Cache Metro transform cache | |
| # 内容寻址(等价 ccache 之于 clang):陈旧条目只影响命中率不影响正确性 | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: Example/e2etest/.metro-cache | |
| key: ${{ runner.os }}-metro-e2e-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-metro-e2e- | |
| - name: Prepare local update artifacts | |
| env: | |
| E2E_PLATFORM: ios | |
| RNU_CLI_ROOT: ${{ github.workspace }}/react-native-update-cli | |
| run: cd Example/e2etest && bun run prepare:e2e | |
| - name: Cache CocoaPods downloads | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: ~/Library/Caches/CocoaPods | |
| key: ${{ runner.os }}-cocoapods-e2e-${{ hashFiles('Example/e2etest/ios/Podfile.lock', 'Example/e2etest/ios/Podfile', 'Example/e2etest/bun.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cocoapods-e2e- | |
| - name: Cache built e2e app (keyed on native inputs) | |
| # 命中 = native 输入(两个 ios 工程、cpp/jni、podspec、依赖锁、codegen 输入) | |
| # 一字未改,跳过 pod install + xcodebuild,只重新注入 JS bundle(见下)。 | |
| # codegen 输入必须参与 key:TurboModule 胶水在 pod install 时由根 | |
| # package.json 的 codegenConfig + src/Native*.ts spec 生成,漏了它们 | |
| # 会在改 spec 后把新 JS 注入到旧胶水的二进制上。 | |
| # 故意不设 restore-keys:部分命中就是错的二进制,宁可全量重建。 | |
| id: cache-ios-app | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: | | |
| Example/e2etest/ios/build/Build/Products/Release-iphonesimulator/AwesomeProject.app | |
| Example/e2etest/ios/build/hermesc | |
| key: ${{ runner.os }}-e2e-app-xcode-26.4-${{ hashFiles('Example/e2etest/ios/**', 'Example/e2etest/package.json', 'Example/e2etest/bun.lock', 'react-native-update.podspec', 'react-native.config.js', 'expo-module.config.json', 'ios/**', 'cpp/**', 'android/jni/**', 'src/Native*.ts', 'package.json') }} | |
| - name: Install CocoaPods dependencies | |
| if: steps.cache-ios-app.outputs.cache-hit != 'true' | |
| # USE_CCACHE=1 让 react_native_post_install 给所有 pod target 接上 | |
| # RN 自带的 ccache 编译器包装脚本 | |
| run: cd Example/e2etest/ios && USE_CCACHE=1 pod install | |
| - name: Cache Detox iOS framework | |
| id: cache-detox-ios-framework | |
| uses: actions/cache@v5.0.4 | |
| with: | |
| path: ~/Library/Detox | |
| key: ${{ runner.os }}-detox-ios-framework-xcode-26.4-${{ hashFiles('Example/e2etest/bun.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-detox-ios-framework-xcode-26.4- | |
| - name: Build Detox iOS framework cache | |
| if: steps.cache-detox-ios-framework.outputs.cache-hit != 'true' | |
| run: cd Example/e2etest && bunx detox build-framework-cache | |
| - name: Detox build (ios.sim.release) | |
| if: steps.cache-ios-app.outputs.cache-hit != 'true' | |
| env: | |
| RNU_CLI_ROOT: ${{ github.workspace }}/react-native-update-cli | |
| run: | | |
| cd Example/e2etest && E2E_PLATFORM=ios bunx detox build --configuration ios.sim.release | |
| # hermesc 进缓存区:命中 run 没有 Pods,注入脚本需要它编 HBC | |
| cp ios/Pods/hermes-engine/destroot/bin/hermesc ios/build/hermesc | |
| - name: Refresh JS bundle in cached app | |
| if: steps.cache-ios-app.outputs.cache-hit == 'true' | |
| run: cd Example/e2etest && ./scripts/refresh-ios-app-bundle.sh | |
| - name: Detox test (ios.sim.release) | |
| env: | |
| RNU_CLI_ROOT: ${{ github.workspace }}/react-native-update-cli | |
| RNU_E2E_SKIP_PREPARE: 'true' | |
| run: cd Example/e2etest && E2E_PLATFORM=ios bunx detox test --configuration ios.sim.release --retries 1 | |
| - name: Upload Detox artifacts | |
| # cancelled() 覆盖 job 超时被杀的场景,否则超时时拿不到现场 | |
| if: failure() || cancelled() | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: e2e-ios-detox-artifacts | |
| path: Example/e2etest/artifacts | |
| if-no-files-found: ignore | |
| retention-days: 7 |