Proposal: partialMocked - mocked, but less strict return/resolved values.
See original GitHub issueIssue :
I want to do something like this…
const mockFoo = mocked(foo);
mockFoo.mockReturnValue({
valueNeededForTest: 'string' // TypeScript mad! foo returns other values too!
});
But because foo
returns a dozen other properties that the test doesn’t rely on, so we get errors like this:
Error:(21, 43) TS2345: Argument of type '{ valueNeededForTest: string }' is not assignable to parameter of type '{ buildPath: string; babelReactIntlPath:
string; cachePath: string; coveragePath: string; isCI: boolean; githubHostname: string; githubOrg: string; githubRepo: string; localPublicPath: string; ... 7 more ...; getPathWithoutRepoDirectory:
(pathToShorten: string) => string; }'.
Type '{ valueNeededForTest: string; }' is missing the following properties from type '{ buildPath: string; babelReactIntlPath: string; cachePath: string;
coveragePath: string; isCI: boolean; githubHostname: string; githubOrg: string; githubRepo: string; localPublicPath: string; ... 7 more ...;
getPathWithoutRepoDirectory: (pathToShorten: string) => string; }': buildPath, babelReactIntlPath, cachePath, coveragePath, and 12 more.
Workarounds:
This takes away the nice typing mocked
provides:
const mockFoo = mocked(foo);
mockFoo.mockReturnValue(({
valueNeededForTest: 'string'
} as unknown) as ReturnType<foo>);
This isn’t always possible, as running the original function can have side effects, or return something that can’t be easily merged like a promise, and jest.requireActual
’s return type is any
so it doesn’t even solve the original problem.
const mockFoo = mocked(foo);
mockFoo.mockReturnValue({
...jest.requireActual('./foo'),
valueNeededForTest: 'string'
});
Preferred behavior :
A new function called partialMocked
(maybe there’s a better name?) that allows returnType
/resolvedValue
/etc to be a deep partial of what it normally returns.
const mockFoo = partialMocked(foo);
mockFoo.mockReturnValue({
valueNeededForTest: 'string' // TypeScript happy, developer happy!
});
Example implementation :
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends Array<infer U>
? Array<DeepPartial<U>>
: T[P] extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: DeepPartial<T[P]>
};
type PartialReturnType<T extends MockableFunction> =
ReturnType<T> extends Promise<infer U>
? Promise<DeepPartial<U>>
: ReturnType<T> extends Array<infer P>
? Array<DeepPartial<P>>
: DeepPartial<ReturnType<T>>;
interface MockWithArgs<T extends MockableFunction> extends jest.MockInstance<PartialReturnType<T>, ArgumentsOf<T>> {
new (...args: ConstructorArgumentsOf<T>): T;
(...args: ArgumentsOf<T>): PartialReturnType<T>;
}
This fixed the issues I was having. I’m still fairly new with TypeScript, so I’m not sure if this is a complete solution or the right way to do it, so that’s why I made this ticket instead of starting with a pull request.
Thoughts?
Issue Analytics
- State:
- Created 4 years ago
- Reactions:10
- Comments:5
Top GitHub Comments
there is a discussion about mock utils in #1048 . If jest team agrees to migrate mock utils to jest repo, perhaps this proposal can go into jest repo.
I have pasted this issue on https://github.com/facebook/jest/issues/13325. Hopefully, it will be picked up 🥲