Skip to content

[DO NOT MERGE] feat(e2e): replace Mockttp with Go-based mock server#27904

Open
cmd-ob wants to merge 22 commits intomainfrom
feat/go-mock-server-v2
Open

[DO NOT MERGE] feat(e2e): replace Mockttp with Go-based mock server#27904
cmd-ob wants to merge 22 commits intomainfrom
feat/go-mock-server-v2

Conversation

@cmd-ob
Copy link
Contributor

@cmd-ob cmd-ob commented Mar 25, 2026

Description

Replaces the Node.js/Mockttp-based E2E mock server with a compiled Go binary for improved performance, reliability, and CI portability.

What changed and why:

  • Go mock server (tests/mock-server/): A self-contained Go binary that handles proxy interception, URL/body matching, rule storage (thread-safe), request forwarding with port translation, live request tracking, and default mock deserialization. Built for darwin-arm64, darwin-amd64, linux-arm64, linux-amd64.
  • TypeScript wrapper (tests/api-mocking/GoMockServer.ts): Manages the Go binary lifecycle (start/stop/reset) and exposes the same interface as MockServerE2E so call sites need minimal changes.
  • MockttpCompat interface (tests/api-mocking/MockttpCompat.ts): A compatibility shim that lets existing test code keep using Mockttp-style .thenReply() / testSpecificMock patterns while the Go server handles the actual interception.
  • FixtureHelper wired to GoMockServer: FixtureHelper.ts now starts/stops GoMockServer instead of MockServerE2E.
  • PortManager: New MOCK_SERVER_CONTROL resource type for the Go server's control port.
  • CI binary freshness check (build.yml): Fails CI if the committed binaries are stale vs the Go source, preventing silent drift.
  • thenCallback migration deferred: 80 occurrences across 15 files (polymarket 29, ramps 12, perps 11, etc.) are too risky to convert in one PR. The MockttpCompat shim routes thenCallback calls through the existing mockttp layer; each file will be migrated in a domain-specific follow-up.
  • Swap mocks & analytics tracking fixed for the Go server path.
  • Account syncing multi-SRP test re-enabled after Go server wiring stabilised it.

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

Feature: Go mock server E2E infrastructure

  Scenario: E2E tests pass with Go mock server as the interceptor
    Given the Go mock server binaries are built and committed
    When any E2E smoke or regression test runs locally or in CI
    Then the Go binary starts, intercepts HTTP traffic, and returns mocked responses
    And tests that use thenCallback continue to work via the MockttpCompat shim

  Scenario: CI catches stale Go binaries
    Given a developer modifies a .go source file without rebuilding
    When CI runs the binary freshness check
    Then the build fails with a clear message indicating binaries need rebuilding

Screenshots/Recordings

Before

N/A — infrastructure change, no UI impact.

After

N/A — infrastructure change, no UI impact.

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

High Risk
High risk because it replaces core E2E network interception with a new Go proxy/control-plane plus a Node callback bridge, and updates many tests/types to the new MockttpCompat interface; failures could broadly break smoke/regression suites and CI.

Overview
Replaces the E2E mock server implementation: fixtures now start GoMockServer (a spawned Go binary) instead of the previous Node/Mockttp server, and a new MockttpCompat TypeScript shim preserves the existing .forGet/.forPost(...).thenReply/thenJson/thenCallback style APIs.

Adds a Go mock server with a control API and forwarding logic under tests/mock-server/, including rule storage/matching, live-request tracking, and port-translation forwarding; static default mocks are now posted over HTTP instead of passed via a large CLI arg, and dynamic .thenCallback mocks run via a Node “callback bridge” that the Go proxy consults first.

Updates test infra and a few mocks for compatibility: introduces a dedicated control-port allocation (MOCK_SERVER_CONTROL), switches many tests/helpers to type against MockttpCompat, tweaks swap/smart-tx and metametrics mocks to ensure dynamic behavior and request-payload visibility, re-enables the multi-SRP identity smoke test, and adds CI checks to fail when committed mock-server binaries drift from Go sources (plus ignores .worktrees/).

Written by Cursor Bugbot for commit 47677ef. This will update automatically on new commits. Configure here.

cmd-ob and others added 20 commits March 24, 2026 19:13
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Audited all .thenCallback() usages across the test suite to inform the
Go MockServer migration strategy. Found 80 usages across 15 files outside
of MockServerE2E.ts itself, concentrated in api-mocking/mock-responses/.
Chose Option A (defer migration) given the volume and semantic complexity
of the dynamic responses involved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…atch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…erE2E

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ockttpCompat

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Support asPriority() in CallbackBridge: sort handlers by priority
  descending so higher-priority handlers always win regardless of
  registration order, matching mockttp semantics
- Track all bridge requests in _seenRequests so getMockedEndpoints()
  exposes analytics event payloads to getEventsPayloads()
- Route metametrics mock through bridge (function response) so segment
  event bodies are captured and queryable in swap segment tests
- Fix STX UUID deduplication: generate unique UUID per submitTransactions
  call and respond dynamically to batchStatus for each UUID
- Restore correct catch-all SSE mock order in swap-mocks.ts (asPriority(1)
  now properly loses to specific mocks at priority 999)
- Go proxy: add callback bridge forwarding (control.go, main.go, proxy.go)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cmd-ob cmd-ob self-assigned this Mar 25, 2026
@github-actions
Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot metamaskbot added the team-qa QA team label Mar 25, 2026
@cmd-ob cmd-ob marked this pull request as ready for review March 25, 2026 09:55
@cmd-ob cmd-ob requested review from a team as code owners March 25, 2026 09:55
@cmd-ob cmd-ob requested a review from a team as a code owner March 25, 2026 09:55
@cmd-ob cmd-ob changed the title feat(e2e): replace Mockttp with Go-based mock server [DO NOT MERGE] feat(e2e): replace Mockttp with Go-based mock server Mar 25, 2026
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

}[] {
return this._seenRequests.map(({ url, bodyText }) => ({
url,
method: 'POST',
Copy link

Choose a reason for hiding this comment

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

getSeenRequests hardcodes method ignoring actual request method

Medium Severity

CallbackBridge.getSeenRequests() destructures only url and bodyText from each SeenBridgeRequest, discarding the stored method field. It then hardcodes method: 'POST' for every returned request. This means all seen requests are reported as POST regardless of their actual HTTP method, which corrupts the data available to getMockedEndpoints() and downstream analytics event tracking via getEventsPayloads().

Fix in Cursor Fix in Web

- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.21'
Copy link

Choose a reason for hiding this comment

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

Go version mismatch between CI and go.mod

High Severity

The CI freshness check installs Go 1.21 but tests/mock-server/go.mod declares go 1.24.2. Since Go 1.21+ treats the go directive as a minimum version requirement, the build step will either fail or silently auto-download Go 1.24.2 via toolchain management, making the freshness check unreliable. The go-version in CI needs to match (or exceed) the version in go.mod.

Fix in Cursor Fix in Web

}

w.WriteHeader(resp.StatusCode)
w.Write(respBody)
Copy link

Choose a reason for hiding this comment

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

Go forwarder drops all response headers from upstream

Medium Severity

The Forward method reads the upstream response body and writes the status code and body to the client, but never copies response headers (e.g., Content-Type, Transfer-Encoding) from resp.Header to w.Header(). Forwarded responses to real services like Anvil/Ganache lose their Content-Type: application/json header, which can cause the app's HTTP client to misparse RPC responses.

Fix in Cursor Fix in Web

@codecov-commenter
Copy link

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.54%. Comparing base (9564fd6) to head (3b9826c).
⚠️ Report is 21 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #27904      +/-   ##
==========================================
+ Coverage   82.52%   82.54%   +0.02%     
==========================================
  Files        4800     4825      +25     
  Lines      123748   123877     +129     
  Branches    27576    27594      +18     
==========================================
+ Hits       102122   102255     +133     
  Misses      14567    14567              
+ Partials     7059     7055       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

cmd-ob and others added 2 commits March 25, 2026 11:27
…ry check path

- Add `thenCallback` and `asPriority` to `MockttpCompatRule` interface so
  `.forPost(url).asPriority(n).thenCallback(handler)` (used in cardholder-mocks.ts)
  type-checks correctly. Resolves TS2339 in CI lint:tsc job.
- Implement both in `makeRule` via a URL predicate fed to `makeTerminal`,
  consistent with how `.matching(pred).asPriority(n)` already works.
- Fix `git diff --exit-code tests/bin/` → `../bin/` in ci.yml: the check runs
  from `tests/mock-server/` so the relative path was resolving to a non-existent
  `tests/mock-server/tests/bin/`, causing `fatal: ambiguous argument` and a false
  positive failure on every run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…on Linux

The Go mock server was spawned with --defaults <json> which passes all default
mock rules as a single command-line argument. On Linux CI runners, this JSON
can exceed the kernel ARG_MAX limit, causing `spawn E2BIG` errors and failing
all Android E2E tests.

Fix: Remove --defaults from the spawn call entirely. Instead, after the binary
becomes healthy, POST each static (non-function) default mock rule individually
to the existing POST /mocks control API endpoint. Function-based rules continue
to go through the callback bridge as before.

Also removes the now-unused _serializeEvents() private method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added the risk-high Extensive testing required · High bug introduction risk label Mar 25, 2026
@github-actions
Copy link
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeConfirmations, SmokeAccounts, SmokeIdentity, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeTrade, SmokeWalletPlatform, SmokeCard, SmokePerps, SmokeRamps, SmokeMultiChainAPI, SmokePredictions, FlaskBuildTests
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: high
  • AI Confidence: 95%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR introduces a fundamental migration of the E2E test mock server infrastructure from MockServerE2E (backed by the mockttp npm package) to GoMockServer (backed by compiled Go binaries). This is a critical infrastructure change that affects ALL E2E tests.

Key changes analyzed:

  1. Core infrastructure replacement: FixtureHelper.ts now instantiates GoMockServer instead of MockServerE2E. Since withFixtures and createMockAPIServer are used by virtually every E2E test, this change affects the entire test suite.

  2. New Go binary mock server: New platform-specific binaries (darwin-amd64, darwin-arm64, linux-amd64, linux-arm64) replace the Node.js mockttp server. The Go server handles static mock rules via a control API, while dynamic thenCallback handlers are routed through a JavaScript callback bridge.

  3. Type migration: All test files changed MockttpMockttpCompat type annotations. While these are type-only changes, they confirm the new interface is being used across all feature areas: confirmations, accounts, identity, perps, ramps, swap, trending, snaps, seedless, stake, predict, wallet analytics.

  4. MetaMetrics tracking fix: metametrics-test.ts changed from static response to function response so analytics event payloads are tracked through the callback bridge - this affects analytics validation in SmokeWalletPlatform and other analytics-dependent tests.

  5. Smart transactions mocks: Updated to dynamically generate unique UUIDs per submission and handle batch status responses dynamically - directly affects SmokeTrade swap flows.

  6. Multi-SRP test un-skipped: tests/smoke/identity/account-syncing/multi-srp.spec.ts had describe.skip removed, re-enabling a previously quarantined SmokeIdentity test.

  7. CI workflow: New job added to validate Go binary freshness.

Since the mock server is the backbone of all E2E tests (every test that uses fixtures relies on it), ALL test tags must be run to validate the new infrastructure works correctly across all feature areas. The risk is high because:

  • A bug in the Go mock server or callback bridge could silently break any test
  • The new binary-based approach has different failure modes than the Node.js mockttp approach
  • The callback bridge priority system is new and could affect test isolation
  • The analytics tracking change could affect tests that validate event payloads

All tags are selected to ensure comprehensive validation of the new infrastructure.

Performance Test Selection:
No performance tests are needed. The changes are entirely within the E2E test infrastructure (mock server migration from Node.js mockttp to Go binary). No app source code was changed, no UI components were modified, no controllers or state management was altered. The Go mock server only affects test execution environment, not app performance characteristics.

View GitHub Actions results

@sonarqubecloud
Copy link

@github-actions
Copy link
Contributor

E2E Fixture Validation — Schema is up to date
17 value mismatches detected (expected — fixture represents an existing user).
View details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk-high Extensive testing required · High bug introduction risk size-XL team-qa QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants