How to set up Synpress for Web3 dApp Frontend Test Automation with MetaMask

Setup, configuration, and example tests using Synpress / Cypress for end-to-end frontend test automation of a Web3 dApp with MetaMask login.

Max
andamp
4 min readMar 30, 2022

--

TL;DR: Add Synpress as a dependency to your project, create the default Cypress folder structure and a synpress.json config file. Run your tests with env-cmd -f .env npx synpress run -cf synpress.json --config supportFile='support/index.js'

Synpress github repository

End-to-end frontend testing of a Web3 dApp presents unique challenges and sometimes requires special tooling compared to regular web apps. A particular problem presents the use of MetaMask as a means for authentication through the wallet address of users. Existing standard tooling does not support browser plugins, and therefore is inadequate as a fully automated end-to-end frontend testing suite.

This article will focus on the use of Synpress, a wrapper for the popular frontend testing framework Cypress. We will cover how to set our project up with Synpress, how to configure it, use the extended commands and how to write tests. MetaMask will not only serve as a means of authentication but also for interacting with a smart contract.

This guide is heavily influenced by the README of the Synpress project.

Set up

We will follow the recommended folder structure from Cypress: example.

Default Cypress folder structure

The next step is to create a package.json file to install the Synpress package and the necessary dev dependencies. Most of the dependencies are already taken care of by the Synpress package.json, like cypress, @testing-library/cypress and the necessary eslint-plugin packages. If we want to use a later version of Cypress or any other package, we can also overrule the version defined by Synpress here.

Configuration of Synpress

The necessary configurations for Synpress/Cypress, like the viewport, timeouts, and default folders need to be specified in thesynpress.json file. Here we also define our baseUrl and our test file naming syntax.

The synpress.jsonfile has to be included with each Synpress execution with either the--configFile synpress.json or the-cf synpress.json flag.

Example synpress.json

Setting up MetaMask, selecting a network, and adding one or multiple accounts can be done via environment variables.

Selecting the network is done via theNETWORK_NAME variable. We can choose between mainnet, ropsten, kovan, rinkeby, goerli and localhost.

To configure the account, we have the option to either pass in a private-key with PRIVATE_KEYor a secret passphrase of a wallet with SECRET_WORDS

Example with localhost and a secret pass-phrase (in this particular case the hardhat default pass-phrase) default accounts

Linting and code-hinting

To use linting of test files with eslint we need to create a .eslintrc.js config file and extend with the Synpress eslint configuration

Writing tests for Synpress

Tests are written in either the integration or e2e folder and generally follow one of the two naming conventions:

<name>.spec.js<name>.test.js

Cypress provides a good quick-start tutorial on how to write tests: writing your first test

Since we are using Synpress, we can also use the custom commands, to interact with MetaMask. All commands are described here: index.d.ts

For most use cases, one of the following commands will be sufficient:

cy.rejectMetamaskAccess()
cy.acceptMetamaskAccess()
cy.rejectMetamaskTransaction()
cy.acceptMetamaskTransaction()

Most of the Synpress custom commands are asynchronous and return a boolean response once finished.

Following the recommended Cypress test structure, a test using the new Synpress commands can look similar to our login.spec.js test.

New custom commands

Often it is cleaner to extract frequently used functionality in our test. For example, the setup and teardown of tests can be moved into custom commands, that can be executed like built-in cypress commands like cy.commandName().

To define custom commands, we can use the support/commands.js file, provided by Cypress.

Example commands.js with login custom command

To include the new commands with Synpress, we have to include them in the index.js file. Since the functionality of Synpress is also provided by custom commands, we have to load them in the same index.js file, credit goes to cs-balazs for describing the solution here: https://github.com/Synthetixio/synpress/issues/346#issuecomment-1060506096

To run Synpress using our newly defined index.js file, we have to pass the supportFile flag as configuration like so:

npx synpress run -cf synpress.json --config supportFile='support/index.js'

Helpful custom commands

Synpress does not handle multiple accounts well. This custom command can be helpful, to disconnect all accounts and to have a clean setup for each test.

Example command to disconnect three accounts from dApp

Switching between the first three connected MetaMask accounts, with an additional check of successful switch:

Example command to switch between connected accounts

Running Synpress

Synpress adds in addition to the new commands a global before() where it installs the MetaMask plugin, and sets it up, as defined in the env file.

Setup of MetaMask by Synpress

To run all tests following the specified naming convention, we can execute the following command:

A successful test of our dApp app.banity.com looks like this:

gallery.spec.js

🎉 That’s it! Now you have the necessary tool to test your dApp and provide a more reliable dev process.

Disclaimer: &amp developed the app app.banity.com for decom.ch

If you have any questions, don’t hesitate to contact me:

✉️ Email

--

--