Skip to content

test(e2e): mock NFT API to remove from allowlist (MMQA-1781)#29620

Merged
chrisleewilcox merged 5 commits into
mainfrom
MMQA-1781-tier-3-nft-api-mocks
May 4, 2026
Merged

test(e2e): mock NFT API to remove from allowlist (MMQA-1781)#29620
chrisleewilcox merged 5 commits into
mainfrom
MMQA-1781-tier-3-nft-api-mocks

Conversation

@chrisleewilcox
Copy link
Copy Markdown
Contributor

@chrisleewilcox chrisleewilcox commented May 1, 2026

Description

Tier 3 of MMQA-1364 (allowlist reduction), scoped to the nft.api.cx.metamask.io endpoints. Closes out Tier 3 (signature-insights done in MMQA-1779).

Matcher Method Response
^https://nft\.api\.cx\.metamask\.io/users/0x[0-9a-fA-F]+/tokens\?.*$ GET { tokens: [], continuation: null }
^https://nft\.api\.cx\.metamask\.io/collections\?.*$ GET { collections: [] }
^https://nft\.api\.cx\.metamask\.io/explore/sites\?.*$ GET { dapps: [] }

Why these response shapes.

  • /users/.../tokens shape verified from @metamask/assets-controllers NftDetectionController._getOwnerNfts (consumer calls .tokens.filter(...)).
  • /explore/sites shape verified from app/components/UI/Sites/hooks/useSiteData/useSitesData.ts:146 (data.dapps.map(...) then mergePortfolioSite() falls back to a hard-coded Portfolio entry on empty input).
  • /collections shape is a guess — the caller can't be located in the current SDK (path was likely refactored away from the singular /collections?contract= form to the /tokens POST batch endpoint in NftController._getNftInformationFromApi). The matcher is harmless insurance: either it never fires, or it fires and returns empty. No active spec asserts on collection content.

Why regex, not exact URLs. Same rationale as Tier 2 / Tier 3 Part 1: the previous allowlist enumerated specific contract addresses and a specific user account. Any new NFT in fixtures, any new chainId, or any new test account would re-introduce live requests. Regex covers the entire category.

Why dev-api / uat-api hosts can drop without mocking. Neither is referenced anywhere in app/ or node_modules/@metamask/*. The SDK hardcodes nft.api.cx.metamask.io (prod) only via controller-utils/constants.cjs:193. The dev/uat entries were added defensively in PR #26141 alongside portfolio.dev-api/portfolio.uat-api patterns and are dead.

Spec audit.

  • tests/regression/assets/nft-detection-modal.spec.tsdescribe.skip (not active).
  • tests/smoke/snaps/test-snap-get-preferences.spec.ts — only sets useNftDetection: true as a flag; doesn't assert on detected NFT content.
  • No active spec positively asserts on NFTs being present, collection content, or /explore/sites content. Empty defaults are safe.

Files changed

  • tests/api-mocking/mock-responses/defaults/nft-api.ts — new
  • tests/api-mocking/mock-responses/defaults/index.ts — import + spread into DEFAULT_MOCKS.GET
  • tests/api-mocking/mock-e2e-allowlist.ts — removed 3 hosts + 3 URLs

Out of scope

  • Polymarket hosts (3) — separate Tier 1 follow-up
  • Tier 4 entries (api.avax.network, mainnet.era.zksync.io, rpc.atlantischain.network, testnet-rpc.monad.xyz)
  • metamask.github.io — handled by MMQA-1367

Changelog

CHANGELOG entry: null

Related issues

MMQA-1781 — parent epic MMQA-1364

Manual testing steps

Feature: NFT API default mocks for E2E tests

  Scenario: NFT detection sweep is mocked
    Given the E2E mock server is running with default mocks loaded
    When NftDetectionController fires GET /users/<address>/tokens for the connected account
    Then mockttp returns { tokens: [], continuation: null }
    And no NFTs are added to wallet state
    And validateLiveRequests() does not record a live request to nft.api

  Scenario: NFT collection lookup is mocked
    Given a fixture transaction history references an unknown NFT contract
    When the wallet looks up collection metadata via GET /collections?…
    Then mockttp returns { collections: [] }
    And the wallet falls back to its default rendering

  Scenario: Sites tab is mocked
    Given the user opens the Sites tab
    When useSitesData fetches GET /explore/sites?…
    Then mockttp returns { dapps: [] }
    And the Portfolio entry is shown via the hard-coded fallback

Screenshots/Recordings

Before

mock-e2e-allowlist.ts allowlisted the entire nft.api.cx.metamask.io host plus 3 specific URLs. Every E2E run that exercised the connected account, NFT-bearing tx history, or the Sites tab fired live requests to the production NFT API. The host wildcard silenced validateLiveRequests(), so the leaks were invisible to the test runner. The dev/uat host entries were there defensively but never hit.

After

mockttp intercepts the three known endpoints with empty default responses that match each consumer's shape expectations. The 3 hosts and 3 URLs are gone from the allowlist; validateLiveRequests() records zero leaks for nft.api.cx.metamask.io. New chainIds, new fixture NFT contracts, and new test accounts all stay covered automatically because the matchers are regex-based.

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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

Low Risk
Low risk; changes are confined to E2E test mocking/allowlisting, with the main risk being unexpected NFT API call patterns causing new test failures if they aren’t matched by the regex mocks.

Overview
E2E tests no longer rely on live nft.api.cx.metamask.io traffic: the PR removes NFT hosts/URLs from mock-e2e-allowlist.ts and adds default regex-based mocks for the NFT API.

DEFAULT_MOCKS now includes NFT_API_MOCKS, returning empty-shaped responses for GET /users/:address/tokens, GET /collections, and GET /explore/sites, reducing allowlisted leakage while keeping tests stable.

Reviewed by Cursor Bugbot for commit 95f6a27. Bugbot is set up for automated code reviews on this repo. Configure here.

Adds default GET mocks for the three nft.api.cx.metamask.io endpoints
the wallet hits during E2E runs, then removes the corresponding host
and URL allowlist entries.

- /users/0x*/tokens → empty tokens array (NftDetectionController scan)
- /collections → empty collections array (legacy NFT contract lookup)
- /explore/sites → empty dapps array (Sites tab in useSitesData)

Drops 3 hosts (prod/dev/uat) and 3 URL entries. dev-api/uat-api hosts
are not referenced anywhere in app or SDK code — added defensively in
PR #26141; safe to remove without mocking.

Regex matchers cover the entire category, so new fixture contracts /
new chainIds / new tx-history NFTs won't reintroduce live requests.

Tier 3 of MMQA-1364. Closes out the NFT API portion (signature-insights
done in MMQA-1779).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

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.

@metamaskbotv2 metamaskbotv2 Bot added the team-qa QA team label May 1, 2026
@github-actions github-actions Bot added the size-S label May 1, 2026
@chrisleewilcox chrisleewilcox marked this pull request as ready for review May 1, 2026 18:38
@chrisleewilcox chrisleewilcox requested a review from a team as a code owner May 1, 2026 18:38
@chrisleewilcox chrisleewilcox added no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed no changelog required No changelog entry is required for this change labels May 1, 2026
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.81%. Comparing base (51b6bbd) to head (cf2524b).
⚠️ Report is 33 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #29620      +/-   ##
==========================================
- Coverage   82.15%   81.81%   -0.34%     
==========================================
  Files        5178     5226      +48     
  Lines      137450   138584    +1134     
  Branches    31079    31456     +377     
==========================================
+ Hits       112924   113388     +464     
- Misses      16875    17466     +591     
- Partials     7651     7730      +79     

☔ 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 78%
click to see 🤖 AI reasoning details

E2E Test Selection:
The changes are purely in the E2E test infrastructure (mock server configuration):

  1. mock-e2e-allowlist.ts: Removed NFT API hosts/URLs from the allowlist. Previously, NFT API calls would be forwarded to live servers; now they must be mocked.

  2. nft-api.ts (new file): Provides default mock responses for NFT API endpoints using regex patterns:

    • /users/{address}/tokens → returns { tokens: [], continuation: null }
    • /collections → returns { collections: [] }
    • /explore/sites → returns { dapps: [] }
  3. defaults/index.ts: Integrates NFT_API_MOCKS into DEFAULT_MOCKS, which is used by FixtureHelper.ts as the base mock configuration for ALL E2E tests.

Impact Assessment:

  • The explore/sites endpoint is used by useSitesData.ts in the Sites/Trending feature, which is part of SmokeWalletPlatform (Trending tab with Sites section)
  • NFT collections/tokens endpoints are used by the wallet's NFT display features
  • The change makes tests more deterministic by replacing live API calls with controlled mocks
  • Tests that previously relied on live NFT API data will now receive empty arrays, which could affect tests that assert on NFT content
  • SmokeConfirmations is included as confirmations tests often involve wallet state that may trigger NFT detection calls

The primary risk is that tests relying on NFT API responses (even implicitly) may behave differently with empty mock responses. SmokeWalletPlatform is the most directly affected tag due to the Trending/Sites integration. Running these tags validates that the new default mocks don't break existing test flows.

Performance Test Selection:
These changes are purely in the E2E test infrastructure (mock server configuration). They do not affect any app source code, UI components, state management, or runtime behavior. No performance impact is expected.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 4, 2026

@chrisleewilcox chrisleewilcox added this pull request to the merge queue May 4, 2026
Merged via the queue into main with commit f110b3f May 4, 2026
115 checks passed
@chrisleewilcox chrisleewilcox deleted the MMQA-1781-tier-3-nft-api-mocks branch May 4, 2026 16:47
@github-actions github-actions Bot locked and limited conversation to collaborators May 4, 2026
@metamaskbotv2 metamaskbotv2 Bot added the release-7.77.0 Issue or pull request that will be included in release 7.77.0 label May 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

no changelog required No changelog entry is required for this change no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed release-7.77.0 Issue or pull request that will be included in release 7.77.0 size-S team-qa QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants