refactor(e2e): cross-network test coverage + scaffolding#366
Merged
Conversation
Add infrastructure the rest of the e2e refactor plan leans on, without moving or rewriting any existing spec: - `e2e/fixtures/networks.ts` — typed table of every production + testnet network (ChainID, slug, adapter family, canonical block/tx/address/ token) and groupings (EVM_PRODUCTION, EVM_TESTNETS, L2_NETWORKS). Lets future cross-network specs iterate instead of copy-pasting per chain. - `e2e/fixtures/localStorage.ts` — `clearAppState`, `setLanguage`, `setTheme`, `setRpcStrategy`, `readLocalStorage` so settings-touching specs can reset state explicitly rather than relying on fullyParallel isolation guarantees. - `e2e/fixtures/rpcMock.ts` — `page.route` helpers for JSON-RPC stubs, HTTP errors, 429-then-success, and offline. Needed by the upcoming strategy / worker-fallover / error-path specs. - `e2e/fixtures/assertionsL2.ts` — `expectArbitrumL1Fields`, `expectOpStackL1Fee`, `expectBlobFields`. One-call assertions for the fields L2 adapters exist to surface. - `e2e/fixtures/test.ts` — replace the unbounded growing-timeout retry with a fixed 60s base + 30s retry bonus, and log retries so flakiness is visible in CI output. - `playwright.config.ts` — add a `mocked` project scoped to `e2e/tests/shared/mocked/**/*.spec.ts`. Default `chromium` project explicitly excludes it so hermetic tests and live-RPC tests don't cross-pollute. CI retries dropped from 3 to 2 (more signal, less masking). - Seed `e2e/tests/shared/`, `e2e/tests/shared/mocked/`, `e2e/tests/testnets/`, and `e2e/tests/solana/` with placeholders so the directories land in git. No existing spec is modified or moved. Playwright test discovery still reports the same 281 tests; typecheck clean.
Self-review of 6294053 uncovered three issues that would silently break downstream specs: - `networks.ts` slugs invented rather than taken from `src/config/networks.json`: `ethereum` → `eth`, `arbitrum` → `arb`, `optimism` → `op`, `avalanche` → `avax`. Also add a `urlPath` field so specs know whether to put chainId or slug into the `/:networkId` URL segment (the convention used by existing per-network specs: chainId for EVM, slug for Bitcoin / Solana). - `localStorage.ts` used several keys that don't exist in the app: `openScan_theme`, `openScan_rpcStrategy`, `openScan_workerUrl`, `OPENSCAN_METADATA_RPCS`, `openScan_customNetworks`. The real layout (per `SettingsContext.tsx` and `configExportImport.ts`) is a single bundled `openScan_user_settings` JSON blob plus a top-level `openScan_language` override. Rewrite the helper to merge-patch the bundle via `setUserSetting`, and expose `readUserSetting` for assertions. Drop the phantom keys from the clear list. - `playwright.config.ts`: revert the gratuitous CI retries reduction from 3 → 2. The scaffolding commit shouldn't alter flakiness tuning; that belongs in its own change with evidence.
Land the cross-cutting specs the research flagged as highest-ROI gaps: - `shared/errors.spec.ts` (20 tests): assert the app root and footer stay mounted after navigation to non-existent block / tx / address, malformed input (non-hex, non-digit), and an unknown network slug. Across Ethereum, Arbitrum, Optimism, Base. Deliberately does not assert specific i18n copy so the suite doesn't rot when strings change. - `shared/settings.spec.ts` (6 tests): theme=light applies the `light-theme` body class; rpcStrategy and language overrides survive a reload; `setUserSetting` merges without clobbering sibling fields; `clearAppState` removes the bundled settings blob. Pure localStorage, no RPC dependency. - `shared/search.spec.ts` (10 tests): navbar search routes tx hashes / addresses / block numbers to the correct chain-scoped URL; malformed input stays on the page. Covers Ethereum, Arbitrum, Base. - `shared/mocked/nft-safety.spec.ts` (3 test.skip): regression test skeleton for the H-2 fix (`toSafeExternalHref`). Full implementation deferred to phase 4 because hermetic rendering of a token page requires stubbing `tokenURI` / `name` / `symbol` / `ownerOf` eth_calls *and* the metadata JSON fetch — too much surface for phase 1. - `shared/mocked/rpc-strategy.spec.ts` (4 test.skip): skeleton for fallback / parallel / race strategy verification + worker Cloudflare → Vercel failover. Deferred to phase 4 with the same rationale. Total: 281 → 329 tests (40 runnable + 7 skipped placeholders). Typecheck clean; Playwright discovers both the `chromium` (live) and `mocked` (hermetic) projects as defined in phase 0.
Self-review of c9873cc surfaced two issues: - `shared/settings.spec.ts`: the "rpcStrategy survives a reload" test used `addInitScript` to seed and then called `page.reload()`. But addInitScript re-runs on every navigation including the reload, so the assertion passed tautologically — it never actually exercised SettingsContext's write-back path. Rewrite as a single navigation that waits for the context mount effect to merge DEFAULT_SETTINGS with the seeded patch before asserting the seeded field is still present. Rename "survives a reload" to reflect what the test actually proves (hydration + write-back preserves seeded fields). Same rename for the language test. - `shared/mocked/nft-safety.spec.ts` and `shared/mocked/rpc-strategy.spec.ts`: skipped bodies contained `expect(true).toBe(true)` purely to make `expect` a used import. Drop the bodies and the expect import; add "— TODO phase 4" to each describe name so the CI report makes the defer explicit.
Add the assertions the research review flagged as the biggest quality
gap: the whole reason the L2 adapters exist (ArbitrumAdapter,
OptimismAdapter, BaseAdapter) is to surface fields the vanilla
EVMAdapter does not, and yet nothing in the current suite asserted any
of them.
- `evm-networks/l2-fields.spec.ts` (4 runnable + 3 skip-placeholders):
- Arbitrum tx: receipt `l1BlockNumber`.
- Arbitrum block: `sendCount`, `sendRoot` (L2→L1 messages).
- Optimism tx: `l1Fee`, `l1GasPrice`, `l1GasUsed`.
- Base tx: same OP-stack L1 fee breakdown.
Each test drives off the first tx / block already pinned in the
per-network fixture tables (`e2e/fixtures/{arbitrum,optimism,base}.ts`),
so we reuse data the team has already validated rather than inventing
fresh hashes.
- `e2e/fixtures/assertionsL2.ts` revision: split the original monolithic
`expectArbitrumL1Fields` into `expectArbitrumTxL1Fields` (for
`l1BlockNumber` on the tx page) and `expectArbitrumBlockFields` (for
`sendCount` / `sendRoot` on the block page) — the original helper
conflated two pages. Also swap the blob fields regex from
`Blob Gas Price` to `Excess Blob Gas`, which is what BlockDisplay.tsx
actually renders per `src/locales/en/block.json`. Label text sourced
by grepping the English locale files so the assertions match exactly
what the UI renders.
Blob-field assertions (Ethereum / OP / Base post-Dencun with real
blob-carrying blocks) deferred to phase 4 with explicit TODOs — picking
stable blob-bearing blocks per chain is a research task, and the
BlockDisplay component gates rendering on `blobGasUsed > 0`.
Self-review of 8176aea surfaced two minor cleanup items: - Remove every `await page.waitForLoadState("domcontentloaded", …)` call. Playwright's `expect(locator).toBeVisible()` already auto- retries until the element appears or DEFAULT_TIMEOUT elapses; the extra wait is a no-op under HashRouter (DOMContentLoaded fires before client-side routing) and only obscures intent. - `ARB_TX_HASH` selector simplified from `[1] ?? [0]` to `[0]`. Both Arbitrum fixture txs are post-Nitro and both carry `l1BlockNumber` in their receipts, so the first one is fine — there was no real reason to prefer the EIP-1559 entry over the legacy one. No behavior change; tests still discover as 7 specs (4 runnable + 3 deferred).
Production networks that were registered in `src/config/networks.json` and routed in `adaptersFactory.ts` but had zero e2e coverage: - `evm-networks/avalanche.spec.ts` (4 tests): block, address (WAVAX contract), zero address, placeholder tx. Avalanche C-Chain (43114) uses the default EVMAdapter path; these smokes are shallow but close the "any page at all renders" gap. - `solana/smoke.spec.ts` (5 tests): network landing, slots list, slot detail (canonical pinned slot), system-program account page, validators list. Solana adapter + pages existed with zero e2e — a regression would be invisible until a user reported it. Deep field assertions deferred to phase 4 with a `solana.ts` fixture. - `testnets/smoke.spec.ts` (18 tests): table-driven over the 6 EVM testnets registered via metadata v1.2.1-alpha.0 — Sepolia, Arb Sepolia, OP Sepolia, Base Sepolia, Polygon Amoy, Avalanche Fuji. Block + address + tx page per testnet. The 5 new testnets from PR 22f5845 shipped without CI gating; this restores that gate. 281 → 363 tests (40 runnable additions + 7 deferred placeholders). Removes the stray `.gitkeep` files from `solana/` and `testnets/` now that real specs live there. All new specs use the shared `expectStillMounted` pattern introduced in `shared/errors.spec.ts` and drive off `ALL_NETWORKS` / `EVM_TESTNETS` groupings from phase 0's `networks.ts`, so adding a new production network in the future only requires one fixture-table entry plus one spec file rather than copy-pasting a full template.
The phase 3 smokes (avalanche, solana, testnets) plus phase 1's errors.spec.ts each redefined the same `expectStillMounted` helper with the same footer selector and timeout constants. Four copies of a six-line function is copy-paste drift waiting to happen. Move the helper and its `FOOTER_SELECTOR` constant to `e2e/fixtures/assertions.ts` and import it from each spec. One file to update when the footer selector rotates or the mount-verification strategy changes. No test behavior change; 363 tests discover identically.
Add three shallow specs that cover cross-network features the existing suite touches only incidentally: - `shared/contract-interaction.spec.ts` (3 tests): on USDC mainnet, assert the "Read Functions (N)" and "Write Functions (N)" section headers render. Neither submits a transaction (wallet signing is out of scope for e2e). Plus one smoke on a non-verified address to verify the page still renders without an ABI. Label regex sourced from `src/locales/en/address.json` (`readFunctionsCount` / `writeFunctionsCount`). - `shared/ai-and-worker.spec.ts` (2 tests): on a tx page, assert the `<section class="ai-analysis-panel">` renders and the `.ai-analysis- button` is enabled. We don't click Analyze — that would burn Groq budget and couple to live availability. Worker failover (Cloudflare 5xx → Vercel) remains in the `mocked/rpc-strategy.spec.ts` TODO. - `shared/large-tx.spec.ts` (1 test): on the USDC approval tx pinned in `e2e/fixtures/mainnet.ts`, assert `.tx-log` row renders in `EventLogsTab`. Baseline coverage for the log-decode path; stress against a 100+ log tx deferred to phase 6 once a stable fixture is curated. Full hermetic `shared/mocked/nft-safety.spec.ts` (regression test for the H-2 `toSafeExternalHref` fix) remains a skip-placeholder. A robust version requires mocking `tokenURI` + `name` + `symbol` + `ownerOf` eth_calls as well as the metadata JSON fetch, which is still heavier than the phase-4 budget. 363 → 369 tests runnable (+6 runnable, skips unchanged).
Self-review of 8dd0d9a: the third `contract-interaction.spec.ts` test claimed to cover "contract with code but no verified source" but used the zero address — which is an EOA with zero bytecode. The assertion passed trivially and it duplicated `${net.name} — zero address renders` already present in `errors.spec.ts`. Remove the test rather than paper over it; note in a comment that a real unverified-contract coverage case is a phase-6 item that requires picking a stably-unverified mainnet contract. 369 → 368 tests runnable.
Extend the CI matrix so every spec group added in phases 1–4 has a trigger, and add a nightly cron so live-RPC drift between PRs is caught without blocking merges. - `e2e-evm-networks.yml`: add `avalanche` shard (phase 3 Avalanche smoke) and `l2-fields` shard (phase 2 L2 adapter assertions) to the existing matrix. - `e2e-shared.yml` (new): cross-network matrix over errors, search, settings, contract-interaction, ai-and-worker, large-tx. Six parallel shards, same shape as the evm-networks workflow. Uses the explicit `--project=chromium` flag so CI never accidentally runs the deferred `mocked` project's placeholder skips. - `e2e-solana.yml` (new): single job for `e2e/tests/solana/`. Solana RPC is discovered via `@openscan/metadata` — no dedicated secret required. - `e2e-testnets.yml` (new): single job for `e2e/tests/testnets/`. Same metadata-driven RPC discovery; takes the optional INFURA / ALCHEMY secrets for mainnet-adjacent cross-chain calls (ENS resolution during search). - `e2e-all.yml`: thread the three new workflows into the orchestrator so manual "run everything" and the nightly both hit them. - `e2e-nightly.yml` (new): 06:00 UTC cron that calls `e2e-all.yml`. Explicit comment in the header noting it must not gate merges — nightly red ≠ PR red. Total CI coverage: 6 shards (up from 5) in evm-networks, 6 new shards in shared, 1 new job each for solana / testnets, 1 nightly orchestrator. Each per-PR workflow still triggers on `pull_request` → `main`, preserving the existing gate model.
Phase 4's review commit re-scoped the "large-tx" spec down to a single "at least one event log renders" assertion but left the filename as-is. The file no longer exercises large-tx pagination or virtualization — it just covers event-log decoding for a single-log tx. Rename for honesty and update the CI matrix entry in `e2e-shared.yml` to match. True "large tx" stress (100+ logs, virtualization) remains a phase-6 backlog item.
End of the refactor. No `.only` markers, no commented-out tests, no unjustified timeouts in any spec added across phases 0–5. Two documentation updates: - `README.md`: expand the E2E section to reflect the new `e2e/tests/` layout (eth-mainnet, evm-networks, bitcoin, solana, testnets, shared, shared/mocked), list what each area covers, and describe the PR-vs-nightly CI triggers. Also document the two Playwright projects (`chromium` live + `mocked` hermetic) for readers who wonder why some specs are excluded from the default project. - `.claude/rules/commands.md`: add the `--project=chromium` invocation as a documented recipe so future contributors know how to skip the hermetic suite when they don't need it. Backlog not closed in this refactor (explicit TODOs landed in the placeholder spec bodies): - `shared/mocked/nft-safety.spec.ts` — H-2 regression with full `tokenURI` + metadata fetch mocking. - `shared/mocked/rpc-strategy.spec.ts` — fallback / parallel / race strategy verification plus Cloudflare → Vercel worker failover. - `evm-networks/l2-fields.spec.ts` — blob field assertions (blobGasUsed / excessBlobGas) on post-Dencun blocks. - `solana/` deep field assertions (need a curated `solana.ts` fixture equivalent to `mainnet.ts`). - Large-tx stress (100+ logs) in `event-logs.spec.ts`. - Unverified-contract coverage in `contract-interaction.spec.ts`. Final test count: 281 → 369 discovered (~88 additions; roughly 77 runnable + ~11 skip-placeholders documenting deferred work).
Self-review: the README E2E section described what exists but gave no pointer for how to extend it. Contributors reading the file fresh would need to reverse-engineer from existing specs + CI workflows to figure out where a new spec belongs. Add a short 4-step "Adding a new spec" block covering the four common cases (new network / cross-network feature / chain-specific feature / hermetic test) and which file + workflow touch each requires. Keeps the change narrow to docs so it can't regress the code.
Running the refactor-scoped suite against a local dev server exposed
four bugs, all in specs added during phases 2–4. No application code
changes.
- `event-logs.spec.ts`: `TxAnalyser` starts collapsed for non-
super-users (`collapsed = !isSuperUser`). Clicking the "Events (N)"
tab is what expands the panel and mounts `.tx-log`. The original
spec skipped this step. Also switch the fixture tx from the 2022
USDC approval (block 15M, flaky on public RPCs) to the EIP-1559
tx at block 20M that's already pinned in `mainnet.ts`.
- `contract-interaction.spec.ts`: two bugs —
1. USDC is a proxy; `ContractInteraction.tsx` surfaces only the
proxy's tiny admin ABI, so "Write Functions" never renders.
Swap to WETH9 (verified, non-proxy, small stable ABI).
2. Contract Details is collapsed by default. The `openContractDetails`
helper now waits explicitly for the header element and then
clicks it — the previous `Balance: OR Contract Details` race
could resolve on `Balance:` before the header mounted, causing
the subsequent `isVisible` check to return false and the click
to be skipped.
- `l2-fields.spec.ts` / `assertionsL2.ts`:
1. Default Playwright 5s timeout was too short — L2 receipts via
public RPC can take 10–20s. Bump the helper timeout to
`DEFAULT_TIMEOUT * 4` across all L2 assertions.
2. The Arbitrum tx / block cases need an RPC that returns
Arbitrum's extended receipt shape (`l1BlockNumber`, `sendCount`,
`sendRoot`). Public endpoints strip these fields and the local
Alchemy/Infura used in testing doesn't expose them either.
Mark both as `test.fixme` with an explicit comment — to be
un-fixmed once a confirmed Arbitrum-native RPC is wired into
CI secrets and a conditional skip on that env var is added.
The OP/Base L1 fee specs pass (OP clean, Base flaky-on-retry).
Run result on my local dev server with the test's Alchemy/Infura seed:
75 passed, 5 skipped (2 new fixme + 3 blob placeholders), 0 failed in
57s. Typecheck clean.
None of these tests come from the e2e refactor — they've been failing
intermittently on the `dev` branch against public RPCs because of the
same two root causes surfaced by the full-suite run:
1. `.loader-container` doesn't exist on `/blocks` — the component
renders a skeleton table while loading (`src/components/pages/evm/
blocks/index.tsx:165`). `toBeHidden({ timeout })` on that locator
therefore passes instantly, leaving the subsequent assertions to
race real data loading under default 5s timeouts. Rewrite the wait
to anchor on `.blocks-header-main` — the element that mounts only
in the data branch — with an RPC-sized budget.
2. Click-then-assert races on pagination: clicking "Older" triggers a
navigate + RPC round-trip. The 5s default for "Newer becomes
enabled" isn't enough when public endpoints are rate-limited.
Replace with `page.waitForURL(/fromBlock=/)` as the navigation
signal, then `toBeEnabled({ timeout: DEFAULT_TIMEOUT * 3 })`.
Covered:
- `blocks.spec.ts:5` (header) — anchor on data-branch element.
- `blocks.spec.ts:53` (single-line header) — same.
- `blocks.spec.ts:114` (pagination) — waitForURL + longer enabled-wait.
- `txs.spec.ts:120` (tx pagination navigate-between) — same
multiplier-bump treatment applied to all pagination assertions.
- `arbitrum.spec.ts:250` (Uniswap V3 swap details) — Arbitrum public
RPCs are slower than mainnet; every field assertion now gets the
standard `DEFAULT_TIMEOUT * 3`.
- `transaction.spec.ts:80` (input data tab) — the "Input Data" tab
lives inside `TxAnalyser`, which only mounts once `hasInputData`
is true — derived from the receipt, which arrives after
`waitForTxContent`. Explicit timeout on the tab assertion.
Re-run result on my local machine (public RPC, parallel workers):
before — 5 failed; after — 2 failed + 2 flaky (same tests), 51 passed.
The remaining 2 (USDC 2022 approval tx, Arbitrum V3 swap) appear to
hit an app-side stale-data bug when the public RPC returns a null /
partial tx — out of scope for e2e stability tuning.
…Price locator
Deep-dive on the last 2 "pre-existing" failures: the app is behaving
correctly in both cases; the tests had bugs.
1) `transaction.spec.ts` / `mainnet.ts` — the `USDC_APPROVAL` constant
pointed to `0xc55e2b90168af69721…`. The fixture entry for that hash
in `mainnet.ts` described it as a Type-2 USDC approval at block
15,537,394 with `hasInputData: true`. On-chain reality (verified
directly against a public RPC): that hash resolves to a **2016
Binance transfer at block 2,000,000** with `input: "0x"` (no
calldata). USDC did not deploy until 2018, so the fixture metadata
was fabricated.
The "displays transaction with input data" test looks for the
"Input Data" tab inside `TxAnalyser`, which only mounts when
`hasInputData` is true — derived from the actual tx.input byte
length. Against real RPCs it therefore never rendered and the test
timed out. Replace `USDC_APPROVAL` with `TX_WITH_INPUT_DATA`
pointing to `0xbb4b3fc2…` (the EIP-1559 tx at block 20M already
pinned in the fixture and verified to have 242 bytes of input
data). Remove the stale USDC entry from `mainnet.ts` with a
comment explaining what was wrong, so nobody reads the old
metadata and re-imports it.
2) `arbitrum.spec.ts:250` — the locator
`locator(".tx-label", { hasText: "Gas Price:" })` matches two
spans on Arbitrum post-Nitro pages: `Gas Price:` AND
`Effective Gas Price:` (receipt vs. tx). Playwright's
`toBeVisible` in strict mode fails when the locator resolves to
multiple elements. My first fix attempt (`/^Gas Price:$/`) also
failed because the span's textContent is `"Gas Price:" +` the
HelperTooltip's text — the span is not a pure text node. Use a
start-anchored regex `/^Gas Price:/` (no `$`) so the match
allows the tooltip suffix but still excludes the "Effective"-
prefixed sibling.
Re-ran both specs in isolation: 8/8 passed in 1.3m. The refactor-
scoped suite also still passes unchanged. Zero changes to the app.
|
🚀 Preview: https://pr-366--openscan.netlify.app |
MatiasOS
approved these changes
Apr 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
End-to-end test suite refactor addressing the gaps identified in the earlier e2e coverage review. Adds cross-network shared specs, L2 adapter-field assertions, coverage for previously orphaned production networks (Avalanche, Solana) and the 6 EVM testnets, plus scaffolding (typed network fixture table, hermetic
mockedPlaywright project, assertion helpers) so future specs are additions rather than copy-paste. Structured as 7 phases, each with its own implementation commit and a self-review commit. Ends with a live-RPC run of the full suite on a local dev server (350/361 pass) and fixes for every failure surfaced.Zero app code changed.
Related Issue
Internal e2e coverage review.
Type of Change
Changes Made
Phase 0 — Scaffolding (
6294053,962a266)e2e/fixtures/networks.ts— typed fixture table for every production + testnet network withchainId,slug,family,urlPath, and canonical block/tx/address/token. Drives cross-network iteration.e2e/fixtures/localStorage.ts—clearAppState,setLanguage,setTheme,setRpcStrategy,setUserSetting,readUserSetting. Keys verified againstSettingsContext.tsx/configExportImport.ts.e2e/fixtures/rpcMock.ts—page.routehelpers for JSON-RPC stubs, HTTP errors, 429-then-success, offline.e2e/fixtures/assertionsL2.ts+assertions.ts— reusable L2 field assertions andexpectStillMountedsmoke helper.e2e/fixtures/test.ts— bounded retries with per-retry logging.playwright.config.ts— split intochromium(live) andmocked(hermetic) projects.Phase 1 — Cross-network shared specs (
c9873cc,d6d3c23)shared/errors.spec.ts(25 tests) — 404 tx / 404 block / malformed input / zero address / unknown network across Ethereum, Arbitrum, Optimism, Base.shared/settings.spec.ts(6 tests) — theme / rpcStrategy / language persistence through the bundledopenScan_user_settingsblob.shared/search.spec.ts(10 tests) — navbar search routes tx / address / block across chains.shared/mocked/nft-safety.spec.ts,shared/mocked/rpc-strategy.spec.ts— skeletons with explicit "TODO phase 4" markers.Phase 2 — L2 adapter field assertions (
8176aea,2908954)evm-networks/l2-fields.spec.ts— first specs that assert the fields the L2 adapters exist to surface: Arbitruml1BlockNumber/sendCount/sendRoot, OP-stackl1Fee/l1GasPrice/l1GasUsed. Drives off the per-network fixture tables. Blob-field assertions deferred with TODOs.Phase 3 — Orphaned-network coverage (
51c59a9,d87ea40)evm-networks/avalanche.spec.ts(4 tests) — C-Chain (43114) smoke.solana/smoke.spec.ts(5 tests) — network / slots / slot detail / account / validators.testnets/smoke.spec.ts(18 tests) — table-driven over Sepolia, Arb Sepolia, OP Sepolia, Base Sepolia, Polygon Amoy, Avalanche Fuji.Phase 4 — Feature depth (
8dd0d9a,ebfa9ab)shared/contract-interaction.spec.ts— Read/Write function section headers on WETH9 (verified, non-proxy).shared/ai-and-worker.spec.ts— AI Analysis panel + button rendering on tx pages.shared/event-logs.spec.ts—.tx-logrendering inEventLogsTab.Phase 5 — CI wiring (
f0e5a8e,5a1bd3b)e2e-shared.yml— 6-shard matrix for the cross-network specs.e2e-solana.yml,e2e-testnets.yml— new workflows.e2e-nightly.yml— 06:00 UTC cron callinge2e-all.yml, explicitly documented as non-blocking.e2e-evm-networks.ymlmatrix extended withavalanche+l2-fieldsshards.e2e-all.ymlorchestrator threads the new workflows.Phase 6 — Docs (
f4516fe,25efaca)README.md— expanded E2E section with directory layout, CI trigger matrix, and an "Adding a new spec" contributor guide..claude/rules/commands.md— documented--project=chromiumrecipe.Post-run fixes (
e5127ee,5512207,0ad83f3)Running the suite against a local dev server surfaced real bugs, all in tests (refactor-scoped and pre-existing), none in app code:
e5127ee— refactor specs:TxAnalyserstarts collapsed (need to click Events tab first); USDC is a proxy so Read/Write sections don't render (switched to WETH9); L2 assertion timeouts bumped; Arbitrum L1-field specs markedfixmepending an Arbitrum-native RPC.5512207— 3 of 5 pre-existing failing mainnet specs:.loader-containerdoesn't exist on/blocks(skeleton table only); pagination click-then-assert races; Arbitrum Uniswap V3 test needed longer timeouts.0ad83f3— last 2 pre-existing failures, both test-data bugs:mainnet.tshad a fabricated fixture: hash0xc55e2b90…labeled as "Type-2 USDC approval block 15,537,394" actually resolves on-chain to a 2016 Binance transfer at block 2M with empty input. USDC didn't deploy until 2018. Swapped to0xbb4b3fc2…(verified EIP-1559 tx at block 20M with 242 bytes input data).Gas Price:andEffective Gas Price:spans (strict-mode violation). Start-anchored regex/^Gas Price:/isolates the target.Test plan
npm run typecheck— passes.npm run format:fix/npm run lint:fix— clean (one pre-existinggetAlchemyBtcUrlwarning unrelated).npx playwright test --project=chromiumrun on local dev server: 350 passed, 5 failed, 1 flaky, 5 skipped, 29 min.Additional Notes
SECURITY_REVIEW_2026-04-23.mdis intentionally not tracked by this branch — it belongs to the earlier security review task.shared/mocked/nft-safety.spec.ts).shared/mocked/rpc-strategy.spec.ts).event-logs.spec.ts.