# E2E Tests with Playwright + Synpress: A Developer's Journey

*ChainHackers Weekly - Developer Notes Entry #5*

By [ChainHacker](https://paragraph.com/@chainhacker) · 2025-07-24

betswirl, devtools, e2e, tests, web3

---

So you've decided to dive into end-to-end testing for your Web3 app? Excellent choice! Getting started with e2e testing is straightforward with the right tools, and once you get the hang of it, you'll wonder how you ever lived without it.

Why Playwright + Synpress?
--------------------------

Before we jump into code, let's talk about why this combo works well. **Playwright** gives you a solid foundation for browser automation with great debugging tools, while **Synpress** adds Web3-specific features – MetaMask integration, wallet caching, and transaction handling.

Getting Started: The Setup Dance
--------------------------------

First things first, let's get everything installed. It's surprisingly straightforward:

    npm install @synthetixio/synpress

Now, here's where it gets interesting. Your basic test setup looks something like this:

    import { testWithSynpress } from '@synthetixio/synpress';
    import { MetaMask, metaMaskFixtures } from '@synthetixio/synpress/playwright';
    import basicSetup from './wallet-setup/metamask.setup';
    
    const test = testWithSynpress(metaMaskFixtures(basicSetup));
    let metamask: MetaMask;
    const { expect } = test;

This setup tells Synpress to use MetaMask in your tests with your specified configuration.

![](https://storage.googleapis.com/papyrus_images/ba05ee336232049212192c1df6df5ca8.png)

[

sdk/packages/ui-react/test/wallet-setup/basic.setup.ts at main · BetSwirl/sdk
-----------------------------------------------------------------------------

SDK to interact with BetSwirl's smart-contracts. Contribute to BetSwirl/sdk development by creating an account on GitHub.

https://github.com

![](https://storage.googleapis.com/papyrus_images/a86123f28875211d38ff8a94bd7663f1.png)

](https://github.com/BetSwirl/sdk/blob/main/packages/ui-react/test/wallet-setup/basic.setup.ts)

Writing Tests: Connect That Wallet!
-----------------------------------

Let's start with something every Web3 app needs – connecting a wallet. Here's what a basic test looks like:

    test.describe('My Awesome DApp Tests', () => {
      test('should connect wallet successfully', async ({ page }) => {
        // Navigate to your app
        await page.goto('http://localhost:3000');    
        // Click that connect button
        await page.click('[data-testid="connect-wallet"]');
        
        // Synpress handles the MetaMask popup automatically
    
        // Check if we're connected
        await expect(page.locator('[data-testid="wallet-address"]')).toBeVisible();
      });
    });

What I love about this is how **clean** it is. No wrestling with popup windows or iframe nightmares – Synpress handles all that for you.

The Transaction Test: Where Things Get Real
-------------------------------------------

Once you've mastered wallet connection, it's time for the main event – testing transactions:

    test('should send tokens successfully', async ({ page }) => {
        // Navigate to coin toss game
        await page.goto("/coinToss.html")
    
        // Connect wallet
        const connectButton = page.getByTestId("ockConnectButton")
        await connectButton.click()
    
        // Find and click play button
        const playButton = page.locator('button:has-text("Place Bet")')
    	// Click play button
        await playButton.click()
    	await metamask.confirmTransaction()
      
        // Verify success
          const resultModal = page.locator('[role="dialog"]').filter({ hasText: /You (won|lost)/i })
          const hasResultModal = await resultModal.isVisible({ timeout: 10000 }).catch(() => false)
    });

![](https://storage.googleapis.com/papyrus_images/25107dbaed68737f0a5649d0a916b0dc.png)

[

sdk/packages/ui-react/tests/coinToss.spec.ts at main · BetSwirl/sdk
-------------------------------------------------------------------

SDK to interact with BetSwirl's smart-contracts. Contribute to BetSwirl/sdk development by creating an account on GitHub.

https://github.com

![](https://storage.googleapis.com/papyrus_images/756403da0e3c1315bd22522f42f39524.png)

](https://github.com/BetSwirl/sdk/blob/main/packages/ui-react/tests/coinToss.spec.ts)

Debugging: When Tests Go Wrong (And They Will)
----------------------------------------------

Let's be real – tests won't work perfectly the first time. Here are essential debugging techniques:

### 1\. The Debug Flag

    DEBUG=synpress:* npm test

This gives you **detailed logs** about what's happening under the hood.

### 2\. Slow Things Down

When a test fails and you need to see what's happening:

    SLOW_MO=1000 npm test

This adds a 1-second delay between actions, making it easier to follow the test execution.

### 3\. Screenshots on Failure

Add this to your test for automatic failure documentation:

    test.afterEach(async ({ page }, testInfo) => {
      if (testInfo.status !== 'passed') {
        await page.screenshot({ path: `screenshots/${testInfo.title}.png` });
      }
    });

The Setup Script That Wouldn't Quit
-----------------------------------

Here's a fun one that had me pulling my hair out. When running `pnpm test:e2e-setup`, the process would just... hang. Forever. No errors, no timeout, just an eternal loading state staring back at me.

The setup script looked innocent enough:

    test("Setup wallet", async ({ context, metamask }) => {
      await metamask.connectToDapp()
      await metamask.switchNetwork('base')
      // ... rest of setup
    })

After what felt like hours of staring at a frozen terminal, I finally ran it with debug flags:

    DEBUG=synpress:* pnpm test:e2e-setup

And there it was! The debug logs revealed MetaMask was showing a network switch confirmation dialog that the script couldn't handle:

    synpress:metamask Switching to network: base
    synpress:metamask Waiting for network switch confirmation...
    [hanging here forever]

**The solution?** Remove the network switch from the setup entirely. The cached wallet doesn't need to be on a specific network – let each test handle its own network requirements. Sometimes the simplest solutions are the best ones.

![](https://storage.googleapis.com/papyrus_images/ba3ab469ad5c530d12dd6a020392c0ce.png)

![](https://storage.googleapis.com/papyrus_images/8b3c258ab072245842d451ca3feb1506.png)

Writing Better Tests
--------------------

Here's what separates good e2e tests from great ones:

1.  **Test user journeys, not implementation details** – Think "user connects wallet and sends tokens" not "button click triggers function X"
    
2.  **Keep tests independent** – Each test should work on its own. No test should depend on another test running first.
    
3.  **Use data-testid attributes** – They're more stable than CSS selectors:
    
        <button data-testid="connect-wallet">Connect</button>
    
4.  **Be generous with assertions** – But not too generous. Check what matters, ignore what doesn't.
    

Wrapping Up
-----------

E2E testing with Playwright and Synpress might seem daunting at first, but it's genuinely worth the investment. Start small – maybe just test your wallet connection flow. Then gradually add more complex scenarios.

Remember: **done is better than perfect**. Tests don't need to cover every edge case right away. They just need to catch the obvious breaks while you focus on building features.

The best part? Once you have a solid test suite, you can refactor with confidence, ship features faster, and actually enjoy your weekends without worrying about production issues.

Happy testing!

---

*Originally published on [ChainHacker](https://paragraph.com/@chainhacker/e2e-tests-with-playwright-synpress)*
