Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to match an array of objects with sinon.js?

How can I match an array of results in a sinon matcher?

For example, how can this code work?

var mystub = sinon.stub();
var myarg = { val: 1, mylist: [ {a:1}, {b:2}, {c:3,d:4} ] };

mystub(myarg);

sinon.assert.calledOnce(mystub).withArgs(
  sinon.match({val: 1, mylist: [{a:1},{b:2},{c:3,d:4}]}) // this doesn't work
);

How can I get this to work? (Note that in my test, I don't have access to myarg - so I need to match it).

Obviously, I could write a custom function matcher, but I'm looking for something a bit easier to read and write.

like image 993
Aneil Mallavarapu Avatar asked Dec 19 '16 21:12

Aneil Mallavarapu


4 Answers

This is an old posting, but I couldn't find the right answer for this question.

Sinon supports nested matchers. So to test the matching of deep object, you can do the following:

const mystub = sinon.stub();
const myarg = {
  val: 1,
  mylist: [{ a: 1, x: 'foo' }, { b: 2, y: 'bar' }, { c: 3, d: 4, e: 5 } ],
};

mystub(myarg);

sinon.assert.calledOnce(mystub);
sinon.assert.calledWithMatch(mystub, {
  val: 1,
  mylist: [
    sinon.match({ a: 1 }),
    sinon.match({ b: 2 }),
    sinon.match({ c: 3, d: 4 }),
  ],
});
like image 155
Eryk Warren Avatar answered Oct 26 '22 03:10

Eryk Warren


Custom matcher.

I recommend writing your own custom sinon matcher.

You can write it in a way that it is general and easy to read when it gets used.

Here is an example approach:

// usage
...withArgs(sinon.match(deepMatch({
    val: 1,
    mylist: [{a:1}, {b:2}, {c:3,d:4}]
})));


// custom matcher
const deepMatch = (expectation) => (actual) => {
    return Object.keys(expectation).every(key => {
        if (checkIfItsObject(expectation[key])) {
            // value is also an object, go deeper and then compare etc.
        } else {
            // compare and return boolean value accordingly
        }
    });
};

// note: checkIfItsObject is pseudocode - there are many ways to
// check if an object is an object so I did not want to complicate
// this code example here
like image 23
lazlojuly Avatar answered Oct 26 '22 05:10

lazlojuly


The custom matching function in the accepted answer is useful to know about but total overkill for this simple use case. To build on the useful answer from Eryk Warren, how about this:

// match each element of the actual array against the corresponding entry in the expected array
sinon.assert.match(actual, expected.map(sinon.match));
like image 2
Jon z Avatar answered Oct 26 '22 05:10

Jon z


Sinon has matchers on the content of arrays, for example, sinon.match.array.deepEquals

This works:

var mystub = sinon.stub();

var myarg = { val: 1, mylist: [ {a:1}, {b:2}, {c:3,d:4} ] };

mystub(myarg);

sinon.assert.calledWith(mystub,
  sinon.match({
    val: 1,
    mylist: sinon.match.array.deepEquals([ {a:1}, {b:2}, {c:3,d:4} ])
  })
);
like image 1
Evgeny Avatar answered Oct 26 '22 05:10

Evgeny