Skip to content

feat: bootstrap AndreGoepel.Testing.E2E - #3

Merged
andregoepel merged 2 commits into
mainfrom
feature/bootstrap-testing-e2e
Jul 26, 2026
Merged

andregoepel merged 2 commits into
mainfrom
feature/bootstrap-testing-e2e

Conversation

@andregoepel

Copy link
Copy Markdown
Owner

Summary

Bootstraps the testing repo and ships AndreGoepel.Testing.E2E, extracting the ~900-line, ~85-95%-duplicated Playwright + .NET Aspire E2E infrastructure that marten-identity, finance-app, and app-foundation each carried locally.

Closes #1

What moved into the package (src/AndreGoepel.Testing.E2E)

  • E2EAppFixture — boots the Aspire app graph once per collection, launches the shared Chromium browser, exposes ProvisionAdminAsync. Takes a Func<string[], Task<IDistributedApplicationTestingBuilder>> in E2EAppFixtureOptions instead of a generic type parameter, so E2ETestBase<TFixture> can stay constrained to one non-generic base regardless of which Projects.* type each host's AppHost generates.
  • E2ETestBase<TFixture> — fresh browser context per test, the shared account flows (LoginAsync, RegisterAsync, ConfirmEmailAsync, LogoutAsync, LoginAsAdminAsync), and trace-capture-on-failure made unconditional (was opt-in / present only in marten-identity; finance-app and app-foundation had no way to debug a headless CI failure until now).
  • PageExtensions — only the verbatim-identical core: WaitForBlazorAsync, GotoAsync, FillFieldAsync, ClickButtonAsync, ClickLinkAsync, AssertOnPathAsync.
  • MailHogClient, TestData, Totp, VirtualAuthenticator — consolidated as-is (identical or near-identical across the three source repos). MailHogClient now implements IDisposable and a new IEmailLinkSource interface (it wasn't disposing its HttpClient before).
  • IEmailLinkSource — new seam so a host can swap MailHog for something else. marten-identity's sample app captures outbound mail itself (no MailHog container) via a local CapturedEmailClient; that stays in marten-identity and gets wired in through E2EAppFixtureOptions.MailSourceFactory.

What stayed app-specific (not moved)

  • finance-app's FillFormFieldAsync / SelectDropDownAsync / UploadFileAsync
  • marten-identity's FilterUsersGridAsync and CapturedEmailClient
  • app-foundation's EnsureEmailConfiguredAsync (drives its own Email Settings admin page)

These stay as local extension methods / helpers in each repo, per AndreGoepel.Testing.E2E's own CLAUDE.md.

Design decisions (open questions for review)

  1. MailHog endpoint name standardized on "http". finance-app's AppHost.cs currently names the endpoint "web"; app-foundation's already names it "http". E2EAppFixtureOptions.MailHogEndpointName defaults to "http" (documented in the package README as the canonical name — it's distinct from MailHog's separate "smtp" endpoint, unlike "web"). finance-app's AppHost.cs needs updating to rename the endpoint (or pass MailHogEndpointName = "web" explicitly) when it migrates onto this package.
  2. Admin-provisioning button text has no default. The three repos' Setup buttons read "Create administrator", "Create admin", and "Create admin & complete setup" respectively — different enough that guessing a shared default risked silently no-op'ing the click in whatever repo didn't match. E2EAppFixtureOptions.ProvisionAdminButtonText is required; each repo supplies its own exact (or stable-prefix) text.
  3. No generic E2EAppFixture<TEntryPoint>. Went with a factory delegate (CreateAppHostBuilder) in the options instead — avoids every consuming repo spelling out E2EAppFixtureBase<Projects.AndreGoepel_FinanceApp_AppHost> as a base-class type argument, and keeps E2ETestBase<TFixture> constrainable to a single non-generic base type.

Testing

  • tests/AndreGoepel.Testing.E2E.Tests covers the only genuinely unit-testable logic in the package: MailHogClient's message decoding (quoted-printable, MIME parts, link extraction) and Totp's key normalization. Everything else is Playwright/Aspire orchestration with no meaningful behavior in isolation — deliberately not padded with hollow tests for it. internal members are exposed to the test project via InternalsVisibleTo.
  • dotnet build / dotnet test / dotnet csharpier check . / dotnet pack all pass locally; dotnet list package --vulnerable --include-transitive reports no findings.

Also fixed

The copied .gitignore's standard "Visual Studio Trace Files" rule (*.e2e) case-insensitively matched this repo's own src/AndreGoepel.Testing.E2E/ directory and silently excluded the whole library from tracking. Added a scoped !/src/AndreGoepel.Testing.E2E/ exception.

Still needed before the first release

  • nuget.org trusted publishing must be configured for this package name (owner: andregoepel, repo: testing, workflow: ci.yml) before a v1.0.0 tag can publish — that's a manual step on nuget.org's side, not something this PR can do.
  • Branch protection / repo settings are intentionally out of scope here per the issue — left for the repo owner.

Test plan

  • dotnet build -c Release
  • dotnet test -c Release (17/17 passing)
  • dotnet csharpier check .
  • dotnet pack src/AndreGoepel.Testing.E2E/AndreGoepel.Testing.E2E.csproj -c Release
  • dotnet list package --vulnerable --include-transitive (no findings)
  • Migrate marten-identity / finance-app / app-foundation onto the package (follow-up PRs, out of scope here)

…enticator helpers

Extracts the genuinely shared Playwright + Aspire E2E infrastructure from
marten-identity, finance-app, and app-foundation's near-identical local
copies. E2EAppFixture takes a Func<string[], Task<IDistributedApplicationTestingBuilder>>
instead of a generic type parameter, so E2ETestBase<TFixture> can stay
constrained to one non-generic base regardless of which Projects.* type
each host's AppHost generates. MailHog endpoint name defaults to the
canonical "http"; the admin-provisioning button text has no default since
its wording differs per app.

Also fixes a real bug in the copied .gitignore: the standard
"Visual Studio Trace Files" rule (*.e2e) case-insensitively matched this
repo's own src/AndreGoepel.Testing.E2E/ directory and silently excluded
it from tracking.
rollForward: disable required an exact 10.0.301 match, which the GitHub-
hosted runner didn't have (it only had 10.0.302 preinstalled), failing CI's
restore step before anything else could run. latestPatch still pins the
SDK to the 10.0.3xx band but tolerates a newer patch than the floor.
@andregoepel
andregoepel merged commit 9a29a22 into main Jul 26, 2026
3 checks passed
@andregoepel
andregoepel deleted the feature/bootstrap-testing-e2e branch August 21, 2026 05:35
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.

Bootstrap repo + AndreGoepel.Testing.E2E package (plan E1)

1 participant