[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
vitest docs guide migration mocha.md
5.0 kB


title: Migrating from Mocha + Chai + Sinon | Guide outline: deep #

Migrating from Mocha + Chai + Sinon {#mocha-chai-sinon} #

Vitest provides excellent support for migrating from Mocha+Chai+Sinon test suites. While Vitest uses a Jest-compatible API by default, it also provides Chai-style assertions for spy/mock testing, making migration easier.

Test Structure #

Mocha and Vitest have similar test structures, but with some differences:

// Mocha
describe('suite', () => {
  before(() => { /* setup */ })
  after(() => { /* teardown */ })
  beforeEach(() => { /* setup */ })
  afterEach(() => { /* teardown */ })

  it('test', () => {
    // test code
  })
})

// Vitest - same structure works!
import { afterAll, afterEach, beforeAll, beforeEach, describe, it } from 'vitest'

describe('suite', () => {
  beforeAll(() => { /* setup */ })
  afterAll(() => { /* teardown */ })
  beforeEach(() => { /* setup */ })
  afterEach(() => { /* teardown */ })

  it('test', () => {
    // test code
  })
})

Assertions #

Vitest includes Chai assertions by default, so Chai assertions work without changes:

// Both Mocha+Chai and Vitest
import { expect } from 'vitest' // or 'chai' in Mocha

expect(value).to.equal(42)
expect(value).to.be.true
expect(array).to.have.lengthOf(3)
expect(obj).to.have.property('key')

Spy/Mock Assertions #

Vitest provides Chai-style assertions for spies and mocks, allowing you to migrate from Sinon without rewriting assertions:

// Before (Mocha + Chai + Sinon)
const sinon = require('sinon')
const chai = require('chai')
const sinonChai = require('sinon-chai')
chai.use(sinonChai)

const spy = sinon.spy(obj, 'method')
obj.method('arg1', 'arg2')

expect(spy).to.have.been.called
expect(spy).to.have.been.calledOnce
expect(spy).to.have.been.calledWith('arg1', 'arg2')

// After (Vitest) - same assertion syntax!
import { expect, vi } from 'vitest'

const spy = vi.spyOn(obj, 'method')
obj.method('arg1', 'arg2')

expect(spy).to.have.been.called
expect(spy).to.have.been.calledOnce
expect(spy).to.have.been.calledWith('arg1', 'arg2')

Complete Chai-Style Assertion Support #

Vitest supports all common sinon-chai assertions:

Sinon-Chai Vitest Description
spy.called called Spy was called at least once
spy.calledOnce calledOnce Spy was called exactly once
spy.calledTwice calledTwice Spy was called exactly twice
spy.calledThrice calledThrice Spy was called exactly three times
spy.callCount(n) callCount(n) Spy was called n times
spy.calledWith(...) calledWith(...) Spy was called with specific args
spy.calledOnceWith(...) calledOnceWith(...) Spy was called once with specific args
spy.returned(value) returned Spy returned specific value

See the Chai-Style Spy Assertions documentation for the complete list.

Creating Spies and Mocks #

Replace Sinon's spy/stub/mock creation with Vitest's vi utilities:

// Sinon
const sinon = require('sinon')
const spy = sinon.spy()
const stub = sinon.stub(obj, 'method')
const mock = sinon.mock(obj)

// Vitest
import { vi } from 'vitest'
const spy = vi.fn()
const stub = vi.spyOn(obj, 'method')
// Vitest doesn't have "mocks" - use spies instead

Stubbing Return Values #

// Sinon
stub.returns(42)
stub.onFirstCall().returns(1)
stub.onSecondCall().returns(2)

// Vitest
stub.mockReturnValue(42)
stub.mockReturnValueOnce(1)
stub.mockReturnValueOnce(2)

Stubbing Implementations #

// Sinon
stub.callsFake(arg => arg * 2)

// Vitest
stub.mockImplementation(arg => arg * 2)

Restoring Spies #

// Sinon
spy.restore()
sinon.restore() // restore all

// Vitest
spy.mockRestore()
vi.restoreAllMocks() // restore all

Timers #

Both Sinon and Vitest use @sinonjs/fake-timers internally:

// Sinon
const clock = sinon.useFakeTimers()
clock.tick(1000)
clock.restore()

// Vitest
import { vi } from 'vitest'
vi.useFakeTimers()
vi.advanceTimersByTime(1000)
vi.useRealTimers()

Key Differences #

  1. Globals: Mocha provides globals by default. In Vitest, either import from vitest or enable globals config
  2. Assertion style: You can use both Chai-style (expect(spy).to.have.been.called) and Jest-style (expect(spy).toHaveBeenCalled())
  3. Parallel execution: Vitest runs tests in parallel by default, Mocha runs sequentially

For more information, see: