chai: expect(array).to.deep.include({...}) does not apply deep equality recursively

As the title says, if I run expect(array).to.deep.include(obj) I would expect to apply deep equality to each of the property of obj.

But it does not behave like this, is it a bug?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 24 (9 by maintainers)

Most upvoted comments

This fails with assert on chai v4.1.0: expect([ { id: 1, name: 'first'}, { id: 2, name: 'second'}]).to.deep.include({ name: 'first' })

AssertionError: expected [ Array(2) ] to deep include { name: ‘first’ }

This is bug? How i can test if array include object with some specified properties?

upd: can be fixed with chai-subset plugin. Code is something like:

expect([ { id: 1, name: 'first'}, { id: 2, name: 'second'}]).to.containSubset([{ name: 'first' }])

@deksden chai-subset plugin is what I was looking for 👍

@lucasfcosta imo the default should be to search by object reference. I would then expect assert.deepInclude or should.deep.include to do a deep comparison, just like equals and deepEquals behave.

Hi @djom20, I think you could try to use a matcher or search for a plugin which would allow you to do that easily in a single assertion.

As a last resort you could also do:

const checkItemsInclude = (arr, str) => arr.some(i => i.includes(str));
expect(checkItemsInclude(yourArray, 'end')).to.be.equal(true);

If you’re checking for multiple items in the same array you can make that function curried:

const arrayIncludeMatcher = arr => str => arr.some(i => i.includes(str));
const arrayIncludes = arrayIncludeMatcher(yourArray);
expect(arrayIncludes('something')).to.be.equal(true);
expect(arrayIncludes('something wrong')).to.be.equal(false);

Currently we don’t even differentiate .deep.contain from .contain.

@lucasfcosta that sounds not like desirable behavior to me. Indeed I was surprised that [{}].should.not.contain({}) fails, while [{}].indexOf({}).should.equal(-1) succeeds. If this is the intended behavior I think it should be documented with the includes method. Also in general it would be nice if a warning was issued if a non identity flag (like deep) is set on a method that doesn’t support it. Looking at the documentation of deep it only says that it is used by equal and property but it is (at least) also used by members (which doesn’t mention on what kind of target it can be used). Any reason not to support general ES6 iterables here?

Whoops forgot to close this issue. Fixed via #761, will be released in 4.x (alpha release will be available on npm soon).

Another basic failure case for “include” is:

expect({k1: []}).to.include({k1: []});
-->
AssertionError: expected { k1: [] } to have a property 'k1' of [], but got []

Ultimately, it’s using an ‘===’ on the value assertion.

I’ve tried various “deep” flags and other tricks (“contain”, “keys”, “members”) but to no avail. How can I make such a simple assertion (without using “property” as I don’t want the assertion subject to change - which is why I’m using “include” in the first place).

This doesn’t work for nested arrays either. I need to test whether an associative array contains some entry but the following fails:

[['a','A'],['b','B']].should.deep.contain(['a','A'])
--> 
AssertionError: expected [ [ 'a', 'A' ], [ 'b', 'B' ] ] to include [ 'a', 'A' ]

What I find surprising is, that it works as expected using include.deep.members:

[['a','A'],['b','B']].should.include.deep.members([['a','A']])

How do you do this with assert style? there is no assert.deepInclude()