Skip to content
This repository was archived by the owner on Feb 28, 2023. It is now read-only.

Commit 981d0c8

Browse files
authored
more stubbing examples (#254)
1 parent b75bef6 commit 981d0c8

File tree

7 files changed

+182
-48
lines changed

7 files changed

+182
-48
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ See the presentation at [https://testing-workshop-cypress.netlify.app/][presenta
116116
| [🔗](#component-testing) | Component testing | [17-component-testing](cypress/integration/17-component-testing) | [17-component-testing](slides/17-component-testing/PITCHME.md) | [link](https://testing-workshop-cypress.netlify.app?p=17-component-testing)
117117
| [🔗](#backend) | Backend code | [18-backend](cypress/integration/18-backend) | [18-backend](slides/18-backend/PITCHME.md) | [link](https://testing-workshop-cypress.netlify.app?p=18-backend)
118118
| [🔗](#code-coverage) | Code coverage | [19-code-coverage](cypress/integration/19-code-coverage) | [19-code-coverage](slides/19-code-coverage/PITCHME.md) | [link](https://testing-workshop-cypress.netlify.app?p=19-code-coverage)
119-
| | Stubbing methods | [20-stubbing](./cypress/integration/20-stubbing) | [20-stubbing](./slides/20-stubbing/PITCHME.md) | [link](https://testing-workshop-cypress.netlify.app?p=20-stubbing)
119+
| [🔗](#stubbing-methods) | Stubbing methods | [20-stubbing](./cypress/integration/20-stubbing) | [20-stubbing](./slides/20-stubbing/PITCHME.md) | [link](https://testing-workshop-cypress.netlify.app?p=20-stubbing)
120120
| | The end | - | [end](slides/end/PITCHME.md) | [link](https://testing-workshop-cypress.netlify.app?p=end)
121121

122122
## For speakers 🎙

cypress/integration/12-custom-commands/spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ it.skip('passes when object gets new property', () => {
3737
// add assertions
3838
})
3939

40-
it.only('creates todos', () => {
40+
it('creates todos', () => {
4141
cy.get('.new-todo')
4242
.type('todo 0{enter}')
4343
.type('todo 1{enter}')
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/// <reference types="cypress" />
2+
3+
describe('cy.on', () => {
4+
// these test handles every "window" object
5+
// by attaching the stub whenever any window is created
6+
// https://on.cypress.io/catalog-of-events
7+
it('works', () => {
8+
// there is no "window.track" yet,
9+
// thus we cannot stub just yet
10+
let track // the real track when set by the app
11+
let trackStub // our stub around the real track
12+
13+
// use "cy.on" to prepare for "window.track" assignment
14+
// this code runs for every window creation, thus we
15+
// can track events from the "cy.reload()"
16+
cy.on('window:before:load', (win) => {
17+
Object.defineProperty(win, 'track', {
18+
get() {
19+
return trackStub
20+
},
21+
set(fn) {
22+
// if the stub does not exist yet, create it
23+
if (!track) {
24+
track = fn
25+
// give the created stub an alias so we can retrieve it later
26+
trackStub = cy.stub().callsFake(track).as('track')
27+
}
28+
}
29+
})
30+
})
31+
32+
cy.visit('/')
33+
34+
// make sure the page called the "window.track" with expected arguments
35+
cy.get('@track').should('have.been.calledOnceWith', 'window.load')
36+
37+
cy.reload()
38+
cy.reload()
39+
40+
cy.get('@track')
41+
.should('have.been.calledThrice')
42+
// confirm every call was with "window.load" argument
43+
.invoke('getCalls')
44+
.should((calls) => {
45+
calls.forEach((trackCall, k) => {
46+
expect(trackCall.args, `call ${k + 1}`).to.deep.equal(['window.load'])
47+
})
48+
})
49+
})
50+
})
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/// <reference types="cypress" />
2+
3+
// variable that will hold cy.stub created in the test
4+
let stub
5+
6+
// use Cypress.on in its own spec to avoid every test running it
7+
// https://on.cypress.io/catalog-of-events
8+
Cypress.on('window:before:load', (win) => {
9+
// if the test has prepared a stub
10+
if (stub) {
11+
// the stub function is ready
12+
// always returns it when the application
13+
// is trying to use "window.track"
14+
Object.defineProperty(win, 'track', {
15+
get() {
16+
return stub
17+
}
18+
})
19+
}
20+
})
21+
22+
describe('Cypress.on', () => {
23+
beforeEach(() => {
24+
// let the test create the stub if it needs it
25+
stub = null
26+
})
27+
28+
it('works', () => {
29+
// note: cy.stub returns a function
30+
stub = cy.stub().as('track')
31+
cy.visit('/')
32+
33+
// make sure the page called the "window.track" with expected arguments
34+
cy.get('@track').should('have.been.calledOnceWith', 'window.load')
35+
36+
cy.reload()
37+
cy.reload()
38+
39+
cy.get('@track')
40+
.should('have.been.calledThrice')
41+
// confirm every call was with "window.load" argument
42+
.invoke('getCalls')
43+
.should((calls) => {
44+
calls.forEach((trackCall, k) => {
45+
expect(trackCall.args, `call ${k + 1}`).to.deep.equal(['window.load'])
46+
})
47+
})
48+
})
49+
50+
it('works with reset', () => {
51+
stub = cy.stub().as('track')
52+
cy.visit('/')
53+
54+
// make sure the page called the "window.track" with expected arguments
55+
cy.get('@track')
56+
.should('have.been.calledOnceWith', 'window.load')
57+
// cy.stub().reset() brings the counts back to 0
58+
.invoke('reset')
59+
60+
cy.reload()
61+
cy.reload()
62+
63+
cy.get('@track').should('have.been.calledTwice')
64+
})
65+
})

cypress/integration/20-stubbing/answer.js

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ describe('Stubbing window.track', () => {
2626
cy.get('@track').should('have.been.calledWith', 'todo.remove', 'write code')
2727
})
2828

29+
it('resets the count', () => {
30+
cy.visit('/').then((win) => {
31+
cy.stub(win, 'track').as('track')
32+
})
33+
34+
enterTodo('write code')
35+
cy.get('@track').should('be.calledOnce')
36+
37+
enterTodo('write tests')
38+
cy.get('@track')
39+
.should('be.calledTwice')
40+
// reset the stub
41+
.invoke('reset')
42+
43+
cy.get('@track').should('not.be.called')
44+
enterTodo('control the state')
45+
cy.get('@track').should('be.calledOnce')
46+
})
47+
2948
it('stops working if window changes', () => {
3049
cy.visit('/').then((win) => {
3150
cy.stub(win, 'track').as('track')
@@ -36,12 +55,16 @@ describe('Stubbing window.track', () => {
3655

3756
cy.reload()
3857
enterTodo('write tests')
58+
59+
/* eslint-disable-next-line cypress/no-unnecessary-waiting */
60+
cy.wait(500) // wait just in case the call happens late
61+
3962
// note that our stub was still called once
4063
// meaning the second todo was never counted
4164
cy.get('@track').should('be.calledOnce')
4265
})
4366

44-
it.only('adds stub after reload', () => {
67+
it('adds stub after reload', () => {
4568
const trackStub = cy.stub().as('track')
4669

4770
cy.visit('/').then((win) => {
@@ -84,48 +107,4 @@ describe('Stubbing window.track', () => {
84107
// make sure the page called the "window.track" with expected arguments
85108
cy.get('@track').should('have.been.calledOnceWith', 'window.load')
86109
})
87-
88-
it('works via event handler', () => {
89-
// there is no "window.track" yet,
90-
// thus we cannot stub just yet
91-
let track // the real track when set by the app
92-
let trackStub // our stub around the real track
93-
94-
// use "cy.on" to prepare for "window.track" assignment
95-
// this code runs for every window creation, thus we
96-
// can track events from the "cy.reload()"
97-
cy.on('window:before:load', (win) => {
98-
Object.defineProperty(win, 'track', {
99-
get() {
100-
return trackStub
101-
},
102-
set(fn) {
103-
// if the stub does not exist yet, create it
104-
if (!track) {
105-
track = fn
106-
// give the created stub an alias so we can retrieve it later
107-
trackStub = cy.stub().callsFake(track).as('track')
108-
}
109-
}
110-
})
111-
})
112-
113-
cy.visit('/')
114-
115-
// make sure the page called the "window.track" with expected arguments
116-
cy.get('@track').should('have.been.calledOnceWith', 'window.load')
117-
118-
cy.reload()
119-
cy.reload()
120-
121-
cy.get('@track')
122-
.should('have.been.calledThrice')
123-
// confirm every call was with "window.load" argument
124-
.invoke('getCalls')
125-
.should((calls) => {
126-
calls.forEach((trackCall, k) => {
127-
expect(trackCall.args, `call ${k + 1}`).to.deep.equal(['window.load'])
128-
})
129-
})
130-
})
131110
})

cypress/integration/20-stubbing/spec.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ describe('Stubbing window.track', () => {
2626
// with expected arguments
2727
})
2828

29+
it('resets the count', () => {
30+
// add a couple of items
31+
// confirm the stub was called N times
32+
// reset the stub
33+
// by invoking ".reset()" method
34+
// trigger more events
35+
// confirm the new number
36+
})
37+
2938
it('adds stub after reload', () => {
3039
// create a single stub with
3140
// const trackStub = cy.stub().as('track')
@@ -44,12 +53,20 @@ describe('Stubbing window.track', () => {
4453
// after the visit command confirm the stub was called
4554
})
4655

47-
it('works via event handler', () => {
56+
it('works via cy.on event handler', () => {
4857
// need to return the same stub when using cy.visit
4958
// and cy.reload calls that create new "window" objects
5059
// tip: use the cy.on('window:before:load', ...) event listener
5160
// which is called during cy.visit and during cy.reload
5261
// during the test reload the page several times, then check
5362
// the right number of "window.track" calls was made
63+
// https://on.cypress.io/catalog-of-events
64+
})
65+
66+
it('works via Cypress.on event handler', () => {
67+
// create a single stub in the test
68+
// return it to anyone trying to use window.track
69+
// from Cypress.on('window:before:load') callback
70+
// https://on.cypress.io/catalog-of-events
5471
})
5572
})

slides/20-stubbing/PITCHME.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,29 @@ it('tracks item delete', () => {
7474
})
7575
```
7676

77+
+++
78+
## TODO: reset the count
79+
80+
```js
81+
it('resets the count', () => {
82+
cy.visit('/').then((win) => {
83+
cy.stub(win, 'track').as('track')
84+
})
85+
86+
enterTodo('write code')
87+
cy.get('@track').should('be.calledOnce')
88+
89+
enterTodo('write tests')
90+
cy.get('@track')
91+
.should('be.calledTwice')
92+
// reset the stub?
93+
94+
cy.get('@track').should('not.be.called')
95+
enterTodo('control the state')
96+
cy.get('@track').should('be.calledOnce')
97+
})
98+
```
99+
77100
---
78101
## What if object changes
79102

0 commit comments

Comments
 (0)