Uniswap / web-e2e

Run, create, and debug Playwright e2e tests for the web app. ALWAYS invoke this skill using the SlashCommand tool (i.e., `/web-e2e`) BEFORE attempting to run any e2e tests, playwright tests, anvil tests, or debug test failures. DO NOT run `bun playwright test` or other e2e commands directly - you must invoke this skill first to learn the correct commands and test architecture.

1 views
0 installs

Skill Content

---
name: web-e2e
description: Run, create, and debug Playwright e2e tests for the web app. ALWAYS invoke this skill using the SlashCommand tool (i.e., `/web-e2e`) BEFORE attempting to run any e2e tests, playwright tests, anvil tests, or debug test failures. DO NOT run `bun playwright test` or other e2e commands directly - you must invoke this skill first to learn the correct commands and test architecture.
allowed-tools: [Read, Write, Edit, Bash, Glob, Grep, mcp__playwright__browser_navigate, mcp__playwright__browser_snapshot, mcp__playwright__browser_click, mcp__playwright__browser_type, mcp__playwright__browser_take_screenshot, mcp__playwright__browser_console_messages, mcp__playwright__browser_network_requests, mcp__playwright__browser_evaluate]
---

# Web E2E Testing Skill

This skill helps you create and run end-to-end (e2e) Playwright tests for the Uniswap web application.

## Test Architecture

### Test Location
- All e2e tests live in `apps/web/src/` directory structure
- Test files use the naming convention: `*.e2e.test.ts`
- Anvil-specific tests (requiring local blockchain): `*.anvil.e2e.test.ts`

### Automatic Wallet Connection

**Important**: When running Playwright tests, the app automatically connects to a test wallet:
- **Address**: `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` (constant: `TEST_WALLET_ADDRESS`)
- **Display name**: `test0` (the Unitag associated with this address)
- **Connection**: Happens automatically via `wagmiAutoConnect.ts` when in Playwright environment

This means:
- Tests start with a wallet already connected
- You can immediately test wallet-dependent features
- The wallet button will show "test0" instead of "Connect wallet"

**When using Playwright MCP**: To enable automatic wallet connection when browsing via MCP tools, set the environment variable `REACT_APP_IS_PLAYWRIGHT_ENV=true` before starting the dev server. This makes the app behave identically to how it does in automated tests, with the test wallet auto-connected.

### Custom Fixtures

The web app uses custom Playwright fixtures and mocks that extend base Playwright functionality.
They are located in `apps/web/src/playwright/fixtures/*` and `apps/web/src/playwright/mocks/*`.

#### Import Pattern
```typescript
import { expect, getTest } from 'playwright/fixtures'

// For regular tests (no blockchain)
const test = getTest()

// For anvil tests (with blockchain)
const test = getTest({ withAnvil: true })
```

#### Available Fixtures

1. **graphql** - Mock GraphQL responses
   ```typescript
   await graphql.intercept('OperationName', Mocks.Path.to_mock)
   await graphql.waitForResponse('OperationName')
   ```

2. **anvil** - Local blockchain client (only in anvil tests)
   ```typescript
   // Set token balances
   await anvil.setErc20Balance({ address, balance })

   // Check balances
   await anvil.getBalance({ address })
   await anvil.getErc20Balance(tokenAddress, ownerAddress)

   // Manage allowances
   await anvil.setErc20Allowance({ address, spender, amount })
   await anvil.setPermit2Allowance({ token, spender, amount })

   // Mining blocks
   await anvil.mine({ blocks: 1 })

   // Snapshots for isolation
   const snapshotId = await anvil.takeSnapshot()
   await anvil.revertToSnapshot(snapshotId)
   ```

3. **tradingApi** - Mock Trading API responses
   ```typescript
   await stubTradingApiEndpoint({
     page,
     endpoint: uniswapUrls.tradingApiPaths.swap
   })
   ```

4. **amplitude** - Analytics mocking (automatic)

### Test Structure

```typescript
import { expect, getTest } from 'playwright/fixtures'
import { TestID } from 'uniswap/src/test/fixtures/testIDs'

const test = getTest({ withAnvil: true }) // or getTest() for non-anvil

test.describe('Feature Name', () => {
  test.beforeEach(async ({ page }) => {
    // Setup before each test
  })

  test('should do something', async ({ page, anvil, graphql }) => {
    // Setup mocks
    await graphql.intercept('Operation', Mocks.Path.mock)

    // Setup blockchain state (if anvil test)
    await anvil.setErc20Balance({ address, balance })

    // Navigate to page
    await page.goto('/path')

    // Interact with UI using TestIDs
    await page.getByTestId(TestID.SomeButton).click()

    // Make assertions
    await expect(page.getByText('Expected Text')).toBeVisible()
  })
})
```

### Best Practices

1. **Use TestIDs** - Always use the TestID enum for selectors (not string literals)
   ```typescript
   // Good
   await page.getByTestId(TestID.ReviewSwap)

   // Bad
   await page.getByTestId('review-swap')
   ```

2. **Mock External Services** - Use fixtures to mock GraphQL, Trading API, REST API etc.
   ```typescript
   await graphql.intercept('PortfolioBalances', Mocks.PortfolioBalances.test_wallet)
   await stubTradingApiEndpoint({ page, endpoint: uniswapUrls.tradingApiPaths.quote })
   ```

3. **Use Mocks Helper** - Import mock paths from `playwright/mocks/mocks.ts`
   ```typescript
   import { Mocks } from 'playwright/mocks/mocks'
   await graphql.intercept('Token', Mocks.Token.uni_token)
   ```

4. **Test Constants** - Use constants from the codebase
   ```typescript
   import { USDT, DAI } from 'uniswap/src/constants/tokens'
   import { TEST_WALLET_ADDRESS } from 'playwright/fixtures/wallets'

   // TEST_WALLET_ADDRESS is the automatically connected wallet
   // It displays as "test0" in the UI
   ```

5. **Anvil State Management** - Set up blockchain state properly
   ```typescript
   // Always set token balances before testing swaps
   await anvil.setErc20Balance({
     address: assume0xAddress(USDT.address),
     balance: 100_000_000n
   })
   ```

## Running Tests

The following commands must be run from the `apps/web/` folder.

**⚠️ PREREQUISITE**: Playwright tests require the Vite preview server to be running at `http://localhost:3000` BEFORE tests start. The `bun e2e` commands handle this automatically, but if running tests directly you must start the server first.

### Development Commands

The `e2e` commands handle all requisite setup tasks for the playwright tests. These include building the app for production and running the Vite preview server.

```bash
# Run all e2e tests (starts anvil, builds, and runs tests)
bun e2e

# Run only non-anvil tests (faster, no blockchain required)
bun e2e:no-anvil

# Run only anvil tests (blockchain tests only)
bun e2e:anvil

# Run specific test file
bun e2e TokenSelector.e2e.test
```

### Direct Playwright Commands

In some cases it may be helpful to run the commands more directly with the different tasks in different terminals.

```bash
# Step 1: Build the web app for e2e
bun build:e2e

# Step 2: Start the Vite preview server (REQUIRED - must be running before tests)
bun preview:e2e
# Wait for "Local: http://localhost:3000" message

# (Optional) Step 3: Start Anvil (note, Anvil tests can start this themselves)
bun anvil:mainnet
# Wait for "Listening on 127.0.0.1:8545" message

# Step 4: Run the playwright tests (only after servers are ready)
bun playwright:test
```

### Test Modes

```bash
# Headed mode (see browser)
bun playwright test --headed

# Debug mode with Playwright Inspector
bun playwright test --debug

# UI mode (interactive)
bun playwright test --ui
```

## Configuration

### Playwright Config (`playwright.config.ts`)

Key settings:
- `testDir`: `./src`
- `testMatch`: `**/*.e2e.test.ts`
- `workers`: 1 (configured in CI)
- `fullyParallel`: false
- `baseURL`: `http://localhost:3000`

## Common Patterns

### Navigation and URL Testing
```typescript
await page.goto('/swap?inputCurrency=ETH&outputCurrency=USDT')
await expect(page.getByTestId(TestID.ChooseInputToken + '-label')).toHaveText('ETH')
```

### Form Interactions
```typescript
await page.getByTestId(TestID.AmountInputIn).fill('0.01')
await page.getByTestId(TestID.AmountInputIn).clear()
```

### Token Selection
```typescript
await page.getByTestId(TestID.ChooseOutputToken).click()
await page.getByTestId('token-option-1-USDT').first().click()
```

### Waiting for Transaction Completion
```typescript
await page.getByTestId(TestID.Swap).click()
await expect(page.getByText('Swapped')).toBeVisible()
```

### Blockchain Verification
```typescript
const balance = await anvil.getBalance({ address: TEST_WALLET_ADDRESS })
await expect(balance).toBeLessThan(parseEther('10000'))
```

## Troubleshooting

### Tests Timeout
- Check if Anvil is running: `bun anvil:mainnet`
- Ensure preview server is running: `bun preview:e2e`

### Anvil Issues
- Tests automatically manage Anvil snapshots for isolation
- Anvil restarts automatically if unhealthy
- For manual restart: stop the e2e command and run again

### Mock Not Working
- Ensure mock path is correct in `Mocks` object
- Check GraphQL operation name matches exactly
- Verify timing - intercept before the request is made

### Test Flakiness
- Use proper waiting: `await expect(element).toBeVisible()`
- Don't use fixed `setTimeout` - use Playwright's auto-waiting
- Check for race conditions with network requests

### Debugging

- Run tests with `--headed` flag to watch the browser
- Use `--debug` flag to step through with Playwright Inspector
- Add `await page.pause()` in your test to stop at a specific point
- Check test output and error messages carefully
- Review screenshots/videos in `test-results/` directory after failures

## Playwright Documentation References

For more details on Playwright features, refer to:

- **[Writing Tests](https://playwright.dev/docs/writing-tests)** - Test structure, actions, assertions
- **[Test Fixtures](https://playwright.dev/docs/test-fixtures)** - Creating custom fixtures (like our anvil/graphql fixtures)
- **[Running Tests](https://playwright.dev/docs/running-tests)** - Command line options, filtering, debugging
- **[API Testing](https://playwright.dev/docs/api-testing)** - Mocking and intercepting network requests
- **[Locators](https://playwright.dev/docs/locators)** - Finding elements (we use `getByTestId` primarily)
- **[Assertions](https://playwright.dev/docs/test-assertions)** - Available expect matchers
- **[Test Hooks](https://playwright.dev/docs/api/class-test#test-before-each)** - beforeEach, afterEach, beforeAll, afterAll
- **[Test Configuration](https://playwright.dev/docs/test-configuration)** - playwright.config.ts options
- **[Debugging Tests](https://playwright.dev/docs/debug)** - UI mode, inspector, trace viewer

## Playwright MCP Integration (Optional but Recommended)

The Playwright MCP (Model Context Protocol) provides browser automation capabilities that make test development and debugging easier:
- **Interactive debugging** - Navigate the app in a real browser to understand behavior
- **Creating tests** - Explore the UI to identify selectors and interactions
- **Debugging failures** - Inspect page state when tests fail

### Installing Playwright MCP

If you don't have the Playwright MCP installed, you can add it to your Claude Code configuration:

1. Open Claude Code settings (Command/Ctrl + Shift + P → "Claude Code: Open Settings")
2. Add the Playwright MCP to your `mcpServers` configuration:

```json
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["-y", "@executeautomation/playwright-mcp-server"]
    }
  }
}
```

3. Restart Claude Code

Alternatively, follow the installation guide at: https://github.com/executeautomation/playwright-mcp

### Using Playwright MCP for Test Development (Optional)

**If you have the MCP installed**, you can use these tools during development:

1. **Navigate and explore** - Use `mcp__playwright__browser_navigate` to visit pages
2. **Take snapshots** - Use `mcp__playwright__browser_snapshot` to see the page structure and find TestIDs
3. **Interact with elements** - Use `mcp__playwright__browser_click` and `mcp__playwright__browser_type` to test interactions
4. **Inspect state** - Use `mcp__playwright__browser_console_messages` and `mcp__playwright__browser_network_requests` to debug
5. **Take screenshots** - Use `mcp__playwright__browser_take_screenshot` to visualize issues

## When to Use This Skill

Use this skill when you need to:
- Create new end-to-end tests for web features
- Debug or fix failing e2e tests
- Run e2e tests during development
- Understand the e2e testing architecture
- Set up test fixtures or mocks
- Work with Anvil blockchain state in tests