-
-
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(expect): allow extending matcher interfaces by moving expect
types to @jest/types
package
#12059
Conversation
|
||
expect.addSnapshotSerializer = () => void 0; |
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.
Is it breaking to remove this line? Could also be left in place with // @ts-expect-error
.
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.
breaking, yes
@@ -15,18 +15,18 @@ import { | |||
toThrowErrorMatchingSnapshot, | |||
} from 'jest-snapshot'; | |||
|
|||
export type Expect = typeof expect; | |||
export default (config: Config.GlobalConfig): Expect.JestExpect => { | |||
const jestExpect = expect as Expect.JestExpect; |
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.
Interface merging or casting? My thinking was: if it is possible without merging, then better to avoid another declare module
. Merging is less explicit. Usually hiding in another file. Felt like code is more readable with type casting.
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.
agreed, if this can also work out for consumers outside of this module 🙂
Codecov Report
@@ Coverage Diff @@
## main #12059 +/- ##
==========================================
- Coverage 67.71% 67.49% -0.23%
==========================================
Files 328 329 +1
Lines 16990 17043 +53
Branches 4817 4818 +1
==========================================
- Hits 11505 11503 -2
- Misses 5452 5507 +55
Partials 33 33
Continue to review full report at Codecov.
|
export type BuildInRawMatcherFn = Expect.RawMatcherFn & { | ||
[BUILD_IN_MATCHER_FLAG]?: boolean; | ||
}; |
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 not be optional, because this prop will be added to each matcher
. At the same time, in code it works only as optional prop. Hm.. Feels like it does not belong to this type.
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 taking the time to put this together! My main concern is - ideally people who install just expect
would be able to add extra matchers to it without worrying about @jest/types
- can we keep the types in expect
instead of moving? I don't fully follow why it has to move
@SimenB Thanks for taking a look. I was spending some time to dig deeper into types of all packages. My aim was to find a solution for this problem: How Jest’s own types could become a single source of truth and could be used instead of A draft branch with full solution is almost done (only one final touch is missing). I will open an issue to show the whole picture with link to that branch. It is hardly possible to land it as a single PR, but this could become a milestone for Jest 28. This PR is part of that draft. The proposed changes make much more sense looking at larger picture. I think it has to wait for Jest 28 and to land without adding any workarounds. |
Would you mind rebasing this? Also, I think possibly moving matchers to a separate module from |
Managed to rebase it. Something goes wrong with module augmentation. Works on IDE, but fails to build. Most probably will fail here too. Thinking about it. |
Not happy about this fix. Type tests will fail, because of the same module augmentation problem. Have to dig deep into this. @SimenB What you think about removing |
We need to keep |
Ah.. Got it. That makes sense. |
Closing in favour of #12404 |
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. |
Summary
The idea is simple – move
expect
types to@jest/types
.Fixed:
Expect
types instead of copy (jest-jasmine2, jest-snapshot);expect
type toTestFrameworkGlobals
;snapshotState
type toMatcherState
through interface merging (jest-snapshot);Matchers
andSnapshotMatchers
;Expect
andJestExpect
(only the latter one includesaddSnapshotSerializer
andSnapshotMatchers
).All this makes
Expect
type more precise forexpect
andjest
users.Feature:
Also it becomes possible to extend
AsymmetricMatchers
andMatchers
interfaces:Alternatively it might be possible to extend the interfaces from
@jest/globals
. I was trying it out. Additional exports has to be added to@jest/globals
. The same interfaces would be exported from@jest/globals
and@jest/types
. It means that the same result could be achieved in two different ways. That’s not the best. Also matchers are not a globals, they do not belong there.Keeping interfaces at
@jest/types
simplifies usage. The same pattern works equally good forjest
and forexpect
users: import expect fromexpect
, extend matchers fromexpect.extend
, extend types from@jest/types
. The@jest/types
package is anyway a dependency ofexpect
. Easy to explain, easy to use. For me this looks like an optimal solution.Why types should be moved at all?
I was trying to expose types from
expect
package (breaking for now, but might be a solution for the future). Unfortunately this approach creates circular dependencies if we importexpect
types to@jest/types
. Theexpect
typings are needed forTestFrameworkGlobals
and from here Circus and Jasmin are loading them. So moving types seemed to be necessary.Actually the idea of moving
expect
types came to my mind while looking through code ofjest-circus
. The typings ofjest-circus
live in@jest/types
. This fact made me to think that movingexpect
types could solve many issues.Problem (and possible Solution)
Unfortunately, there is one problem.
this.utils
, which is part ofMatcherState
interface, depends onjest-matcher-utils
. Importingjest-matcher-utils
to@jest/types
creates circular dependencies. Here is what I tried:One. Write manual typings for
this.utils
. Why not? Some of the utils depend on another Jest packages and these create circular dependencies again or enormous amount of manual typings. That would be hard to maintain.Two. Use interface merging to patch
MatcherState
. This is implemented right now. And this is the dirt this PR is trying to bring into code base. Could be acceptable, but only for short term.Long term solution: to move all
expect
utils (including print helpers,iterableEquality
,subsetEquality
, and alsoisEqual
) fromthis.utils
tojest-matcher-utils
package and to import them from there instead ofthis.utils
. Removethis.utils
and the interface merging patch in Jest 28.This solution would help to get rid of
"./build/utils.js"
export fromexpect
. Would resolve #11867 and #11816. By the way,this.utils
example in Jest’s documentation is suggesting thattoBe
matcher is callingthis.utils.matcherHint()
. In realitymatcherHint()
helper is imported fromjest-matcher-utils
. Seems like this is better pattern also for the userland.If this long term change seem acceptable, then the temporary interface merging patch is fine. (Just to add, I would be glad to help moving the utils.)
This PR might look huge, but it is not. I had to make adjustments in every place where
Expect
types are consumed and to remove previous workarounds. Actual change is rather minimal. Will add few comments.Test plan
An example which demonstrates how interface merging for
AsymmetricMatchers
andMatchers
works is added toexamples
folder.I extended typechecks (or type tests) too. Had to move them from root into packages so that types of
expect
package could be checked in isolation. The test makes sure that types added by Jest (snapshotState
,addSnapshotSerializer
andSnapshotMatchers
) do not leak toexpect
.Moving type test files into the packages also allowed to simply the setup of typechecks.