Skip to content

Add integration testing with testcontainers and Playwright#442

Open
prk-Jr wants to merge 18 commits intomainfrom
feature/integration-testing-with-testcontainers
Open

Add integration testing with testcontainers and Playwright#442
prk-Jr wants to merge 18 commits intomainfrom
feature/integration-testing-with-testcontainers

Conversation

@prk-Jr
Copy link
Collaborator

@prk-Jr prk-Jr commented Mar 5, 2026

Summary

  • Add end-to-end integration testing infrastructure using testcontainers for HTTP-level tests and Playwright for browser tests against WordPress and Next.js containers
  • Add Playwright browser tests verifying script injection, SPA navigation, deferred script execution, API passthrough, and form URL rewriting in a real Chromium browser
  • Introduce a /health endpoint and CI workflow for running both test suites separately from the main CI

Changes

File Change
crates/fastly/src/main.rs Add /health GET endpoint returning 200 with "ok" body
crates/integration-tests/Cargo.toml New crate with reqwest, testcontainers, and tokio dependencies
crates/integration-tests/tests/common/ Core test infrastructure: runtime traits, config builder, assertion helpers including assert_form_action_rewritten (9 unit tests)
crates/integration-tests/tests/environments/ Fastly/Viceroy runtime environment with dynamic port allocation
crates/integration-tests/tests/frameworks/ Framework abstractions for WordPress and Next.js with 7 standard + 5 custom scenarios
crates/integration-tests/tests/integration.rs Matrix test runner (test_all_combinations, per-framework tests)
crates/integration-tests/fixtures/configs/ Viceroy and Fastly config templates with KV stores and secrets
crates/integration-tests/fixtures/frameworks/wordpress/ WordPress Docker image: PHP built-in server with minimal test theme and /wp-admin/ stub
crates/integration-tests/fixtures/frameworks/nextjs/ Next.js 14 Docker image: 4 pages, API routes, forms, shared navigation with hydration signal, deferred route scripts
crates/integration-tests/browser/ Playwright test suite: global setup/teardown, Docker + Viceroy infra helpers with cleanup-on-failure
crates/integration-tests/browser/tests/shared/ Cross-framework browser tests: script injection, script bundle loading
crates/integration-tests/browser/tests/nextjs/ Next.js browser tests: 4-page SPA navigation chain, deferred script execution, API passthrough, form URL rewriting
crates/integration-tests/browser/tests/wordpress/ WordPress browser tests: admin page script injection
.github/workflows/integration-tests.yml CI workflow with parallel HTTP-level and browser test jobs, split artifact uploads for Playwright reports and traces
scripts/integration-tests.sh Shell script for HTTP-level test orchestration (WASM build + Docker + test run)
scripts/integration-tests-browser.sh Shell script for browser test orchestration (WASM build + Docker + Playwright install + test run)
crates/integration-tests/README.md Full documentation: prerequisites, quick start, test scenario tables, architecture overview
INTEGRATION_TESTS_PLAN.md Design document with architecture decisions and progress tracking
Cargo.toml Add integration-tests to workspace members
Cargo.lock Updated lockfile with new dependencies

Test coverage

HTTP-level (Rust + testcontainers)

Scenario Frameworks
HtmlInjection WordPress, Next.js
ScriptServing WordPress, Next.js
AttributeRewriting WordPress, Next.js
ScriptServingUnknownFile404 WordPress, Next.js
WordPressAdminInjection WordPress
NextJsRscFlight Next.js
NextJsServerActions Next.js
NextJsApiRoute Next.js
NextJsFormAction Next.js

Browser-level (Playwright + Chromium)

Spec Frameworks
script-injection WordPress, Next.js
script-bundle WordPress, Next.js
navigation (4-page SPA chain + back button + deferred route script) Next.js
api-passthrough Next.js
form-rewriting Next.js
admin-injection WordPress

Totals: 12 Next.js + 5 WordPress browser tests, 0 flaky

Known gaps

  • GDPR consent propagation — the consent field exists in AuctionRequest but is not yet populated upstream. Requires implementation before it can be tested.
  • Browser suite uses manual Docker orchestration — HTTP-level tests use the Rust testcontainers crate; browser tests use docker run/docker stop via Playwright's globalSetup/globalTeardown (Node.js cannot use the Rust crate).

Closes

Closes #398

Test plan

  • cargo test --workspace (excluding integration-tests, which requires native target)
  • cargo clippy --all-targets --all-features -- -D warnings (excluding integration-tests)
  • cargo fmt --all -- --check
  • JS tests: pre-existing ESM/CJS failure on main (not introduced by this branch)
  • JS format: cd crates/js/lib && npm run format -- passes
  • Docs format: cd docs && npm run format -- passes
  • Integration-tests crate compiles for native target: cargo test -p integration-tests --target aarch64-apple-darwin --no-run
  • HTTP integration tests: ./scripts/integration-tests.sh -- all pass
  • Browser integration tests: ./scripts/integration-tests-browser.sh -- 17 pass, 0 fail
  • Cargo clippy on integration-tests: cargo clippy --manifest-path crates/integration-tests/Cargo.toml --tests -- clean

Checklist

  • Changes follow CLAUDE.md conventions
  • No unwrap() in production code — use expect("should ...")
  • Uses log macros (not println!)
  • New code has tests (9 unit tests for assertions and config, 17 browser tests)
  • No secrets or credentials committed

@prk-Jr prk-Jr self-assigned this Mar 5, 2026
@prk-Jr prk-Jr marked this pull request as draft March 5, 2026 14:12
prk-Jr added 7 commits March 5, 2026 20:12
The integration-tests crate defines traits, error types, and helpers
consumed by Docker-dependent tests. Without Docker the compiler sees
them as unused and -D warnings promotes them to errors. A crate-level
allow keeps CI green.
Proves that a next/script with strategy="afterInteractive" executes
after a client-side navigation through the trusted-server proxy.
The test SPA-navigates from / to /dashboard, waits for the script's
global marker, asserts it ran exactly once, and confirms no
document-level request fired (true SPA, not full reload).
@prk-Jr prk-Jr changed the title Add integration testing infrastructure with testcontainers Add integration testing with testcontainers and Playwright Mar 7, 2026
@prk-Jr prk-Jr marked this pull request as ready for review March 9, 2026 14:47
Copy link
Collaborator

@aram356 aram356 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid integration testing infrastructure. The RuntimeEnvironment + FrontendFramework matrix design is clean and extensible, the two-layer approach (Rust HTTP + Playwright browser) gives good coverage, and the assertion library having its own unit tests is a nice touch.

Cross-cutting notes

📝 Separate Cargo.lock — The 3400-line crates/integration-tests/Cargo.lock is disconnected from the workspace lock. If error-stack (or any shared dep) is updated in the workspace but not here, they silently diverge. Consider documenting the upgrade process or adding a CI check that validates shared dependency versions stay in sync.

📝 Viceroy config placeholdersviceroy-template.toml uses key = "placeholder" / data = "placeholder" for all KV stores. This means integration tests don't exercise KV store functionality, which is fine but worth a comment in the config noting this intentional scope limitation.

.gitignore missing trailing newline — The last line lacks a POSIX-compliant trailing newline.

What's done well

👍 Drop impl on ViceroyHandle ensures process cleanup even on panics — good defensive design.

👍 Assertion functions (assertions.rs) have thorough unit tests covering both passing and failing cases.

👍 Browser tests use hydration detection (data-hydrated attribute) before SPA navigation — avoids the classic "clicked before client router was ready" flake.

👍 Health check endpoint is namespaced (/__trusted-server/health) to minimize publisher route conflicts.

👍 Shell scripts detect native target dynamically via rustc -vV — no hardcoded platform assumptions.

👍 Smart use of PHP built-in server for WordPress fixture — avoids MySQL dependency while still testing real HTML processing behavior.

branches: [main]
pull_request:
pull_request_review:
types: [submitted]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌱 pull_request_review trigger means integration tests re-run on every review submission, even when no code changed. Combined with the pull_request trigger, an approval on an existing PR triggers a full redundant run. Consider removing this trigger or using workflow_dispatch for on-demand runs.

Copy link
Collaborator

@ChristianPavilonis ChristianPavilonis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below

Copy link
Collaborator

@ChristianPavilonis ChristianPavilonis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One follow-up I still recommend:

.github/workflows/integration-tests.yml currently runs on pull_request_review approvals, which can trigger full integration + browser reruns without any code change.
Severity: P2 (efficiency/cost)
Suggestion: remove the pull_request_review trigger and keep pull_request + workflow_dispatch for canonical/manual runs.
Verdict: needs discussion (not a hard blocker).

Comment on lines +10 to +11
pull_request_review:
types: [submitted]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 (efficiency/cost): pull_request_review triggers will re-run the full integration + browser test suites on every review submission — even when there are no code changes. Consider removing this trigger and keeping just pull_request + workflow_dispatch for canonical/manual runs.

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.

Integration tests: WordPress and Next.js frontends with Testcontainers

3 participants