Ability to overload matchers with `expect.extend` and call the previous implementation if any.
See original GitHub issue🚀 Feature Proposal
When extending jest with new custom matchers, I did not find anything about what happens if a new custom matcher is named exactly the same as an existing matcher. The code suggests it simply overrides the previous matcher.
My suggestion is that we keep the previous implementation, and provide the ability for the new implementation to call the previous one, if any.
Motivation
This would allow to really extend existing matchers, using the same name for new purposes.
For instance, imagine a custom matcher named toBeEmpty
that checks if the value is an array or object that is empty, as provided here. Then imagine jest-dom wants to add a toBeEmpty
to check if a DOM node is empty. But given it has such a potentially common name, it wouldn’t want to break other uses of that matcher. If the argument it receives is a DOM node, it does its thing, otherwise it calls the previous implementation, if it exists, or throws an error about the argument type not supported.
Example
If implemented, I imagined that the previous implementation could be provided as a new property of this
, perhaps this.super
:
function toBeEmpty(target) {
if (!(htmlElement instanceof HTMLElement)) {
if (this.super) {
return this.super(target);
}
throw new Error('expected a HTML element');
}
// Continue with checking if the html element `target` is empty or not...
}
this.super
should be undefined
if there was no previous implementation of a matcher with the same name.
Inspiration
I originally got the idea from chai-dom’s to.be.empty
matcher, that does exactly what is described above, to avoid breaking the standard chai to.be.empty
matcher.
Downside
Maybe having this capability could be considered bad practice, that the same name can mean different things. I can imagine that it could be a nightmare to support in a typed environment, such as flow or TypeScript.
Pitch
I think this could be implemented in userland:
function extendJestExpect(matchers) {
Object.entries(matchers).forEach(([name, matcher]) => {
if (expect[name] != null) {
matcher.super = expect[name];
}
});
expect.extend(matchers);
}
However repositories of custom matchers that wanted to support this, would need to instruct their users to use something like this. And each one of them would need to provide a utility like the above one. Providing this by the library’s core means to add custom matchers would make it official, not to mention that it would be better implemented, and less opportunity to break with new versions than user implementations.
I’m willing to work on this myself if accepted.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:11
- Comments:6 (2 by maintainers)
Top GitHub Comments
The proposed solution works if the different implementation are exclusive, like the
toBeEmpty
example, wherejest-dom
addresses only HTMLElements andjest-extended
addresses strings and arrays. What if a third library introduces anothertoBeEmpty
and handles both cases within? I’m not sure if jest can provide a generic solution to handle such cases. Providing a warning (#9678) and leaving up the setup to the user might be the best idea.For now I’m hacking around it like this.
Not very happy but I need it…