Typescript using the incorrect type with jest when there are multiple available

Viewed 759

I am new to typescript and noticed a behaviour I wasn't expecting. When I go to mock a named import with the js-cookie package, it mocks a particular instance of the property, but incorrectly chooses the correct type to use.

import Cookies from "js-cookie"
import { mocked } from "ts-jest/utils"

jest.mock("js-cookie")
const mockedCookies = mocked(Cookies, true)

beforeEach(() => {
  mockedCookies.get = jest.fn().mockImplementation(() => "123")
})

it("SampleTest", () => {
  //this line throws an error as it is using a difference interface to check against
  mockedCookies.get.mockImplementationOnce(() => undefined)
  //continue test...
}

In the @types/js-cookies there are two definitions for this and it always uses the get() version when I reference it as mockCookie.get.<some-jest-function>. Hence, I get typescript errors saying Type 'undefined' is not assignable to type '{ [key: string]: string; }'..

/**
* Read cookie
*/
get(name: string): string | undefined;

/**
* Read all available cookies
*/
get(): {[key: string]: string};

I can fix this by always redeclaring the jest.fn() every time, but would prefer to use the handy jest functions (like mockImplementationOnce).

Am I doing something wrong? Is there a way to enforce which get type to use?

2 Answers

I am not sure if this helps but you may use mockedCookies.get.mockImplementationOnce(() => ({})) as of now to get rid of this error.

Updated: After some testing, I see that these mock functions are stored in dictionary style format. The last function with same name always replace the previous ones.

If you try to move get(name: string) below get() from 'js-cookie', you will see that this error is gone. So there is no way to get specific function with same name.

I don't know much about your use-case, but you may do better not using jest mocks and instead use jest's jsdom environment. You can then set up your environment using js-cookie's methods.

In your example, you can run Cookies.remove(<cookie name>); as setup, then when you run Cookies.get(<cookie name>), you should get undefined, no? You do have to be careful about state persisting between tests, but you have to do that in the mock version of this anyway.

I tested jsdom's implementation for a couple simple cases, but I have no idea how thorough their mock is for more advanced use cases involving multiple domains, etc.

Related