Prepare To Spy
📺 Watch these examples explained in the video Prepare To Spy On A Method Added Dynamically.
Wait for the property to exist
We can automatically wait for a new window
property to be added before spying on it. For example, let's spy on the window.logEvent
method after the application sets it up.
<button id="action">Action!</button>
<script>
setTimeout(() => {
console.log('loading app')
window.logEvent = (name) => console.log('log event %s', name)
// immediately log something
logEvent('initialized')
}, 10)
document
.getElementById('action')
.addEventListener('click', () => {
logEvent('action')
})
</script>
console.log('loading test')
cy.window().its('logEvent')
cy.window().then((win) => {
cy.spy(win, 'logEvent').as('logEvent')
})
Now we can click on the button and confirm the spy logEvent
is called correctly.
cy.contains('button', 'Action').click()
cy.get('@logEvent').should(
'have.been.calledOnceWithExactly',
'action',
)
Prepare to spy
But what about the very first logEvent
call? The once that happens immediately after the application creates it?
window.logEvent = (name) => console.log('log event %s', name)
// immediately log something
logEvent('initialized')
How do we spy on the logEvent('initialized')
call? By the time the test "figures" out the new property exists, it is too late.
cy.window().its('logEvent')
// too late, the app already called it
<button id="action">Action!</button>
<script>
setTimeout(() => {
console.log('loading app')
window.logEvent = (name) => console.log('log event %s', name)
// immediately log something
logEvent('initialized')
}, 10)
document
.getElementById('action')
.addEventListener('click', () => {
logEvent('action')
})
</script>
console.log('loading test')
// prepare new stub instance
const stub = cy.stub().as('logEvent')
// prepare for the application to set "window.logEvent"
cy.window().then((win) => {
let logEvent
Object.defineProperty(win, 'logEvent', {
get() {
return logEvent
},
set(method) {
// we want to spy on the "window.logEvent",
// so we call the real method function
logEvent = stub.callsFake(method)
},
})
})
As soon as the application tries to set the window.logEvent = ...
we "catch" the assignment and wrap it in our Sinon stub.
cy.get('@logEvent').should(
'have.been.calledOnceWithExactly',
'initialized',
)