Jest: Error: expect(jest.fn())[.not].toHaveBeenCalledTimes() jest.fn() value must be a mock function or spy. Received: function: [Function getItem]

Created on 14 Dec 2018  路  3Comments  路  Source: facebook/jest

馃悰 Bug Report

I get

Error: expect(jest.fn())[.not].toHaveBeenCalledTimes()

jest.fn() value must be a mock function or spy.
Received:
  function: [Function getItem]

import localStorageWrapper from "./localStorage";

const mockStorage = {
  string: "some string value",
  object: `{"foo": "bar"}`
};
beforeEach(() => {
  window.localStorage = {
    getItem: jest.fn(key => mockStorage[key]),
    setItem: jest.fn()
  };
});

describe("get", () => {
  it("should get string item", () => {
    const key = "string";
    const result = localStorageWrapper.get(key);

    expect(window.localStorage.getItem).toHaveBeenCalledTimes(1);
    expect(window.localStorage.getItem.mock.calls[0][0]).toEqual(key);
    expect(result).toEqual(mockStorage.string);
  });

  it("should get object item", () => {
    const key = "object";
    const result = localStorageWrapper.get(key);

    expect(window.localStorage.getItem).toHaveBeenCalledTimes(1);
    expect(window.localStorage.getItem.mock.calls[0][0]).toEqual(key);
    expect(result).toEqual(JSON.parse(mockStorage.object));
  });
});

describe("set", () => {
  it("should set string item", () => {
    localStorageWrapper.set("foo", "bar");

    expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
    expect(window.localStorage.setItem.mock.calls[0]).toMatchSnapshot();
  });

  it("should set object item", () => {
    localStorageWrapper.set("some_object", { foo: "bar" });

    expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
    expect(window.localStorage.setItem.mock.calls[0]).toMatchSnapshot();
  });
});

To Reproduce

Steps to reproduce the behavior:

Expected behavior

A clear and concise description of what you expected to happen.

Link to repl or repo (highly encouraged)

Please provide either a repl.it demo or a minimal repository on GitHub.

Issues without a reproduction link are likely to stall.

Run npx envinfo --preset jest

Paste the results here:


Bug

Most helpful comment

Jest uses jsdom under the hood for simulating dom. In browsers and in jsdom, you cannot just set window.localStorage to new object, because setter function for it is undefined.
Instead do this in order to override original window.localStorage

beforeEach(() => {
  const localStorageMock = {
    getItem: jest.fn(key => mockStorage[key]),
    setItem: jest.fn((args) => console.log(args)),
  };
  Object.defineProperty(window, 'localStorage', {
    value: localStorageMock,
    writable: true
  })
});

Your code was working in the older version of Jest, because jsdom did not have it's own implementation for localStorage. window.localStorage was undefined and you could assign whatever you wanted to it.

All 3 comments

These tests are not running with latest jest version but were working earlier.

Jest uses jsdom under the hood for simulating dom. In browsers and in jsdom, you cannot just set window.localStorage to new object, because setter function for it is undefined.
Instead do this in order to override original window.localStorage

beforeEach(() => {
  const localStorageMock = {
    getItem: jest.fn(key => mockStorage[key]),
    setItem: jest.fn((args) => console.log(args)),
  };
  Object.defineProperty(window, 'localStorage', {
    value: localStorageMock,
    writable: true
  })
});

Your code was working in the older version of Jest, because jsdom did not have it's own implementation for localStorage. window.localStorage was undefined and you could assign whatever you wanted to it.

Nice answer @grosto, thanks!

Was this page helpful?
0 / 5 - 0 ratings