Skip to content

Broaden e2e coverage: pin ~10-15 core behaviors in one PR #112

Description

@vchelaru

Goal

We now have a working Playwright .NET e2e harness (issue #97, PR #110) and two smoke tests: boot-and-run (#97) and repeated-restart resilience (#90, PR #111). This issue widens coverage in one PR — pin the ~10-15 most important user-visible behaviors so a regression in any core path fails CI. Not aiming for 100% coverage; aiming for "confident the basics work."

Deliberately one PR (not many small ones) to keep review/merge overhead low. Reuse the e2e-testing skill patterns (publish → in-process Kestrel → headless Chromium + SwiftShader; observable-signal sync; null-and-wait).

This subsumes the planned #95 sample-switch guard — fold that test in here rather than opening a separate PR. (#90 already shipped in #111; #95 was still pending.)

Candidate tests

Grouped by area. Each notes what it pins, the signal to sync on, and what it needs. Implementer: pick the ~12 highest-value; if you cut any, say which and why (no silent drops). Foundation tests 0.a/0.b already exist.

0. Foundation (already in SmokeTest.cs)

A. Compile / run core — signal-driven, high confidence

  1. Compile error surfaces cleanly — type invalid C#, Run → diagnostics show failure, #blazor-error-ui stays hidden, no game starts. Pins the Roslyn error path + graceful failure.
  2. Stop clears the running game — Run, then Stop → canvas cleared, status "Stopped.", Run button returns to "Run". Needs a testid on the Stop button.
  3. Edit-then-rerun recompiles vs cache-hit — Run (compiles → "Compiled in Xs"), Run again unchanged (cache hit → "Restarted without recompile"), edit code, Run (recompiles). Pins the CompileFingerprint cache. Sync on the diagnostics <pre> text.

B. Examples / graphics profile — needs testids
4. Load a different example (A→B) — open Examples modal, pick another example → its code loads into Monaco and runs. Core of #95. Needs testids on the Examples button + modal cards.
5. Sample-switch round-trip A→B→A stays alive (full #95) — with a new GetInputDebugState app hook (exposes Mouse.GetState() position / touch count via JS interop) for a deterministic input assertion instead of a flaky pixel-read. This is the one place a new app-code hook is justified (see e2e-testing skill boundary).
6. Reach↔HiDef profile switch (issue #25 canvas-swap path — historically fragile) — all built-in examples are HiDef, so type a hand-written Reach game and a HiDef game and switch between them → _canvasContextType flips webglwebgl2, both run, no error banner.

C. Share / persistence — URL round-trip, browser-only wiring
7. #code= round-trip — Share writes the hash; reload at that URL → same code loads + runs. Round-trips UrlCodec through the real app.
8. #snippet= round-trip — same, through SnippetReverter/SnippetExpander. (Unit tests cover the codec; this pins the app wiring.)
9. Cold-boot deep link — navigate straight to a #code=<payload> URL → loads + runs with no manual paste.

D. Editor / IntelliSense — browser-only Roslyn, unit tests can't reach
10. Monaco boots with default code visible — editor mounted + non-empty. Cheap, high value.
11. IntelliSense completion returns results — prefer calling the completion JSInvokable via page.EvaluateAsync and asserting non-empty, rather than driving the Monaco widget (fragile). Pins the in-browser language service.

E. Embed mode
12. ?embed=1 → editor hidden, game runs, canvas fills. Pins embed layout + the embed FPS-cap path.

Optional / heavier (include only if wall-clock allows — flag if cut):
13. Load an asset via file input → appears in Assets and is usable by Content.Load. Drag-drop is hard to synthesize; use Playwright SetInputFilesAsync if there's a file <input> (verify).
14. Shader (.fx) example compiles + runs — downloads ~17 MB DXC wasm, slow. One test, tag with an NUnit [Category] so CI can exclude it if the e2e job balloons.
15. Export project → .zip download fires — assert the download event only; can't validate the zip builds in e2e. Lower value.

App-code changes this needs (call out in the PR)

  • data-testid attributes on: Stop button, Examples button + modal + cards, Share, Assets, embed canvas, diagnostics pane. Only run-button exists today. These are test hooks, not behavior.
  • One debug hookGetInputDebugState JSInvokable (for test 5). Per the e2e-testing skill, add app hooks only for input/game-state assertions the DOM can't express.

Harness / infra

  • Per-test isolation: the fixture currently shares one IPage via OneTimeSetUp. With 10-15 tests, add a [SetUp] that gives each test a fresh page / re-navigation (keep browser + host shared in OneTimeSetUp — those are the expensive parts) so a still-running game or a set _canvasContextType can't leak across tests.
  • CI stays windows-latest (KNI XNA.Framework.Media case-sensitivity, see e2e.yml); dotnet test auto-discovers new tests — no workflow edit unless the shader test needs a category filter.
  • Update the e2e-testing skill with any new patterns discovered (per issue-workflow §7).

Acceptance criteria

  • ~10-15 e2e tests added in one PR, covering (at least) tests 1-12 above; any cuts justified in the PR.
  • App changes limited to test hooks (testids) + the single GetInputDebugState debug hook — no behavior changes.
  • #95 folded in and closed as superseded by this PR.
  • Full e2e job green on CI; note total wall-clock (flag if the shader test pushes it high).
  • e2e-testing skill updated if new patterns emerged.

Out of scope

Pixel-perfect render assertions; validating the exported zip actually builds; mobile/touch behavior (headless Chromium can't send real touch — that stays manual, per game-lifecycle).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions