home / skills / ladderchaos / tora-skills / synpress-e2e
This skill guides end-to-end testing of Web3 dApps with Synpress, automating wallet interactions, transactions, and on-chain verifications.
npx playbooks add skill ladderchaos/tora-skills --skill synpress-e2eReview the files below or copy the command above to add this skill to your agents.
---
name: synpress-e2e
description: End-to-end testing with wallet automation using Synpress. Use this skill for testing dApp flows that require MetaMask/wallet interactions, transaction signing, and on-chain verification.
---
# Synpress E2E Testing
This skill guides E2E testing of Web3 dApps using Synpress, which extends Playwright with MetaMask automation capabilities.
## When to Use This Skill
Invoke this skill when:
- Testing wallet connection flows
- Testing transaction signing
- Testing on-chain state changes
- Automating multi-step DeFi interactions
- Testing wallet-dependent UI states
## Prerequisites
### Installation
```bash
cd apps/web
pnpm add -D @synthetixio/synpress
```
### Environment Setup
Create `.env.e2e`:
```bash
# Test wallet (DO NOT use with real funds)
TEST_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
TEST_NETWORK_NAME=Base Sepolia
TEST_NETWORK_RPC=https://sepolia.base.org
TEST_CHAIN_ID=84532
```
## Synpress Test Structure
### Basic Test Template
```typescript
// apps/web/e2e/wallet-connect.spec.ts
import { testWithSynpress } from '@synthetixio/synpress';
import { MetaMask, metaMaskFixtures } from '@synthetixio/synpress/playwright';
const test = testWithSynpress(metaMaskFixtures);
test.describe('Wallet Connection', () => {
test('should connect wallet', async ({ page, metamask }) => {
// Navigate to app
await page.goto('http://localhost:5173');
// Click connect button
await page.click('[data-testid="connect-wallet"]');
// Approve connection in MetaMask
await metamask.connectToDapp();
// Verify connected state
await expect(page.locator('[data-testid="wallet-address"]')).toBeVisible();
});
});
```
### Transaction Test Template
```typescript
test('should place an order', async ({ page, metamask }) => {
// Setup: Connect wallet
await page.goto('http://localhost:5173/market/1');
await page.click('[data-testid="connect-wallet"]');
await metamask.connectToDapp();
// Action: Fill order form
await page.fill('[data-testid="order-amount"]', '100');
await page.click('[data-testid="place-order-btn"]');
// Handle MetaMask confirmation
await metamask.confirmTransaction();
// Verify: Check transaction success
await expect(page.locator('text=Order placed')).toBeVisible({ timeout: 30000 });
});
```
## Synpress Commands Reference
### Wallet Setup
```typescript
// Import wallet from private key
await metamask.importWallet(process.env.TEST_PRIVATE_KEY);
// Add custom network
await metamask.addNetwork({
name: 'Base Sepolia',
rpcUrl: 'https://sepolia.base.org',
chainId: 84532,
symbol: 'ETH',
});
// Switch network
await metamask.switchNetwork('Base Sepolia');
```
### Transaction Handling
```typescript
// Confirm transaction (approve gas)
await metamask.confirmTransaction();
// Confirm with custom gas
await metamask.confirmTransaction({ gasLimit: 500000 });
// Reject transaction
await metamask.rejectTransaction();
// Sign message
await metamask.confirmSignature();
```
### Token Approval
```typescript
// Handle ERC20 approval popup
await metamask.approveTokenPermission();
// Or with specific amount
await metamask.approveTokenPermission({ spendLimit: '1000' });
```
## Sooth-Specific Test Patterns
### Market Creation Flow
```typescript
test('should create a market', async ({ page, metamask }) => {
await page.goto('http://localhost:5173/create');
await metamask.connectToDapp();
// Fill market details
await page.fill('[data-testid="market-question"]', 'Will ETH reach $5000?');
await page.fill('[data-testid="creator-deposit"]', '100');
await page.selectOption('[data-testid="resolution-date"]', '2025-12-31');
// Submit creation
await page.click('[data-testid="create-market-btn"]');
// Approve USDC spend
await metamask.approveTokenPermission();
await metamask.confirmTransaction();
// Verify creation
await expect(page.locator('[data-testid="market-created-success"]')).toBeVisible();
});
```
### Order Placement Flow
```typescript
test('should place YES order', async ({ page, metamask }) => {
await page.goto('http://localhost:5173/market/1');
await metamask.connectToDapp();
// Select YES outcome
await page.click('[data-testid="outcome-yes"]');
// Enter order details
await page.fill('[data-testid="order-amount"]', '50');
await page.fill('[data-testid="limit-price"]', '0.65');
// Place order
await page.click('[data-testid="place-order"]');
// Handle approvals
await metamask.approveTokenPermission();
await metamask.confirmTransaction();
// Verify order in book
await expect(page.locator('[data-testid="open-orders"]')).toContainText('50 USDC');
});
```
## Test Configuration
### playwright.config.ts
```typescript
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
timeout: 60000, // Longer timeout for blockchain
retries: 2,
workers: 1, // Serial execution for wallet state
use: {
baseURL: 'http://localhost:5173',
trace: 'on-first-retry',
},
webServer: {
command: 'pnpm dev',
url: 'http://localhost:5173',
reuseExistingServer: !process.env.CI,
},
});
```
### Running Tests
```bash
# Run all E2E tests
pnpm test:e2e
# Run with UI
pnpm test:e2e:ui
# Run specific test
pnpm test:e2e -- --grep "wallet connect"
# Debug mode
pnpm test:e2e -- --debug
```
## Best Practices
### Wait for Blockchain State
```typescript
// Wait for transaction confirmation
await expect(async () => {
const balance = await page.locator('[data-testid="balance"]').textContent();
expect(parseFloat(balance)).toBeGreaterThan(0);
}).toPass({ timeout: 30000 });
```
### Handle Network Delays
```typescript
// Retry pattern for chain state
await page.waitForFunction(
() => document.querySelector('[data-testid="tx-confirmed"]'),
{ timeout: 45000 }
);
```
### Clean State Between Tests
```typescript
test.beforeEach(async ({ metamask }) => {
// Reset to known state
await metamask.switchNetwork('Base Sepolia');
});
```
## Troubleshooting
### MetaMask Not Loading
- Ensure Chrome extension path is correct
- Check that no other MetaMask instances are running
- Clear extension cache
### Transaction Stuck
- Increase gas limit in `confirmTransaction()`
- Check RPC endpoint health
- Verify test wallet has sufficient balance
### Flaky Tests
- Add explicit waits for blockchain state
- Use `toPass()` with timeout for async checks
- Run tests serially (`workers: 1`)
This skill provides end-to-end testing for Web3 dApps using Synpress to automate MetaMask and wallet interactions. It focuses on flows that require wallet connection, transaction signing, token approvals, and on-chain verification. Use it to reliably automate DeFi flows, UI states tied to wallet status, and multi-step transactions.
The skill extends Playwright with Synpress fixtures to control a MetaMask instance inside tests. Tests import a test wallet, add and switch networks, interact with the dApp UI, and handle MetaMask prompts programmatically (connect, confirm/reject transactions, sign messages, approve tokens). It also provides patterns for waiting on blockchain state and managing test configuration for stable runs.
How do I set up a test wallet and network?
Import a test private key via metamask.importWallet and add the network with metamask.addNetwork, then switch using metamask.switchNetwork.
How do I handle flaky transaction confirmations?
Increase timeouts, use explicit waits for chain state, increase gasLimit in confirmTransaction, and verify RPC endpoint health.