最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Mocking a Node Module which uses chained function calls with Jest in Node - Stack Overflow

programmeradmin1浏览0评论

Allow me to note that a similar question to this one can be found here, but the accepted answer's solution did not work for me. There was another question along the same lines, the answer of which suggested to directly manipulate the function's prototypes, but that was equally non-fruitful.

I am attempting to use Jest to mock this NPM Module, called "sharp". It takes an image buffer and performs image processing/manipulation operations upon it.

The actual implementation of the module in my codebase is as follows:

const sharp = require('sharp');

module.exports = class ImageProcessingAdapter {
    async processImageWithDefaultConfiguration(buffer, size, options) {
        return await sharp(buffer)
            .resize(size)
            .jpeg(options)
            .toBuffer();
    }
}

You can see that the module uses a chained function API, meaning the mock has to have each function return this.

The Unit Test itself can be found here:

jest.mock('sharp');
const sharp = require('sharp');

const ImageProcessingAdapter = require('./../../adapters/sharp/ImageProcessingAdapter');

test('Should call module functions with correct arguments', async () => {
    // Mock values
    const buffer = Buffer.from('a buffer');
    const size = { width: 10, height: 10 };
    const options = 'options';

    // SUT
    await new ImageProcessingAdapter().processImageWithDefaultConfiguration(buffer, size, options);

    // Assertions
    expect(sharp).toHaveBeenCalledWith(buffer);
    expect(sharp().resize).toHaveBeenCalledWith(size);
    expect(sharp().jpeg).toHaveBeenCalledWith(options);
});

Below are my attempts at mocking:

Attempt One

// __mocks__/sharp.js
module.exports = jest.genMockFromModule('sharp');

Result

Error: Maximum Call Stack Size Exceeded

Attempt Two

// __mocks__/sharp.js
module.exports = jest.fn().mockImplementation(() => ({
    resize: jest.fn().mockReturnThis(),
    jpeg: jest.fn().mockReturnThis(),
    toBuffer:jest.fn().mockReturnThis()
}));

Result

Expected mock function to have been called with:
      [{"height": 10, "width": 10}]
But it was not called.

Question

I would appreciate any aid in figuring out how to properly mock this third-party module such that I can make assertions about the way in which the mock is called.

I have tried using sinon and proxyquire, and they don't seem to get the job done either.

Reproduction

An isolated reproduction of this issue can be found here.

Thanks.

Allow me to note that a similar question to this one can be found here, but the accepted answer's solution did not work for me. There was another question along the same lines, the answer of which suggested to directly manipulate the function's prototypes, but that was equally non-fruitful.

I am attempting to use Jest to mock this NPM Module, called "sharp". It takes an image buffer and performs image processing/manipulation operations upon it.

The actual implementation of the module in my codebase is as follows:

const sharp = require('sharp');

module.exports = class ImageProcessingAdapter {
    async processImageWithDefaultConfiguration(buffer, size, options) {
        return await sharp(buffer)
            .resize(size)
            .jpeg(options)
            .toBuffer();
    }
}

You can see that the module uses a chained function API, meaning the mock has to have each function return this.

The Unit Test itself can be found here:

jest.mock('sharp');
const sharp = require('sharp');

const ImageProcessingAdapter = require('./../../adapters/sharp/ImageProcessingAdapter');

test('Should call module functions with correct arguments', async () => {
    // Mock values
    const buffer = Buffer.from('a buffer');
    const size = { width: 10, height: 10 };
    const options = 'options';

    // SUT
    await new ImageProcessingAdapter().processImageWithDefaultConfiguration(buffer, size, options);

    // Assertions
    expect(sharp).toHaveBeenCalledWith(buffer);
    expect(sharp().resize).toHaveBeenCalledWith(size);
    expect(sharp().jpeg).toHaveBeenCalledWith(options);
});

Below are my attempts at mocking:

Attempt One

// __mocks__/sharp.js
module.exports = jest.genMockFromModule('sharp');

Result

Error: Maximum Call Stack Size Exceeded

Attempt Two

// __mocks__/sharp.js
module.exports = jest.fn().mockImplementation(() => ({
    resize: jest.fn().mockReturnThis(),
    jpeg: jest.fn().mockReturnThis(),
    toBuffer:jest.fn().mockReturnThis()
}));

Result

Expected mock function to have been called with:
      [{"height": 10, "width": 10}]
But it was not called.

Question

I would appreciate any aid in figuring out how to properly mock this third-party module such that I can make assertions about the way in which the mock is called.

I have tried using sinon and proxyquire, and they don't seem to get the job done either.

Reproduction

An isolated reproduction of this issue can be found here.

Thanks.

Share Improve this question asked Jun 13, 2019 at 23:38 user6233283user6233283
Add a ment  | 

1 Answer 1

Reset to default 8

Your second attempt is really close.

The only issue with it is that every time sharp gets called a new mocked object is returned with new resize, jpeg, and toBuffer mock functions...

...which means that when you test resize like this:

expect(sharp().resize).toHaveBeenCalledWith(size);

...you are actually testing a brand new resize mock function which hasn't been called.

To fix it, just make sure sharp always returns the same mocked object:

__mocks__/sharp.js

const result = {
  resize: jest.fn().mockReturnThis(),
  jpeg: jest.fn().mockReturnThis(),
  toBuffer: jest.fn().mockReturnThis()
}

module.exports = jest.fn(() => result);
发布评论

评论列表(0)

  1. 暂无评论