Stub calls depending on the arguments
Cypress bundled Sinon.js that allows one to stub method calls depending on the argument. Here are a few examples, for more see the Spies, Stubs & Clocks.
Stub all calls
Imagine we have an object with the method x
that doubles any value given to it.
const doubler = {
double(x) {
return x + x
},
}
We can test its actual behavior
expect(doubler.double(10), '10 x2').to.equal(20)
We can stub the method and any call would return the same mocked value
cy.stub(doubler, 'double').returns(42)
expect(doubler.double(10), '10 x2').to.equal(42)
expect(doubler.double('fun'), 'fun x2').to.equal(42)
We can confirm the number of times the stubbed method was called
expect(doubler.double).to.have.been.calledTwice
And we can confirm the call arguments
expect(doubler.double).to.have.been.calledWith(10)
expect(doubler.double).to.have.been.calledWith('fun')
// an example of a negative assertion
expect(doubler.double).to.not.have.been.calledWith(-5)
We can reset the call history
doubler.double.resetHistory()
expect(doubler.double).to.not.be.called
expect(doubler.double(3)).to.equal(42)
expect(doubler.double).to.have.been.calledOnce
We can restore the default method behavior
doubler.double.restore()
expect(doubler.double('fun')).to.equal('funfun')
Stub calls by order
We can respond differently to different method calls. For example, we can return 1 on the first call, 2 on the second
const doubler = {
double(x) {
return x + x
},
}
cy.stub(doubler, 'double')
.onFirstCall()
.returns(1)
.onSecondCall()
.returns(2)
expect(doubler.double('first')).to.equal(1)
expect(doubler.double('second')).to.equal(2)
expect(doubler.double).to.have.been.calledTwice
All unspecified calls will get undefined
result
expect(doubler.double('third')).to.equal(undefined)
Stub plus callThrough
If you want to stub some calls, but call the original method for all other calls, use callThrough
const doubler = {
double(x) {
return x + x
},
}
cy.stub(doubler, 'double')
.callThrough()
.onFirstCall()
.returns(1)
.onSecondCall()
.returns(2)
expect(doubler.double('first')).to.equal(1)
expect(doubler.double('second')).to.equal(2)
expect(doubler.double).to.have.been.calledTwice
All calls after the first two execute the original doubler.double
method
expect(doubler.double('third')).to.equal('thirdthird')
expect(doubler.double(4)).to.equal(8)
Stub by specific argument value
You can returns different mocked responses based on the specific value of the arguments.
const doubler = {
double(x) {
return x + x
},
}
cy.stub(doubler, 'double')
.withArgs('first')
.returns('11')
.withArgs('second')
.returns('22')
To add other stub behaviors take the stubbed method and use Sinon helpers.
expect(doubler.double('first')).to.equal('11')
expect(doubler.double('second')).to.equal('22')
expect(doubler.double('first')).to.equal('11')
expect(doubler.double).to.have.been.calledThrice
All other called get undefined
expect(doubler.double(4)).to.equal(undefined)
If you want to call the original method for all unmatched arguments, use callThrough()
Stub by type of the argument
const doubler = {
double(x) {
return x + x
},
}
cy.stub(doubler, 'double')
.withArgs(Cypress.sinon.match.number)
.returns(42)
.withArgs(Cypress.sinon.match.string)
.returns('hello')
All other called get undefined
expect(doubler.double('first')).to.equal('hello')
expect(doubler.double(3)).to.equal(42)
expect(doubler.double(true)).to.equal(undefined)
expect(doubler.double).to.have.been.calledThrice
Stub by your own predicate
Unfortunately, seems in Cypress v12 the Sinon version has broken withArgs(sinon.match(predicate))
feature. Thus the following test should work, but does not
const doubler = {
double(x) {
return x + x
},
}
Let's only stub even number arguments.
const isEven = (n) => n % 2 === 0
cy.stub(doubler, 'double')
.withArgs(Cypress.sinon.match(isEven, 'even'))
.returns(42)
// all other calls go to the original method
.callThrough()
expect(doubler.double('first')).to.equal('firstfirst') // original method
expect(doubler.double(3)).to.equal(42)
Note: while stubbing with the predicate match might be broken, the assertion calledWithMatch
is working, see the recipe Stub called with the match.