38

I am setting up my tests for the results to a REST endpoint that returns me an array of Mongo database objects.

[{_id: 5, title: 'Blah', owner: 'Ted', description: 'something'...},
 {_id: 70, title: 'GGG', owner: 'Ted', description: 'something'...}...]

What I want my tests to verify is that in the return array it conatins the specific titles that should return. Nothing I do using Chai/Chai-Things seems to work. Things like res.body.savedResults.should.include.something.that.equals({title: 'Blah'}) error out I'm assuming since the record object contains other keys and values besides just title.

Is there a way to make it do what I want? I just need to verify that the titles are in the array and don't care what the other data might be (IE _id).

Thanks

8 Answers 8

44

This is what I usually do within the test:

var result = query_result;

var members = [];
result.forEach(function(e){
    members.push(e.title);
});

expect(members).to.have.members(['expected_title_1','expected_title_2']);

If you know the order of the return array you could also do this:

expect(result).to.have.deep.property('[0].title', 'expected_title_1');
expect(result).to.have.deep.property('[1].title', 'expected_title_2');
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. since I cannot guarantee the result order, that works to solve what I want to test for
I would like to mention, that while your answer is correct, it might be better to use .map() instead of .forEach() in combination with push(). Map is faster than forEach [1] and more readable. :) [1] codeburst.io/javascript-map-vs-foreach-f38111822c0f
38

As stated here following code works now with [email protected] and chai-things. I just love the natural readability of this approach.

var chai = require('chai'),
    expect = chai.expect;

chai.use(require('chai-like'));
chai.use(require('chai-things')); // Don't swap these two

expect(data).to.be.an('array').that.contains.something.like({title: 'Blah'});

Comments

12

Probably the best way now a days would be to use deep.members property

This checks for unordered complete equality. (for incomplete equality change members for includes)

i.e.

expect([ {a:1} ]).to.have.deep.members([ {a:1} ]); // passes
expect([ {a:1} ]).to.have.members([ {a:1} ]); // fails

Here is a great article on testing arrays and objects https://medium.com/building-ibotta/testing-arrays-and-objects-with-chai-js-4b372310fe6d

DISCLAIMER: this is to not only test the title property, but rather a whole array of objects

Comments

10

ES6+

Clean, functional and without dependencies, simply use a map to filter the key you want to check

something like:

const data = [{_id: 5, title: 'Blah', owner: 'Ted', description: 'something'},{_id: 70, title: 'GGG', owner: 'Ted', description: 'something'}];


expect(data.map(e=>({title:e.title}))).to.include({title:"Blah"});

or even shorter if you only check one key:

expect(data.map(e=>(e.title))).to.include("Blah");

https://www.chaijs.com/api/bdd/

Comments

1

I loved the suggestion from @sebastien-horin But another way with Should syntax (for the specific property):

const data = [
    { _id: 5, title: 'Blah', owner: 'Ted', description: 'something' },
    { _id: 7, title: 'Test', owner: 'Ted', description: 'something' },
];

data.map((e) => e.title).every((title) => title.should.equal('Blah'));

Comments

0

Here is another approach that I found to be more helpful. Basically, use string interpolation and map your array of objects to an array of string literals. Then you can write expectations against the array of strings.

const locations: GeoPoint[] = [
  {
    latitude: 10,
    longitude: 10
  },
  {
    latitude: 9,
    longitude: 9
  },
  {
    latitude: -10,
    longitude: -10
  },
  {
    latitude: -9,
    longitude: -9
  }
];
const stringLocations: string[] = locations.map((val: GeoPoint) => 
  `${val.latitude},${val.longitude}`
);

expect(stringLocations).to.contain('-9.5,-9.5');
expect(stringLocations).to.contain('9.5,9.5');

Comments

0

I had the same problem and fixed it by the below assertion:

res.body.savedResults[0].title.should.eql("you value");
// or
expect(res.body.savedResults[0].title).to.be.eql("your value") 

Actually, I use assertions directly on value. it doesn't matter what it is.

Comments

-4

An alternative solution could be extending the array object with a function to test if an object exists inside the array with the desired property matching the expected value, like this

/**
 * @return {boolean}
 */
Array.prototype.HasObjectWithPropertyValue = function (key, value) {
    for (var i = 0; i < this.length; i++) {
        if (this[i][key] === value) return true;
    }
    return false;
};

(i put this in my main test.js file, so that all other nested tests can use the function)

Then you can use it in your tests like this

var result = query_result;
// in my case (using superagent request) here goes
// var result = res.body;

result.HasObjectWithPropertyValue('property', someValue).should.equal(true);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.