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
20 changes: 16 additions & 4 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1129,13 +1129,25 @@ function nativeProofConfigFromModule(loaded: unknown): NativeProofConfig | undef
return isNativeProofConfig(current) ? current : undefined;
}

/**
* The selection the preflight resolves the project with: CLI flags first, then the same
* env vars the runner itself reads (PLATFORM / NATIVEPROOF_PROJECT). Without the env
* fallback, `PLATFORM=ios nativeproof` preflighted the android project (wrong Appium
* driver ensured, macOS guard skipped) and then ran the ios one.
*/
export function runSelection(args: CliArgs, env: NodeJS.ProcessEnv = process.env): RunnerEnv {
const selection: RunnerEnv = {};
const platform = args.platform ?? env.PLATFORM;
const project = args.project ?? env.NATIVEPROOF_PROJECT;
if (platform) selection.platform = platform;
if (project) selection.project = project;
return selection;
}

async function runTests(args: CliArgs): Promise<number> {
const { wdioConfig, configPath, extraEnv } = resolveRunner(args);
const userConfig = await loadNativeProofConfig(configPath);
const selection: RunnerEnv = {};
if (args.platform) selection.platform = args.platform;
if (args.project) selection.project = args.project;
const project = resolveProject(userConfig, selection);
const project = resolveProject(userConfig, runSelection(args));
const appium = await ensureAppium(userConfig.appium, args.startAppium, project.platform);
try {
return await new Promise<number>((resolve, reject) => {
Expand Down
8 changes: 7 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export interface RunnerEnv {
spec?: string;
}

/** Pick the project by explicit name, else by platform, else the first one. */
/** Pick the project by explicit name, else by platform (loudly failing on no match), else the first one. */
export function resolveProject(config: RunnerConfig, env: RunnerEnv = {}): DeviceProject {
if (env.project) {
const named = config.projects.find((project) => project.name === env.project);
Expand All @@ -191,6 +191,12 @@ export function resolveProject(config: RunnerConfig, env: RunnerEnv = {}): Devic
if (env.platform) {
const byPlatform = config.projects.find((project) => project.platform === env.platform);
if (byPlatform) return byPlatform;
// Falling back to projects[0] here silently ran the WRONG platform: `--ios` with an
// android-only config did an android run with android evidence and zero warning.
const available = config.projects.map((project) => `${project.name} (${project.platform})`).join(", ");
throw new Error(
`nativeproof: no ${env.platform} project in nativeproof.config.ts — available: ${available}`,
);
}
const first = config.projects[0];
if (!first) throw new Error("nativeproof: config has no `projects`");
Expand Down
10 changes: 10 additions & 0 deletions test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
onboardCommand,
parseArgs,
resolveRunner,
runSelection,
type ScaffoldIo,
scaffold,
scaffoldFiles,
Expand Down Expand Up @@ -649,3 +650,12 @@ test("updateConfigAppPath survives comments containing apostrophes and braces",
assert.match(updated.slice(androidAt), /"appium:app": "\.\/old\.apk"/); // android untouched
assert.doesNotMatch(updated.slice(androidAt), /New\.app/);
});

test("runSelection falls back to the env vars the runner itself reads", () => {
const args = parseArgs([]);
// Flags win; without them, PLATFORM/NATIVEPROOF_PROJECT steer the preflight exactly
// like they steer the runner — previously the CLI preflighted projects[0] instead.
assert.deepEqual(runSelection(args, { PLATFORM: "ios" }), { platform: "ios" });
assert.deepEqual(runSelection(args, { NATIVEPROOF_PROJECT: "beta" }), { project: "beta" });
assert.deepEqual(runSelection(parseArgs(["--android"]), { PLATFORM: "ios" }), { platform: "android" });
});
8 changes: 8 additions & 0 deletions test/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,11 @@ test("findConfigFile locates nativeproof.config.* via the injected exists check"
null,
);
});

test("resolveProject errors when an explicit platform has no matching project", () => {
// Falling back to projects[0] silently ran the wrong platform for `--ios`.
assert.throws(
() => resolveProject({ projects }, { platform: "ios2" }),
/no ios2 project in nativeproof\.config\.ts — available: .*android/,
);
});