Files
callstack__agent-device/vitest.config.ts
Michał Pierzchała c984bd5902 fix(ci): upload hidden diagnostics (#1443)
* fix(ci): upload hidden diagnostics

* fix(ci): capture all hidden diagnostics
2026-07-28 12:30:42 +02:00

137 lines
5.6 KiB
TypeScript

import { defineConfig } from 'vitest/config';
import slowTestGateReporter from './scripts/vitest-slow-test-reporter.ts';
// Tests that stub a real binary (adb/xcrun/npx) by mutating process.env.PATH and
// then spawn it, so each case waits real subprocess/retry/poll time. Run at the
// unit suite's default ~7x file parallelism they contend for CPU and their stub
// spawns get starved past an internal budget, so production takes a generic
// failure path and returns a different error than the assertion expects — a
// contention flake whose failing subset shifts between runs (see
// docs/agents/testing.md "tests must not wait real time"). Serialized below with
// per-file isolation so only one such file spawns stubs at a time, the same
// execution contract the pre-split android index.test.ts aggregation provided.
export const SUBPROCESS_STUB_TESTS = [
'src/platforms/android/__tests__/{app-lifecycle-install,app-lifecycle-open,device-input-state,input-actions,notifications,settings}.test.ts',
'src/daemon/__tests__/runtime-hints.test.ts',
'src/platforms/apple/core/__tests__/index.test.ts',
// Stubs npx + the package managers on PATH and spawns a real Metro dev server per case.
'src/__tests__/client-metro.test.ts',
// Proves the parser fuzz harness still fails (#1414): every case spawns a node subprocess or a
// worker thread and one target is a deliberate hang, so it waits real watchdog time.
'scripts/fuzz/harness.test.ts',
// Replays the fuzz regression corpus (#1414) through that same worker watchdog, so a promoted
// hang case fails against its per-case budget instead of wedging the unit job.
'scripts/fuzz/corpus-replay.test.ts',
];
export default defineConfig({
test: {
// Wall-clock discipline: unit tests must not wait real time. Measured
// 2026-07-04: the suite's duration was bounded by files sleeping through
// production timeout budgets. slowTestThreshold surfaces creep in local
// output; the slow-test reporter enforces the ratchet (pinned offenders
// only shrink). Isolation stays ON and pool stays forks: measured
// --no-isolate = 205s wall vs 48s (module state thrashes across files),
// threads = no change.
slowTestThreshold: 500,
reporters: ['default', slowTestGateReporter()],
projects: [
{
test: {
name: 'unit-core',
// Explicit script entries keep maintained conformance guards in the
// unit suite without waking every ad-hoc *.test.ts under scripts/.
include: [
'src/**/*.test.ts',
'scripts/__tests__/help-conformance-bench.test.ts',
'scripts/__tests__/help-conformance-sample-outputs.test.ts',
'scripts/__tests__/help-conformance-topic-coverage.test.ts',
// Parses CI configuration only, so this action guard needs no device or subprocess lane.
'test/ci/upload-agent-device-artifacts.test.ts',
'test/skillgym/suites/local-cli-help-policy.test.ts',
// The frozen replay-compat corpus (#1417): parse-only, no device or
// subprocess work, so it belongs in the fast lane next to the
// grammar it guards.
'test/replay-compat/corpus.test.ts',
// The Maestro conformance oracle runs via `node --test` in its own CI
// job (scripts/maestro-conformance), like the layering guard.
],
exclude: SUBPROCESS_STUB_TESTS,
setupFiles: [
'src/__tests__/hermetic-env-setup.ts',
'src/__tests__/process-memo-setup.ts',
],
},
},
{
// The subprocess-stub tests stub adb/xcrun/npx by mutating process.env
// (PATH, AGENT_DEVICE_TEST_ARGS_FILE) and wait real subprocess/retry/poll
// time, so the group runs serialized with per-file isolation — the same
// execution contract the pre-split android index.test.ts aggregation
// provided without leaking module caches between split files.
test: {
name: 'subprocess-stub',
include: SUBPROCESS_STUB_TESTS,
setupFiles: [
'src/__tests__/hermetic-env-setup.ts',
'src/__tests__/process-memo-setup.ts',
],
fileParallelism: false,
isolate: true,
maxWorkers: 1,
},
},
{
test: {
name: 'provider-integration',
include: ['test/integration/provider-scenarios/**/*.test.ts'],
setupFiles: [
'src/__tests__/hermetic-env-setup.ts',
'src/__tests__/process-memo-setup.ts',
],
},
},
{
test: {
name: 'interaction-contract',
include: ['test/integration/interaction-contract/**/*.test.ts'],
setupFiles: [
'src/__tests__/hermetic-env-setup.ts',
'src/__tests__/process-memo-setup.ts',
],
},
},
{
test: {
name: 'output-economy',
include: ['test/output-economy/**/*.test.ts'],
setupFiles: [
'src/__tests__/hermetic-env-setup.ts',
'src/__tests__/process-memo-setup.ts',
],
},
},
],
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov', 'json-summary'],
thresholds: {
statements: 78,
lines: 80,
},
include: ['src/**/*.ts'],
exclude: [
'src/**/*.test.ts',
'src/**/__tests__/**',
'src/**/*-types.ts',
'src/**/types.ts',
'src/sdk/**',
'src/bin.ts',
'src/client/client-types.ts',
'src/core/interactor-types.ts',
'src/remote/remote-config.ts',
],
},
},
});