0

After all my researches, i could not find an answer to my problem.

As i try to mock busboy in my project using jest, it keeps on saying that mockImplementation (and mockRestore) is not a function

import * as Busboy from 'busboy';

jest.mock('busboy');
describe('Sample test', () => {
  const mockedEvenMap = {};

  beforeAll(() => {
    Busboy.mockImplementation(() => {
      return { // mock `on` event of Busby instance
        on: (event, callback) => {
          mockedEvenMap[event] = callback;
        },
      };
    });

  });

  afterAll(() => {
    Busboy.mockRestore();
  });
}

Busboy exports its constructor as a default value of the module, but the mock does not seem to be applied.

busboy index.d.ts

declare module 'busboy' {
    const temp: busboy.BusboyConstructor;
    export = temp;
}

Jest version 24.9

Busboy version 0.3.1

any idea?

Lin Du
  • 88,126
  • 95
  • 281
  • 483

2 Answers2

0

You should use the second argument of jest.mock(moduleName, factory, options) method to mock the constructor of Busboy.

E.g.

main.ts:

import Busboy from 'busboy';

export function main() {
  const busboy = new Busboy({});
  busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
    console.log(
      'File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype,
    );
  });
}

main.test.ts:

import { main } from './main';
import Busboy from 'busboy';

jest.mock('busboy', () => {
  const mBusboy = {
    on: jest.fn(),
  };
  return jest.fn(() => mBusboy);
});

describe('59731700', () => {
  let busboy;
  beforeEach(() => {
    busboy = new Busboy({});
  });
  afterEach(() => {
    jest.clearAllMocks();
    jest.restoreAllMocks();
  });
  it('should pass', () => {
    const mockedEvenMap = {};
    busboy.on.mockImplementation((event, callback) => {
      mockedEvenMap[event] = callback;
    });
    const logSpy = jest.spyOn(console, 'log');
    main();
    mockedEvenMap['file']('a', 'b', 'c', 'd', 'e');
    expect(logSpy).toBeCalledTimes(1);
  });
});

Unit test results with coverage report:

 PASS  src/stackoverflow/59731700/main.test.ts (16.143s)
  59731700
    ✓ should pass (22ms)

  console.log node_modules/jest-mock/build/index.js:860
    File [a]: filename: c, encoding: d, mimetype: e

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 main.ts  |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        18.09s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59731700

Lin Du
  • 88,126
  • 95
  • 281
  • 483
0

I'm going to take a different angle here. You're probably building an app rather than the Busboy library, and your needs probably are to make sure the app works correctly.

Have you thought about passing through the Express.js stack in your test? Because it's quite straightforward to write a test that sends a multipart/form-data request. For example, using supertest, you could do:

request(app)
  .post('/')
  .field('name', 'my awesome avatar')
  .attach('avatar', 'test/fixtures/avatar.jpg')
  ...

That way, you wouldn't have to try to mock up the right combo of Busboy events.

pspi
  • 11,189
  • 1
  • 20
  • 18