Skip to content

Add isolated Redis e2e suite for registerInitialCache and handler-level correctness - #240

Merged
AyronK merged 11 commits into
masterfrom
feature/initial-cache-e2e
Aug 12, 2026
Merged

Add isolated Redis e2e suite for registerInitialCache and handler-level correctness#240
AyronK merged 11 commits into
masterfrom
feature/initial-cache-e2e

Conversation

@AyronK

@AyronK AyronK commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a self-contained Playwright suite (examples/redis-minimal/e2e/isolated/) that manages its own ephemeral Redis container(s) and next start process(es), independent of the existing shared e2e suite's server/Redis. It proves behavior the shared suite can't reach because it only observes an already-running, already-mutated server:

  • registerInitialCache actually populates Redis on boot — asserted directly against Redis before any HTTP request is made, for both App Router and Pages Router (fallback: false) routes, plus fetch-cache-derived tags.
  • setOnlyIfNotExists behaves correctly in both directions — a pre-existing key survives when the flag is true and is overwritten when left at its default false, using the identical seeded input in both cases (a real A/B control, not just a single-condition observation).
  • sharedTagsKey/sharedTagsTtlKey population rules and real Redis TTL, tested via direct construction of the redis-strings handler (the same public @fortedigital/nextjs-cache-handler/redis-strings subpath export the example app's own cache-handler.mjs uses) against a real Redis instance — no next start needed, so it can cover a full matrix of revalidate values and the lifespan: null permanent-key case that's unreachable via any real route at runtime.
  • revalidateTag mechanics — selective deletion (untouched entries proven byte-for-byte unchanged), safe no-op on no match, and the non-obvious distinction between an implicit tag (_N_T_...) that matches an existing entry (eagerly deleted, same as any tag) versus one that doesn't (only bookkeeping is written — the genuinely lazy path) — plus the TTL-expiry sweep that runs as a side effect of every revalidateTag call.
  • Full pipeline bridge — one test drives revalidateTag through the real /api/revalidate HTTP route and asserts the Redis deletion directly, rather than inferring it from a timestamp change.

Also:

  • Splits the CI redis-minimal-e2e job into two parallel jobs (main suite + isolated suite), each fully self-contained.
  • Adds JUnit-based test reporting (dorny/test-reporter) to both integration-tests.yml and node.js.yml, surfaced as GitHub Check runs.
  • Fixes two real flakes surfaced along the way: a per-attempt Redis connect timeout (a hung TCP handshake right after docker run -d -p could swallow an entire retry budget on Linux CI), and a port-collision race between sequential spec files (fixed by allocating a genuinely free OS-assigned port per container/server instead of sharing hardcoded ports).
  • Documents the two testing styles (boot next start vs. direct handler construction) in the new-e2e-test skill for future additions.

Test plan

  • tsc --noEmit clean
  • Full isolated suite passes locally (25/25), run multiple times to check for the port-collision flake
  • Every new/changed assertion mutation-tested (flipped to a wrong expected value, confirmed a real failure, reverted) — including the subtlest ones (implicit-tag bookkeeping-only path, TTL cross-checks)
  • Root-level pnpm test:e2e:isolated verified to correctly trigger the Turborepo build chain from a clean .next/dist (this is what CI actually invokes)
  • No leftover Docker containers after any run
  • CI green on this PR (parallel jobs + JUnit reporting)

AyronK added 11 commits August 12, 2026 14:22
Adds a self-contained Playwright suite (examples/redis-minimal/e2e/isolated)
that boots its own ephemeral Redis container and next start process to
verify registerInitialCache actually writes build-time artifacts to Redis
on boot, plus the setOnlyIfNotExists option's behavior - previously
untested anywhere in the repo since the shared e2e suite only observes an
already-running, already-mutated server/Redis.
@AyronK
AyronK merged commit b557915 into master Aug 12, 2026
5 checks passed
@AyronK
AyronK deleted the feature/initial-cache-e2e branch August 12, 2026 14:34
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