Files
Michał Pierzchała 9d7d60c5e0 test(coverage): declare every public command's coverage judgments once (#2418)
* test(coverage): declare every public command's six platform coverage judgments once

One row per public command in test/integration/command-coverage/declarations.ts
carries the android-emulator, ios-simulator, macOS, tvOS, web and Linux
classifications with the same fields the six per-platform manifests use today.
Each platform's Record<PublicCommand, ...> is projected from that table at load
time by a small per-platform view module, so no projected record is committed.

No judgment is derived from another platform's: all six stay authored per command.

* test(coverage): read the projected per-platform coverage view

The six coverage smoke tests, live harnesses and coverage reports now import the
platform view module that projects the declaration table. Both the depgraph
blast-radius query and the device-lane test follow the iOS and macOS paths.

* test(coverage): delete the six per-platform coverage manifests

Their rows now live once, per command, in the declaration table; each platform's
record is projected from it at load time.

* fix(check-affected): extend macos-coverage and integration-node ownership to command-coverage/

test/integration/command-coverage/declarations.ts now carries the per-command
coverage judgments that used to live directly under test/integration/macos-e2e/.
Its nested path wasn't matched by macosCoverageOwnership (top-level or macos-e2e/
only) or isNodeIntegrationPath (no nested segments), so it fell through to
vitest-related, which can't actually run its node --test consumers. Extend both
rules to also match test/integration/command-coverage/.
2026-09-09 15:55:00 +02:00

196 lines
7.6 KiB
TypeScript

// Device-lane ownership (#1781 A9-2): planted paths per family, and the two properties the
// ios.yml routing leans on — an Apple-owned change carries its iOS checks in a narrow plan, and
// a tooling change beside it still fails open to the full set.
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { deviceLaneLeaf, deviceLanesFor, isDeviceLaneSurface, isUnitTest } from './device-lanes.ts';
import { selectChecks, type CheckId } from './model.ts';
const IOS: readonly CheckId[] = ['replay-ios', 'replay-ios-device'];
function lanes(file: string): CheckId[] {
const plan = selectChecks({ changedFiles: [file] });
assert.equal(plan.failOpen, false, `${file} must not fail open`);
return plan.checks.filter((id) =>
/^macos-coverage$|^replay-|^linux-command-evidence$|^web-smoke$|^swift-runner-|^macos-helper$|^android-helpers$/.test(
id,
),
);
}
test('a TypeScript-only Apple change selects the iOS and macOS lanes without a Swift build', () => {
for (const file of [
'packages/platform-apple/src/core/app-resolution.ts',
'packages/platform-apple/src/runtime.ts',
'packages/platform-apple/src/os/macos/desktop-scroll.ts',
]) {
assert.deepEqual(lanes(file), ['replay-ios', 'replay-ios-device', 'replay-macos'], file);
assert.ok(
selectChecks({ changedFiles: [file] }).reasons.some(
(reason) => reason.rule === 'own:device-lane:apple',
),
);
}
assert.deepEqual(lanes('packages/capture-kit/src/ios-snapshot-engine/action-shelf.ts'), [...IOS]);
assert.deepEqual(lanes('test/integration/replays/macos/01-desktop.ad'), ['replay-macos']);
});
test('a Swift runner change selects both builds and every Apple lane', () => {
assert.deepEqual(lanes('apple/runner/AgentDeviceRunner/Sources/Foo.swift'), [
'swift-runner-ios',
'swift-runner-macos',
'replay-ios',
'replay-ios-device',
'replay-macos',
]);
});
test('an iOS replay script and the iOS smoke files own the iOS lanes', () => {
for (const file of [
'test/integration/replays/ios/simulator/01-settings.ad',
'test/integration/replays/ios/fixture/02-checkout-release.ad',
'test/integration/smoke-ios-simulator.test.ts',
'test/integration/ios-simulator-e2e/live-runner.ts',
'test/integration/ios-simulator-e2e-cleanup.test.ts',
]) {
assert.deepEqual(lanes(file), [...IOS], file);
}
});
test('the macOS coverage manifest selects its executable gate and macOS replay lane', () => {
assert.deepEqual(lanes('test/integration/smoke-macos-coverage.test.ts'), [
'macos-coverage',
'replay-macos',
]);
assert.deepEqual(lanes('test/integration/macos-e2e/coverage.ts'), [
'macos-coverage',
'replay-macos',
]);
});
test('shared runtime surface owns every device lane', () => {
for (const file of [
'src/daemon/handlers/session.ts',
'packages/kernel/src/errors.ts',
'src/daemon/android-system-dialog.ts', // naming convention in a shared dir, not a boundary
'test/integration/smoke-daemon-clean.test.ts',
'packages/provision-kit/src/install-source.ts',
]) {
assert.equal(deviceLaneLeaf(file), 'shared', file);
assert.deepEqual(lanes(file), [
'web-smoke',
'replay-ios',
'replay-ios-device',
'replay-macos',
'replay-linux',
'linux-command-evidence',
'replay-android',
]);
}
});
test('another family owns only its own lanes, so an Android-only change carries no iOS check', () => {
assert.deepEqual(lanes('packages/platform-android/src/perf.ts'), ['replay-android']);
assert.deepEqual(lanes('packages/platform-android/src/inventory.ts'), ['replay-android']);
assert.deepEqual(lanes('android/snapshot-helper/src/main/java/X.java'), [
'android-helpers',
'replay-android',
]);
assert.deepEqual(lanes('test/integration/replays/android/emulator/01-settings.ad'), [
'replay-android',
]);
assert.deepEqual(lanes('test/integration/smoke-android-emulator.test.ts'), ['replay-android']);
assert.deepEqual(lanes('test/integration/android-emulator-e2e/live-runner.ts'), [
'replay-android',
]);
assert.deepEqual(lanes('packages/platform-linux/src/snapshot.ts'), [
'replay-linux',
'linux-command-evidence',
]);
assert.deepEqual(lanes('linux/atspi-dump.py'), ['replay-linux', 'linux-command-evidence']);
assert.deepEqual(lanes('packages/platform-web/src/provider.ts'), ['web-smoke']);
assert.deepEqual(lanes('test/integration/smoke-web-platform.test.ts'), ['web-smoke']);
// Families with no CI lane fall through to the static gates only.
assert.deepEqual(lanes('packages/platform-harmonyos/src/hdc.ts'), []);
assert.deepEqual(lanes('packages/platform-vega/src/index.ts'), []);
});
test('the fixture app owns the mobile lanes whichever subtree changes', () => {
assert.deepEqual(lanes('examples/test-app/app/index.tsx'), [
'replay-ios',
'replay-ios-device',
'replay-android',
]);
assert.equal(deviceLaneLeaf('examples/test-app/modules/lab/android/build.gradle'), 'fixture-app');
});
test('unit tests under src/ and packages/*/src own no lane', () => {
for (const file of [
'src/daemon/selectors.test.ts',
'src/__tests__/contracts/interaction-guarantees.test.ts',
'packages/platform-apple/src/core/__tests__/apps.test.ts',
'packages/platform-apple/src/runtime.test.ts',
]) {
assert.ok(isUnitTest(file), file);
assert.ok(!isDeviceLaneSurface(file), file);
assert.deepEqual(lanes(file), [], file);
}
// Non-TypeScript under __tests__ is a fixture the selector cannot place, not a unit test.
assert.ok(!isUnitTest('src/__tests__/test-utils/android-ime-capture.raw.json'));
// Package tests outside src/ have no owner and keep failing open.
assert.ok(!isUnitTest('packages/maestro/test/conformance/verify.test.ts'));
assert.equal(
selectChecks({ changedFiles: ['packages/maestro/test/conformance/verify.test.ts'] }).failOpen,
true,
);
});
test('a mixed tree is shared, and two Apple leaves are still Apple', () => {
assert.equal(deviceLaneLeaf('packages/platform-apple/src/os/macos/x.ts'), 'apple');
assert.equal(deviceLaneLeaf('test/integration/android-emulator-e2e/ios/x.ts'), 'shared');
assert.deepEqual(deviceLanesFor('packages/platform-apple/src/os/macos/x.ts').lanes, [
'replay-ios',
'replay-ios-device',
'replay-macos',
]);
});
test('the surface never narrows a file the selector could not otherwise place', () => {
for (const file of [
'src/global.d.ts',
'src/foo.json',
'test/integration/ios-simulator-e2e/a.png',
]) {
assert.ok(!isDeviceLaneSurface(file), file);
assert.equal(selectChecks({ changedFiles: [file] }).failOpen, true, file);
}
});
test('a golden table owns the parity unit test and both runner builds', () => {
const plan = selectChecks({ changedFiles: ['contracts/fixtures/tap-point-policy.json'] });
assert.equal(plan.failOpen, false);
for (const id of ['unit', 'swift-runner-ios', 'swift-runner-macos'] as const) {
assert.ok(plan.checks.includes(id), id);
}
assert.ok(plan.reasons.some((reason) => reason.rule === 'own:golden-table'));
});
test('a tooling change beside an Android-only change still fails open to the full set', () => {
for (const tooling of [
'.github/workflows/ios.yml',
'.github/actions/setup-apple-runner-build/action.yml',
'package.json',
'pnpm-lock.yaml',
'tsconfig.json',
'vitest.config.ts',
'scripts/check-affected/device-lanes.ts',
'packages/platform-android/package.json',
]) {
const plan = selectChecks({ changedFiles: ['packages/platform-android/src/perf.ts', tooling] });
assert.equal(plan.failOpen, true, tooling);
assert.ok(plan.checks.includes('swift-runner-ios'), tooling);
assert.ok(plan.checks.includes('replay-ios'), tooling);
}
});