chai icon indicating copy to clipboard operation
chai copied to clipboard

".not.have.keys" construction does not work

Open akopchinskiy opened this issue 5 years ago • 3 comments

This code passes the test, however it shouldn't.

const test = {
    data: 123,
    data2: 123,
    data3: 123
};

expect(test).not.to.have.keys(['data']);

mocha: 6.2.0 chai: 4.2.0

akopchinskiy avatar Dec 10 '19 14:12 akopchinskiy

Chai uses all by default with `keys. So your expression is equivalent to

expect(test).not.to.have.all.keys(['data']);

Which means that it is expected that all of the target's keys are not a match to the provided list of keys. You should use not.to.have.any.keys.

That being said, this behavior feels counter-intuitive to me.

@keithamus What do you think about making not.to.have.keys default to not.to.have.any.keys, and to.have.keys default to to.have.all.keys?

Neob91 avatar Feb 02 '20 15:02 Neob91

IIRC @meeber spent some time working through this assertions. I bet @meeber has some thoughts on this.

keithamus avatar Feb 02 '20 15:02 keithamus

Been awhile since I looked at or thought about this. Here's a related blast from the past: https://github.com/chaijs/chai/issues/881. In the first post of that thread, I propose deprecating .any. But in this follow-up comment, I concede that .any does have a use in some negated assertions (e.g., .not.have.any.keys): https://github.com/chaijs/chai/issues/881#issuecomment-271054027.

I agree that the intuitive behavior is .all for normal .keys, and .any for negated .keys, but that does create inconsistency from one angle, and potentially complicates the assertion logic (such that the .keys assertion has to be aware whether it's being negated).

Another approach would be to deprecate negated .keys altogether. The replacement to .not.to.have.any.keys(['meow', 'bark']) would be two assertions: not.to.have.property(meow) and not.to.have.property('bark').

meeber avatar Feb 02 '20 18:02 meeber