Commit ffe1441d authored by Alexandros Georgantas's avatar Alexandros Georgantas

test(app): more cypress

parent 30bac86a
......@@ -10,16 +10,17 @@ context('Actions', () => {
it('.type() - type into a DOM element', () => {
// https://on.cypress.io/type
cy.get('.action-email')
.type('fake@email.com').should('have.value', 'fake@email.com')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
// .type() with special character sequences
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
.type('{del}{selectall}{backspace}')
// .type() with key modifiers
.type('{alt}{option}') //these are equivalent
.type('{ctrl}{control}') //these are equivalent
.type('{meta}{command}{cmd}') //these are equivalent
.type('{alt}{option}') // these are equivalent
.type('{ctrl}{control}') // these are equivalent
.type('{meta}{command}{cmd}') // these are equivalent
.type('{shift}')
// Delay each keypress by 0.1 sec
......@@ -35,21 +36,27 @@ context('Actions', () => {
it('.focus() - focus on a DOM element', () => {
// https://on.cypress.io/focus
cy.get('.action-focus').focus()
cy.get('.action-focus')
.focus()
.should('have.class', 'focus')
.prev().should('have.attr', 'style', 'color: orange;')
.prev()
.should('have.attr', 'style', 'color: orange;')
})
it('.blur() - blur off a DOM element', () => {
// https://on.cypress.io/blur
cy.get('.action-blur').type('About to blur').blur()
cy.get('.action-blur')
.type('About to blur')
.blur()
.should('have.class', 'error')
.prev().should('have.attr', 'style', 'color: red;')
.prev()
.should('have.attr', 'style', 'color: red;')
})
it('.clear() - clears an input or textarea element', () => {
// https://on.cypress.io/clear
cy.get('.action-clear').type('Clear this text')
cy.get('.action-clear')
.type('Clear this text')
.should('have.value', 'Clear this text')
.clear()
.should('have.value', '')
......@@ -58,9 +65,12 @@ context('Actions', () => {
it('.submit() - submit a form', () => {
// https://on.cypress.io/submit
cy.get('.action-form')
.find('[type="text"]').type('HALFOFF')
cy.get('.action-form').submit()
.next().should('contain', 'Your form has been submitted!')
.find('[type="text"]')
.type('HALFOFF')
cy.get('.action-form')
.submit()
.next()
.should('contain', 'Your form has been submitted!')
})
it('.click() - click on a DOM element', () => {
......@@ -116,7 +126,9 @@ context('Actions', () => {
// Our app has a listener on 'dblclick' event in our 'scripts.js'
// that hides the div and shows an input on double click
cy.get('.action-div').dblclick().should('not.be.visible')
cy.get('.action-div')
.dblclick()
.should('not.be.visible')
cy.get('.action-input-hidden').should('be.visible')
})
......@@ -125,26 +137,34 @@ context('Actions', () => {
// By default, .check() will check all
// matching checkbox or radio elements in succession, one after another
cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]')
.check().should('be.checked')
cy.get('.action-checkboxes [type="checkbox"]')
.not('[disabled]')
.check()
.should('be.checked')
cy.get('.action-radios [type="radio"]').not('[disabled]')
.check().should('be.checked')
cy.get('.action-radios [type="radio"]')
.not('[disabled]')
.check()
.should('be.checked')
// .check() accepts a value argument
cy.get('.action-radios [type="radio"]')
.check('radio1').should('be.checked')
.check('radio1')
.should('be.checked')
// .check() accepts an array of values
cy.get('.action-multiple-checkboxes [type="checkbox"]')
.check(['checkbox1', 'checkbox2']).should('be.checked')
.check(['checkbox1', 'checkbox2'])
.should('be.checked')
// Ignore error checking prior to checking
cy.get('.action-checkboxes [disabled]')
.check({ force: true }).should('be.checked')
.check({ force: true })
.should('be.checked')
cy.get('.action-radios [type="radio"]')
.check('radio3', { force: true }).should('be.checked')
.check('radio3', { force: true })
.should('be.checked')
})
it('.uncheck() - uncheck a checkbox element', () => {
......@@ -154,21 +174,25 @@ context('Actions', () => {
// checkbox elements in succession, one after another
cy.get('.action-check [type="checkbox"]')
.not('[disabled]')
.uncheck().should('not.be.checked')
.uncheck()
.should('not.be.checked')
// .uncheck() accepts a value argument
cy.get('.action-check [type="checkbox"]')
.check('checkbox1')
.uncheck('checkbox1').should('not.be.checked')
.uncheck('checkbox1')
.should('not.be.checked')
// .uncheck() accepts an array of values
cy.get('.action-check [type="checkbox"]')
.check(['checkbox1', 'checkbox3'])
.uncheck(['checkbox1', 'checkbox3']).should('not.be.checked')
.uncheck(['checkbox1', 'checkbox3'])
.should('not.be.checked')
// Ignore error checking prior to unchecking
cy.get('.action-check [disabled]')
.uncheck({ force: true }).should('not.be.checked')
.uncheck({ force: true })
.should('not.be.checked')
})
it('.select() - select an option in a <select> element', () => {
......@@ -177,14 +201,16 @@ context('Actions', () => {
// Select option(s) with matching text content
cy.get('.action-select').select('apples')
cy.get('.action-select-multiple')
.select(['apples', 'oranges', 'bananas'])
cy.get('.action-select-multiple').select(['apples', 'oranges', 'bananas'])
// Select option(s) with matching value
cy.get('.action-select').select('fr-bananas')
cy.get('.action-select-multiple')
.select(['fr-apples', 'fr-oranges', 'fr-bananas'])
cy.get('.action-select-multiple').select([
'fr-apples',
'fr-oranges',
'fr-bananas',
])
})
it('.scrollIntoView() - scroll an element into view', () => {
......@@ -194,25 +220,25 @@ context('Actions', () => {
// because they're not within
// the viewable area of their parent
// (we need to scroll to see them)
cy.get('#scroll-horizontal button')
.should('not.be.visible')
cy.get('#scroll-horizontal button').should('not.be.visible')
// scroll the button into view, as if the user had scrolled
cy.get('#scroll-horizontal button').scrollIntoView()
cy.get('#scroll-horizontal button')
.scrollIntoView()
.should('be.visible')
cy.get('#scroll-vertical button')
.should('not.be.visible')
cy.get('#scroll-vertical button').should('not.be.visible')
// Cypress handles the scroll direction needed
cy.get('#scroll-vertical button').scrollIntoView()
cy.get('#scroll-vertical button')
.scrollIntoView()
.should('be.visible')
cy.get('#scroll-both button')
.should('not.be.visible')
cy.get('#scroll-both button').should('not.be.visible')
// Cypress knows to scroll to the right and down
cy.get('#scroll-both button').scrollIntoView()
cy.get('#scroll-both button')
.scrollIntoView()
.should('be.visible')
})
......@@ -228,12 +254,12 @@ context('Actions', () => {
cy.get('.trigger-input-range')
.invoke('val', 25)
.trigger('change')
.get('input[type=range]').siblings('p')
.get('input[type=range]')
.siblings('p')
.should('have.text', '25')
})
it('cy.scrollTo() - scroll the window or element to a position', () => {
// https://on.cypress.io/scrollTo
// You can scroll to 9 specific positions of an element:
......
......@@ -12,9 +12,13 @@ context('Aliasing', () => {
// We don't have to traverse to the element
// later in our code, we reference it with @
cy.get('.as-table').find('tbody>tr')
.first().find('td').first()
.find('button').as('firstBtn')
cy.get('.as-table')
.find('tbody>tr')
.first()
.find('td')
.first()
.find('button')
.as('firstBtn')
// when we reference the alias, we place an
// @ in front of its name
......@@ -26,7 +30,6 @@ context('Aliasing', () => {
})
it('.as() - alias a route for later use', () => {
// Alias the route to wait for its response
cy.server()
cy.route('GET', 'comments/*').as('getComment')
......@@ -36,7 +39,8 @@ context('Aliasing', () => {
cy.get('.network-btn').click()
// https://on.cypress.io/wait
cy.wait('@getComment').its('status').should('eq', 200)
cy.wait('@getComment')
.its('status')
.should('eq', 200)
})
})
......@@ -67,7 +67,7 @@ context('Assertions', () => {
// automatically until it passes all your explicit assertions or times out.
cy.get('.assertions-p')
.find('p')
.should(($p) => {
.should($p => {
// https://on.cypress.io/$
// return an array of texts from all of the p's
// @ts-ignore TS6133 unused variable
......@@ -94,7 +94,7 @@ context('Assertions', () => {
cy.get('.docs-header')
.find('div')
// .should(cb) callback function will be retried
.should(($div) => {
.should($div => {
expect($div).to.have.length(1)
const className = $div[0].className
......@@ -103,7 +103,7 @@ context('Assertions', () => {
})
// .then(cb) callback is not retried,
// it either passes or fails
.then(($div) => {
.then($div => {
expect($div, 'text content').to.have.text('Introduction')
})
})
......@@ -111,7 +111,7 @@ context('Assertions', () => {
it('can throw any error', () => {
cy.get('.docs-header')
.find('div')
.should(($div) => {
.should($div => {
if ($div.length !== 1) {
// you can throw your own errors
throw new Error('Did not find 1 element')
......@@ -129,26 +129,26 @@ context('Assertions', () => {
/**
* Text from the first element.
* @type {string}
*/
*/
let text
/**
* Normalizes passed text,
* useful before comparing text with spaces and different capitalization.
* @param {string} s Text to normalize
*/
const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase()
*/
const normalizeText = s => s.replace(/\s/g, '').toLowerCase()
cy.get('.two-elements')
.find('.first')
.then(($first) => {
.then($first => {
// save text from the first element
text = normalizeText($first.text())
})
cy.get('.two-elements')
.find('.second')
.should(($div) => {
.should($div => {
// we can massage text before comparing
const secondText = normalizeText($div.text())
......
......@@ -7,10 +7,9 @@ context('Connectors', () => {
it('.each() - iterate over an array of elements', () => {
// https://on.cypress.io/each
cy.get('.connectors-each-ul>li')
.each(($el, index, $list) => {
console.log($el, index, $list)
})
cy.get('.connectors-each-ul>li').each(($el, index, $list) => {
console.log($el, index, $list)
})
})
it('.its() - get properties on the current subject', () => {
......@@ -26,7 +25,8 @@ context('Connectors', () => {
// $('.connectors-div').hide()
// https://on.cypress.io/invoke
cy.get('.connectors-div').should('be.hidden')
cy.get('.connectors-div')
.should('be.hidden')
// call the jquery method 'show' on the 'div.container'
.invoke('show')
.should('be.visible')
......@@ -45,12 +45,11 @@ context('Connectors', () => {
it('.then() - invoke a callback function with the current subject', () => {
// https://on.cypress.io/then
cy.get('.connectors-list > li')
.then(($lis) => {
expect($lis, '3 items').to.have.length(3)
expect($lis.eq(0), 'first item').to.contain('Walk the dog')
expect($lis.eq(1), 'second item').to.contain('Feed the cat')
expect($lis.eq(2), 'third item').to.contain('Write JavaScript')
})
cy.get('.connectors-list > li').then($lis => {
expect($lis, '3 items').to.have.length(3)
expect($lis.eq(0), 'first item').to.contain('Walk the dog')
expect($lis.eq(1), 'second item').to.contain('Feed the cat')
expect($lis.eq(2), 'third item').to.contain('Write JavaScript')
})
})
})
......@@ -26,16 +26,17 @@ context('Cookies', () => {
cy.get('#getCookies .set-a-cookie').click()
// cy.getCookies() yields an array of cookies
cy.getCookies().should('have.length', 1).should((cookies) => {
// each cookie has these properties
expect(cookies[0]).to.have.property('name', 'token')
expect(cookies[0]).to.have.property('value', '123ABC')
expect(cookies[0]).to.have.property('httpOnly', false)
expect(cookies[0]).to.have.property('secure', false)
expect(cookies[0]).to.have.property('domain')
expect(cookies[0]).to.have.property('path')
})
cy.getCookies()
.should('have.length', 1)
.should(cookies => {
// each cookie has these properties
expect(cookies[0]).to.have.property('name', 'token')
expect(cookies[0]).to.have.property('value', '123ABC')
expect(cookies[0]).to.have.property('httpOnly', false)
expect(cookies[0]).to.have.property('secure', false)
expect(cookies[0]).to.have.property('domain')
expect(cookies[0]).to.have.property('path')
})
})
it('cy.setCookie() - set a browser cookie', () => {
......
......@@ -8,33 +8,38 @@ context('Cypress.Commands', () => {
// https://on.cypress.io/custom-commands
it('.add() - create a custom command', () => {
Cypress.Commands.add('console', {
prevSubject: true,
}, (subject, method) => {
// the previous subject is automatically received
// and the commands arguments are shifted
// allow us to change the console method used
method = method || 'log'
// log the subject to the console
// @ts-ignore TS7017
console[method]('The subject is', subject)
// whatever we return becomes the new subject
// we don't want to change the subject so
// we return whatever was passed in
return subject
})
Cypress.Commands.add(
'console',
{
prevSubject: true,
},
(subject, method) => {
// the previous subject is automatically received
// and the commands arguments are shifted
// allow us to change the console method used
method = method || 'log'
// log the subject to the console
// @ts-ignore TS7017
console[method]('The subject is', subject)
// whatever we return becomes the new subject
// we don't want to change the subject so
// we return whatever was passed in
return subject
},
)
// @ts-ignore TS2339
cy.get('button').console('info').then(($button) => {
// subject is still $button
})
cy.get('button')
.console('info')
.then($button => {
// subject is still $button
})
})
})
context('Cypress.Cookies', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
......@@ -72,7 +77,6 @@ context('Cypress.Cookies', () => {
})
})
context('Cypress.Server', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
......@@ -108,7 +112,7 @@ context('Cypress.config()', () => {
it('Get and set configuration options', () => {
// https://on.cypress.io/config
let myConfig = Cypress.config()
const myConfig = Cypress.config()
expect(myConfig).to.have.property('animationDistanceThreshold', 5)
expect(myConfig).to.have.property('baseUrl', null)
......@@ -138,8 +142,8 @@ context('Cypress.dom', () => {
// https://on.cypress.io/dom
it('.isHidden() - determine if a DOM element is hidden', () => {
let hiddenP = Cypress.$('.dom-p p.hidden').get(0)
let visibleP = Cypress.$('.dom-p p.visible').get(0)
const hiddenP = Cypress.$('.dom-p p.hidden').get(0)
const visibleP = Cypress.$('.dom-p p.visible').get(0)
// our first paragraph has css class 'hidden'
expect(Cypress.dom.isHidden(hiddenP)).to.be.true
......@@ -172,7 +176,10 @@ context('Cypress.env()', () => {
// get all environment variable
expect(Cypress.env()).to.have.property('host', 'veronica.dev.local')
expect(Cypress.env()).to.have.property('api_server', 'http://localhost:8888/v2/')
expect(Cypress.env()).to.have.property(
'api_server',
'http://localhost:8888/v2/',
)
})
})
......@@ -186,7 +193,6 @@ context('Cypress.log', () => {
})
})
context('Cypress.platform', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
......
......@@ -33,7 +33,8 @@ context('Files', () => {
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
cy.wait('@getComment')
.its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
......@@ -44,7 +45,8 @@ context('Files', () => {
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
cy.wait('@getComment')
.its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
......@@ -56,22 +58,26 @@ context('Files', () => {
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
cy.wait('@getComment')
.its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
})
it('cy.fixture() or require - load a fixture', function () {
it('cy.fixture() or require - load a fixture', function() {
// we are inside the "function () { ... }"
// callback and can use test context object "this"
// "this.example" was loaded in "beforeEach" function callback
expect(this.example, 'fixture in the test context')
.to.deep.equal(requiredExample)
expect(this.example, 'fixture in the test context').to.deep.equal(
requiredExample,
)
// or use "cy.wrap" and "should('deep.equal', ...)" assertion
// @ts-ignore
cy.wrap(this.example, 'fixture vs require')
.should('deep.equal', requiredExample)
cy.wrap(this.example, 'fixture vs require').should(
'deep.equal',
requiredExample,
)
})
it('cy.readFile() - read a files contents', () => {
......@@ -79,7 +85,7 @@ context('Files', () => {
// You can read a file and yield its contents
// The filePath is relative to your project's root.
cy.readFile('cypress.json').then((json) => {
cy.readFile('cypress.json').then(json => {
expect(json).to.be.an('object')
})
})
......@@ -91,11 +97,10 @@ context('Files', () => {
// Use a response from a request to automatically
// generate a fixture file for use later
cy.request('https://jsonplaceholder.cypress.io/users')
.then((response) => {
cy.writeFile('cypress/fixtures/users.json', response.body)
})
cy.fixture('users').should((users) => {
cy.request('https://jsonplaceholder.cypress.io/users').then(response => {
cy.writeFile('cypress/fixtures/users.json', response.body)
})
cy.fixture('users').should(users => {
expect(users[0].name).to.exist
})
......@@ -107,7 +112,7 @@ context('Files', () => {
email: 'jane@example.com',
})
cy.fixture('profile').should((profile) => {
cy.fixture('profile').should(profile => {
expect(profile.name).to.eq('Jane')
})
})
......
......@@ -10,40 +10,46 @@ context('Local Storage', () => {
it('cy.clearLocalStorage() - clear all data in local storage', () => {
// https://on.cypress.io/clearlocalstorage
cy.get('.ls-btn').click().should(() => {
expect(localStorage.getItem('prop1')).to.eq('red')
expect(localStorage.getItem('prop2')).to.eq('blue')
expect(localStorage.getItem('prop3')).to.eq('magenta')
})
cy.get('.ls-btn')
.click()
.should(() => {
expect(localStorage.getItem('prop1')).to.eq('red')
expect(localStorage.getItem('prop2')).to.eq('blue')
expect(localStorage.getItem('prop3')).to.eq('magenta')
})
// clearLocalStorage() yields the localStorage object
cy.clearLocalStorage().should((ls) => {
cy.clearLocalStorage().should(ls => {
expect(ls.getItem('prop1')).to.be.null
expect(ls.getItem('prop2')).to.be.null
expect(ls.getItem('prop3')).to.be.null
})
// Clear key matching string in Local Storage
cy.get('.ls-btn').click().should(() => {
expect(localStorage.getItem('prop1')).to.eq('red')
expect(localStorage.getItem('prop2')).to.eq('blue')
expect(localStorage.getItem('prop3')).to.eq('magenta')
})
cy.get('.ls-btn')
.click()
.should(() => {
expect(localStorage.getItem('prop1')).to.eq('red')
expect(localStorage.getItem('prop2')).to.eq('blue')
expect(localStorage.getItem('prop3')).to.eq('magenta')
})
cy.clearLocalStorage('prop1').should((ls) => {
cy.clearLocalStorage('prop1').should(ls => {
expect(ls.getItem('prop1')).to.be.null
expect(ls.getItem('prop2')).to.eq('blue')
expect(ls.getItem('prop3')).to.eq('magenta')
})
// Clear keys matching regex in Local Storage
cy.get('.ls-btn').click().should(() => {
expect(localStorage.getItem('prop1')).to.eq('red')
expect(localStorage.getItem('prop2')).to.eq('blue')
expect(localStorage.getItem('prop3')).to.eq('magenta')
})
cy.get('.ls-btn')
.click()
.should(() => {
expect(localStorage.getItem('prop1')).to.eq('red')
expect(localStorage.getItem('prop2')).to.eq('blue')
expect(localStorage.getItem('prop3')).to.eq('magenta')
})
cy.clearLocalStorage(/prop1|2/).should((ls) => {
cy.clearLocalStorage(/prop1|2/).should(ls => {
expect(ls.getItem('prop1')).to.be.null
expect(ls.getItem('prop2')).to.be.null
expect(ls.getItem('prop3')).to.eq('magenta')
......
......@@ -12,9 +12,11 @@ context('Location', () => {
it('cy.location() - get window.location', () => {
// https://on.cypress.io/location
cy.location().should((location) => {
cy.location().should(location => {
expect(location.hash).to.be.empty
expect(location.href).to.eq('https://example.cypress.io/commands/location')
expect(location.href).to.eq(
'https://example.cypress.io/commands/location',
)
expect(location.host).to.eq('example.cypress.io')
expect(location.hostname).to.eq('example.cypress.io')
expect(location.origin).to.eq('https://example.cypress.io')
......
......@@ -12,7 +12,9 @@ context('Misc', () => {
// and force Cypress to re-query from the root element
cy.get('.misc-table').within(() => {
// ends the current chain and yields null
cy.contains('Cheryl').click().end()
cy.contains('Cheryl')
.click()
.end()
// queries the entire table again
cy.contains('Charles').click()
......@@ -26,7 +28,8 @@ context('Misc', () => {
// so you can take actions necessary for
// your test outside the scope of Cypress.
cy.exec('echo Jane Lane')
.its('stdout').should('contain', 'Jane Lane')
.its('stdout')
.should('contain', 'Jane Lane')
// we can use Cypress.platform string to
// select appropriate command
......@@ -35,32 +38,39 @@ context('Misc', () => {
if (Cypress.platform === 'win32') {
cy.exec('print cypress.json')
.its('stderr').should('be.empty')
.its('stderr')
.should('be.empty')
} else {
cy.exec('cat cypress.json')
.its('stderr').should('be.empty')
.its('stderr')
.should('be.empty')
cy.exec('pwd')
.its('code').should('eq', 0)
.its('code')
.should('eq', 0)