mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
d5f11f6e2f
* refactor: import package types directly instead of re-exporting from internal modules
Post-#1636 review feedback: internal src modules were re-exporting package
types (export type { X } from '@agent-device/...'), giving one declaration
several import paths and hiding its provenance. New rule applied repo-wide:
internal modules import directly from the owning package; only published
entry surfaces (src/sdk/* entries, client-types, finders, metro composition,
remote-config-schema) may re-export.
Eleven internal re-exports removed and ~110 import sites redirected to the
packages, the big two being CommandFlags (core/dispatch chain, 39 sites) and
SessionAction (daemon/types.ts, 19 sites). Two were already dead
(RefFrameEffect via daemon-command-registry, DiffSnapshotCommandResult via
capture/runtime/snapshot). Entry-surface chains now re-export from the
package rather than laundering through a second internal module
(client-types/client-metro MetroBridgeScope).
Side effect: the R9 type cycle shrinks again, 49 -> 47 (daemon-server
19 -> 17); ceilings lowered to match.
* refactor: drop command-schema's CliFlags re-export (#1640 review P2)
The one consumer (cli/parser/args.ts, a multi-line import the sweep's
single-line scan missed) now imports CliFlags from contracts/command;
FlagDefinition/FlagKey stay — they are src-declared types, not package
laundering.
98 lines
3.7 KiB
TypeScript
98 lines
3.7 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { PUBLIC_COMMANDS } from '../../../src/command-catalog.ts';
|
|
import type { RawSnapshotNode } from '@agent-device/kernel/snapshot';
|
|
import type { SnapshotDiffLine } from '@agent-device/contracts/capture';
|
|
import {
|
|
assertFilesDiffer,
|
|
assertJsonContains,
|
|
assertMp4File,
|
|
assertNonEmptyFile,
|
|
createLiveDeviceAssertions,
|
|
} from '../live-device-e2e/assertions.ts';
|
|
import type { CliJsonResult } from '../cli-json.ts';
|
|
import type { AndroidEmulatorBehaviorId } from './behavior-coverage.ts';
|
|
import { type LiveContext, runStep, verifyCommand } from './live-harness.ts';
|
|
|
|
export { assertFilesDiffer, assertJsonContains, assertMp4File, assertNonEmptyFile };
|
|
|
|
export const { assertElementText, assertWaitSelector, assertWaitText, capturePng } =
|
|
createLiveDeviceAssertions<AndroidEmulatorBehaviorId, LiveContext>(
|
|
runStep,
|
|
verifyCommand,
|
|
PUBLIC_COMMANDS.wait,
|
|
);
|
|
|
|
export function assertDiffLine(
|
|
result: CliJsonResult,
|
|
kind: SnapshotDiffLine['kind'],
|
|
expectedText: string,
|
|
): void {
|
|
const lines: unknown = result.json?.data?.lines;
|
|
assert.ok(Array.isArray(lines), `snapshot diff has no lines: ${JSON.stringify(result.json)}`);
|
|
assert.ok(
|
|
lines.some(
|
|
(line: unknown) =>
|
|
isSnapshotDiffLine(line) && line.kind === kind && line.text.includes(expectedText),
|
|
),
|
|
`expected ${kind} snapshot line containing ${expectedText}: ${JSON.stringify(result.json)}`,
|
|
);
|
|
}
|
|
|
|
export function requireAndroidResourceId(
|
|
result: CliJsonResult,
|
|
suffix: string,
|
|
): {
|
|
identifier: string;
|
|
rect: { height: number; width: number; x: number; y: number };
|
|
} {
|
|
const nodes: unknown = result.json?.data?.nodes;
|
|
assert.ok(Array.isArray(nodes), `snapshot has no nodes: ${JSON.stringify(result.json)}`);
|
|
const node = nodes.find(
|
|
(candidate: unknown): candidate is RawSnapshotNode & { identifier: string } =>
|
|
isSnapshotNode(candidate) &&
|
|
typeof candidate.identifier === 'string' &&
|
|
(candidate.identifier === suffix || candidate.identifier.endsWith(`:id/${suffix}`)),
|
|
);
|
|
assert.ok(
|
|
node,
|
|
`snapshot missing Android resource-id for ${suffix}: ${JSON.stringify(result.json)}`,
|
|
);
|
|
assert.ok(node.rect, `resource-id ${suffix} has no rect`);
|
|
for (const value of [node.rect.x, node.rect.y, node.rect.width, node.rect.height]) {
|
|
assert.ok(Number.isFinite(value), `resource-id ${suffix} has invalid rect`);
|
|
}
|
|
return { identifier: node.identifier, rect: node.rect };
|
|
}
|
|
|
|
export function assertPersistentAndroidHelper(
|
|
result: CliJsonResult,
|
|
options: { reused?: boolean } = {},
|
|
): void {
|
|
const metadata: unknown = result.json?.data?.androidSnapshot;
|
|
assert.ok(
|
|
typeof metadata === 'object' && metadata !== null,
|
|
`snapshot has no Android helper metadata: ${JSON.stringify(result.json)}`,
|
|
);
|
|
const helper = metadata as Record<string, unknown>;
|
|
assert.equal(helper.backend, 'android-helper', JSON.stringify(metadata));
|
|
assert.equal(helper.helperTransport, 'persistent-session', JSON.stringify(metadata));
|
|
if (options.reused !== undefined) {
|
|
assert.equal(helper.helperSessionReused, options.reused, JSON.stringify(metadata));
|
|
}
|
|
}
|
|
|
|
function isSnapshotNode(value: unknown): value is RawSnapshotNode & { identifier: string } {
|
|
if (typeof value !== 'object' || value === null) return false;
|
|
const node = value as RawSnapshotNode;
|
|
return typeof node.identifier === 'string';
|
|
}
|
|
|
|
function isSnapshotDiffLine(value: unknown): value is SnapshotDiffLine {
|
|
if (typeof value !== 'object' || value === null) return false;
|
|
const line = value as Partial<SnapshotDiffLine>;
|
|
return (
|
|
(line.kind === 'added' || line.kind === 'removed' || line.kind === 'unchanged') &&
|
|
typeof line.text === 'string'
|
|
);
|
|
}
|