426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
198 lines
6.8 KiB
JavaScript
198 lines
6.8 KiB
JavaScript
/**
|
|
* Pure decision logic behind the one-command iOS Simulator e2e orchestrator
|
|
* (`ios-e2e.mjs`, wired as `test:e2e:ios`). The orchestrator itself is all
|
|
* side effects — boot a simulator, build, `simctl install`, drive the auth and
|
|
* full-Bun chat legs — so the parts worth testing are pulled out here as
|
|
* deterministic functions with no I/O: CLI parsing, the ordered step plan a
|
|
* given flag set produces, the "which simulator is booted" selection over
|
|
* `simctl list … --json`, the app-id extraction, and the exact argv each leg
|
|
* is invoked with.
|
|
*
|
|
* The load-bearing invariant these encode is the orchestrator's contract:
|
|
* it must fail LOUDLY and must never report success vacuously. That is why
|
|
* `planIosE2eSteps` distinguishes setup/optional cloud work from the two
|
|
* simulator-app verification legs (auth / local-chat), and
|
|
* `assertNonVacuousPlan` refuses a run that would print "ALL iOS E2E PASSED"
|
|
* without exercising a single real app path. Runs under the packages/app vitest suite
|
|
* (`bun run --cwd packages/app test`), i.e. the root test:client lane.
|
|
*/
|
|
|
|
export const DEFAULT_IOS_SIMULATOR = "iPhone 16 Pro";
|
|
|
|
// Ordered once, consumed everywhere. Build is setup; the rest are the real
|
|
// device-path assertions. Order is the run order and is load-bearing: install
|
|
// must precede any launch, auth registers the deep-link before chat drives it.
|
|
export const IOS_E2E_STEP_IDS = ["build", "auth", "local-chat", "cloud"];
|
|
export const IOS_E2E_VERIFICATION_STEP_IDS = ["auth", "local-chat"];
|
|
|
|
/**
|
|
* Parse the orchestrator argv into an explicit flag record. Kept total (every
|
|
* field always present) so callers branch on booleans, never on `argv.includes`
|
|
* scattered through the flow.
|
|
*/
|
|
export function parseIosE2eArgs(argv) {
|
|
const has = (flag) => argv.includes(flag);
|
|
const val = (flag) => {
|
|
const i = argv.indexOf(flag);
|
|
return i >= 0 && i + 1 < argv.length ? argv[i + 1] : undefined;
|
|
};
|
|
return {
|
|
device: val("--device"),
|
|
appPath: val("--app-path"),
|
|
output: val("--output"),
|
|
skipBuild: has("--skip-build"),
|
|
skipAuth: has("--skip-auth"),
|
|
skipLocalChat: has("--skip-local-chat"),
|
|
cloud: has("--cloud"),
|
|
noWait: has("--no-wait"),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* The ordered list of steps a flag set produces. Each descriptor carries a
|
|
* stable `id`, a human `label`, and `verification: true` for the legs that
|
|
* actually assert a real device path (so a plan can be checked for vacuity).
|
|
*/
|
|
export function planIosE2eSteps(flags) {
|
|
const steps = [];
|
|
if (!flags.skipBuild) {
|
|
steps.push({
|
|
id: "build",
|
|
label: "build + install the iOS Simulator app",
|
|
verification: false,
|
|
});
|
|
}
|
|
if (!flags.skipAuth) {
|
|
steps.push({
|
|
id: "auth",
|
|
label: "auth route: deep-link / callback registration + drive",
|
|
verification: true,
|
|
});
|
|
}
|
|
if (!flags.skipLocalChat) {
|
|
steps.push({
|
|
id: "local-chat",
|
|
label: "local route: on-device agent + smallest model + real chat",
|
|
verification: true,
|
|
});
|
|
}
|
|
if (flags.cloud) {
|
|
steps.push({
|
|
id: "cloud",
|
|
label: "cloud route: real provisioning probe",
|
|
verification: false,
|
|
});
|
|
}
|
|
return steps;
|
|
}
|
|
|
|
/**
|
|
* Guard against a vacuous green: a run that skips every simulator-app
|
|
* verification leg would otherwise sail to "ALL iOS E2E PASSED" having proven
|
|
* no app/auth/chat path. Cloud is useful optional coverage, but it is not a
|
|
* substitute for exercising the installed simulator app, so refuse those
|
|
* combinations up front with an actionable message instead of exiting 0.
|
|
*/
|
|
export function assertNonVacuousPlan(steps) {
|
|
const verifying = steps.filter((s) => s.verification);
|
|
if (verifying.length === 0) {
|
|
throw new Error(
|
|
"refusing to run: every simulator-app verification leg (auth / local-chat) is skipped, " +
|
|
"so the orchestrator would report success without proving the installed app path. " +
|
|
"Drop --skip-auth or --skip-local-chat; --cloud alone is not enough.",
|
|
);
|
|
}
|
|
return verifying;
|
|
}
|
|
|
|
/**
|
|
* Select a booted simulator udid from the parsed output of
|
|
* `xcrun simctl list devices booted --json`. Returns the first Booted device's
|
|
* udid, or null when none is booted. Tolerant of the shape (missing `devices`,
|
|
* non-array runtimes) because simctl JSON varies across Xcode versions.
|
|
*/
|
|
export function selectBootedUdid(listJson) {
|
|
const devices = listJson?.devices;
|
|
if (!devices || typeof devices !== "object") return null;
|
|
for (const runtime of Object.values(devices)) {
|
|
if (!Array.isArray(runtime)) continue;
|
|
const booted = runtime.find((d) => d?.state === "Booted");
|
|
if (booted?.udid) return booted.udid;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** Resolve the target simulator name, defaulting to the pinned dev device. */
|
|
export function resolveTargetDevice(deviceArg) {
|
|
return deviceArg ?? DEFAULT_IOS_SIMULATOR;
|
|
}
|
|
|
|
/**
|
|
* Extract the Capacitor app id from `app.config.ts` source. The bundle id is
|
|
* the `simctl` handle for install/terminate/uninstall, so a missing match falls
|
|
* back to the known default rather than throwing mid-orchestration.
|
|
*/
|
|
export function extractAppId(configSrc) {
|
|
return configSrc.match(/appId:\s*["']([^"']+)["']/)?.[1] ?? "ai.elizaos.app";
|
|
}
|
|
|
|
// Leg command builders. Each returns { cmd, args } exactly as spawned. Kept
|
|
// pure so the tests pin the flags that make each leg *real* — e.g. the chat leg
|
|
// must carry --require-installed (no host fallback) and --ios-full-bun-smoke
|
|
// (the real on-device engine), and the auth leg must target the booted udid.
|
|
|
|
export function buildIosSimBuildCommand() {
|
|
return { cmd: "bun", args: ["run", "build:ios:local:sim"] };
|
|
}
|
|
|
|
export function buildAuthSmokeCommand(udid) {
|
|
if (!udid) throw new Error("buildAuthSmokeCommand requires a simulator udid");
|
|
return {
|
|
cmd: "node",
|
|
args: [
|
|
"../../packages/app-core/scripts/mobile-auth-simulator-smoke.mjs",
|
|
"--platform",
|
|
"ios",
|
|
"--device",
|
|
udid,
|
|
],
|
|
};
|
|
}
|
|
|
|
export function buildLocalChatSmokeCommand() {
|
|
return {
|
|
cmd: "node",
|
|
args: [
|
|
"scripts/mobile-local-chat-smoke.mjs",
|
|
"--platform",
|
|
"ios",
|
|
"--require-installed",
|
|
"--ios-select-local",
|
|
"--ios-full-bun-smoke",
|
|
],
|
|
};
|
|
}
|
|
|
|
export function buildCloudProvisioningCommand() {
|
|
return { cmd: "node", args: ["scripts/cloud-provisioning-e2e.mjs"] };
|
|
}
|
|
|
|
/**
|
|
* Classify a spawned leg's exit status into the loud-or-pass decision. A
|
|
* non-zero (or null, i.e. killed by signal) status is a hard failure that must
|
|
* abort the whole orchestration — never a warn-and-continue.
|
|
*/
|
|
export function classifyStepExit(status) {
|
|
if (status === 0) return { ok: true };
|
|
return {
|
|
ok: false,
|
|
reason:
|
|
status === null ? "terminated by signal" : `exited with code ${status}`,
|
|
};
|
|
}
|
|
|
|
/** Whether a `simctl get_app_container` result proves the app is installed. */
|
|
export function isAppInstalled(container) {
|
|
return typeof container === "string" && container.trim().length > 0;
|
|
}
|