How to Jest Test By Mocking Imports

Wed Jan 01 2020

Jest is one of the top libraries for running javascript tests.

It's great for unit tests, integrations, and more.

The single little pain I encounter each time I work with Jest is when I need to mock imports.

Now when I'm talking about imports there two types: old-style exports and ES6 export. i.e.:

module.exports = theModule
module.exports.another = anotherModule
// vs
export default = theModule
export const another = anotherModule

So let's say I have a module that I want to test. The module uses another module that depends on some 3rd party service. In my tests, I don't want to be dependent on the 3rd party service for the success of my tests.

Why is that?

Let's say the 3rd party service is down for some reason. That means my tests will fail each time until their service is functional again.

Example

// dependency.js
import fetchData from 'third-party-service'

export default async _ => {
  const data = await fetchData()
  return {
    name: data.defaultName,
    score: data.score,
  }
}

export const namedExport = async name => {
  const data = await fetchData(name)
  return {
    name: data.name,
    score: data.score,
  }
}

As you can see above we have two methods that fetch data from a 3rd party service. One method is the default one for the package and the other is named.

// testSubject.js
import defaultImport, { namedExport } from './dependency'

export const returnDefaultImport = _ => {  
  return defaultImport()
}

export const returnNamedImport = _ => {
  return namedExport()
}

In our test subject here it uses our dependency module for getting data. It depends on our dependency and not the 3rd party.

The Tests

Jest testing with imports was always a hard thing that was hard for me to solve each time. I'm quite sure that are better ways to do what I'm doing, and I probably have some mistakes.

But, it will surely give you a head start of moving forward.

import { returnDefaultImport returnNamedImport } from './testSubject'
jest.mock('./dependency')
import defaultExport, * as theRest from './dependency'

describe('mock default', () => {
  beforeEach(() => {
    jest.resetModules()
    defaultExport.mockClear()
  })

  it('work', () => {
    defaultExport.mockImplementation(() => {
      return 'mockedDefaultMethod'
    })
    theRest.namedExport.mockImplementation(() => {
      return 'mockedNameMethod'
    })
    expect(returnDefaultImport()).toBe('mockedDefaultMethod')
    expect(returnNamedImport()).toBe('mockedNameMethod')
  })
})