Skip to content

ci(examples): wire Playwright e2e suites into check and CI#71

Merged
wolpert merged 1 commit into
mainfrom
ci/e2e-playwright-demos
Jun 14, 2026
Merged

ci(examples): wire Playwright e2e suites into check and CI#71
wolpert merged 1 commit into
mainfrom
ci/e2e-playwright-demos

Conversation

@wolpert

@wolpert wolpert commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

What

The three demos (spring-boot-demo, dropwizard-demo, micronaut-demo) each carry a Playwright e2e suite that drives the full passkey ceremony through Chrome's CDP virtual WebAuthn authenticator — but nothing ran them: they weren't Gradle subprojects and no workflow referenced them. This wires them into both Gradle check and CI.

Wiring (pkauth.e2e-conventions plugin)

  • New convention plugin applied to all three demos, registering an e2eTest task that does npm cinpx playwright install chromenpx playwright test (the Playwright webServer boots the demo via its Gradle run task).
  • Opt-in: the task is wired into check only when PK_RUN_E2E=1 (or -PrunE2e) is set, so a default local ./gradlew check and the existing CI build job stay fast and Chrome-free. The flag is resolved to a plain Boolean at configuration time, keeping the wiring configuration-cache-safe.
  • Shared-port safety: every demo's webServer binds :8080, and org.gradle.parallel=true would let sibling e2eTest tasks collide. A shared BuildService lock (maxParallelUsages = 1) serializes them across a single build (no-op in CI, where each demo runs on its own runner).

CI

  • New e2e matrix job — one isolated ubuntu-latest runner per adapter, fail-fast: false, flips PK_RUN_E2E=1 and installs Chrome + OS deps via PW_INSTALL_DEPS=1. Parallel across runners, so the shared :8080 is a non-issue.

Pre-existing bugs fixed (surfaced once the suites actually ran)

  1. playwright.config.ts (all 3): the webServer invoked ../../../gradlew from the e2e/ dir, so Gradle took e2e/ as the project dir and failed ("not part of the build"). Pass -p ../../.. to root Gradle at the repo. This only ever "passed" before when a demo was already running on :8080 and reuseExistingServer reused it.
  2. micronaut-demo DI bug: magicLinkService/otpService are unconditional singletons requiring EmailSender/SmsSender, but those beans are @Requires(property = "pkauth.dev-mode", value = "true"). dev-mode was set only in application.yml, which — like the relying-party keys (per the existing workaround in that build file) — doesn't reach bean conditions reliably, so the senders never activated and magic-link/OTP routes 500'd. Fixed by passing -Dpkauth.dev-mode=true as a system property in the run task. (This demo had no prior tests, so the e2e suite is the first end-to-end exercise of it.)

Validation

All three suites pass 5/5 locally, including a single root-level PK_RUN_E2E=1 run across all three demos (verifying the serialization lock):

Demo Result
Spring Boot 5/5 ✓
Dropwizard 5/5 ✓
Micronaut 5/5 ✓

🤖 Generated with Claude Code

The three demos' Playwright e2e suites (Chrome CDP virtual WebAuthn) were
never run by Gradle or CI. Wire them in via a new `pkauth.e2e-conventions`
plugin that registers an opt-in `e2eTest` task per demo:

- Gated on PK_RUN_E2E=1 (or -PrunE2e); only then does `check` depend on it,
  so the default local `check` and the existing CI `build` job stay fast and
  Chrome-free. Resolved to a plain Boolean at configuration time so the
  wiring is configuration-cache-safe.
- A shared BuildService lock (maxParallelUsages=1) serializes the suites
  across a single build, since every demo's webServer binds :8080 and
  org.gradle.parallel=true would otherwise let them collide.
- Adds a CI `e2e` matrix job (one isolated runner per adapter, fail-fast
  false) that flips the flag and installs Chrome via PW_INSTALL_DEPS.

Also fixes two pre-existing defects the suites surfaced once they actually ran:

- playwright.config.ts (all 3): the webServer ran `../../../gradlew` from the
  e2e/ dir, so Gradle took e2e/ as the project dir and failed. Pass
  `-p ../../..` to root Gradle at the repo.
- micronaut-demo: dev-mode was set only in application.yml, which (like the
  relying-party keys) does not reach bean conditions reliably — so the
  @requires(pkauth.dev-mode=true) LoggingEmailSender/LoggingSmsSender beans
  never activated and the unconditional magicLinkService/otpService singletons
  failed to inject EmailSender/SmsSender (500 at request time). Pass
  -Dpkauth.dev-mode=true as a system property in the run task.

All three suites now pass 5/5.

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

Copy link
Copy Markdown

@wolpert
wolpert enabled auto-merge (rebase) June 14, 2026 04:25
@wolpert
wolpert merged commit 74ed5ce into main Jun 14, 2026
8 checks passed
@wolpert
wolpert deleted the ci/e2e-playwright-demos branch June 14, 2026 04:27
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