Reputation: 9177
I'm trying to validate that an array of objects like this:
[
{
a: 1,
b: 2,
c: 3
},
{
a: 4,
b: 5,
c: 6
},
...
]
contains at least one object with both { a: 1 }
and { c: 3 }
:
I thought I could do this with chai-things, but I don't know all the properties of the object to be able to use
expect(array).to.include.something.that.deep.equals({ ??, a: 1, c: 3});
and contain.a.thing.with.property
doesn't work with multiple properties :/
What's the best way to test something like this?
Upvotes: 23
Views: 30418
Reputation: 18745
Found the simplest solution without external dependencies:
expect(
[
{ a: 1, b: 2, c: 3 },
{ a: 4, b: 5, c: 6 },
].map(({a,b}) => { return {a,b} })
).to.include.deep.members([
{ a: 1, b: 2 },
]);
Upvotes: 2
Reputation: 158
Solution without third libraries or plugins:
let array = [
{ a: 1, b: 2, c: 3 },
{ a: 4, b: 5, c: 6 }
];
let match = array.map(({a, c}) => ({a, c})).to.deep.include({ a:1, c:3});
Upvotes: 4
Reputation: 9177
Most elegant solution I could come up with (with the help of lodash):
expect(_.some(array, { 'a': 1, 'c': 3 })).to.be.true;
Upvotes: 20
Reputation: 1303
Most straight forward way I can think of is:
const chai = require('chai');
const expect = chai.expect;
chai.use(require('chai-like'));
chai.use(require('chai-things'));
expect([
{
a: 1,
b: 2,
c: 3,
},
{
a: 4,
b: 5,
c: 6,
},
]).to.be.an('array').that.contains.something.like({ a: 1, c: 3 });
Upvotes: 4
Reputation: 143
Seems like the chai-subset
plugin from chai
seems to have done the trick. Here is something I have working:
const chai = require('chai');
const chaiSubset = require('chai-subset');
chai.use(chaiSubset);
const expect = chai.expect;
expect([ { type: 'text',
id: 'name',
name: 'name',
placeholder: 'John Smith',
required: 'required' },
{ type: 'email',
id: 'email',
name: 'email',
placeholder: '[email protected]',
required: 'required' },
{ type: 'submit' } ]).containSubset([{ type: 'text', type: 'email', type: 'submit' }]);
Upvotes: 3
Reputation: 3782
The desired solution seems to be something like:
expect(array).to.include.something.that.includes({a: 1, c: 3});
I.e. array
contains an item which includes those properties. Unfortunately, it appears to not be supported by chai-things at the moment. For the foreseeable future.
After a number of different attempts, I've found that converting the original array makes the task easier. This should work without additional libraries:
// Get items that interest us/remove items that don't.
const simplifiedArray = array.map(x => ({a: x.a, c: x.c}));
// Now we can do a simple comparison.
expect(simplifiedArray).to.deep.include({a: 1, c: 3});
This also allows you to check for several objects at the same time (my use case).
expect(simplifiedArray).to.include.deep.members([{
a: 1,
c: 3
}, {
a: 3,
c: 5
}]);
Upvotes: 18
Reputation: 63524
You could write your own function to test the array. In this example you pass in the array and the object containing the relevant key/value pairs:
function deepContains(arr, search) {
// first grab the keys from the search object
// we'll use the length later to check to see if we can
// break out of the loop
var searchKeys = Object.keys(search);
// loop over the array, setting our check variable to 0
for (var check = 0, i = 0; i < arr.length; i++) {
var el = arr[i], keys = Object.keys(el);
// loop over each array object's keys
for (var ii = 0; ii < keys.length; ii++) {
var key = keys[ii];
// if there is a corresponding key/value pair in the
// search object increment the check variable
if (search[key] && search[key] === el[key]) check++;
}
// if we have found an object that contains a match
// for the search object return from the function, otherwise
// iterate again
if (check === searchKeys.length) return true;
}
return false;
}
deepContains(data, { a: 4, c: 6 }); // true
deepContains(data, { a: 1, c: 6 }); // false
Upvotes: 0