.deep and .not are permanent?
See original GitHub issueI wrote the following test for a function that I expect to assign an object’s properties to another object (in a similar vein to Object.assign
):
expect(setPrivs(target, props)).not.to.equal(props).and.to.deep.equal(props);
This fails, even if I switch the order (deep before not). If I separate out the expressions, however, it passes:
expect(setPrivs(target, props)).not.to.equal(props);
expect(setPrivs(target, props)).to.deep.equal(props);
Looking at the documentation, I can understand why it fails. Both deep
and not
apply to any chains following and there appears to be no way to unset them that I can see. Looking at the natural language of my expression, it makes sense that the and
chain should unset them.
I realise that this would be a breaking change, so perhaps an alternative would be to introduce but
:
expect(setPrivs(target, props)).not.to.equal(props).but.to.deep.equal(props);
This behaviour would be very natural as “but” is “used to introduce a phrase or clause contrasting with what has already been mentioned.”
Hopefully this makes sense and I haven’t overlooked something.
Issue Analytics
- State:
- Created 7 years ago
- Comments:12 (8 by maintainers)
Top GitHub Comments
In general, I strongly promote a one-assertion-per-block style of testing.
Conceptually, if I wanted to test if something was green and tasty, then my code would be structured as follows:
I prefer this style of testing over more concise alternatives that perform both assertions inside the same
it
block or even on the same line using language chains. The main reason I prefer the more verbose style is because if the first assertion fails, I usually still want to know if the second assertion passes or fails. A secondary reason for my preference is that the verbose style typically offers more descriptive output when running the test suite.With all of that said, there are occasions when we need to perform two or more assertions in order to test a single concept. More importantly, there are occasions when there’s no point in running the second assertion when the first assertion fails. @andyearnshaw’s original example is such an occasion:
It’s appropriate to include both of these assertions inside a single block. And it’s more convenient to be able to do so by combining the assertions in a single line using language chains.
But is the convenience worth a breaking change to
.but
? My suspicion is no, as I believe the “not this, but instead this” construct to be rare. Does it have any uses beyond the specific “not equal, but instead deep equal” example? I don’t like the keys example as there should be enough certainty in the test conditions to specify all of the keys that are expected instead of having to specify some keys that aren’t expected and some keys that are expected.I think I’d be more accepting of a non-breaking change, such as adding a new language chain like
.instead
that canceled the negate flag, but even then I’m not sure there’s enough application for this to justify the change.Hello guys, thanks for your issue @andyearnshaw! Actually, we do have
.but
. It was introduced as ano-op
word due to this issue: #621. In that issue we would like to be able to write consistent phrases using.not
only for the second assertion (which would beby
in that case).At that time I didn’t think about assigning a behavior to it, but it does make sense to make it cancel any previous
not
statements.Another possible solution for this is “consuming” the
negate
flag as soon as the first assertion after it has run, but that would be too confuse and would introduce a hidden and “magical” behavior IMO.I can’t (right away) think of any edge cases
but
(with the behavior described by @andyearnshaw) would introduce bugs or undesired behavior, because if we used.not
right after it thenegate
flag would be turnedon
again.I think it would be a great addition, what do you guys think? However, if we all agree upon this feature I’d like to have more time to really investigate the implications of this change, since what I’ve written above is just what I was able to remember without looking at the whole code.