-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
feat: Type inference in 'have been called with' parameters #15129
Conversation
✅ Deploy Preview for jestjs ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site configuration. |
34acf3e
to
c515dc0
Compare
Interesting to see some progress in this field. Some time ago I was walking more or less the same path. All was fun until I realised that asymmetric matcher can be also nested. Also that expected value and target arguments even can have different shapes: expect(
jestExpect(
jest.fn<(date: Date, name?: [string, string]) => void>(),
).toHaveBeenCalledWith(jestExpect.any(Date), [
jestExpect.any(String),
jestExpect.any(String),
]),
).type.toBeVoid();
expect(
jestExpect(
jest.fn<(date: Date, name?: [string, string]) => void>(),
).toHaveBeenCalledWith(jestExpect.any(Date), jestExpect.any(Array)),
).type.toBeVoid(); |
@mrazauskas Thanks, this is a good use/test case! I think it's solvable with changing the current type WithAsymmetricMatchers<P extends Array<any>> =
Array<unknown> extends P ? never : {[K in keyof P]: P[K] | AsymmetricMatcher}; to: type WithAsymmetricMatchers<P extends Array<any>> =
Array<unknown> extends P
? never
: {[K in keyof P]: DeepAsymmetricMatcher<P[K]>};
type DeepAsymmetricMatcher<T> = T extends object
? AsymmetricMatcher | {[K in keyof T]: DeepAsymmetricMatcher<T[K]>}
: AsymmetricMatcher | T; I would've preferred that all the asymmetric-matchers-producing functions will return the type that the matcher is supposed to stand for: jestExpect.stringContaining('') // returns `string`
jestExpect.any(Number) // returns `number` As it will allow for even better type checking. However, I'm not sure it's possible, and even if it is, it's likely going to break a lot of things. Do you mind addressing to questions regarding this PR that I posted in the issue?
|
By the way, I updated the example in my previous comment. Finally I recalled that the biggest challenge was to handle optional arguments like |
c26fc92
to
604d3a7
Compare
That didn't work for me.
The code seems to handle this as well. See my updated commit with all the new test cases. |
Ah.. Both I see currently you are importing one type from Some time later I will try out updated types. Really interesting. |
604d3a7
to
7d3c48a
Compare
@mrazauskas That works 😃 I amended my last commit with this addtional change. |
7d3c48a
to
10837e7
Compare
If I got it right, your implementation only supports type inference for the jest.spyOn(globalThis, 'setTimeout');
jest(setTimeout).toHaveBeenLastCalledWith(jest.any(Function), 1000); Not a blocker. That is fine, of course. I just wanted to check if that is by design or this got overlooked? |
10837e7
to
43b166a
Compare
@mrazauskas That's an oversight :) I adjusted the code to support both |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for working on this!
and thanks for reviewing @mrazauskas 🙏
packages/expect/package.json
Outdated
@@ -31,7 +31,8 @@ | |||
"@fast-check/jest": "^1.3.0", | |||
"@jest/test-utils": "workspace:*", | |||
"chalk": "^4.0.0", | |||
"immutable": "^4.0.0" | |||
"immutable": "^4.0.0", | |||
"jest-mock": "workspace:*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be in dependencies
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love that you've added a bunch of tests (thanks!), but this is getting pretty big. maybe we should have a packages/jest-types/__typetests__/expect/mocks.test.ts
or something? or packages/jest-types/__typetests__/expect/toHaveBeenCalled.test.ts
to group by matcher?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SimenB My thoughts exactly :)
I like the idea of having an expect/
directory with a file per function. I'll see about arranging the PR so it's clear which tests were moved and which were added.
@@ -307,3 +308,148 @@ export interface Matchers<R extends void | Promise<void>, T = unknown> { | |||
*/ | |||
toThrow(expected?: unknown): R; | |||
} | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the extensive comments 👍
@@ -20,6 +20,7 @@ | |||
- `[jest-environment-jsdom]` [**BREAKING**] Upgrade JSDOM to v22 ([#13825](https://github.com/jestjs/jest/pull/13825)) | |||
- `[@jest/environment-jsdom-abstract]` Introduce new package which abstracts over the `jsdom` environment, allowing usage of custom versions of JSDOM ([#14717](https://github.com/jestjs/jest/pull/14717)) | |||
- `[jest-environment-node]` Update jest environment with dispose symbols `Symbol` ([#14888](https://github.com/jestjs/jest/pull/14888) & [#14909](https://github.com/jestjs/jest/pull/14909)) | |||
- `[expect, @jest/expect]` [**BREAKING**] Add type inference for function parameters in `CalledWith` assertions ([#15129](https://github.com/facebook/jest/pull/15129)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this a breaking change? the odl type was just Function
or something?
also, only expect
seems to be impacted? I don't see any changes to @jest/expect
at least 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SimenB I'm thinking it will likely break some existing tests that use "have been called" functions due to incorrect typing, like it did in tests/examples in this repo. I'm not sure what are the full implications of this "tag", so obviously I will let you decide.
As for @jest/expect
, I merely copied it from the last PR that tried to introduce this feature. I can obviously remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just used as a way to catch the reader's eye.
I really should have included a migration guide thing when I started landing breaking changes, where how the breaking change might affect you would be listed 😅 I'll have to add one
43b166a
to
64be9af
Compare
64be9af
to
02ea166
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
@mrazauskas @SimenB Thanks for your help on this PR. I couldn't have done it without you ❤️ Please let me know if you have more concerns. As for the changelog, I'm keeping it for you to decide whether to include the "breaking" tag and whether |
@eyalroth I was playing with updated types. All works as expected. Great job! |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Fixes #15034.
Summary
See #15034.
This feature has been attempted at the past (#13268), but introduced a breaking change (#13337) with overloaded functions, and thus was reverted.
To reach the desired typing -- especially the handling of overloaded functions vs no-args function vs the default
jest.fn()
type -- I eventually found this code and modified it slightly to fit better to the use-case.Test plan
See the tests added to the PR.