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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ This repo encodes invariants as self-declaring gates. The correct response to a

## PR Readiness Checklist
- Static gates first: required checks from **Testing Matrix** pass, `pnpm check:fallow --base origin/main` is clean when code quality/dead-code risk is relevant, CI guards are green, and no conflict markers or unmerged paths remain.
- Do not report a PR as CI-green from a local `--project unit` run alone: the **Integration Tests** and **Coverage** jobs run the `provider-integration` project, so verify green on the actual PR head across those jobs, not just unit.
- Do not report a PR as CI-green from a local unit-only run alone: use `pnpm test:unit` for the repo unit bundle, or `vitest run --project unit-core --project android-adb` when invoking Vitest directly. The **Integration Tests** and **Coverage** jobs run the `provider-integration` project, so verify green on the actual PR head across those jobs, not just unit.
- Command-surface changes preserve CLI, Node.js, daemon, MCP, help, docs, and SkillGym coverage where that surface is affected. Do not duplicate command contracts across layers.
- Device-facing behavior is not merge-ready until it has real simulator/emulator/device evidence for the changed path. Fixture-backed tests can prove contracts, but they do not replace a live run that creates or observes the artifact/state the feature claims to handle.
- If live verification is blocked, state the blocker, exact command or device needed, and downgrade the PR to residual risk instead of calling it ready.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@
"test-app:maestro": "node scripts/run-test-app-maestro-suite.mjs",
"test-app:maestro:ios": "node scripts/run-test-app-maestro-suite.mjs --platform ios",
"test-app:maestro:android": "node scripts/run-test-app-maestro-suite.mjs --platform android",
"test": "vitest run --project unit",
"test:unit": "vitest run --project unit",
"test": "vitest run --project unit-core --project android-adb",
"test:unit": "vitest run --project unit-core --project android-adb",
"test:coverage": "vitest run --coverage",
"test:integration:provider": "vitest run --project provider-integration",
"test:integration:progress": "node --experimental-strip-types scripts/integration-progress.ts",
Expand Down
10 changes: 5 additions & 5 deletions scripts/vitest-slow-test-reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ const PINNED_SLOW_UNIT_TESTS = new Set([
"src/platforms/android/__tests__/devices.test.ts :: ensureAndroidEmulatorBooted launches emulator with GUI by default",
"src/platforms/android/__tests__/devices.test.ts :: ensureAndroidEmulatorBooted reuses running emulator for headless requests",
"src/platforms/android/__tests__/devices.test.ts :: listAndroidDevices falls back to model when emulator avd name is unavailable",
"src/platforms/android/__tests__/index.test.ts :: fillAndroid uses chunk-safe shell input and retries when verification still fails",
"src/platforms/android/__tests__/index.test.ts :: installAndroidApp .aab reports missing bundletool tooling",
"src/platforms/android/__tests__/index.test.ts :: installAndroidApp installs .aab via bundletool build-apks + install-apks",
"src/platforms/android/__tests__/index.test.ts :: installAndroidApp installs .apk via adb install -r",
"src/platforms/android/__tests__/index.test.ts :: installAndroidApp resolves packageName and launchTarget from nested archive artifacts",
"src/platforms/android/__tests__/input-actions.test.ts :: fillAndroid uses chunk-safe shell input and retries when verification still fails",
"src/platforms/android/__tests__/app-lifecycle-install.test.ts :: installAndroidApp .aab reports missing bundletool tooling",
"src/platforms/android/__tests__/app-lifecycle-install.test.ts :: installAndroidApp installs .aab via bundletool build-apks + install-apks",
"src/platforms/android/__tests__/app-lifecycle-install.test.ts :: installAndroidApp installs .apk via adb install -r",
"src/platforms/android/__tests__/app-lifecycle-install.test.ts :: installAndroidApp resolves packageName and launchTarget from nested archive artifacts",
"src/platforms/android/__tests__/perf.test.ts :: stopAndroidSimpleperfProfile fails before pull when remote artifact never stabilizes",
"src/platforms/android/__tests__/snapshot-helper-session.test.ts :: allows a persistent session snapshot to use the helper command budget",
"src/platforms/apple/core/__tests__/index.test.ts :: openIosSimulatorApp times out instead of hanging indefinitely",
Expand Down
35 changes: 35 additions & 0 deletions src/__tests__/test-utils/mocked-binaries.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { promises as fs } from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import type { DeviceInfo } from '../../kernel/device.ts';
import { ANDROID_EMULATOR } from './device-fixtures.ts';

/**
* Creates a temporary stub `adb` binary that logs all args to a file,
Expand Down Expand Up @@ -67,3 +69,36 @@ export async function withMockedXcrun(
await fs.rm(tmpDir, { recursive: true, force: true });
}
}

/**
* Like {@link withMockedAdb}, but with a caller-provided stub `adb` script so
* tests can shape per-subcommand responses instead of only recording args.
* The callback also receives the canonical Android emulator device fixture.
*/
export async function withScriptedAdb(
tempPrefix: string,
script: string,
run: (ctx: { argsLogPath: string; device: DeviceInfo }) => Promise<void>,
): Promise<void> {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), tempPrefix));
const adbPath = path.join(tmpDir, 'adb');
const argsLogPath = path.join(tmpDir, 'args.log');
await fs.writeFile(adbPath, script, 'utf8');
await fs.chmod(adbPath, 0o755);

const previousPath = process.env.PATH;
const previousArgsFile = process.env.AGENT_DEVICE_TEST_ARGS_FILE;
process.env.PATH = `${tmpDir}${path.delimiter}${previousPath ?? ''}`;
process.env.AGENT_DEVICE_TEST_ARGS_FILE = argsLogPath;

try {
// Fresh copy per call: tests may tailor the device without leaking
// mutations into the shared fixture.
await run({ argsLogPath, device: { ...ANDROID_EMULATOR } });
} finally {
process.env.PATH = previousPath;
if (previousArgsFile === undefined) delete process.env.AGENT_DEVICE_TEST_ARGS_FILE;
else process.env.AGENT_DEVICE_TEST_ARGS_FILE = previousArgsFile;
await fs.rm(tmpDir, { recursive: true, force: true });
}
}
2 changes: 1 addition & 1 deletion src/__tests__/vitest-slow-test-reporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ test('integration paths get the larger budget', () => {
test('pinned tests never become offenders', () => {
const offender = classifySlowTest({
root: '/repo',
moduleId: '/repo/src/platforms/android/__tests__/index.test.ts',
moduleId: '/repo/src/platforms/android/__tests__/app-lifecycle-install.test.ts',
name: 'installAndroidApp installs .apk via adb install -r',
fullName: 'installAndroidApp installs .apk via adb install -r',
durationMs: 9_000,
Expand Down
Loading
Loading