test(e2e): mock NFT API to remove from allowlist (MMQA-1781)#29620
Conversation
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>
|
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. |
Codecov Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
Impact Assessment:
The primary risk is that tests relying on NFT API responses (even implicitly) may behave differently with empty mock responses. Performance Test Selection: |
|



Description
Tier 3 of MMQA-1364 (allowlist reduction), scoped to the
nft.api.cx.metamask.ioendpoints. Closes out Tier 3 (signature-insights done in MMQA-1779).^https://nft\.api\.cx\.metamask\.io/users/0x[0-9a-fA-F]+/tokens\?.*${ tokens: [], continuation: null }^https://nft\.api\.cx\.metamask\.io/collections\?.*${ collections: [] }^https://nft\.api\.cx\.metamask\.io/explore/sites\?.*${ dapps: [] }Why these response shapes.
/users/.../tokensshape verified from@metamask/assets-controllersNftDetectionController._getOwnerNfts(consumer calls.tokens.filter(...))./explore/sitesshape verified fromapp/components/UI/Sites/hooks/useSiteData/useSitesData.ts:146(data.dapps.map(...)thenmergePortfolioSite()falls back to a hard-coded Portfolio entry on empty input)./collectionsshape 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/tokensPOST batch endpoint inNftController._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/ornode_modules/@metamask/*. The SDK hardcodesnft.api.cx.metamask.io(prod) only viacontroller-utils/constants.cjs:193. The dev/uat entries were added defensively in PR #26141 alongsideportfolio.dev-api/portfolio.uat-apipatterns and are dead.Spec audit.
tests/regression/assets/nft-detection-modal.spec.ts—describe.skip(not active).tests/smoke/snaps/test-snap-get-preferences.spec.ts— only setsuseNftDetection: trueas a flag; doesn't assert on detected NFT content./explore/sitescontent. Empty defaults are safe.Files changed
tests/api-mocking/mock-responses/defaults/nft-api.ts— newtests/api-mocking/mock-responses/defaults/index.ts— import + spread intoDEFAULT_MOCKS.GETtests/api-mocking/mock-e2e-allowlist.ts— removed 3 hosts + 3 URLsOut of scope
api.avax.network,mainnet.era.zksync.io,rpc.atlantischain.network,testnet-rpc.monad.xyz)metamask.github.io— handled by MMQA-1367Changelog
CHANGELOG entry: null
Related issues
MMQA-1781 — parent epic MMQA-1364
Manual testing steps
Screenshots/Recordings
Before
mock-e2e-allowlist.tsallowlisted the entirenft.api.cx.metamask.iohost 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 silencedvalidateLiveRequests(), 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 fornft.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)
trace()for usage andaddTokenfor an exampleFor performance guidelines and tooling, see the Performance Guide.
Pre-merge reviewer checklist
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.iotraffic: the PR removes NFT hosts/URLs frommock-e2e-allowlist.tsand adds default regex-based mocks for the NFT API.DEFAULT_MOCKSnow includesNFT_API_MOCKS, returning empty-shaped responses forGET /users/:address/tokens,GET /collections, andGET /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.