Web3 uygulamanızın testini yazmak istediğinizde synpress, en mantıklı seçeneklerden biri olabilir. Cypress plugini olarak geliştirilmiş olan bu kütüphane ile ilgili deneyimlerimi ve karşılaştığım problemleri sizlerle paylaşmak istiyorum. Bu makale, web3 testleri konusunda temel bilgiye sahip olan ve bu konuda daha derinlemesine bilgi edinmek isteyen okuyucular için yazılmıştır.

Kurulum

Synpress'i projenizde kullanmak için aşağıdaki komutları kullanabilirsiniz:

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

Not: Synpress'in 3.7.1 versiyonunu kullanmamın nedeni, daha yeni versiyonlarının betada olması ve stabil bir şekilde çalışmamış olmasıdır. Cypress'in 12.17.3 versiyonunu kullanma sebebim ise şu issue ile alakalıdır.

package.json için örnek bir çalıştırma scripti şu şekildedir:

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

Burada özel bir env dosyası ve config tanımlaması yapıyoruz.

Proje yapısı:

project_dir
└── src
└── tests
    └── e2e
        └── .eslintrc.js
        └── support.js
        └── tsconfig.json
        └── specs
            └── example-spec.js
        └── pages
            └── example-page.js
  1. .eslintrc.js dosyasını (/project_dir/tests/e2e) klasörü altında oluşturun:
const path = require("path");
const synpressPath = path.join(
  process.cwd(),
  "/node_modules/@synthetixio/synpress"
);

module.exports = {
  extends: `${synpressPath}/.eslintrc.js`,
};
  1. support.js dosyasını (/project_dir/tests/e2e) klasörü altında oluşturun:
import "@synthetixio/synpress/support/index";
  1. tsconfig.json dosyasını (/project_dir/tests/e2e) klasörü altında oluşturun:
{
  "compilerOptions": {
    "allowJs": true,
    "baseUrl": "../../node_modules",
    "types": [
      "cypress",
      "@synthetixio/synpress/support",
      "cypress-wait-until",
      "@testing-library/cypress"
    ],
    "outDir": "./output"
  },
  "include": ["**/*.*"]
}

Yukarıdaki işlemleri tamamladıktan sonra örnek bir env dosyasına ihtiyacınız olacak:

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

Bu örnek .env.testing kullanırken ben hardhat ile bir blockchain networku ayağa kaldırıyorum. Bu yüzden NETWORK_NAME, RPC_URL, CHAIN_ID, SYMBOL, PASSWORD ve (PRIVATE_KEY veya SECRET_WORDS) değerlerini networkünüzün değerlerine göre değiştirmeniz gerekiyor. package.json altındaki örnek scripti içinde env-cmd ile bu .env.testing dosyasını kullanıyoruz.

Kullanım

specs klasörü altında testlerinizi yazabilirsiniz. Örnek bir test dosyası şu şekildedir:

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());
  });
});

Bu örnek test üzerinden gidelim. Bu test başlamadan önce aslında before kısmı var gibi düşünebilirsiniz burada env üzerinde tanımladığınız bilgiler ile cy.setupMetamask() fonksiyonu çalışıyor ve test başlamadan önce metamask wallet açılıp tanımlamalar yapılıyor. Eğer bu aşamada bir hata alıyorsanız konfigrasyon özelinde bir hata vardır diye düşünebilirsiniz.

Örnekte wallet path'ine gidip h1 tagi içinde Wallet yazdığını kontrol ediyoruz. Daha sonra Connect butonuna tıklıyoruz. Bu aşamada metamask access isteği geliyor ve cy.acceptMetamaskAccess() fonksiyonu ile bu isteği kabul ediyoruz. Daha sonra p.text-body içinde Connected address yazdığını kontrol ediyoruz. Son olarak p.address içinde metamask adresimizin yazdığını kontrol ediyoruz.

Bu testler içerisinde cypress api ek olarak synpress apilerinide kullanabilirsiniz.

Synpress dökümanın aksine verilen örneklerdeki env kaynaklı çalışmama problemi yaşabilirsiniz bunlara dikkat etmenizi tavsiye ederim. Özellikle METAMASK_VERSION=lastest kullanmamanızı öneriyorum çünkü bu plugin yazılırken belli bir metamask'a göre yazılıyor ve sonraki versiyonlarda çalışmaz.

Ben synpress'i --headless mode'ta çalıştıramadım wallet özellinde hatalar aldım. Nitekim synpress open'da da testlerde metamask wallet takılıyor ve açılmıyor. Sonra wallet'ı yeniden başlatayım mı mesajı veriyor. Bunlarıda aşamadım.

ENV yönetimini en yukarıda yazdığım gibi env-cmd paketi üzerinden sağladım diğerlerinde başarılı olamadım.

cy.confirmMetamaskPermissionToSpend() fonksiyonlarında cy.wait(5000) eklemek zorunda kaldım. Aksi takdirde zamanın yeterli olmadığı durumlar oldu. Bu benim local hardhat network'ümün olduğu halde böyleydi sizin kullanacağınız testnetlerin durumunu bilemiyorum ancak bunlara bakmanızı tavsiye ederim.

İkinci bir account import etmek istediğinizde autoconnect problemi ile karşılaşabilirsiniz. Bunu çözmek için aşağıdaki gibi bir hacky çözüm buldum.

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");
  });
});

Sonuç

Synpress ile metamask testlerini yazmak mümkün. Ancak benim deneyimlediğim kadarıyla bir çok sorunla karşılaştım. Bunları çözerken başlangıçta planladığımın üzerinde vakit harcadım. Sizlerde bu tarz problemleri yaşamamak adına bu yazıyı okuyarak başlangıçta karşılaşabileceğiniz problemleri çözebilirsiniz.