e2e-testing-web3

Playwright E2E test patterns for Web3 and blockchain features — mocking wallet providers (MetaMask, Phantom), testing wallet connection flows, and handling async blockchain confirmations.

8 stars

Best use case

e2e-testing-web3 is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Playwright E2E test patterns for Web3 and blockchain features — mocking wallet providers (MetaMask, Phantom), testing wallet connection flows, and handling async blockchain confirmations.

Teams using e2e-testing-web3 should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/e2e-testing-web3/SKILL.md --create-dirs "https://raw.githubusercontent.com/marvinrichter/clarc/main/skills/e2e-testing-web3/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/e2e-testing-web3/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How e2e-testing-web3 Compares

Feature / Agente2e-testing-web3Standard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Playwright E2E test patterns for Web3 and blockchain features — mocking wallet providers (MetaMask, Phantom), testing wallet connection flows, and handling async blockchain confirmations.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# E2E Testing — Web3 & Blockchain

Playwright patterns for testing applications that integrate with browser wallets and blockchain transactions.

## When to Activate

- Writing E2E tests for wallet connection flows (MetaMask, Phantom, WalletConnect)
- Testing DeFi features that trigger on-chain transactions
- Mocking browser wallet providers (`window.ethereum`, `window.solana`) in tests
- Handling async blockchain confirmation waits in test flows

> For general Playwright E2E patterns (page objects, CI artifacts, visual testing) — see skill `e2e-testing`.

## Wallet / Web3 Testing

### Mock Wallet Provider (Ethereum/MetaMask)

```typescript
test('wallet connection', async ({ page, context }) => {
  // Mock wallet provider
  await context.addInitScript(() => {
    window.ethereum = {
      isMetaMask: true,
      request: async ({ method }) => {
        if (method === 'eth_requestAccounts')
          return ['0x1234567890123456789012345678901234567890']
        if (method === 'eth_chainId') return '0x1'
      }
    }
  })

  await page.goto('/')
  await page.locator('[data-testid="connect-wallet"]').click()
  await expect(page.locator('[data-testid="wallet-address"]')).toContainText('0x1234')
})
```

### Financial / Critical Flow Testing

```typescript
test('trade execution', async ({ page }) => {
  // Skip on production — real money
  test.skip(process.env.NODE_ENV === 'production', 'Skip on production')

  await page.goto('/markets/test-market')
  await page.locator('[data-testid="position-yes"]').click()
  await page.locator('[data-testid="trade-amount"]').fill('1.0')

  // Verify preview
  const preview = page.locator('[data-testid="trade-preview"]')
  await expect(preview).toContainText('1.0')

  // Confirm and wait for blockchain
  await page.locator('[data-testid="confirm-trade"]').click()
  await page.waitForResponse(
    resp => resp.url().includes('/api/trade') && resp.status() === 200,
    { timeout: 30000 }
  )

  await expect(page.locator('[data-testid="trade-success"]')).toBeVisible()
})
```

## Wallet Rejection Flow

```typescript
test('wallet rejection shows error state', async ({ page, context }) => {
  await context.addInitScript(() => {
    window.ethereum = {
      isMetaMask: true,
      request: async ({ method }) => {
        if (method === 'eth_requestAccounts') {
          // Simulate user clicking "Reject" in MetaMask
          throw { code: 4001, message: 'User rejected the request.' }
        }
        if (method === 'eth_chainId') return '0x1'
      }
    }
  })

  await page.goto('/')
  await page.locator('[data-testid="connect-wallet"]').click()

  // Error state should appear, not the wallet address
  await expect(page.locator('[data-testid="wallet-error"]')).toContainText('rejected')
  await expect(page.locator('[data-testid="wallet-address"]')).not.toBeVisible()
})
```

## Network Switch Required

```typescript
test('prompts network switch when on wrong chain', async ({ page, context }) => {
  await context.addInitScript(() => {
    window.ethereum = {
      isMetaMask: true,
      chainId: '0x89',  // Polygon, not mainnet
      request: async ({ method, params }) => {
        if (method === 'eth_requestAccounts')
          return ['0xdeadbeef00000000000000000000000000000000']
        if (method === 'eth_chainId') return '0x89'
        if (method === 'wallet_switchEthereumChain')
          throw { code: 4902, message: 'Chain not added' }
      }
    }
  })

  await page.goto('/')
  await page.locator('[data-testid="connect-wallet"]').click()

  // App should prompt user to switch networks
  await expect(page.locator('[data-testid="wrong-network-banner"]')).toBeVisible()
  await expect(page.locator('[data-testid="switch-network-btn"]')).toBeVisible()
})
```

## Gas Estimation Failure

```typescript
test('shows gas error when estimation fails', async ({ page, context }) => {
  await context.addInitScript(() => {
    window.ethereum = {
      isMetaMask: true,
      request: async ({ method }) => {
        if (method === 'eth_requestAccounts')
          return ['0x1234567890123456789012345678901234567890']
        if (method === 'eth_chainId') return '0x1'
        if (method === 'eth_estimateGas')
          throw { code: -32603, message: 'execution reverted: insufficient balance' }
      }
    }
  })

  await page.goto('/swap')
  await page.locator('[data-testid="amount-input"]').fill('999999')
  await page.locator('[data-testid="swap-btn"]').click()

  await expect(page.locator('[data-testid="gas-error"]')).toContainText('insufficient balance')
  await expect(page.locator('[data-testid="swap-btn"]')).toBeDisabled()
})
```

## Web3 Test Checklist

- [ ] Wallet provider mocked via `addInitScript` (not real wallet)
- [ ] Blockchain confirmations awaited with generous timeout (30s+)
- [ ] Production guard applied to tests involving real transactions
- [ ] Wallet address assertions use `toContainText` (partial match — chain-dependent format)
- [ ] Error states tested: rejected wallet request, insufficient funds, network switch required

Related Skills

visual-testing

8
from marvinrichter/clarc

Visual Regression Testing: tool comparison (Chromatic/Percy/Playwright screenshots/BackstopJS), pixel-diff vs AI-based comparison, baseline management, flakiness strategies (masks, tolerances, waitForLoadState), CI integration with GitHub Actions, and Storybook integration.

typescript-testing

8
from marvinrichter/clarc

TypeScript testing patterns: Vitest for unit/integration, Playwright for E2E, MSW for API mocking, Testing Library for React components. Core TDD methodology for TypeScript/JavaScript projects.

swift-testing

8
from marvinrichter/clarc

Swift testing patterns: Swift Testing framework (Swift 6+), XCTest for UI tests, async/await test cases, actor testing, Combine testing, and XCUITest for UI automation. TDD for Swift/SwiftUI.

swift-protocol-di-testing

8
from marvinrichter/clarc

Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.

security-review-web3

8
from marvinrichter/clarc

Security patterns for Web3 and blockchain applications — Solana wallet signature verification, transaction validation, smart contract interaction security, and checklist for DeFi/NFT features.

scala-testing

8
from marvinrichter/clarc

Scala testing with ScalaTest, MUnit, and ScalaCheck: FunSpec/FlatSpec test structure, property-based testing with forAll, mocking with MockitoSugar, Cats Effect testing with munit-cats-effect (runTest/IOSuite), ZIO Test, Testcontainers-Scala for database integration tests, and CI integration with sbt. Use when writing or reviewing Scala tests.

rust-testing

8
from marvinrichter/clarc

Rust testing patterns — unit tests with mockall, integration tests with sqlx transactions, HTTP handler testing (axum), benchmarks (criterion), property tests (proptest), fuzzing, and CI with cargo-nextest.

rust-testing-advanced

8
from marvinrichter/clarc

Advanced Rust testing anti-patterns and corrections — cfg(test) placement, expect() over unwrap(), mockall expectation ordering, executor mixing (#[tokio::test] vs block_on), PgPool isolation with

ruby-testing

8
from marvinrichter/clarc

RSpec testing patterns for Ruby and Rails — factories, mocks, request specs, feature specs, VCR, and SimpleCov coverage.

r-testing

8
from marvinrichter/clarc

R testing patterns: testthat 3e with expect_* assertions, snapshot testing, mocking with mockery and httptest2, covr code coverage, lintr static analysis, property-based testing with hedgehog, testing Shiny apps with shinytest2. Use when writing or reviewing R tests.

python-testing

8
from marvinrichter/clarc

Python testing strategies using pytest, TDD methodology, fixtures, mocking, and parametrization. Core testing fundamentals.

python-testing-advanced

8
from marvinrichter/clarc

Advanced Python testing — async testing with pytest-asyncio, exception/side-effect testing, test organization, common patterns (API, database, class methods), pytest configuration, and CLI reference. Extends python-testing.