-
Notifications
You must be signed in to change notification settings - Fork 452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jest.mock doesn't modify the type of the mocked class #576
Comments
I'm not sure it's possible to automatically cast the class - if it is, it's beyond my typescript-fu. Definitely agree the documentation could be clearer. Would love a PR |
Badly it's not possible to dynamically update a class like that. Modules could be overridden, but knowing their path and the overrides can only be written with static strings. So here it's the documentation that should be updated, nothing can be done code-wise. example override of a module (I might be wrong at module file location, it's just an example): import Vue from 'vue' // so that existing types aren't erased by our override
declare module 'vue/types' { // <== this issue would need this string to be dynamic
interface VueConstructor { // already declared in 'vue/types.d.ts' package's file
myProp: string // added prop
}
} A possible way of doing so (but I did not check and anyway it would be a big feature) is by creating a ts-server plugin....... |
The `jest.mock()` does not change the type of the exported values from a module. So we have to: ```ts expect((foo as any).mock.calls[0][0]).toBe('foo') ``` Now with the `mocked` helper it is possible to do: ```ts expect(mocked(foo).mock.calls[0][0]).toBe('foo') ``` It is also possible to deeply mock a module right after importing it. Docs will be updated with related details. Closes kulshekhar#576
Can't do this by a language service plugin. Nothing even a lang service plugin can change the typing of an import, neither of a var. That is why I chose the helper way to fix this, see the PR |
I fell down an internet hole for hours trying to figure this one out. Glad I found this thread! For anyone else that ends up here, I refer you to mocked() e.g. import { mocked } from 'ts-jest/utils';
import { thingThatCallsMyFunc } from './ThingUnderTest'; // <-- this is the item under test
import { myFunc } from './MyDependency'; // <-- this is the dependecy we're mocking
jest.mock('./MyDependency'); // <-- gotta declare the module as mocked up here
describe('a test', () => {
test('my test 1', () => {
// and override the mocked behaviour down here
mocked(myFunc).mockImplementation(() => true); // <-- because myFunc.mockImplementation(...) can't be done in typescript
expect(thingThatCallsMyFunc.doSomething()).toBe(true);
});
test('my test 2', () => {
mocked(myFunc).mockImplementation(() => false); // <-- different mock implementations per test
expect(thingThatCallsMyFunc.doSomething()).toBe(false);
});
}) |
same issue. When call
|
This doesn't work for classes
Example. Snoowrap is a class that I'm trying to mock. It's a class with a constructor, not an instance. import Snoowrap = require("snoowrap")
jest.mock("snoowrap")
beforeEach(() => {
var myMockClass = mocked(Snoowrap) // this generates the above error before I'm even able to mock it
}) This works, but then no typings are available: import Snoowrap from "snoowrap"
const mockComposeMessage = jest.fn()
jest.mock("snoowrap", () => {
return jest.fn().mockImplementation(() => ({
composeMessage: mockComposeMessage
}))
})
chai.should()
beforeEach(() => {
mockComposeMessage.mockClear()
}) Referring to the docs here works great for javascript, but I can't figure this out at all for typescript |
|
this works perfect with react-boilerplate-typescript. thanks, man |
|
After 2 days of all sorts of gymnastics this one worked in a few minutes for me. Thanks for suggesting! |
For people still ending up here, this works for me without the need for import { SomeClass } from './class-file';
jest.mock('./class-file');
describe('test', () => {
const object = new SomeClass();
test('first test', () => {
object.get = jest.fn(() => null);
// ...
});
test('second test', () => {
object.get = jest.fn(() => 'blabla');
object.save = jest.fn(() => { id: 1 });
// ...
});
}); I just can't find a way to do |
Needed to install ts-jest to avoid typescript errors when trying to clear mocked implementation. See link below: kulshekhar/ts-jest#576 Also CRA has outdated jsdom (v14.1.0) which results in MutationObserver error when trying to use WaitFor's in react testing library. Needed to jsdom-sixteen package to run jest with jsdom v16. See the link below testing-library/dom-testing-library#477
@ahgentil try this: import { mocked } from 'ts-jest/utils';
import { thingThatCallsMyFunc } from './ThingUnderTest';
import { myFunc } from './MyDependency';
jest.mock('./MyDependency');
describe('a test', () => {
const mocks = {
myFunc: mocked(myFunc)
}
afterEach(()=>{
Object.values(mocks).forEach(mock => mock.mockClear())
})
test('my test 1', () => {
// and override the mocked behaviour down here
mocks.myFunc.mockImplementation(() => true);
expect(thingThatCallsMyFunc.doSomething()).toBe(true);
});
test('my test 2', () => {
mocks.myFunc.mockImplementation(() => false); // <-- You could have also used: mockImplementationOnce
expect(thingThatCallsMyFunc.doSomething()).toBe(false);
});
}) |
The solution ;(Utilities as jest.Mock<Utilities>).mockClear() worked for me but I had to prefix it with beforeEach(() => {
jest.resetAllMocks()
;(Utilities as jest.Mock<Utilities>).mockClear()
}) |
The documentation says:
However, when it is used, the auto-mocked class' type signature isn't updated with the jest mock extensions, which results in errors like:
The only "simple" work around I've found is to typecast the mocked class as a jest.Mock like:
Ideally provide some way to update the type definitions of auto-mocked classes.
If that's not possible, then at least update the documentation to call out this limitation and provide samples of how to work around it.
The text was updated successfully, but these errors were encountered: