Skip to content

test(e2e): migrate e2e suite to agentry - #3

Merged
dortort merged 5 commits into
mainfrom
test/e2e-agentry
Aug 2, 2026
Merged

dortort merged 5 commits into
mainfrom
test/e2e-agentry

Conversation

@dortort

@dortort dortort commented Jul 31, 2026 •

Copy link
Copy Markdown
Owner

What

Migrate the end-to-end suite from a hand-rolled Vitest harness that spawned claude directly to tests written against agentry ("Playwright for AI Agents"), and make the scenarios deterministic and hermetic.

Depends on dortort/agentry#1 (--plugin-dir + per-run env passthrough). Merge that first.

How it works

  • New self-contained pnpm project under e2e/. Each scenario drives a scheduler slash command through a real Claude agent and asserts on the reply with tolerant, multi-alternative matching.
  • agentry is linked via file:../../agentry/packages/cli with pnpm.overrides rewriting its workspace:* deps to the sibling paths — keeping agentry out of the npm-managed root so npm ci in CI is unaffected.
  • State isolation: the scheduler reads global ~/.claude state that a cwd sandbox can't isolate. This PR adds a CLAUDE_SCHEDULER_STATE_DIR override (getStateDir() + the status/list/history/logs command prompts); each scenario points it at a per-sandbox state/ dir and seeds fixtures there. Auth-safe — $HOME is untouched, so the claude CLI keeps its OAuth credentials (a $HOME remap drops them).

Scope

  • Ported the 8 read scenarios (empty/populated status/list/history/logs).
  • Dropped the mutating /scheduler:add scenario — it does real OS registration (launchd/cron) the state dir can't isolate; still covered by the unit suite.

Verification

  • npm run typecheck / lint / test (340) / build — all green (root manifest unchanged, npm ci-safe).
  • Full live run: 8/8 green (~$0.30) on a machine with pre-existing real scheduled tasks — confirming the isolation.

Removed

  • vitest.config.e2e.ts, src/__tests__/e2e/{commands.test.ts,helpers.ts,fixtures.ts}; test:e2e now shells into e2e/.

🤖 Generated with Claude Code

Replace the hand-rolled Vitest suite that spawned `claude` directly with
tests written against agentry ("Playwright for AI Agents"). Each scenario
drives a scheduler slash command through a real Claude agent — the plugin is
loaded via the new `--plugin-dir` passthrough — and asserts on the agent's
reply with the same tolerant, multi-alternative matching as before.

The harness lives in `e2e/` as a self-contained pnpm project that links
agentry via `file:` (with `pnpm.overrides` rewriting its `workspace:*` deps).
This keeps agentry entirely out of the npm-managed root so `npm ci` in CI is
unaffected. Runs live and local-only, matching the prior suite (e2e is not in
CI); `test:e2e` now shells into the e2e project.

Constraint: scheduler is npm + CI uses `npm ci`, which cannot resolve
agentry's workspace:* deps — hence the isolated pnpm sub-project.
Constraint: agentry's directory sandbox isolates cwd, not $HOME; the scheduler
reads global ~/.claude and ~/Library/LaunchAgents, so empty/populated
scenarios assume a machine with no pre-existing scheduled tasks.
Rejected: add agentry to the root package.json | breaks `npm ci` on all jobs
Rejected: $HOME remap for determinism | risks breaking the claude CLI's own auth
Confidence: high
Scope-risk: narrow
Not-tested: full green live run (env-coupled to global scheduler state; the
plugin-load path and assertions are verified live on representative scenarios)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 31, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

dortort and others added 4 commits July 31, 2026 09:20
…ER_STATE_DIR

The scheduler's global state (schedules, logs, history) is fixed at ~/.claude,
which makes the read commands impossible to test without touching real machine
state. Add a `getStateDir()` seam honoring `CLAUDE_SCHEDULER_STATE_DIR` (default
unchanged) in the library, and resolve the same env var in the status/list/
history/logs command prompts (Bash `${CLAUDE_SCHEDULER_STATE_DIR:-$HOME/.claude}`
expansion). OS registration (launchd/cron) still uses the real home.

Constraint: the slash commands read literal paths from prompts, not the TS
library — so the env seam has to live in the prompts too, not just config.ts.
Constraint: must not change behavior when the var is unset (default ~/.claude).
Rejected: remap $HOME to isolate state | breaks the claude CLI's own OAuth auth
Confidence: high
Scope-risk: moderate
Directive: keep the command prompts and getStateDir() in sync — both resolve the
same env var; OS-registration paths intentionally do NOT honor it
Not-tested: Linux cron command paths (only the macOS read paths are exercised)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point CLAUDE_SCHEDULER_STATE_DIR (via agentry's per-run env) at a `state/`
subdir of each scenario's sandbox and seed fixtures there, so empty/populated
states are hermetic and independent of the machine's real ~/.claude — verified
live (8/8 green) on a machine with pre-existing scheduled tasks. Auth-safe:
$HOME is untouched, so the claude CLI keeps its credentials.

Drop the /scheduler:add scenario: it performs real OS registration the state
dir can't isolate (covered by the unit suite instead). The populated history
scenario now asserts the seeded records rather than just "runs without error".

Rejected: $HOME remap for isolation | drops the claude CLI's OAuth auth
Confidence: high
Scope-risk: narrow
Not-tested: mutating commands (intentionally excluded from the hermetic suite)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A machine with orphaned real launchd plists could make /scheduler:status lead
with an "orphaned registrations" report and omit the empty-state line (the OS
registration dir isn't isolatable by CLAUDE_SCHEDULER_STATE_DIR). Guarantee the
`Tasks: none configured` line is always emitted first (orphan notes stay as a
secondary append), and broaden the assertion to accept the orphan-report
phrasing. Enable `retries: 2` in the e2e config to absorb the residual, inherent
phrasing variance of live model runs. Verified 8/8 green across repeated runs.

Rejected: assert only on final phrasing | live output varies run to run
Confidence: high
Scope-risk: narrow
Not-tested: Linux (cron) status path

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dortort
dortort merged commit fc79730 into main Aug 2, 2026
5 checks passed
@dortort
dortort deleted the test/e2e-agentry branch August 2, 2026 05:46
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.

1 participant