0
// processData.js code (all in the same file)
export const getCurrentTotals = async () => {
  // setup etc. 
  const data = await s3.getObject(params).promise();
  return JSON.parse(data.Body.toString('utf-8'));
};

export const calculateTotalsAndRecents = async (input) => {
  const currentTotals = await getCurrentTotals();
  // do calculations etc



// processData.test.js
import * as processData from './processData.js';
// ...
describe('#calculateTotalsAndRecents', () => {
  beforeEach(() => {
      const mock = jest.spyOn(processData, 'getCurrentTotals');
      mock.mockImplementationOnce(() => Promise.resolve({}));
  });
  it('calculates totals', async () => {
      const r = await processData.calculateTotalsAndRecents({ year: 2019, ...});

The issue here is that the call to getCurrentTotals in calculateTotalsAndRecents always calls the actual function instead. I've tried a few possible fixes like

How can I mock an ES6 module import using Jest?

Jest mock async function from default import

Tried adding jest.mock('./processData.js') after the import but that mocks all the functions in the file. I want to override just one function in the file for just the one test.

Do I have to mock the whole file with __mocks__ or is there a simpler way to do this?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
jcollum
  • 43,623
  • 55
  • 191
  • 321
  • Possible duplicate of [Partial module mock function created using Jest is not called by function under test](https://stackoverflow.com/questions/52722751/partial-module-mock-function-created-using-jest-is-not-called-by-function-under) – skyboyer Jun 23 '19 at 20:40
  • 1
    you cannot mock module partially. and you actually don't need that: just mock any things _external_ to module under test(in this case you need to mock `s3.getObject().promise()` to return some stale data. – skyboyer Jun 23 '19 at 20:41
  • If you're using Babel, see also: https://www.npmjs.com/package/babel-plugin-explicit-exports-references – Xunnamius Dec 21 '21 at 16:24

1 Answers1

0

Solution:

  1. Put anything you need to mock in a separate file:
// __mocks__/s3Access.js
export const getCurrentTotals = jest.fn().mockImplementation(() => Promise.resolve({}));

export const putObjectToS3 = jest.fn().mockImplementation(() => Promise.resolve(true));
  1. Add this to the top of your test file:
jest.mock('./s3Access.js');
import { getCurrentTotals, putObjectToS3 } from './s3Access.js'; 

  1. Add before/after blocks under your describe:
  beforeEach(() => {
      getCurrentTotals.mockImplementationOnce(() => Promise.resolve(totals));
    });

 afterEach(() => {
      getCurrentTotals.mockRestore();
    });
jcollum
  • 43,623
  • 55
  • 191
  • 321