Skip to content

test: version-pinned end-to-end suite for generated apps#124

Draft
dawsontoth wants to merge 4 commits into
mainfrom
claude/create-harper-e2e-tests-233d4f
Draft

test: version-pinned end-to-end suite for generated apps#124
dawsontoth wants to merge 4 commits into
mainfrom
claude/create-harper-e2e-tests-233d4f

Conversation

@dawsontoth

Copy link
Copy Markdown
Contributor

What & why

A way to test create-harper's generated apps against real Harper, with the Harper version under test as a knob — so we catch changed API surfaces, instability, and defaults create-harper should follow before a Harper release breaks a scaffolded app.

It's the deeper tier above the existing per-PR runtimeSmoke.js; both now share one isolated-Harper boot module.

How a run works

node template.tests/e2e/run.js --template <name> [--harper <spec> | --harper-ref <ref>]

  1. Generate the app with the real CLI (throwaway temp dir)
  2. Overlay e2e fixtures (schema + custom resource + a framework component that fetches the API)
  3. Install app deps
  4. Resolve Harper (no global install) — see below
  5. Build the app if it has a build step
  6. Playwright boots one isolated Harper, seeds a record, runs the specs

Picking the Harper version (precedence)

Mechanism Purpose
HARPER_BIN=… Reuse an existing install/build (a .js path is launched via node)
--harper-ref <sha|branch|tag> Unpublished Harper built from a commit — clones harperfast/harper (public; override via --harper-repo), npm install + npm run build, runs dist/bin/harper.js
--harper <spec> (default latest) Any npm spec: latest, next, 5.2.0-beta.1, a tarball …

Scenarios

Every template runs the API specs (framework-agnostic Harper surface); SPA templates also run the frontend + browser specs.

Spec Proves Templates
crud Schema-driven auto-REST lifecycle (create/read/update/filter/delete), exact status codes asserted as a version canary all
resource A custom resources/ class loads and answers GET with JSON all
frontend The frontend is served at / SPA
browser A real React/Vue/vanilla component fetches the API and renders it in a browser SPA

CI

  • Per PR — unchanged: the fast runtimeSmoke.js check (integration.yaml) against latest Harper.
  • Nightly + on demande2e.yaml: scheduled latest and next across a representative template subset (vanilla-ts, react-ts, vue-ts, react-ts-ssr), files a deduped e2e-canary issue on failure. workflow_dispatch inputs: harper-version, harper-ref, template.

No cruft in users' apps

Fixtures live under template.tests/ — outside template-*/ (so scaffolding can't copy them) and outside the npm files allowlist (so they're not published). Verified: npm pack --dry-run ships zero e2e/fixture files.

Validated locally (real Harper)

  • react-ts @ 5.1.22 — 4/4 (incl. browser rendering live API data)
  • vanilla-ts @ 5.1.22 — 4/4 (plain-DOM overlay, no build step)
  • react-ts @ next (5.2.0-beta.1) — 4/4
  • react-ts @ --harper-ref (5.2.0-beta.1 built from source) — 4/4
  • react-ts-ssr @ 5.1.22 — API specs pass, frontend/browser correctly skipped → green
  • format, lint, and all 213 unit tests still pass

Findings this already surfaced

  • No GraphQL query-over-HTTP endpoint in Harper (/graphql → 404). "GraphQL" = schema DSL + auto REST/WS; dropped that scenario rather than assert a nonexistent surface.
  • SSR / returns 404 under harper run (SSR templates set static.index:false; / is served by the entry-server). Treated as an unverified SSR concern, not a create-harper regression — the frontend/browser specs are gated off for SSR (E2E_SSR), which run the API specs only. Confirming intended SSR serving is a good first use of the harness.
  • Harper main doesn't pass its own tsc typecheck right now (TS2345 in resources/DatabaseTransaction.ts). Harper ships anyway — build-tools/build.sh runs npm run build || true since tsc still emits dist/ — so run.js mirrors that: tolerate the build's exit code, require the entrypoint was emitted.

Notes / decisions to weigh

  • Adds @playwright/test as a devDependency (+ npx playwright install chromium in CI, cached).
  • The --harper-ref source build is the heavy path (full install + tsc emit, ~1–2 min); it's on-demand only, not in the nightly schedule.
  • Source builds use a shallow fetch-by-SHA (works on GitHub); a mirror that disallows arbitrary-SHA fetches would need a full-clone fallback.
  • Commit typed test: (patch bump per .releaserc.json's type: * rule), since this is internal tooling, not a user-facing feature.

🤖 Generated with Claude Code

Scaffolds each template with the real create-harper CLI, exercises it
against a real Harper instance, and lets the Harper version under test be
pinned — including unpublished builds from a git commit — so we can catch
API-surface changes and instability before a Harper release breaks a
generated app.

- template.tests/e2e/: bootHarper (shared isolated-instance module),
  overlay (a schema + custom resource + a frontend component that consumes
  the API), Playwright specs (auto-REST CRUD, custom resource, frontend,
  browser), and run.js (generate -> overlay -> install -> resolve Harper
  -> build -> test).
- Harper resolution, no global install: HARPER_BIN, or
  --harper-ref <sha|branch|tag> (clone + build harperfast/harper from
  source), or --harper <npm-spec> (default latest; next/beta/tarball too).
- runtimeSmoke.js refactored onto the shared bootHarper module.
- .github/workflows/e2e.yaml: nightly latest+next canary that files an
  issue on failure, plus workflow_dispatch (harper-version / harper-ref /
  template).
- Fixtures live under template.tests/ (outside template-*/ and the npm
  files allowlist), so they can never reach a scaffolded app.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive end-to-end testing suite using Playwright, which scaffolds a real application, overlays fixtures, boots an isolated Harper instance, and runs browser and API specs. It also refactors the existing runtime smoke test to share the new Harper booting logic. The review feedback highlights several critical improvements: registering signal handlers (SIGINT/SIGTERM) in both the Harper boot utility and the runner script to ensure proper cleanup of detached processes and temporary directories on interruption; ensuring heavy temporary directories (harperPrefix and harperSrc) are always cleaned up even when --keep is specified; and noting that git fetch will fail with short SHAs, requiring documentation or handling for full 40-character SHAs.

Comment thread template.tests/e2e/harper.js
Comment thread template.tests/e2e/run.js
Comment thread template.tests/e2e/run.js Outdated
Comment thread template.tests/e2e/run.js
dawsontoth and others added 3 commits July 21, 2026 13:17
workflow_dispatch can't be triggered until this workflow lands on the
default branch, so add a temporary pull_request trigger (scoped to a
single cheap cell: react-ts @ latest) to exercise the workflow on GitHub
runners before merge. Revert before merging — PRs stay on the fast
runtimeSmoke check by design.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Validated on real runners via PR #124 (react-ts @ latest, 4/4 green).
The E2E workflow stays nightly + workflow_dispatch only; PRs keep using
the fast runtimeSmoke check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address PR review feedback:
- bootHarper now installs SIGINT/SIGTERM handlers that kill the detached
  Harper (and run an onStop hook) so an interrupted run can't orphan a
  Harper process holding its ports; stop() deregisters them so it stays
  idempotent across boots.
- runtimeSmoke delegates its injected-resource cleanup to onStop instead
  of maintaining duplicate signal handlers.
- run.js cleans its temp dirs on SIGINT/SIGTERM, and --keep now retains
  only the generated app under test — the heavy Harper install/build dirs
  are always removed.
- --harper-ref requires a full 40-char sha (git can't fetch a short sha
  directly); documented, with a preflight guard that rejects a short sha
  with a clear message. Branches/tags still work as refs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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