Skip to content

Commit da81ac3

Browse files
committed
Add cypress tutorial
1 parent 3e752f2 commit da81ac3

29 files changed

+3583
-0
lines changed

Diff for: cypress-tutorial/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

Diff for: cypress-tutorial/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# cypress tutorial
2+
3+
End-to-end testing with cypress.
4+
5+
Useful links:
6+
7+
YouTube: https://youtu.be/mBnTY9GI9q4
8+
9+
Cypress: https://www.cypress.io/

Diff for: cypress-tutorial/cypress.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

Diff for: cypress-tutorial/cypress/fixtures/example.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "Using fixtures to represent data",
3+
"email": "[email protected]",
4+
"body": "Fixtures are a great way to mock data for responses to routes"
5+
}

Diff for: cypress-tutorial/cypress/integration/amazon.spec.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference types="cypress" />
2+
3+
it("adds item to basket", () => {
4+
cy.visit("https://www.amazon.co.uk/");
5+
6+
cy.get("input[name=field-keywords]").type("Super Mario 3D World");
7+
cy.get("#nav-search-submit-button").click();
8+
9+
cy.contains("Super Mario 3D World + Bowser Fury").click();
10+
11+
cy.get("#add-to-cart-button").click();
12+
13+
cy.get("#hlb-subcart")
14+
.should("contain.text", "1 item")
15+
.and("contain.text", "£44.98");
16+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/// <reference types="cypress" />
2+
3+
context('Actions', () => {
4+
beforeEach(() => {
5+
cy.visit('https://example.cypress.io/commands/actions')
6+
})
7+
8+
// https://on.cypress.io/interacting-with-elements
9+
10+
it('.type() - type into a DOM element', () => {
11+
// https://on.cypress.io/type
12+
cy.get('.action-email')
13+
.type('[email protected]').should('have.value', '[email protected]')
14+
15+
// .type() with special character sequences
16+
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
17+
.type('{del}{selectall}{backspace}')
18+
19+
// .type() with key modifiers
20+
.type('{alt}{option}') //these are equivalent
21+
.type('{ctrl}{control}') //these are equivalent
22+
.type('{meta}{command}{cmd}') //these are equivalent
23+
.type('{shift}')
24+
25+
// Delay each keypress by 0.1 sec
26+
.type('[email protected]', { delay: 100 })
27+
.should('have.value', '[email protected]')
28+
29+
cy.get('.action-disabled')
30+
// Ignore error checking prior to type
31+
// like whether the input is visible or disabled
32+
.type('disabled error checking', { force: true })
33+
.should('have.value', 'disabled error checking')
34+
})
35+
36+
it('.focus() - focus on a DOM element', () => {
37+
// https://on.cypress.io/focus
38+
cy.get('.action-focus').focus()
39+
.should('have.class', 'focus')
40+
.prev().should('have.attr', 'style', 'color: orange;')
41+
})
42+
43+
it('.blur() - blur off a DOM element', () => {
44+
// https://on.cypress.io/blur
45+
cy.get('.action-blur').type('About to blur').blur()
46+
.should('have.class', 'error')
47+
.prev().should('have.attr', 'style', 'color: red;')
48+
})
49+
50+
it('.clear() - clears an input or textarea element', () => {
51+
// https://on.cypress.io/clear
52+
cy.get('.action-clear').type('Clear this text')
53+
.should('have.value', 'Clear this text')
54+
.clear()
55+
.should('have.value', '')
56+
})
57+
58+
it('.submit() - submit a form', () => {
59+
// https://on.cypress.io/submit
60+
cy.get('.action-form')
61+
.find('[type="text"]').type('HALFOFF')
62+
63+
cy.get('.action-form').submit()
64+
.next().should('contain', 'Your form has been submitted!')
65+
})
66+
67+
it('.click() - click on a DOM element', () => {
68+
// https://on.cypress.io/click
69+
cy.get('.action-btn').click()
70+
71+
// You can click on 9 specific positions of an element:
72+
// -----------------------------------
73+
// | topLeft top topRight |
74+
// | |
75+
// | |
76+
// | |
77+
// | left center right |
78+
// | |
79+
// | |
80+
// | |
81+
// | bottomLeft bottom bottomRight |
82+
// -----------------------------------
83+
84+
// clicking in the center of the element is the default
85+
cy.get('#action-canvas').click()
86+
87+
cy.get('#action-canvas').click('topLeft')
88+
cy.get('#action-canvas').click('top')
89+
cy.get('#action-canvas').click('topRight')
90+
cy.get('#action-canvas').click('left')
91+
cy.get('#action-canvas').click('right')
92+
cy.get('#action-canvas').click('bottomLeft')
93+
cy.get('#action-canvas').click('bottom')
94+
cy.get('#action-canvas').click('bottomRight')
95+
96+
// .click() accepts an x and y coordinate
97+
// that controls where the click occurs :)
98+
99+
cy.get('#action-canvas')
100+
.click(80, 75) // click 80px on x coord and 75px on y coord
101+
.click(170, 75)
102+
.click(80, 165)
103+
.click(100, 185)
104+
.click(125, 190)
105+
.click(150, 185)
106+
.click(170, 165)
107+
108+
// click multiple elements by passing multiple: true
109+
cy.get('.action-labels>.label').click({ multiple: true })
110+
111+
// Ignore error checking prior to clicking
112+
cy.get('.action-opacity>.btn').click({ force: true })
113+
})
114+
115+
it('.dblclick() - double click on a DOM element', () => {
116+
// https://on.cypress.io/dblclick
117+
118+
// Our app has a listener on 'dblclick' event in our 'scripts.js'
119+
// that hides the div and shows an input on double click
120+
cy.get('.action-div').dblclick().should('not.be.visible')
121+
cy.get('.action-input-hidden').should('be.visible')
122+
})
123+
124+
it('.rightclick() - right click on a DOM element', () => {
125+
// https://on.cypress.io/rightclick
126+
127+
// Our app has a listener on 'contextmenu' event in our 'scripts.js'
128+
// that hides the div and shows an input on right click
129+
cy.get('.rightclick-action-div').rightclick().should('not.be.visible')
130+
cy.get('.rightclick-action-input-hidden').should('be.visible')
131+
})
132+
133+
it('.check() - check a checkbox or radio element', () => {
134+
// https://on.cypress.io/check
135+
136+
// By default, .check() will check all
137+
// matching checkbox or radio elements in succession, one after another
138+
cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]')
139+
.check().should('be.checked')
140+
141+
cy.get('.action-radios [type="radio"]').not('[disabled]')
142+
.check().should('be.checked')
143+
144+
// .check() accepts a value argument
145+
cy.get('.action-radios [type="radio"]')
146+
.check('radio1').should('be.checked')
147+
148+
// .check() accepts an array of values
149+
cy.get('.action-multiple-checkboxes [type="checkbox"]')
150+
.check(['checkbox1', 'checkbox2']).should('be.checked')
151+
152+
// Ignore error checking prior to checking
153+
cy.get('.action-checkboxes [disabled]')
154+
.check({ force: true }).should('be.checked')
155+
156+
cy.get('.action-radios [type="radio"]')
157+
.check('radio3', { force: true }).should('be.checked')
158+
})
159+
160+
it('.uncheck() - uncheck a checkbox element', () => {
161+
// https://on.cypress.io/uncheck
162+
163+
// By default, .uncheck() will uncheck all matching
164+
// checkbox elements in succession, one after another
165+
cy.get('.action-check [type="checkbox"]')
166+
.not('[disabled]')
167+
.uncheck().should('not.be.checked')
168+
169+
// .uncheck() accepts a value argument
170+
cy.get('.action-check [type="checkbox"]')
171+
.check('checkbox1')
172+
.uncheck('checkbox1').should('not.be.checked')
173+
174+
// .uncheck() accepts an array of values
175+
cy.get('.action-check [type="checkbox"]')
176+
.check(['checkbox1', 'checkbox3'])
177+
.uncheck(['checkbox1', 'checkbox3']).should('not.be.checked')
178+
179+
// Ignore error checking prior to unchecking
180+
cy.get('.action-check [disabled]')
181+
.uncheck({ force: true }).should('not.be.checked')
182+
})
183+
184+
it('.select() - select an option in a <select> element', () => {
185+
// https://on.cypress.io/select
186+
187+
// at first, no option should be selected
188+
cy.get('.action-select')
189+
.should('have.value', '--Select a fruit--')
190+
191+
// Select option(s) with matching text content
192+
cy.get('.action-select').select('apples')
193+
// confirm the apples were selected
194+
// note that each value starts with "fr-" in our HTML
195+
cy.get('.action-select').should('have.value', 'fr-apples')
196+
197+
cy.get('.action-select-multiple')
198+
.select(['apples', 'oranges', 'bananas'])
199+
// when getting multiple values, invoke "val" method first
200+
.invoke('val')
201+
.should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas'])
202+
203+
// Select option(s) with matching value
204+
cy.get('.action-select').select('fr-bananas')
205+
// can attach an assertion right away to the element
206+
.should('have.value', 'fr-bananas')
207+
208+
cy.get('.action-select-multiple')
209+
.select(['fr-apples', 'fr-oranges', 'fr-bananas'])
210+
.invoke('val')
211+
.should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas'])
212+
213+
// assert the selected values include oranges
214+
cy.get('.action-select-multiple')
215+
.invoke('val').should('include', 'fr-oranges')
216+
})
217+
218+
it('.scrollIntoView() - scroll an element into view', () => {
219+
// https://on.cypress.io/scrollintoview
220+
221+
// normally all of these buttons are hidden,
222+
// because they're not within
223+
// the viewable area of their parent
224+
// (we need to scroll to see them)
225+
cy.get('#scroll-horizontal button')
226+
.should('not.be.visible')
227+
228+
// scroll the button into view, as if the user had scrolled
229+
cy.get('#scroll-horizontal button').scrollIntoView()
230+
.should('be.visible')
231+
232+
cy.get('#scroll-vertical button')
233+
.should('not.be.visible')
234+
235+
// Cypress handles the scroll direction needed
236+
cy.get('#scroll-vertical button').scrollIntoView()
237+
.should('be.visible')
238+
239+
cy.get('#scroll-both button')
240+
.should('not.be.visible')
241+
242+
// Cypress knows to scroll to the right and down
243+
cy.get('#scroll-both button').scrollIntoView()
244+
.should('be.visible')
245+
})
246+
247+
it('.trigger() - trigger an event on a DOM element', () => {
248+
// https://on.cypress.io/trigger
249+
250+
// To interact with a range input (slider)
251+
// we need to set its value & trigger the
252+
// event to signal it changed
253+
254+
// Here, we invoke jQuery's val() method to set
255+
// the value and trigger the 'change' event
256+
cy.get('.trigger-input-range')
257+
.invoke('val', 25)
258+
.trigger('change')
259+
.get('input[type=range]').siblings('p')
260+
.should('have.text', '25')
261+
})
262+
263+
it('cy.scrollTo() - scroll the window or element to a position', () => {
264+
// https://on.cypress.io/scrollto
265+
266+
// You can scroll to 9 specific positions of an element:
267+
// -----------------------------------
268+
// | topLeft top topRight |
269+
// | |
270+
// | |
271+
// | |
272+
// | left center right |
273+
// | |
274+
// | |
275+
// | |
276+
// | bottomLeft bottom bottomRight |
277+
// -----------------------------------
278+
279+
// if you chain .scrollTo() off of cy, we will
280+
// scroll the entire window
281+
cy.scrollTo('bottom')
282+
283+
cy.get('#scrollable-horizontal').scrollTo('right')
284+
285+
// or you can scroll to a specific coordinate:
286+
// (x axis, y axis) in pixels
287+
cy.get('#scrollable-vertical').scrollTo(250, 250)
288+
289+
// or you can scroll to a specific percentage
290+
// of the (width, height) of the element
291+
cy.get('#scrollable-both').scrollTo('75%', '25%')
292+
293+
// control the easing of the scroll (default is 'swing')
294+
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' })
295+
296+
// control the duration of the scroll (in ms)
297+
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 })
298+
})
299+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/// <reference types="cypress" />
2+
3+
context('Aliasing', () => {
4+
beforeEach(() => {
5+
cy.visit('https://example.cypress.io/commands/aliasing')
6+
})
7+
8+
it('.as() - alias a DOM element for later use', () => {
9+
// https://on.cypress.io/as
10+
11+
// Alias a DOM element for use later
12+
// We don't have to traverse to the element
13+
// later in our code, we reference it with @
14+
15+
cy.get('.as-table').find('tbody>tr')
16+
.first().find('td').first()
17+
.find('button').as('firstBtn')
18+
19+
// when we reference the alias, we place an
20+
// @ in front of its name
21+
cy.get('@firstBtn').click()
22+
23+
cy.get('@firstBtn')
24+
.should('have.class', 'btn-success')
25+
.and('contain', 'Changed')
26+
})
27+
28+
it('.as() - alias a route for later use', () => {
29+
// Alias the route to wait for its response
30+
cy.intercept('GET', '**/comments/*').as('getComment')
31+
32+
// we have code that gets a comment when
33+
// the button is clicked in scripts.js
34+
cy.get('.network-btn').click()
35+
36+
// https://on.cypress.io/wait
37+
cy.wait('@getComment').its('response.statusCode').should('eq', 200)
38+
})
39+
})

0 commit comments

Comments
 (0)