Skip to content

[agent-cli] E2E-cover the status cases the flag removal left uncovered - #72

Merged
Kudo merged 4 commits into
kudo/status-3-no-explainfrom
kudo/status-4-e2e-sweep
Oct 19, 2026
Merged

Kudo merged 4 commits into
kudo/status-3-no-explainfrom
kudo/status-4-e2e-sweep

Conversation

@expo-tuft

@expo-tuft expo-tuft Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Stack 4/4 of the plan to remove status --explain. Based on #71. Tests only; no CHANGELOG entry.

Why

Kudo asked for e2e coverage of every status case. This is the audit of status against e2e/__tests__/status-test.ts after the flag went, and the cases it was missing.

What is covered now

  • --build <id> end to end. The shared stub eas (e2e/stubs/eas.js) answers fingerprint:compare (STUB_EAS_COMPARE_JSON / STUB_EAS_COMPARE_EXIT) and build:view (STUB_EAS_BUILD_VIEW_PLATFORM / STUB_EAS_BUILD_VIEW_EXIT). The shared installEnvFingerprintStubAsync helper, with diff: true, gives a stub fingerprint that answers fingerprint:diff by diffing the two files, the way the real CLI does. Cases: a matching build (eas axis fresh on the build's platform, "not compared" on the other, local axis untouched); a differing build and what it costs (needs-native-build, the added source listed); the text naming vs EAS build <id>; --assert js-only --build judging the eas axis (20 / 0); a build whose platform EAS cannot name (comparison attributed to none, both axes "not compared", --assert exits 22); a failing comparison (exit 0 in text and JSON, freshness note printed, and comparison still names the build: F66).
  • Not an Expo app. next.command is npx @expo/agent-cli new my-app, and not-expo-app is the only follow-up (llp/0004 §Not an Expo app). project-shapes-test.ts already covers the rest.
  • The change detail at scale. Eight rows, … and 2 more, in --json, and platforms whose lists agree printed once (ios, android: 10 sources). The class ladder's head in the follow-ups beside the OTA verdict.
  • The file-level view under a committed tree: nothing changed (total: 0), a JavaScript edit (files 1 changed · 1 js · 0 config · 0 native, class js-only), metro.config.js raising the class to dev-client-compatible with the change-restart-metro follow-up.
  • Follow-ups: runtime-errors with an app connected, install-dev-client for a project Expo Go cannot run and that has no dev client, skills-sync when discovered skills are not linked.
  • Discovery ladder step 2: a dev server the project's start.log names, found with no URL given, source: log.

Still uncovered, on purpose

The device section's present / absent / unknown and the cloud-session next variants depend on xcrun simctl and adb on the runner. They need stubbed platform tools on PATH / ANDROID_HOME and are a separate change.

Test Plan

  • bun run typecheck, bun run test:e2e -- status-test (119 pass, 17 new).

@Kudo
Kudo added this pull request to stack #78 September 16, 2026 06:07
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from ae8f645 to 870a8ea Compare September 16, 2026 19:25
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from 870a8ea to 34d5d52 Compare September 16, 2026 19:39
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from 34d5d52 to b49c535 Compare September 24, 2026 14:29
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from b49c535 to b168aa5 Compare October 15, 2026 12:42
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from b168aa5 to b0a5c2b Compare October 15, 2026 15:03
Comment thread packages/@expo/agent-cli/e2e/__tests__/status-test.ts
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from b0a5c2b to 285bb92 Compare October 15, 2026 19:01
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from 285bb92 to c37d9fc Compare October 15, 2026 19:34
@Kudo
Kudo requested a review from vonovak October 15, 2026 20:20
@expo-tuft
expo-tuft Bot force-pushed the kudo/status-4-e2e-sweep branch from c37d9fc to dfdf7dc Compare October 16, 2026 10:29
@Kudo
Kudo force-pushed the kudo/status-4-e2e-sweep branch 2 times, most recently from 6202928 to 8c2dd26 Compare October 19, 2026 09:05
expo-tuft Bot and others added 3 commits October 19, 2026 18:52
An audit of `status` against `e2e/__tests__/status-test.ts`, branch by branch,
after `--explain` went. What was missing, now covered through the published
bin:

- `--build <id>` end to end. The shared stub `eas` answers
  `fingerprint:compare` and `build:view`, and a stub `fingerprint` diffs the
  two sides the way the real CLI does. A matching build, a differing one and
  what it costs, the text that names the base, the gate judging the eas axis
  under `--assert`, a build whose platform EAS cannot name (attributed to
  none, exit 22), and a comparison that fails (report kept, id echoed, note
  printed — F66).
- A directory that is not an Expo app: `isExpoApp: false`, `next` is
  `new my-app`, the fact second on the project line, exit 0.
- The change detail at scale: eight rows then a count, and platforms whose
  lists agree printed once.
- The file-level view under a committed tree: nothing changed, a JavaScript
  edit (`files 1 changed · 1 js`), and `metro.config.js` raising the class to
  `dev-client-compatible` with the restart follow-up.
- The follow-ups `runtime-errors`, `install-dev-client` and `skills-sync`, each
  on the one fact that fires it; the class ladder's head beside the OTA verdict.
- Step 2 of the discovery ladder: a dev server the project's own `start.log`
  names, found with no URL given and reported as `source: log`.

Co-authored-by: kudo <46429+kudo@users.noreply.github.com>
Co-authored-by: kudo <46429+kudo@users.noreply.github.com>
…l change

Co-authored-by: kudo <46429+kudo@users.noreply.github.com>
@Kudo
Kudo force-pushed the kudo/status-4-e2e-sweep branch from 8c2dd26 to 27bb0e2 Compare October 19, 2026 10:53

@vonovak vonovak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some minor findings


const json = await runBuildAsync(projectRoot, ['--json'], { STUB_EAS_COMPARE_EXIT: '1' });
const report: StatusReport = JSON.parse(json.stdout);
expect(report.errors.freshness).toContain(BUILD_ID);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 suggestion] This PR teaches the shared stub to answer fingerprint:compare. That changes what the older test 'takes --build, and echoes the build it was given' does: it now runs the success path, not the failure path its removed comment described (F66). This new failure test does not take over the F66 check. Its text assertion toContain(BUILD_ID) passes from the vs EAS build <id> header alone. errors.freshness names the id in any case. If compareAgainstEasBuildAsync went back to writing comparison after the call (the F66 bug), both halves would still pass. The unit test mocks the error text, so it does not pin this either. Add expect(report.freshness!.comparison).toMatchObject({ kind: 'eas-build', buildId: BUILD_ID }) to the JSON half, and also assert json.exitCode.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8ac51d0. The JSON half now asserts json.exitCode is 0 and report.freshness.comparison matches { kind: 'eas-build', buildId: BUILD_ID }. I checked that it pins F66: with the comparison write moved back after the call, this test fails (kind: 'last-build').


const report = await reportInAsync(projectRoot);

expect(report.next).toMatchObject({ command: 'npx @expo/agent-cli new my-app' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 suggestion] project-shapes-test.ts ('lets status report, and stops it recommending a build here' and 'says so on the project line') already covers isExpoApp: false, next.rule, empty steps, exit 0 and the project line. This test adds only the new my-app command. The behavior that is not pinned is that buildStatusFollowUps returns only not-expo-app and drops every other rung (llp/0004 §Not an Expo app). Assert report.followups.map((f) => f.id) equals ['not-expo-app'], or move this assertion into the existing project-shapes test. As written, the PR body overstates what this test adds.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8ac51d0. The test now asserts report.followups.map((f) => f.id) equals ['not-expo-app']. I also changed the PR body so it claims only this, the new my-app command and the follow-up, and points to project-shapes-test.ts for the rest.

// @ref llp/0011-impact-and-freshness.rfc.md §When the fingerprint did not move
describe('the changed files, when the fingerprint did not move', () => {
const APP_CONFIG = { type: 'file', filePath: 'app.json', reasons: ['expoConfig'], hash: 'cc' };
const STUB_FINGERPRINT = `#!/usr/bin/env node

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🐧 nit] This is the sixth copy of the env-driven STUB_FINGERPRINT and its install-into-.stub-bin-and-node_modules/.bin setup in this file (the other copies are at lines 846, 978, 1266, 1690 and 1891, and this PR adds two of them). Move it to one top-level helper, for example installEnvFingerprintStubAsync(projectRoot, { diff?: boolean }), so the next change to the stub contract is made in one place.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8ac51d0. installEnvFingerprintStubAsync(projectRoot, { diff?, platformHashes? }) is now the one place the env-driven stub lives. All six copies use it: diff: true for the --build block, and platformHashes for the EAS lookup block, which printed a different hash per platform. #77 and #159 add no copies of their own.

@Kudo
Kudo requested a review from vonovak October 19, 2026 11:49
@Kudo
Kudo merged commit ede34aa into main Oct 19, 2026
15 checks passed
@Kudo
Kudo deleted the kudo/status-4-e2e-sweep branch October 19, 2026 14:47
Kudo added a commit that referenced this pull request Oct 19, 2026
… the tunnel lines of status (#77)

Stack 5/5 of the `status` plan. Based on #72. Tests only.

## Why

The last `status` branches without an e2e were the ones that depend on
what the runner has: `xcrun simctl` and `adb`. #72 listed them as left
out; this closes them.

## How

- A stub `xcrun` in `.stub-bin` (first on the `PATH` the run gets)
answers `simctl list devices booted -j` with a booted iPhone or with
none. A stub `adb` under a per-test `ANDROID_HOME/platform-tools`
answers `devices -l` with an emulator or with none — the resolver reads
`ANDROID_HOME` before `PATH` (`src/device/adb.ts`).
- "Cannot be run" (`unknown`): the execute bit withheld **and** a `PATH`
of the stub directory alone, because a `PATH` search skips a file it
cannot run and finds the machine's own `xcrun` next. `adb` is spawned by
path, so the bit alone suffices there.
- Cases: attached Android device (text `android emulator-5554`); booted
iOS simulator by name with both devices listed (F106; macOS only, the
probe does not run elsewhere); `absent` with the tools' reasons;
`unknown`, never rounded down to none (POSIX only — a `.cmd` shim has no
execute bit to withhold); a dev server up with nothing attached and no
device → an `exp://` address or `navigate / --print-url`, never
`navigate /`; an EAS Simulator session on record → `smoke --ios --eas`
with an app connected, `navigate / --eas` without, the session still
named when the tools could not answer, and the local path kept when a
device *is* here (K7a); a tunnelled dev server (lock + detached log
newer than it) → `hostType: tunnel`, `tunnelUrl`, `openUrls` on the
tunnel host, the `tunnel` fact and `open in …: exp://…` lines (K7c, K8);
a stale tunnel dropped once its dev server is gone.
- Left out on purpose: the 8082–8085 port-scan rung (fixed ports collide
on shared runners).

## Test Plan

- `bun run typecheck`, `bun run lint`, `bun run test:e2e -- status-test`
(130 pass locally on macOS; 2 cases skip on Windows, 1 on Linux by
design).

---------

Co-authored-by: expo-tuft[bot] <288127324+expo-tuft[bot]@users.noreply.github.com>
Co-authored-by: kudo <46429+kudo@users.noreply.github.com>
Co-authored-by: Kudo Chien <kudo@expo.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants