Home

Awesome

npm version Synpress CI CodeQL Release CI synpress Discord Twitter Follow

We're Hiring ๐ŸŽ‰ โ€” Think you have what it takes? We're looking for Software Engineer, find out more.

<p align="center" > <img src="https://i.imgur.com/Bg8Rch6.png" height="200" /> <p align="center"> <a href="https://github.com/Synthetixio/synpress">Synpress</a> is E2E testing framework <br/> based on <a href="https://www.cypress.io/">Cypress</a> and <a href="https://playwright.dev/">Playwright</a> with support for <a href="https://metamask.io/">MetaMask</a>. </p> </p> <p align="center"> <i>Sponsored & used by: </i> <br/> <br/> <a href="https://github.com/Synthetixio"><img src="./images/synthetix.png" height="100" alt="Synthetix" /></a> <a href="https://github.com/ethereum-optimism"><img src="./images/optimism-logo.png" height="100" alt="Optimism" /></a> </p> <p align="center"> <i>Power users:</i> <br/> </br> <a href="https://github.com/phantom"><img src="./images/phantom.png" height="85" alt="Phantom"/></a> <a href="https://github.com/ensdomains"><img src="./images/ens.png" height="85" alt="Ethereum Name Service (ENS)" /></a> <a href="https://github.com/Kwenta"><img src="./images/kwenta.png" height="100" alt="Kwenta" /></a> <br/> <a href="https://github.com/pantherprotocol"><img src="./images/panther.png" height="100" alt="Panther Protocol" /></a> <a href="https://github.com/agoraxyz"><img src="./images/guild.png" height="90" alt="Guild" /></a> <a href="https://github.com/aragon"><img src="./images/aragon.png" height="90" alt="Aragon" /></a> <a href="https://github.com/delvtech/"><img src="./images/delv.png" height="90" alt="Delvtech" /></a> <br/> <a href="https://github.com/OffchainLabs"><img src="./images/offchain-labs.png" height="100" alt="Offchain Labs" /></a> <a href="https://github.com/snapshot-labs"><img src="./images/snapshot-labs.png" height="90" alt="Snapshot Labs" /></a> <a href="https://github.com/hashgraph"><img src="./images/hedera.png" height="100" alt="Hedera" /></a> </p> </p>

<p align="center"> <img src="./images/demo.gif" title="Synpress Demo" alt="Synpress Demo" style="margin-bottom: 10px;"> </p>

Synpress makes sure to always use latest version of metamask and puts a lot of effort to make sure that dapp tests are stable and trustful.

It also provides an easy way to use and access metamask straight from your e2e tests with all features of cypress and playwright.

๐Ÿ”ฅ Synpress works out-of-the-box with other frameworks! There is no need to use it directly. Check usage examples for more details.

โ™จ๏ธ New release

โš ๏ธ This branch showcases the current stable release of Synpress which will receive only critical hotfixes. โš ๏ธ

Active development of the upcoming version of Synpress is happening on this branch. The new release is a full rewrite of Synpress and will feature major breaking changes, and multitude of new features and improvements across the board such as:

Curious and want to learn more? ๐Ÿค“

Read this Twitter thread ๐Ÿงต and do not forget to check out the attached document there!

Table of content

๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ Community

๐Ÿ–ฅ๏ธ Install

# with pnpm
pnpm add --save-dev @synthetixio/synpress
# with npm
npm install --save-dev @synthetixio/synpress
# with yarn
yarn add -D @synthetixio/synpress

โš™๏ธ Supported frameworks

๐Ÿ‘ Supported wallets

โœ๏ธ Usage examples:


For full Synpress commands and their examples, check here.

To see in which direction Synpress is headed to, take a look at planning board.

๐ŸŒŸ Features

๐Ÿ‘ท Example setup for eslint and tsconfig

Project structure:

project_dir
โ””โ”€โ”€ src
โ””โ”€โ”€ tests
    โ””โ”€โ”€ e2e
        โ””โ”€โ”€ .eslintrc.js
        โ””โ”€โ”€ support.js
        โ””โ”€โ”€ tsconfig.json
        โ””โ”€โ”€ specs
            โ””โ”€โ”€ example-spec.js
        โ””โ”€โ”€ pages
            โ””โ”€โ”€ example-page.js
  1. Create .eslintrc.js inside your tests folder (/project_dir/tests/e2e):
const path = require('path');
const synpressPath = path.join(
  process.cwd(),
  '/node_modules/@synthetixio/synpress',
);

module.exports = {
  extends: `${synpressPath}/.eslintrc.js`,
};
  1. Create support.js inside your tests folder (/project_dir/tests/e2e):
import '@synthetixio/synpress/support/index';

^ hint: you can also use this file to extend synpress - add custom commands, and more..

  1. Create tsconfig.json inside your tests folder (/project_dir/tests/e2e):
{
  "compilerOptions": {
    "allowJs": true,
    "baseUrl": "../../node_modules",
    "types": [
      "cypress",
      "@synthetixio/synpress/support",
      "cypress-wait-until",
      "@testing-library/cypress"
    ],
    "outDir": "./output"
  },
  "include": ["**/*.*"]
}
  1. You're done! ๐ŸŽ‰

To change specific values in default config, you can use --config flag. For example, to change path for support.js file, you can use synpress run --config "supportFile=__tests__/e2e/supportFile.js"

If you would like to use custom paths for your tests and configs, you should mirror (full) default synpress config and then modify it for your needs. Then you can direct synpress to use it with --configFile flag.

For example: synpress run --configFile __tests__/e2e/customConfig.config.js

โšก Important notes

Synpress doesn't seem to communicate with metamask properly if "chromeWebSecurity": false flag is set. More about it here.

Thanks to new headless mode in Chrome, tests are now working in headless mode ๐Ÿค– (synpress run --headless). However, I recommend to use it only for local development as this feature is new and experimental and may cause issues on CI (UNIX). So please, stick to non-headless mode on CI.

In the past, tests worked only in non-headless mode because extensions were not supported in headless mode by playwright and Cypress. As a workaround, we've provided Docker ๐Ÿณ containers. They solved this issue and it's an alternative.

You have to setup xvfb and window manager (like fluxbox or xfce4) to run tests without issues on CI (together with DISPLAY env var). Take a look at CI tips & tricks for working examples.

There is a global before() which runs metamask setup before all tests:

It requires environmental variable called SECRET_WORDS to be present in following format => 'word1 word2 word3 ..' (delimited with spaces) or private key in an environmental variable called PRIVATE_KEY.

To change default network (goerli), you can use NETWORK_NAME environmental variable, for example: NETWORK_NAME=sepolia.

Available choices are: mainnet, goerli, sepolia and localhost.

To create and switch to custom network at metamask setup phase, use these:

  1. NETWORK_NAME => ex: synthetix
  2. RPC_URL => ex: https://synthetix-node.io
  3. CHAIN_ID => ex: 123
  4. SYMBOL => ex: SNX
  5. BLOCK_EXPLORER (optional) => ex: https://synthetix-explorer.io
  6. IS_TESTNET (optional) => ex: false

Metamask version is hardcoded and frequently updated under supervision to avoid a case when e2e tests break because of CSS classes changes in new version, so all you need is to keep synpress updated in your project. However, you can still override metamask with METAMASK_VERSION environmental variable, for example: METAMASK_VERSION=10.21.0 or METAMASK_VERSION=latest.

If you don't want to use environmental variables, you can modify setupMetamask() to following:

setupMetamask(secretWordsOrPrivateKey, network, password), for example: setupMetamask('word1 word2 word3 ..', 'mainnet', 'password') (delimited with spaces).

You can also add and switch to custom network by passing an object instead of string inside setupMetamask(secretWordsOrPrivateKey, network, password) function for network parameter.

If you want to use Etherscan API helpers, you will have to provide Etherscan API key using ETHERSCAN_KEY environmental variable.

To fail a test if there are any browser console errors, set FAIL_ON_ERROR to 1 or true.

Automatic waiting for XHR requests to finish before tests start can be turned on with CYPRESS_RESOURCES_WAIT environmental variable, set it to 1 or true.

If you want to skip metamask extension installation or metamask setup, you can use SKIP_METAMASK_INSTALL and SKIP_METAMASK_SETUP separately. Both variables accept 1 or true.

Synpress is blazingly-fast โšก by default! If you want to change that, you can use STABLE_MODE=true (which will introduce delays only between main actions, 300ms by default) / STABLE_MODE=<value> or SLOW_MODE=true (which will introduce delay between every action, 50ms by default) / SLOW_MODE=<value>.

DEBUG=synpress:* is very useful while debugging your tests. It enables following features:

You may encounter 403 errors (on shared IPs & CI) related to rate limiting while fetching metamask releases from GitHub REST API. This should never happen at all, but it's good to mention. To prevent it from happening, you can create new private access token on GitHub (without any additional access) and specify GH_USERNAME & GH_PAT environmental variables.

๐Ÿณ Using with Docker

Docker is awesome for CI. Give it a try.

Requirements

Some neat features

How to run e2e tests for Synpress using Docker

  1. git clone git@github.com:Synthetixio/synpress.git
  2. cd synpress
  3. (optional) Fill env vars inside .env file
  4. (with foundry; preferred) docker-compose --profile synpress --profile foundry up --build --exit-code-from synpress or ./start-tests.sh
    • (without foundry) docker-compose up --profile synpress --build --exit-code-from synpress
  5. (with foundry and ngrok) docker-compose --profile synpress --profile foundry --profile ngrok up --build --exit-code-from synpress

All examples of setup are present in this repository. Just take a look around.

๐Ÿ’โ€โ™‚๏ธ CI tips & tricks

๐Ÿงช Usage & commands

Command line interface (synpress help):

Usage: synpress run [options]

launch tests

Options:
  -b, --browser <name>               run on specified browser (default: "chrome")
  -c, --config <config>              set configuration values, separate multiple values with a comma
  -cf, --configFile <path>          specify a path to *.js file where configuration values are set
  -e, --env <env=val>                set environment variables, separate multiple values with comma
  -s, --spec <path or glob>          run only provided spec files
  -ne, --noExit                     keep runner open after tests finish
  -pr, --project <path>              run with specific project path
  -q, --quiet                        only test runner output in console
  -r, --reporter <reporter>          specify mocha reporter
  -ro, --reporterOptions <options>  specify mocha reporter options, separate multiple values with comma
  -r, --record                       [dashboard] record video of tests running after setting up your project to record
  -k, --key <key>                    [dashboard] set record key
  -p, --parallel                     [dashboard] run recorded specs in parallel across multiple machines
  -g, --group [name]                 [dashboard] group recorded tests together under a single run
  -t, --tag <name>                   [dashboard] add tags to dashboard for test run
  -h, --help                         display help for command
Usage: synpress open [options]

launch test runner UI

Options:
  -cf, --configFile <path>  specify a path to *.js file where configuration values are set
  -h, --help                display help for command

๐Ÿ‘จโ€โš•๏ธ Known problems with MetaMask

If your MetaMask is stuck on the loading screen, check what's happening under the hood in the console. You can find vital information about why it's stuck on this step.

โญ Sentry.io HTTP error 499 (Request has been forbidden by antivirus)

๐Ÿ“ƒ Environmental variables

VariableDescription
SECRET_WORDSSpace separated words for the test wallet recovery phrase (mnemonic; 12 words)
PRIVATE_KEYTest wallet private key
NETWORK_NAMENetwork name (eg NETWORK_NAME=Optimism)
RPC_URLNetwork RPC (egRPC_URL=https://mainnet.optimism.io)
CHAIN_IDNetwork ID (egCHAIN_ID=10)
SYMBOLNative chain token ticker (eg SYMBOL=OP)
IS_TESTNETboolean indicates that the added network is testnet
BLOCK_EXPLORERBlockchain explorer (eg BLOCK_EXPLORER=https://optimistic.etherscan.io/)
SYNDEBUGSet debugging mode to be on
STABLE_MODEIntroduce delay between main actions, 300ms by default (eg STABLE_MODE=300ms, STABLE_MODE=true)
SLOW_MODEIntroduce delay between every action, 50ms by default (eg SLOW_MODE=true, SLOW_MODE=200ms)
METAMASK_VERSIONMetamask version to be installed
SKIP_METAMASK_INSTALLWill skip MetaMask installation
SKIP_METAMASK_SETUPWill skip MetaMask initial setup
GH_USERNAMEGitHub username (used to avoid rate-limit issues while downloading Metamask)
GH_PATGitHub personal access token (used to avoid rate-limit issue while downloading metamask)
ETHERSCAN_KEYEtherscan key (used only for etherscan-related commands)
FAIL_ON_ERRORFail a test if there are any browser console errors
CYPRESS_GROUPGroup tests
CIBoolean value indicates that tests are running from CI/CD pipeline

๐Ÿšข Release process

  1. Create PR from dev branch to master branch
  2. Merge it (new -beta version is automatically released)
  3. Run GitHub Action workflow named Release CI with patch|minor|major depending on your needs to promote your build.

Alternatively, instead of running GitHub Action for release, you can move on with manual release process:

  1. Switch to master branch and pull latest changes
  2. Run pnpm release:patch/minor/major command
  3. Keep dev branch up to date with master

Above actions will lead to:

๐Ÿ“ More resources