Test avec Chai & Moka

(Supporté depuis Remix IDE v0.22.0)

Remix permet de tester vos fichiers en JavaScript à l’aide de la bibliothèque d’assertions Chai et du cadre de test Mocha.

Chai est une bibliothèque d’assertions BDD / TDD pour node et le navigateur qui peut être délicieusement associée à n’importe quel framework de test javascript.

Mocha est un framework de test JavaScript riche en fonctionnalités, fonctionnant sur Node.js et dans le navigateur, qui rend les tests asynchrones simples et amusants.

Rédiger des tests

Create a js file in your project workspace. Better to create it inside scripts folder. Let’s name it sample.test.js.

Écrivez vos tests dans le fichier. Voici un exemple :

const { expect } = require("chai");

describe("Sample", function () {
  it("Sample tests with mocha and chai", async function () {
    var foo = 'bar'
    var beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
    expect(foo).to.be.a('string');
    expect(foo).to.equal('bar');
    expect(foo).to.have.lengthOf(3);
    expect(beverages).to.have.property('tea').with.lengthOf(3);
  });
});

Exécuter les tests

Une fois les tests écrits, faites un clic droit sur le nom du fichier dans le plugin File Explorers. Il affichera quelques options ainsi que l’option Run. Cette option Run est utilisée pour exécuter les scripts JS.

Cliquez sur « Exécuter », les tests seront exécutés et les résultats s’afficheront sur le terminal.

Tester un contrat

De même, des tests unitaires peuvent être écrits pour tester la fonctionnalité d’un contrat intelligent. Un exemple pour tester le contrat par défaut 1_Storage.sol peut être le suivant :

const { expect } = require("chai");

describe("Storage", function () {
  it("test initial value", async function () {
    // Make sure contract is compiled and artifacts are generated
    const metadata = JSON.parse(await remix.call('fileManager', 'getFile', 'contracts/artifacts/Storage.json'))
    const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
    let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
    let storage = await Storage.deploy();
    console.log('storage contract Address: ' + storage.address);
    await storage.deployed()
    expect((await storage.retrieve()).toNumber()).to.equal(0);
  });

  it("test updating and retrieving updated value", async function () {
    const metadata = JSON.parse(await remix.call('fileManager', 'getFile', 'contracts/artifacts/Storage.json'))
    const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
    let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
    let storage = await Storage.deploy();
    await storage.deployed()
    const setValue = await storage.store(56);
    await setValue.wait();
    expect((await storage.retrieve()).toNumber()).to.equal(56);
  });

  it("fail test updating and retrieving updated value", async function () {
    const metadata = JSON.parse(await remix.call('fileManager', 'getFile', 'contracts/artifacts/Storage.json'))
    const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
    let Storage = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
    let storage = await Storage.deploy();
    await storage.deployed()
    const setValue = await storage.store(56);
    await setValue.wait();
    expect((await storage.retrieve()).toNumber()).to.equal(55);
  });
});

Le résultat sera le suivant :

Débogage d’une transaction de test

Pour déboguer une transaction dans l’un des tests, imprimez le hachage de la transaction et saisissez-le dans le [plugin Remix Debugger] (https://remix-ide.readthedocs.io/en/latest/tutorial_debug.html).

Soutien aux casques et aux éthers

Remix prend également en charge les méthodes du plugin hardhat-ethers du cadre Hardhat. Les méthodes disponibles dans le cadre de ce plugin sont les suivantes :

interface Libraries {
  [libraryName: string]: string;
}

interface FactoryOptions {
  signer?: ethers.Signer;
  libraries?: Libraries;
}

function getContractFactory(name: string, signer?: ethers.Signer): Promise<ethers.ContractFactory>;

function getContractFactory(name: string, factoryOptions: FactoryOptions): Promise<ethers.ContractFactory>;

function getContractFactory(abi: any[], bytecode: ethers.utils.BytesLike, signer?: ethers.Signer): Promise<ethers.ContractFactory>;

function getContractAt(name: string, address: string, signer?: ethers.Signer): Promise<ethers.Contract>;

function getContractAt(abi: any[], address: string, signer?: ethers.Signer): Promise<ethers.Contract>;

function getSigners() => Promise<ethers.Signer[]>;

function getSigner(address: string) => Promise<ethers.Signer>;

function getContractFactoryFromArtifact(artifact: Artifact, signer?: ethers.Signer): Promise<ethers.ContractFactory>;

function getContractFactoryFromArtifact(artifact: Artifact, factoryOptions: FactoryOptions): Promise<ethers.ContractFactory>;

function getContractAtFromArtifact(artifact: Artifact, address: string, signer?: ethers.Signer): Promise<ethers.Contract>;

Ainsi, il est possible d’exécuter facilement les tests d’un projet hardhat à l’aide de Remix.

Exemple de test du contrat Storage avec ce plugin : les méthodes peuvent être les suivantes :

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Storage", function () {
  it("test initial value", async function () {
    const Storage = await ethers.getContractFactory("Storage");
    const storage = await Storage.deploy();
    await storage.deployed();
    console.log('storage deployed at:'+ storage.address)
    expect((await storage.retrieve()).toNumber()).to.equal(0);
  });
   it("test updating and retrieving updated value", async function () {
    const Storage = await ethers.getContractFactory("Storage");
    const storage = await Storage.deploy();
    await storage.deployed();
    const storage2 = await ethers.getContractAt("Storage", storage.address);
    const setValue = await storage2.store(56);
    await setValue.wait();
    expect((await storage2.retrieve()).toNumber()).to.equal(56);
  });
});

Le résultat sera le suivant :