Cypress uses Sinon for spies and stubs, but it also exposes Cypress.sinon.match
for more flexible assertions.
I needed a way to check whether an array contains a subsequence of matching values:
cy.expectSubsequence(events, [
{
id: Cypress.sinon.match.string,
timestamp: Cypress.sinon.match.number,
event: 'ready'
},
{
id: Cypress.sinon.match.string,
timestamp: Cypress.sinon.match.number,
event: 'set'
},
{
id: Cypress.sinon.match.string,
timestamp: Cypress.sinon.match.number,
event: 'go'
}
]);
Here’s the custom command I used:
/**
* Asserts that an array contains a subsequence of matching values in order.
* @param {Array} subject - The array to search
* @param {Array} expectedValues - Array of values to match against
*/
Cypress.Commands.add('expectSubsequence', (subject, expectedValues) => {
expect(subject, 'Array to search').to.be.an('array');
expect(expectedValues, 'Expected values').to.be.an('array');
let lastIndex = 0;
expectedValues.forEach((expectedValue) => {
const valuesAfterLast = subject.slice(lastIndex);
const value = valuesAfterLast.find((v) => Cypress.sinon.match(expectedValue).test(v));
expect(value).to.not.equal(
undefined,
`Failed to find a value matching ${JSON.stringify(expectedValue)} in the array`
);
lastIndex = lastIndex + valuesAfterLast.indexOf(value) + 1;
});
});
Note: Cypress.sinon.match()
does partial object matching. This is what I wanted (I don’t care if events contain additional properties), but if you need more strict matching you can use custom matchers.
References
- Cypress.sinon: https://docs.cypress.io/api/utilities/sinon
- Sinon Matchers: https://sinonjs.org/releases/latest/matchers/