When you want to write tests for your Web3 application, synpress might be one of the most logical options. Developed as a Cypress plugin, I'd like to share my experiences with this library and the problems I encountered. This article is written for readers who have basic knowledge about web3 tests and want to delve deeper into the subject.

Setup

To use Synpress in your project, you can use the following commands:

npm install --save-dev [email protected]
npm install --save-dev [email protected]

Note: The reason I use version 3.7.1 of Synpress is that newer versions are in beta and have not worked stably. The reason I use version 12.17.3 of Cypress is related to this issue.

A sample run script for package.json is as follows:

"scripts": {
    "synpress:run": "env-cmd -f .env.testing synpress run --config='fixturesFolder=tests/e2e/fixtures'"
}

Here, we define a special env file and configuration.

Project structure:

project_dir
└── src
└── tests
    └── e2e
        └── .eslintrc.js
        └── support.js
        └── tsconfig.json
        └── specs
            └── example-spec.js
        └── pages
            └── example-page.js
  1. Create the .eslintrc.js file under the /project_dir/tests/e2e folder:
const path = require("path");
const synpressPath = path.join(
  process.cwd(),
  "/node_modules/@synthetixio/synpress"
);

module.exports = {
  extends: `${synpressPath}/.eslintrc.js`,
};
  1. Create the support.js file under the /project_dir/tests/e2e folder:
import "@synthetixio/synpress/support/index";
  1. Create the tsconfig.json file under the /project_dir/tests/e2e folder:
{
  "compilerOptions": {
    "allowJs": true,
    "baseUrl": "../../node_modules",
    "types": [
      "cypress",
      "@synthetixio/synpress/support",
      "cypress-wait-until",
      "@testing-library/cypress"
    ],
    "outDir": "./output"
  },
  "include": ["**/*.*"]
}

After completing the above steps, you will need a sample env file:

NETWORK_NAME="HardhatNetwork"
RPC_URL=http://127.0.0.1:8545/
CHAIN_ID=31337
SYMBOL=ETH
PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
PASSWORD="your_password"

When using this sample .env.testing, I'm running a blockchain network with hardhat. Therefore, you need to change the NETWORK_NAME, RPC_URL, CHAIN_ID, SYMBOL, PASSWORD, and (PRIVATE_KEY or SECRET_WORDS) values according to your network values. In the example script under package.json, we use this .env.testing file with env-cmd.

Usage

You can write your tests under the specs folder. An example test file is as follows:

describe("Wallet", () => {
  it("connect wallet", () => {
    cy.visit("/wallet");
    cy.get("h1").should("contain", "Wallet");
    cy.get("button").contains("Connect").click();
    cy.acceptMetamaskAccess();
    cy.contains("p.text-body", "Connected address");
    cy.contains("p.address", cy.getMetamaskAddress());
  });
});

Let's go over this sample test. Before this test starts, you can think of it as having a before part where the cy.setupMetamask() function works with the information you defined on the env, and the metamask wallet is opened and set up before the test starts. If you get an error at this stage, you can assume there is a configuration-specific error.

In the example, we go to the wallet path and check if it says Wallet in the h1 tag. Then we click the Connect button. At this stage, a metamask access request comes, and we accept this request with the cy.acceptMetamaskAccess() function. Then we check if it says Connected address in p.text-body. Finally, we check if our metamask address is written in p.address.

In these tests, you can use both the cypress API and the synpress APIs.

Contrary to the Synpress document, you may experience env-related malfunctions in the given examples. I recommend paying attention to these. Especially, I suggest not using METAMASK_VERSION=lastest because this plugin is written for a specific metamask, and it doesn't work in subsequent versions.

I couldn't run synpress in --headless mode; I encountered metamask-specific errors. Indeed, even in synpress open, the metamask wallet gets stuck and doesn't open. Then it gives a message asking if I want to restart the wallet. I couldn't overcome these.

I managed ENV management through the env-cmd package as I wrote above; I was unsuccessful in others.

I had to add cy.wait(5000) to the cy.confirmMetamaskPermissionToSpend() functions. Otherwise, there were times when the time was insufficient. Even though I have a local hardhat network, I don't know the situation of the test nets you will use, but I recommend you to look at these.

When you want to import a second account, you may encounter the autoconnect problem. To solve this, I found a hacky solution as follows.

describe("projects", () => {
  it("change account", () => {
    cy.visit("/wallet");
    cy.disconnectMetamaskWalletFromAllDapps();
    cy.fixture("user2.json").then((user) => {
      cy.importMetamaskAccount(user.privateKey);
      cy.switchMetamaskAccount(3);
    });
    cy.resetMetamaskAccount();
    cy.get("button").contains("Connect").click();
    cy.acceptMetamaskAccess({ allAccounts: true });
    cy.contains("p.text-body1", "Connected address");
  });
});

Conclusion

It's possible to write metamask tests with Synpress. However, based on my experience, I encountered many problems. I spent more time than I initially planned to solve them. By reading this article, you can start without having to spend as much time on the problems I encountered.