mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
32b9db2d7a
* test: add Android full emulator coverage * ci: package Android helpers before nightly coverage * fix: harden Android nightly runtime evidence * fix: expose trace artifacts in MCP schema * style: format Android coverage manifest * fix: address Android coverage review findings * refactor: share live device coverage helpers * fix: restore fixture landmarks in device smokes * refactor: centralize live artifact assertions * fix: normalize fixture canary visibility
81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
import {
|
|
assertCoverageComplete,
|
|
cleanupSession,
|
|
createContext,
|
|
runScenario,
|
|
sessionExists,
|
|
writeCoverageReport,
|
|
} from './live-harness.ts';
|
|
import { ANDROID_EMULATOR_FIXTURE_BOOTSTRAP, selectAndroidEmulatorScenarios } from './scenarios.ts';
|
|
import { prepareAndroidEmulatorScenario } from './scenario-start.ts';
|
|
|
|
const SCENARIO_FILTER_ENV = 'AGENT_DEVICE_ANDROID_E2E_SCENARIOS';
|
|
|
|
export type AndroidEmulatorE2EOptions = {
|
|
scenarioIds?: readonly string[];
|
|
};
|
|
|
|
export async function runAndroidEmulatorE2E(
|
|
options: AndroidEmulatorE2EOptions = {},
|
|
): Promise<void> {
|
|
const requestedIds = options.scenarioIds ?? scenarioIdsFromEnv(process.env[SCENARIO_FILTER_ENV]);
|
|
const context = createContext();
|
|
const selectedScenarios = selectAndroidEmulatorScenarios(requestedIds).filter(
|
|
(scenario) => scenario.tier !== 'full' || context.tier === 'full',
|
|
);
|
|
const executedScenarios = [ANDROID_EMULATOR_FIXTURE_BOOTSTRAP, ...selectedScenarios];
|
|
let primaryError: unknown;
|
|
try {
|
|
for (const scenario of executedScenarios) {
|
|
await runScenario(context, {
|
|
id: scenario.id,
|
|
run: async (scenarioContext) => {
|
|
await prepareAndroidEmulatorScenario(scenarioContext, scenario.start);
|
|
await scenario.run(scenarioContext);
|
|
},
|
|
});
|
|
}
|
|
assertCoverageComplete(context, executedScenarios);
|
|
} catch (error) {
|
|
primaryError = error;
|
|
}
|
|
|
|
let cleanupError: unknown;
|
|
try {
|
|
context.sessionOpen = context.sessionOpen || (await sessionExists(context));
|
|
await cleanupSession(context);
|
|
} catch (error) {
|
|
cleanupError = error;
|
|
}
|
|
try {
|
|
const reportPath = writeCoverageReport(context);
|
|
console.log(`Android emulator coverage report: ${reportPath}`);
|
|
console.log(`Android emulator live run: ${Date.now() - context.startedAtMs}ms`);
|
|
for (const timing of context.timings) {
|
|
console.log(` ${timing.id}: ${timing.durationMs}ms`);
|
|
}
|
|
} catch (error) {
|
|
cleanupError = cleanupError ?? error;
|
|
}
|
|
if (primaryError !== undefined && cleanupError !== undefined) {
|
|
throw new AggregateError(
|
|
[primaryError, cleanupError],
|
|
'Android E2E failed and cleanup also failed',
|
|
);
|
|
}
|
|
if (primaryError !== undefined) throw primaryError;
|
|
if (cleanupError !== undefined) throw cleanupError;
|
|
}
|
|
|
|
export function scenarioIdsFromEnv(value: string | undefined): string[] | undefined {
|
|
if (value === undefined) return undefined;
|
|
const scenarioIds = value
|
|
.split(',')
|
|
.map((id) => id.trim())
|
|
.filter(Boolean);
|
|
if (scenarioIds.length === 0) {
|
|
throw new Error(`${SCENARIO_FILTER_ENV} contains no Android emulator E2E scenario ids`);
|
|
}
|
|
return scenarioIds;
|
|
}
|