Migrating from v1 to v2

DeFi Wonderland and Optimism have decided to join forces with our shady-super-coder’s magic to launch a new and improved version of the mocking library you ❤️

We know the breaking changes on the API will make you do some leg work, but we promise it is going to be totally worth it!

Also, special thanks to the Optimism team for recognizing our work and allowing us to host the new library on our Github organization (this marks our first public release 🚀)

Smock V2 focuses mainly on:

  • API improvements

  • Call arguments expectations

  • Custom chai matchers

  • Type extensions with generics

  • Fakes and Mocks division

  • Documentation


Before upgrading

If using Typescript, we highly recommend using Typechain in order to take full advantage of the type extensions we provide. If you decide not to, you can still follow along by using the type Contract from ethers or any.

With Typechain:

import { FakeContract } from '@defi-wonderland/smock';
import { CookieEater } from '@typechained';

let cookieEater: FakeContract<CookieEater>; // will extend all of the CookieEater method types

Without Typechain:

import { FakeContract } from '@defi-wonderland/smock';
import { Contract } from 'ethers';

let cookieEater: FakeContract<Contract>; // will extend all of the CookieEater method types

Installation

Uninstall the old package

yarn remove @eth-optimism/smock

Install the new one

yarn add --dev @defi-wonderland/smock

New concepts

Instead of having Mock and Smod objects, now we use Fakes and Mocks.

  • Fakes are empty contracts that emulate a given interface.
    All of their functions can be watched and pre-programmed. When calling a function of a fake, by default, it will return the return type zero-state.
  • Mocks are deployed contract wrappers that have all of the fake’s functionality and even more.
    Because they are actually deployed contract, they can have actual logic inside that can be called through. And because they have a storage, internal variable values can be overwritten 🥳

API changes

Smockit initialization

Before:

import { ethers } from 'hardhat';
import { smockit } from '@eth-optimism/smock';

const myContractFactory = await ethers.getContractFactory('MyContract');
const myContract = await myContractFactory.deploy(...);
const myMockContract = await smockit(myContract);

After:

import { smock } from '@defi-wonderland/smock';
import { MyContract } from '@typechained';

const myFakeContract = await smock.fake<MyContract>('MyContract');

Returns

Before:

myMockContract.smocked.myFunction.will.return.with('Some return value!');

After:

myFakeContract.myFunction.returns('Some return value!');

Asserting call count

Before:

expect(myMockContract.smocked.myFunction.calls.length).to.equal(1);

After:

expect(myFakeContract.myFunction).to.be.calledOnce;

Asserting call data

Before:

expect(MyMockContract.smocked.myFunction.calls.length).to.equal(1);
expect(MyMockContract.smocked.myFunction.calls[0]).to.deep.equal(['Something', 123]);

After:

expect(myFakeContract.myFunction).to.be.calledOnceWith('Something', 123);

Reverting

Before:

myMockContract.smocked.myFunction.will.revert();
myMockContract.smocked.myOtherFunction.will.revert.with('Some error');

After:

myFakeContract.myFunction.reverts();
myFakeContract.myOtherFunction.reverts('Some error');

Creating a modifiable contract

Before:

import { ethers } from 'hardhat';
import { smoddit } from '@eth-optimism/smock';

const myModifiableContractFactory = await smoddit('MyContract');
const myModifiableContract = await MyModifiableContractFactory.deploy(...);

After:

import { MyContract } from '@typechained';
import { MockContract, MockContractFactory, smock } from '@defi-wonderland/smock';

const myMockContractFactory: MockContractFactory<MyContract> = await smock.mock('MyContract');
const myMockContract: MockContract<MyContract> = await myMockContractFactory.deploy(...);

Modifying a contract variable value

Before:

await myModifiableContract.smodify.put({
  _myInternalVariable: 1234
});

After:

await myMockContract.setVariable('_myInternalVariable', 1234);

And more…

Smock V2 contains plenty of new features, you can check them all out in the docs!