Forcing a module mock to throw an error in a test

Viewed 1452

I have a try/catch block in my functions that I want to test. Both functions call the same execute function and will catch if it throws an error. My tests are setup where I'm mocking the module near the top, and I can then verify how many times that jest function is called.

What I can't seem to figure out is how to force execute to throw an error on the second test, and then go back to the default mock implementation. I've tried re-assigning jest.mock in the individual test but it doesn't seem to work.

import {execute} from '../src/execute'

jest.mock('../src/execute', () => ({
  execute: jest.fn()
}))

describe('git', () => {
  afterEach(() => {
    Object.assign(action, JSON.parse(originalAction))
  })

  describe('init', () => {
    it('should stash changes if preserve is true', async () => {
      Object.assign(action, {
        silent: false,
        accessToken: '123',
        branch: 'branch',
        folder: '.',
        preserve: true,
        isTest: true,
        pusher: {
          name: 'asd',
          email: 'as@cat'
        }
      })

      await init(action)
      expect(execute).toBeCalledTimes(7)
    })
  })

  describe('generateBranch', () => {
    it('should execute six commands', async () => {
       jest.mock('../src/execute', () => ({
         execute: jest.fn().mockImplementation(() => {
           throw new Error('throwing here so. I can ensure the error parsed properly');
         });
      }))

      Object.assign(action, {
        silent: false,
        accessToken: '123',
        branch: 'branch',
        folder: '.',
        pusher: {
          name: 'asd',
          email: 'as@cat'
        }
      })
      
      // With how this is setup this should fail but its passing as execute is not throwing an error
      await generateBranch(action)
      expect(execute).toBeCalledTimes(6)
    })
  })
})

Any help would be appreciated!

1 Answers

jest.mock in should execute six commands doesn't affect ../src/execute module because it has already been imported at top level.

jest.mock at top level already mocks execute with Jest spy. It's preferable to use Once implementation to not affect other tests:

it('should execute six commands', async () => {
     execute.mockImplementationOnce(() => {
       throw new Error('throwing here so. I can ensure the error parsed properly');
     });
     ...

Also the mock should be forced to be ES module because execute is named import:

jest.mock('../src/execute', () => ({
  __esModule: true,
  execute: jest.fn()
}))
Related