Jest spyOn() calls the actual function instead of the mocked
Asked Answered
S

2

7

I'm testing apiMiddleware that calls its helper function callApi. To prevent the call to actual callApi which will issue the API call, I mocked the function. However, it still gets called.

apiMiddleware.js

import axios from 'axios';

export const CALL_API = 'Call API';

export const callApi = (...arg) => {
  return axios(...arg)
    .then( /*handle success*/ )
    .catch( /*handle error*/ );
};

export default store => next => action => {
  // determine whether to execute this middleware
  const callAPI = action[CALL_API];
  if (typeof callAPI === 'undefined') {
    return next(action)
  }

  return callAPI(...callAPI)
    .then( /*handle success*/ )
    .catch( /*handle error*/ );
}

apiMiddleware.spec.js

import * as apiMiddleware from './apiMiddleware';

const { CALL_API, default: middleware, callApi } = apiMiddleware;

describe('Api Middleware', () => {

  const store = {getState: jest.fn()};
  const next = jest.fn();
  let action;

  beforeEach(() => {
    // clear the result of the previous calls
    next.mockClear();
    // action that trigger apiMiddleware
    action = {
      [CALL_API]: {
        // list of properties that change from test to test 
      }
    };
  });

  it('calls mocked version of `callApi', () => {
    const callApi = jest.spyOn(apiMiddleware, 'callApi').mockReturnValue(Promise.resolve());

    // error point: middleware() calls the actual `callApi()` 
    middleware(store)(next)(action);

    // assertion
  });
});

Please ignore the action's properties and argument of callApi function. I don't think they are the concern of the point I'm trying to make.

Tell me if you need further elaboration.

Schargel answered 13/9, 2018 at 4:41 Comment(0)
R
8

The jest mocking only works on imported functions. In your apiMiddleware.js the default function is calling callApi variable, not the "exported" callApi function. To make the mock work, move callApi into its own module, and import it in apiMiddleware.js

Good question!

Rookie answered 13/9, 2018 at 16:47 Comment(0)
P
0

I solved my issues converting my code to a Class, example:

// Implementation 
export class Location {
  getLocation() {
    const environment = this.getEnvironmentVariable();
    return environment === "1" ? "USA" : "GLOBAL";
  }
  getEnvironmentVariable() {
    return process.env.REACT_APP_LOCATION;
  }
}


// Test
import { Location } from "./config";

test('location', () => {
  const config = new Location();
  jest.spyOn(config, "getEnvironmentVariable").mockReturnValue("1")

  const location = config.getLocation();
  expect(location).toBe("USA");
});
Pilocarpine answered 26/3, 2022 at 0:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.