test(wallet): Tier-2 browser-signing e2e (Playwright + mock provider on anvil)#380
Merged
Conversation
…on anvil) Add a headless, deterministic Tier-2 e2e harness that drives the real bridge page (bridgePage.ts) in chromium with an injected mock window.ethereum. eth_sendTransaction is delegated to Node via page.exposeFunction(__glSign), where a viem local account (anvil dev key) actually signs+broadcasts to an ephemeral anvil, so the full loop runs for real: bridge + page JS + session daemon + chain, with zero human/extension. Lanes (all green on anvil): - S1 connect/status/disconnect (descriptor 0600, /api/ping, teardown) - S2 validator-join --wallet browser signs + mines against a recording StakingStub, asserted via real receipt + on-chain callCount - S4 session reuse: two sequential joins over one daemon/tab - S5 config default walletMode=browser; --wallet keystore overrides - S6 user-reject (4001) + tab-closed fail-fast (short env timeouts) Lane B (S3, IC deploy on Docker localnet) is deferred as a nightly follow-up: describe.skip guarded by GENLAYER_E2E_LOCALNET. Prod-safe support changes: GENLAYER_E2E_* env overrides for the timing constants (unset in prod) and a GENLAYER_E2E_NO_OPEN guard so the daemon does not auto-open a system browser under test. New e2e-wallet.yml CI job (informational, not a required gate initially). Playwright specs are kept out of the vitest glob so test:coverage is unaffected.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
What
Adds the Tier-2 browser-wallet signing e2e harness for genlayer-cli, per the design doc. It drives the real daemon bridge page (
src/lib/wallet/bridgePage.ts) in a headless chromium with an injected mockwindow.ethereum, and delegates signing to Node viapage.exposeFunction("__glSign", …)where a viem local account (anvil dev key) actually signs + broadcastseth_sendTransactionto an ephemeral anvil, returning a real tx hash.So the full loop runs for real — bridge + served page JS + session daemon + real chain — with zero human and zero MetaMask.
How the mock works
e2e/fixtures/mockProvider.ts—installMockProvider({address, chainIdHex, behavior})returns an init-script string installed viapage.addInitScript(...)beforepage.goto()(beats the injection race). Behaviors:approve|reject(4001) |wrong-network(4901).eth_sendTransaction→window.__glSign.e2e/helpers/bridgePage.ts— launches chromium, wires__glSignto a viemsendTransactionon anvil, injects the mock, and drives connect.e2e/fixtures/chain.ts—startAnvil()boots anvil on a random port and deploys the recordingStakingStub.e2e/fixtures/cli.ts— runsdist/index.jsunder a scratchHOMEwith a seeded custom-network config (chain-id / rpc / staking → the anvil + stub) soensureChain()matches;spawnConnect()scrapes the printed session URL.Lanes (all green on anvil, ~16s, serial
workers:1)0600{pid live, port, token, address, chainId},/api/ping200, "Connected as …", teardown removes descriptor + pid.staking validator-join --wallet browser— page auto-signs → asserted via a real receipt + on-chain stubcallCount.walletMode=browser— barevalidator-joinsigns via session;--wallet keystoreoverrides (keystore path, no enqueue).page.close()→ stale heartbeat → fail-fast "tab appears to be closed"). ShortGENLAYER_E2E_*timeout overrides keep these in seconds.Staking stub
e2e/fixtures/StakingStub.sol(+ committed compiledStakingStub.json) is a ~10-line recording stub:validatorJoin()/validatorJoin(address)are payable, record the call (callCount,lastOperator/Validator/Amount), and emit theValidatorJoin(operator, validator, amount)event the CLI decodes. It proves the sign→broadcast→receipt loop only — no consensus.Deferred (nightly follow-up)
localnet:describe.skip, guarded byGENLAYER_E2E_LOCALNET, documented ine2e/lane-b-deploy.e2e.ts. Bare anvil has no GenVM/consensus.Prod-safe support changes
sessionConstants.ts—GENLAYER_E2E_{LONG_POLL,HEARTBEAT_DEAD,CONNECT_TIMEOUT}_MSoverrides; unset/invalid → production defaults unchanged.browserBridge.ts— skipopenUrlwhenGENLAYER_E2E_NO_OPENis set (harness drives its own chromium); production unaffected.CI
New
.github/workflows/e2e-wallet.yml(distinct name from the syncede2e.yml): ubuntu + node 20 →npm ci→ build → foundry-toolchain →playwright install --with-deps chromium→npm run test:e2e. Informational — keep off required checks until stable, then promote.How to run
Verification
npm run test:e2e→ 9 passed, 1 skipped (Lane B), stable across 3 runs.npm run test:coverage(Tier-1 vitest) → 733 passed; Playwright specs excluded from the vitest glob.npm run buildclean;tsc --noEmit= 32 errors (pre-existing baseline, zero new).