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
23 changes: 23 additions & 0 deletions .changeset/fix-ios-bootstrap-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"vitest-mobile": patch
---

### fix(harness): prevent bootstrap hang from npx install prompts

Add `--yes` to every `npx` call in the harness builder so npx
auto-confirms package downloads instead of prompting. Under the
spinner, stdin is `'ignore'` — any prompt would hang indefinitely:

- `npx --yes @react-native-community/cli init` (scaffold step, runs
before the project's `node_modules` exist, so npx always needs to
resolve the package over the network)
- `npx --yes react-native build-ios` and `npx --yes react-native
build-android` (build steps; defensive — these usually resolve
locally after `npm install`)

While here, also switch `buildAndroid` from a raw `gradlew
assembleDebug` to `npx react-native build-android` for symmetry with
iOS and to let the RN CLI handle codegen + Gradle wrapper setup.
Pass `--tasks assembleDebug` explicitly: the CLI defaults its task
prefix to `bundle` (producing an `.aab`), not `assemble` (producing
the `.apk` we need). The `--help` text is misleading on this point.
16 changes: 9 additions & 7 deletions packages/vitest-mobile/src/node/harness-builder/android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } fr
import { resolve } from 'node:path';
import { log } from '../logger';
import { applyTemplateTree, fillFilePlaceholders } from '../templates';
import { HARNESS_APP_NAME, HARNESS_BUNDLE_ID, run, runLive } from './_shared';
import { HARNESS_APP_NAME, HARNESS_BUNDLE_ID, runLive } from './_shared';

export function getAndroidBinaryPath(buildDir: string): string {
return resolve(buildDir, 'build', `${HARNESS_APP_NAME}.apk`);
Expand Down Expand Up @@ -46,12 +46,14 @@ export async function buildAndroid(projectDir: string, buildDir: string): Promis
log.info('Building Android debug APK (this may take a few minutes)...');
const gradleStart = Date.now();

const gradlew = resolve(androidDir, 'gradlew');
if (!existsSync(gradlew)) {
throw new Error('gradlew not found in Android project');
}
run(`chmod +x "${gradlew}"`, { cwd: androidDir });
await runLive(`"${gradlew}" assembleDebug -x lint --no-daemon`, { cwd: androidDir });
// Pass --tasks assembleDebug explicitly: `react-native build-android`
// defaults its task prefix to 'bundle' (producing an AAB), not 'assemble'
// (producing an APK). The CLI's --help is misleading on this point.
// Note: the CLI auto-prepends `app:` to each task name, so we pass the
// bare task name (passing `app:assembleDebug` would yield `app:app:...`).
await runLive('npx --yes react-native build-android --tasks assembleDebug --extra-params "-x lint --no-daemon"', {
cwd: projectDir,
});
log.info(` Android build complete (${((Date.now() - gradleStart) / 1000).toFixed(1)}s)`);

const apkPath = resolve(androidDir, 'app', 'build', 'outputs', 'apk', 'debug', 'app-debug.apk');
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest-mobile/src/node/harness-builder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ async function scaffoldProject(buildDir: string, options: HarnessBuildOptions):
// runLive (async when a log sink is active) keeps the spinner animating
// during this ~30s operation; run() would block the event loop sync.
await runLive(
`npx @react-native-community/cli init ${HARNESS_APP_NAME} --version ${options.reactNativeVersion} --skip-install --skip-git-init`,
`npx --yes @react-native-community/cli init ${HARNESS_APP_NAME} --version ${options.reactNativeVersion} --skip-install --skip-git-init`,
{ cwd: buildDir },
);

Expand Down
8 changes: 7 additions & 1 deletion packages/vitest-mobile/src/node/harness-builder/ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,16 @@ export async function buildIOS(projectDir: string): Promise<void> {
log.info('Building for iOS simulator (this may take a few minutes)...');
const stepStart = Date.now();

// --force-pods is required: without it, the CLI only runs `pod install`
// when `react-native.config.js` sets `automaticPodsInstallation: true`
// (the bare RN init template does not). Skipping pod install causes
// xcodebuild to fail with "Unable to load contents of file list" against
// the Pods xcfilelists.
const buildCmd = [
'npx react-native build-ios',
'npx --yes react-native build-ios',
`--scheme ${HARNESS_APP_NAME}`,
'--mode Debug',
'--force-pods',
`--buildFolder "${resolve(iosDir, 'DerivedData')}"`,
].join(' ');

Expand Down
Loading