Skip to content

feat: add end-to-end test suite (Aspire + Playwright)#78

Merged
andregoepel merged 2 commits into
mainfrom
feature/e2e-tests
Jul 12, 2026
Merged

feat: add end-to-end test suite (Aspire + Playwright)#78
andregoepel merged 2 commits into
mainfrom
feature/e2e-tests

Conversation

@andregoepel

Copy link
Copy Markdown
Owner

Closes #76

Adds tests/AndreGoepel.AppFoundation.E2ETests — a browser-driven end-to-end suite that boots the sample AppHost graph (PostgreSQL + MailHog + the sample web app) via Aspire.Hosting.Testing and drives it with Playwright (Chromium).

Coverage (25 tests)

Setup/bootstrap · registration + email confirmation · login/lockout/logout · password reset + resend · TOTP 2FA (enable/login/recovery/disable) · passkeys (WebAuthn via CDP virtual authenticator) · account management (profile/password/delete) · administration (users/roles/authorization) · foundation admin pages (Email Settings, Login Features) · sample home.

Harness

  • Reuses the sample AppHost as-is (Aspire resource web, MailHog http endpoint). MailHog's HTTP API is read for confirmation/reset-link assertions.
  • One app instance per collection; fresh browser context per test; admin provisioned once via /Setup (idempotent). Otp.NET for TOTP, CDP virtual authenticator for passkeys.
  • Radzen/Blazor-aware helpers centralize selectors and the circuit-ready wait.

Integration with the restructured repo

  • Central Package Management: adds Aspire.Hosting.Testing, Microsoft.Playwright, Otp.NET to Directory.Packages.props; the project references packages without versions.
  • Opts out of lock files (RestorePackagesWithLockFile=false) because Aspire.Hosting.Testing pulls RID-specific orchestration packages — same rationale as the sample AppHost. Verified dotnet restore --locked-mode still passes for the whole solution.
  • No new vulnerable packages (dotnet list package --vulnerable clean); formatted with the pinned csharpier.
  • CI: main test job excludes E2E (--filter FullyQualifiedName!~E2ETests); new e2e.yml runs the suite with Docker + Playwright.
  • Added podman.runsettings + README for local runs.

Note

Compiles and all 25 tests are discovered, but the suite has not yet been executed against a live container runtime. The account-flow pages now come from the AndreGoepel.Marten.Identity.Blazor NuGet package, so those selectors should be confirmed on the first live run (Docker or a running Podman machine).

Add tests/AndreGoepel.AppFoundation.E2ETests, a browser-driven E2E suite that
boots the sample AppHost graph (Postgres + MailHog + sample web app) via
Aspire.Hosting.Testing and drives it with Playwright (Chromium). 25 tests across
setup, registration + email confirmation, login/lockout/logout, password reset,
TOTP 2FA, passkeys (WebAuthn via CDP virtual authenticator), account management,
administration, and the foundation admin pages.

- Reuses the sample AppHost as-is (resource web, MailHog http endpoint);
  MailHog captures email for confirmation/reset assertions.
- Central Package Management: adds Aspire.Hosting.Testing, Microsoft.Playwright,
  Otp.NET; project opts out of lock files (RID-specific Aspire orchestration).
- CI: main test job excludes E2E; new e2e.yml workflow runs it with Docker.
- Adds podman.runsettings and README for local runs.
The suite never went green: the first CI run failed 16/25 and, once the
infra issues were peeled back, a real application bug surfaced.

Application fix
- MailService.SmtpEmailSender and MailSettingsProvider (plus the
  IMailSettingsProvider / MailConfiguration they expose) were internal, so
  Wolverine 6 refused to generate the MailMessage handler
  (ServiceLocationPolicy.NotAllowed) and every outgoing email was silently
  discarded after its retries. Making them public restores email delivery
  for registration, password reset, and confirmation across the app.

Test-infrastructure fixes
- AppHost: resolve MailHog's SMTP host/port at run time instead of
  hardcoding localhost:1025, so email works under the Aspire testing host
  (which assigns random proxy ports); run Postgres without its data volume
  when E2E=true so each run starts from an empty database.
- Sample host opts into self-service registration (as a real host would) so
  the registration flows are reachable.
- MailHogClient: only quoted-printable-decode a part that declares that
  transfer encoding (unconditional decoding corrupted confirmation URLs
  whose "=" was followed by two hex digits), and guard null MIME/Content.
- Login helper retries the submit click (a click can be lost on a cold
  Blazor circuit); admin provisioning reloads-and-retries on first-request
  warmup.

Test corrections
- NonAdmin admin-area test asserts the user is bounced off /Administration
  (the app sends an authenticated non-admin to home, not to login).
- Passkey-login test accepts conditional-mediation auto-login, which
  preempts the explicit button click.

Full suite: 25/25 green.
@andregoepel
andregoepel merged commit 8acf438 into main Jul 12, 2026
4 checks passed
@andregoepel
andregoepel deleted the feature/e2e-tests branch July 12, 2026 03:52
andregoepel added a commit to andregoepel/marten-identity that referenced this pull request Jul 12, 2026
Adds tests/AndreGoepel.Marten.Identity.E2ETests — a browser-driven suite that
boots the sample Aspire graph (PostgreSQL + the sample web app) via
Aspire.Hosting.Testing and drives it with Playwright (Chromium). 24 tests cover
setup/bootstrap, registration + email confirmation, login/lockout/logout,
password reset + resend, TOTP 2FA (enable/login/recovery/disable), passkeys
(WebAuthn via a CDP virtual authenticator), account management, administration,
and the sample pages. Modelled on andregoepel/app-foundation#78, since those
account/administration pages originate from this repo's Blazor package.

Harness:
- One app instance per collection; fresh browser context per test; root admin
  provisioned once via /Setup (idempotent). Otp.NET for TOTP, CDP virtual
  authenticator for passkeys. Radzen/Blazor-aware helpers centralise selectors
  and the circuit-ready wait.
- The AppHost runs Postgres without its data volume under E2E=true, so every run
  starts from an empty database.
- The sample sends no real email. Under E2E=true it swaps LoggingEmailSender for
  a CapturingEmailSender and exposes an E2E-only /e2e/emails endpoint that the
  tests read for confirmation/reset links; both are inert in a normal run.

Integration:
- Central Package Management: adds Aspire.Hosting.Testing, Microsoft.Playwright,
  and Otp.NET. The project opts out of lock files (RestorePackagesWithLockFile
  =false) because Aspire.Hosting.Testing pulls RID-specific packages; locked-mode
  restore still passes solution-wide.
- CI: the main test job excludes E2E (--filter FullyQualifiedName!~E2ETests); a
  new e2e.yml runs the suite with Docker + Playwright.
- Formatted with the pinned csharpier.

Verified: all 24 tests pass against a live Podman runtime.
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.

Add end-to-end (E2E) test coverage for the frontend

1 participant