This is short explanation of how tests scripts and helpers might look.
import {initEvm, checkpoint} from './helpers';
export default ({describe, it, use, each}) => {
describe('Subject', () => {
// Initialize VM and put it into test context
use(initEvm({
accounts: {
alice: {balance: '1 eth'},
bob: {balance: 0},
},
}))
// Make each test to add a checkpoint and to rollback
each(checkpoint)
// Run test and change the state
it('test', async (test, ctx) => {
const {alice, bob} = ctx.accounts
await alice.transfer('0.5 eth', bob)
const balance = await bob.getBalance('eth')
assert.equal(balance, '5', 'Balance is 5')
test.end()
})
// Run test with initial state, where Alice has 5 ethers and Bob has zero.
it('test', async (test, ctx) => {
const {alice, bob} = ctx.accounts
const aliceBalance = await alice.getBalance('eth')
const bobBalance = await bob.getBalance('eth')
assert.equal(aliceBalance, '5', 'Alice balance is 5')
assert.equal(bobBalance, '0', 'Bob balance is 0')
test.end()
})
})
}
// Initialize EVM with a given params
export function initEvm(params) {
async function (ctx, next) {
const {evmModule} = ctx.specOpts
const {default: VM, StateManager} = await import(evmModule)
const state = new StateManager()
const evm = await VM.create({state})
const accounts = await createAccountsSomeHow(evm, params)
// Put to context new vaalues `evm`, `state` and `accounts`.
// This call equals to Object.assign(Object.create(ctx), {evm, state, accounts})
await next({
evm,
state,
accounts,
})
}
}
// Add checkpoint and rollback after test end
export async function checkpoint(ctx, next) {
const {evm} = ctx
const state = evm.pStateManager
try {
await state.checkpoint()
await next()
}
finally {
await state.rollback()
}
}