1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-02-05 21:57:24 +03:00

F #3951: Initial testing (#690)

Co-authored-by: Jorge Lobo <jlobo@opennebula.systems>
This commit is contained in:
Jorge Miguel Lobo Escalona 2021-01-21 19:30:40 +01:00 committed by GitHub
parent e08ad357f6
commit 8dbb55587f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1230 additions and 2080 deletions

View File

@ -1,9 +1,16 @@
{
"port": 3001,
"port": 2617,
"numTestsKeptInMemory": 20,
"env":{},
"video": false,
"viewportHeight": 720,
"viewportWidth": 1280,
"baseUrl": "http://localhost:3000"
"baseUrl": "http://localhost:2616",
"reporter": "mochawesome",
"reporterOptions": {
"reportDir": "cypress/results",
"overwrite": false,
"html": false,
"json": true
}
}

View File

@ -0,0 +1,110 @@
const cypress = require('cypress')
const marge = require('mochawesome-report-generator')
const { merge } = require('mochawesome-merge')
const { existsSync, mkdirsSync, readFileSync, writeFileSync, removeSync } = require('fs-extra')
const { dirname } = require('path')
const config = {
browser: 'chrome',
headless: true,
spec: 'cypress/integration/**/*.spec.js'
}
const generateReport = (options = {
reportDir: 'cypress/results',
reportFilename: 'merge-results',
saveJson: true,
saveHtml: false,
files: [
'./cypress/results/*.json'
]
}) => {
return merge(options).then(report => marge.create(report, options))
}
const parseReport = (dataReport = '') => {
if (dataReport && Array.isArray(dataReport) && dataReport.slice(-1).pop()) {
const pathMergeJson = dataReport.slice(-1).pop()
const bsname = dirname(pathMergeJson)
const fileData = readFileSync(pathMergeJson, 'utf8')
if (fileData) {
const dataJSON = JSON.parse(fileData)
const parsedJSON = {}
// version
parsedJSON.version = dataJSON.meta.mochawesome.version
// examples
const examples = []
// results -19
if (dataJSON.results) {
dataJSON.results.forEach(results => {
const pathTest = results.fullFile
// results.suites -28
if (results && results.suites && Array.isArray(results.suites)) {
results.suites.forEach(suites => {
// result.suites.tests -36
if (suites && suites.tests && Array.isArray(suites.tests)) {
suites.tests.forEach(test => {
const parsedTest = {}
parsedTest.id = pathTest
parsedTest.description = test.title || null
parsedTest.full_description = test.fullTitle || null
parsedTest.status = test.pass ? 'passed' : 'failed'
parsedTest.file_path = pathTest
parsedTest.line_number = null
parsedTest.run_time = test.duration || null
parsedTest.pending_message = null
if (test.fail && test.code && test.code.length) {
parsedTest.exception = {
class: test.err.message,
backtrace: test.err.estack && [test.err.estack],
message: test.code
}
}
examples.push(parsedTest)
})
}
})
}
})
}
parsedJSON.examples = examples
// summary
parsedJSON.summary = {
duration: dataJSON.stats.duration,
example_count: dataJSON.stats.tests,
failure_count: dataJSON.stats.failures,
pending_count: dataJSON.stats.pending,
errors_outside_of_examples_count: dataJSON.stats.other
}
// summary_line
parsedJSON.summary_line = `${dataJSON.stats.testsRegistered} examples, ${dataJSON.stats.failures} failures`
// clear results folder
removeSync(bsname)
// create path
if (!existsSync(bsname)) {
mkdirsSync(bsname)
}
// create JSON file
writeFileSync(`${bsname}/results.json`, JSON.stringify(parsedJSON))
}
}
}
cypress.run(config).then(
() => {
generateReport().then(parseReport)
},
error => {
generateReport().then(parseReport)
console.error(error)
process.exit(1)
}
)

View File

@ -7,5 +7,21 @@
"endpoints": {
"login": "/api/auth/",
"userInfo": "/api/user/info"
},
"provision": {
"provision": "hybrid+",
"provider": "aws",
"nameProvider": "aws-frankfurt",
"descriptionProvider": "Elastic cluster on AWS in Frakfurt",
"descriptionProviderEdited": "Elastic cluster on AWS in Frakfurt Edited!",
"descriptionProvision": "Provision description",
"key": "access key",
"keyEdited": "access key Edited!",
"secretKey": "secret access key",
"secretKeyEdited": "secret access key Edited!",
"nameProvision": "aws-cluster",
"numberInstances": "1",
"amiImage": "ami-0b793c1e0d1dc4d28",
"instanceType": "i3-metal"
}
}

View File

@ -1,16 +0,0 @@
// / <reference types="Cypress" />
context('Dashboard', () => {
before(() => {
cy.visit('/');
cy.login();
});
after(() => {
cy.logout();
});
it('has dashboard title on header', () => {
cy.get('[data-cy=header-title]').should('have.text', 'dashboard');
});
});

View File

@ -1,272 +0,0 @@
/// <reference types="Cypress" />
context('Actions', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/actions')
})
// https://on.cypress.io/interacting-with-elements
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() 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('{shift}')
// Delay each keypress by 0.1 sec
.type('slow.typing@email.com', { delay: 100 })
.should('have.value', 'slow.typing@email.com')
cy.get('.action-disabled')
// Ignore error checking prior to type
// like whether the input is visible or disabled
.type('disabled error checking', { force: true })
.should('have.value', 'disabled error checking')
})
it('.focus() - focus on a DOM element', () => {
// https://on.cypress.io/focus
cy.get('.action-focus').focus()
.should('have.class', 'focus')
.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()
.should('have.class', 'error')
.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')
.should('have.value', 'Clear this text')
.clear()
.should('have.value', '')
})
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!')
})
it('.click() - click on a DOM element', () => {
// https://on.cypress.io/click
cy.get('.action-btn').click()
// You can click on 9 specific positions of an element:
// -----------------------------------
// | topLeft top topRight |
// | |
// | |
// | |
// | left center right |
// | |
// | |
// | |
// | bottomLeft bottom bottomRight |
// -----------------------------------
// clicking in the center of the element is the default
cy.get('#action-canvas').click()
cy.get('#action-canvas').click('topLeft')
cy.get('#action-canvas').click('top')
cy.get('#action-canvas').click('topRight')
cy.get('#action-canvas').click('left')
cy.get('#action-canvas').click('right')
cy.get('#action-canvas').click('bottomLeft')
cy.get('#action-canvas').click('bottom')
cy.get('#action-canvas').click('bottomRight')
// .click() accepts an x and y coordinate
// that controls where the click occurs :)
cy.get('#action-canvas')
.click(80, 75) // click 80px on x coord and 75px on y coord
.click(170, 75)
.click(80, 165)
.click(100, 185)
.click(125, 190)
.click(150, 185)
.click(170, 165)
// click multiple elements by passing multiple: true
cy.get('.action-labels>.label').click({ multiple: true })
// Ignore error checking prior to clicking
cy.get('.action-opacity>.btn').click({ force: true })
})
it('.dblclick() - double click on a DOM element', () => {
// https://on.cypress.io/dblclick
// 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-input-hidden').should('be.visible')
})
it('.check() - check a checkbox or radio element', () => {
// https://on.cypress.io/check
// 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-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() accepts an array of values
cy.get('.action-multiple-checkboxes [type="checkbox"]')
.check(['checkbox1', 'checkbox2']).should('be.checked')
// Ignore error checking prior to checking
cy.get('.action-checkboxes [disabled]')
.check({ force: true }).should('be.checked')
cy.get('.action-radios [type="radio"]')
.check('radio3', { force: true }).should('be.checked')
})
it('.uncheck() - uncheck a checkbox element', () => {
// https://on.cypress.io/uncheck
// By default, .uncheck() will uncheck all matching
// checkbox elements in succession, one after another
cy.get('.action-check [type="checkbox"]')
.not('[disabled]')
.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() accepts an array of values
cy.get('.action-check [type="checkbox"]')
.check(['checkbox1', 'checkbox3'])
.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')
})
it('.select() - select an option in a <select> element', () => {
// https://on.cypress.io/select
// Select option(s) with matching text content
cy.get('.action-select').select('apples')
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'])
})
it('.scrollIntoView() - scroll an element into view', () => {
// https://on.cypress.io/scrollintoview
// normally all of these buttons are hidden,
// 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')
// scroll the button into view, as if the user had scrolled
cy.get('#scroll-horizontal button').scrollIntoView()
.should('be.visible')
cy.get('#scroll-vertical button')
.should('not.be.visible')
// Cypress handles the scroll direction needed
cy.get('#scroll-vertical button').scrollIntoView()
.should('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()
.should('be.visible')
})
it('.trigger() - trigger an event on a DOM element', () => {
// https://on.cypress.io/trigger
// To interact with a range input (slider)
// we need to set its value & trigger the
// event to signal it changed
// Here, we invoke jQuery's val() method to set
// the value and trigger the 'change' event
cy.get('.trigger-input-range')
.invoke('val', 25)
.trigger('change')
.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:
// -----------------------------------
// | topLeft top topRight |
// | |
// | |
// | |
// | left center right |
// | |
// | |
// | |
// | bottomLeft bottom bottomRight |
// -----------------------------------
// if you chain .scrollTo() off of cy, we will
// scroll the entire window
cy.scrollTo('bottom')
cy.get('#scrollable-horizontal').scrollTo('right')
// or you can scroll to a specific coordinate:
// (x axis, y axis) in pixels
cy.get('#scrollable-vertical').scrollTo(250, 250)
// or you can scroll to a specific percentage
// of the (width, height) of the element
cy.get('#scrollable-both').scrollTo('75%', '25%')
// control the easing of the scroll (default is 'swing')
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' })
// control the duration of the scroll (in ms)
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 })
})
})

View File

@ -1,42 +0,0 @@
/// <reference types="Cypress" />
context('Aliasing', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/aliasing')
})
it('.as() - alias a DOM element for later use', () => {
// https://on.cypress.io/as
// Alias a DOM element for use later
// 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')
// when we reference the alias, we place an
// @ in front of its name
cy.get('@firstBtn').click()
cy.get('@firstBtn')
.should('have.class', 'btn-success')
.and('contain', 'Changed')
})
it('.as() - alias a route for later use', () => {
// Alias the route to wait for its response
cy.server()
cy.route('GET', 'comments/*').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click()
// https://on.cypress.io/wait
cy.wait('@getComment').its('status').should('eq', 200)
})
})

View File

@ -1,168 +0,0 @@
/// <reference types="Cypress" />
context('Assertions', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/assertions')
})
describe('Implicit Assertions', () => {
it('.should() - make an assertion about the current subject', () => {
// https://on.cypress.io/should
cy.get('.assertion-table')
.find('tbody tr:last')
.should('have.class', 'success')
.find('td')
.first()
// checking the text of the <td> element in various ways
.should('have.text', 'Column content')
.should('contain', 'Column content')
.should('have.html', 'Column content')
// chai-jquery uses "is()" to check if element matches selector
.should('match', 'td')
// to match text content against a regular expression
// first need to invoke jQuery method text()
// and then match using regular expression
.invoke('text')
.should('match', /column content/i)
// a better way to check element's text content against a regular expression
// is to use "cy.contains"
// https://on.cypress.io/contains
cy.get('.assertion-table')
.find('tbody tr:last')
// finds first <td> element with text content matching regular expression
.contains('td', /column content/i)
.should('be.visible')
// for more information about asserting element's text
// see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-elements-text-contents
})
it('.and() - chain multiple assertions together', () => {
// https://on.cypress.io/and
cy.get('.assertions-link')
.should('have.class', 'active')
.and('have.attr', 'href')
.and('include', 'cypress.io')
})
})
describe('Explicit Assertions', () => {
// https://on.cypress.io/assertions
it('expect - make an assertion about a specified subject', () => {
// We can use Chai's BDD style assertions
expect(true).to.be.true
const o = { foo: 'bar' }
expect(o).to.equal(o)
expect(o).to.deep.equal({ foo: 'bar' })
// matching text using regular expression
expect('FooBar').to.match(/bar$/i)
})
it('pass your own callback function to should()', () => {
// Pass a function to should that can have any number
// of explicit assertions within it.
// The ".should(cb)" function will be retried
// automatically until it passes all your explicit assertions or times out.
cy.get('.assertions-p')
.find('p')
.should(($p) => {
// https://on.cypress.io/$
// return an array of texts from all of the p's
// @ts-ignore TS6133 unused variable
const texts = $p.map((i, el) => Cypress.$(el).text())
// jquery map returns jquery object
// and .get() convert this to simple array
const paragraphs = texts.get()
// array should have length of 3
expect(paragraphs, 'has 3 paragraphs').to.have.length(3)
// use second argument to expect(...) to provide clear
// message with each assertion
expect(paragraphs, 'has expected text in each paragraph').to.deep.eq([
'Some text from first p',
'More text from second p',
'And even more text from third p',
])
})
})
it('finds element by class name regex', () => {
cy.get('.docs-header')
.find('div')
// .should(cb) callback function will be retried
.should(($div) => {
expect($div).to.have.length(1)
const className = $div[0].className
expect(className).to.match(/heading-/)
})
// .then(cb) callback is not retried,
// it either passes or fails
.then(($div) => {
expect($div, 'text content').to.have.text('Introduction')
})
})
it('can throw any error', () => {
cy.get('.docs-header')
.find('div')
.should(($div) => {
if ($div.length !== 1) {
// you can throw your own errors
throw new Error('Did not find 1 element')
}
const className = $div[0].className
if (!className.match(/heading-/)) {
throw new Error(`Could not find class "heading-" in ${className}`)
}
})
})
it('matches unknown text between two elements', () => {
/**
* 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()
cy.get('.two-elements')
.find('.first')
.then(($first) => {
// save text from the first element
text = normalizeText($first.text())
})
cy.get('.two-elements')
.find('.second')
.should(($div) => {
// we can massage text before comparing
const secondText = normalizeText($div.text())
expect(secondText, 'second text').to.equal(text)
})
})
it('assert - assert shape of an object', () => {
const person = {
name: 'Joe',
age: 20,
}
assert.isObject(person, 'value is object')
})
})
})

View File

@ -1,56 +0,0 @@
/// <reference types="Cypress" />
context('Connectors', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/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)
})
})
it('.its() - get properties on the current subject', () => {
// https://on.cypress.io/its
cy.get('.connectors-its-ul>li')
// calls the 'length' property yielding that value
.its('length')
.should('be.gt', 2)
})
it('.invoke() - invoke a function on the current subject', () => {
// our div is hidden in our script.js
// $('.connectors-div').hide()
// https://on.cypress.io/invoke
cy.get('.connectors-div').should('be.hidden')
// call the jquery method 'show' on the 'div.container'
.invoke('show')
.should('be.visible')
})
it('.spread() - spread an array as individual args to callback function', () => {
// https://on.cypress.io/spread
const arr = ['foo', 'bar', 'baz']
cy.wrap(arr).spread((foo, bar, baz) => {
expect(foo).to.eq('foo')
expect(bar).to.eq('bar')
expect(baz).to.eq('baz')
})
})
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')
})
})
})

View File

@ -1,78 +0,0 @@
/// <reference types="Cypress" />
context('Cookies', () => {
beforeEach(() => {
Cypress.Cookies.debug(true)
cy.visit('https://example.cypress.io/commands/cookies')
// clear cookies again after visiting to remove
// any 3rd party cookies picked up such as cloudflare
cy.clearCookies()
})
it('cy.getCookie() - get a browser cookie', () => {
// https://on.cypress.io/getcookie
cy.get('#getCookie .set-a-cookie').click()
// cy.getCookie() yields a cookie object
cy.getCookie('token').should('have.property', 'value', '123ABC')
})
it('cy.getCookies() - get browser cookies', () => {
// https://on.cypress.io/getcookies
cy.getCookies().should('be.empty')
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')
})
})
it('cy.setCookie() - set a browser cookie', () => {
// https://on.cypress.io/setcookie
cy.getCookies().should('be.empty')
cy.setCookie('foo', 'bar')
// cy.getCookie() yields a cookie object
cy.getCookie('foo').should('have.property', 'value', 'bar')
})
it('cy.clearCookie() - clear a browser cookie', () => {
// https://on.cypress.io/clearcookie
cy.getCookie('token').should('be.null')
cy.get('#clearCookie .set-a-cookie').click()
cy.getCookie('token').should('have.property', 'value', '123ABC')
// cy.clearCookies() yields null
cy.clearCookie('token').should('be.null')
cy.getCookie('token').should('be.null')
})
it('cy.clearCookies() - clear browser cookies', () => {
// https://on.cypress.io/clearcookies
cy.getCookies().should('be.empty')
cy.get('#clearCookies .set-a-cookie').click()
cy.getCookies().should('have.length', 1)
// cy.clearCookies() yields null
cy.clearCookies()
cy.getCookies().should('be.empty')
})
})

View File

@ -1,222 +0,0 @@
/// <reference types="Cypress" />
context('Cypress.Commands', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
// 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
})
// @ts-ignore TS2339
cy.get('button').console('info').then(($button) => {
// subject is still $button
})
})
})
context('Cypress.Cookies', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
// https://on.cypress.io/cookies
it('.debug() - enable or disable debugging', () => {
Cypress.Cookies.debug(true)
// Cypress will now log in the console when
// cookies are set or cleared
cy.setCookie('fakeCookie', '123ABC')
cy.clearCookie('fakeCookie')
cy.setCookie('fakeCookie', '123ABC')
cy.clearCookie('fakeCookie')
cy.setCookie('fakeCookie', '123ABC')
})
it('.preserveOnce() - preserve cookies by key', () => {
// normally cookies are reset after each test
cy.getCookie('fakeCookie').should('not.be.ok')
// preserving a cookie will not clear it when
// the next test starts
cy.setCookie('lastCookie', '789XYZ')
Cypress.Cookies.preserveOnce('lastCookie')
})
it('.defaults() - set defaults for all cookies', () => {
// now any cookie with the name 'session_id' will
// not be cleared before each new test runs
Cypress.Cookies.defaults({
whitelist: 'session_id',
})
})
})
context('Cypress.Server', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
// Permanently override server options for
// all instances of cy.server()
// https://on.cypress.io/cypress-server
it('.defaults() - change default config of server', () => {
Cypress.Server.defaults({
delay: 0,
force404: false,
})
})
})
context('Cypress.arch', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
it('Get CPU architecture name of underlying OS', () => {
// https://on.cypress.io/arch
expect(Cypress.arch).to.exist
})
})
context('Cypress.config()', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
it('Get and set configuration options', () => {
// https://on.cypress.io/config
let myConfig = Cypress.config()
expect(myConfig).to.have.property('animationDistanceThreshold', 5)
expect(myConfig).to.have.property('baseUrl', null)
expect(myConfig).to.have.property('defaultCommandTimeout', 4000)
expect(myConfig).to.have.property('requestTimeout', 5000)
expect(myConfig).to.have.property('responseTimeout', 30000)
expect(myConfig).to.have.property('viewportHeight', 660)
expect(myConfig).to.have.property('viewportWidth', 1000)
expect(myConfig).to.have.property('pageLoadTimeout', 60000)
expect(myConfig).to.have.property('waitForAnimations', true)
expect(Cypress.config('pageLoadTimeout')).to.eq(60000)
// this will change the config for the rest of your tests!
Cypress.config('pageLoadTimeout', 20000)
expect(Cypress.config('pageLoadTimeout')).to.eq(20000)
Cypress.config('pageLoadTimeout', 60000)
})
})
context('Cypress.dom', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
// 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)
// our first paragraph has css class 'hidden'
expect(Cypress.dom.isHidden(hiddenP)).to.be.true
expect(Cypress.dom.isHidden(visibleP)).to.be.false
})
})
context('Cypress.env()', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
// We can set environment variables for highly dynamic values
// https://on.cypress.io/environment-variables
it('Get environment variables', () => {
// https://on.cypress.io/env
// set multiple environment variables
Cypress.env({
host: 'veronica.dev.local',
api_server: 'http://localhost:8888/v1/',
})
// get environment variable
expect(Cypress.env('host')).to.eq('veronica.dev.local')
// set environment variable
Cypress.env('api_server', 'http://localhost:8888/v2/')
expect(Cypress.env('api_server')).to.eq('http://localhost:8888/v2/')
// 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/')
})
})
context('Cypress.log', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
it('Control what is printed to the Command Log', () => {
// https://on.cypress.io/cypress-log
})
})
context('Cypress.platform', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
it('Get underlying OS name', () => {
// https://on.cypress.io/platform
expect(Cypress.platform).to.be.exist
})
})
context('Cypress.version', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
it('Get current version of Cypress being run', () => {
// https://on.cypress.io/version
expect(Cypress.version).to.be.exist
})
})
context('Cypress.spec', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/cypress-api')
})
it('Get current spec information', () => {
// https://on.cypress.io/spec
// wrap the object so we can inspect it easily by clicking in the command log
cy.wrap(Cypress.spec).should('have.keys', ['name', 'relative', 'absolute'])
})
})

View File

@ -1,114 +0,0 @@
/// <reference types="Cypress" />
/// JSON fixture file can be loaded directly using
// the built-in JavaScript bundler
// @ts-ignore
const requiredExample = require('../../fixtures/example')
context('Files', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/files')
})
beforeEach(() => {
// load example.json fixture file and store
// in the test context object
cy.fixture('example.json').as('example')
})
it('cy.fixture() - load a fixture', () => {
// https://on.cypress.io/fixture
// Instead of writing a response inline you can
// use a fixture file's content.
cy.server()
cy.fixture('example.json').as('comment')
// when application makes an Ajax request matching "GET comments/*"
// Cypress will intercept it and reply with object
// from the "comment" alias
cy.route('GET', 'comments/*', '@comment').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
// you can also just write the fixture in the route
cy.route('GET', 'comments/*', 'fixture:example.json').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
cy.wait('@getComment').its('responseBody')
.should('have.property', 'name')
.and('include', 'Using fixtures to represent data')
// or write fx to represent fixture
// by default it assumes it's .json
cy.route('GET', 'comments/*', 'fx:example').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.fixture-btn').click()
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 () {
// 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)
// or use "cy.wrap" and "should('deep.equal', ...)" assertion
// @ts-ignore
cy.wrap(this.example, 'fixture vs require')
.should('deep.equal', requiredExample)
})
it('cy.readFile() - read a files contents', () => {
// https://on.cypress.io/readfile
// You can read a file and yield its contents
// The filePath is relative to your project's root.
cy.readFile('cypress.json').then((json) => {
expect(json).to.be.an('object')
})
})
it('cy.writeFile() - write to a file', () => {
// https://on.cypress.io/writefile
// You can write to a file
// 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) => {
expect(users[0].name).to.exist
})
// JavaScript arrays and objects are stringified
// and formatted into text.
cy.writeFile('cypress/fixtures/profile.json', {
id: 8739,
name: 'Jane',
email: 'jane@example.com',
})
cy.fixture('profile').should((profile) => {
expect(profile.name).to.eq('Jane')
})
})
})

View File

@ -1,52 +0,0 @@
/// <reference types="Cypress" />
context('Local Storage', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/local-storage')
})
// Although local storage is automatically cleared
// in between tests to maintain a clean state
// sometimes we need to clear the local storage manually
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')
})
// clearLocalStorage() yields the localStorage object
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.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.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')
})
})
})

View File

@ -1,32 +0,0 @@
/// <reference types="Cypress" />
context('Location', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/location')
})
it('cy.hash() - get the current URL hash', () => {
// https://on.cypress.io/hash
cy.hash().should('be.empty')
})
it('cy.location() - get window.location', () => {
// https://on.cypress.io/location
cy.location().should((location) => {
expect(location.hash).to.be.empty
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')
expect(location.pathname).to.eq('/commands/location')
expect(location.port).to.eq('')
expect(location.protocol).to.eq('https:')
expect(location.search).to.be.empty
})
})
it('cy.url() - get the current URL', () => {
// https://on.cypress.io/url
cy.url().should('eq', 'https://example.cypress.io/commands/location')
})
})

View File

@ -1,83 +0,0 @@
/// <reference types="Cypress" />
context('Misc', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/misc')
})
it('.end() - end the command chain', () => {
// https://on.cypress.io/end
// cy.end is useful when you want to end a chain of commands
// 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()
// queries the entire table again
cy.contains('Charles').click()
})
})
it('cy.exec() - execute a system command', () => {
// https://on.cypress.io/exec
// execute a system command.
// 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')
// we can use Cypress.platform string to
// select appropriate command
// https://on.cypress/io/platform
cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`)
if (Cypress.platform === 'win32') {
cy.exec('print cypress.json')
.its('stderr').should('be.empty')
} else {
cy.exec('cat cypress.json')
.its('stderr').should('be.empty')
cy.exec('pwd')
.its('code').should('eq', 0)
}
})
it('cy.focused() - get the DOM element that has focus', () => {
// https://on.cypress.io/focused
cy.get('.misc-form').find('#name').click()
cy.focused().should('have.id', 'name')
cy.get('.misc-form').find('#description').click()
cy.focused().should('have.id', 'description')
})
context('Cypress.Screenshot', function () {
it('cy.screenshot() - take a screenshot', () => {
// https://on.cypress.io/screenshot
cy.screenshot('my-image')
})
it('Cypress.Screenshot.defaults() - change default config of screenshots', function () {
Cypress.Screenshot.defaults({
blackout: ['.foo'],
capture: 'viewport',
clip: { x: 0, y: 0, width: 200, height: 200 },
scale: false,
disableTimersAndAnimations: true,
screenshotOnRunFailure: true,
beforeScreenshot () { },
afterScreenshot () { },
})
})
})
it('cy.wrap() - wrap an object', () => {
// https://on.cypress.io/wrap
cy.wrap({ foo: 'bar' })
.should('have.property', 'foo')
.and('include', 'bar')
})
})

View File

@ -1,56 +0,0 @@
/// <reference types="Cypress" />
context('Navigation', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io')
cy.get('.navbar-nav').contains('Commands').click()
cy.get('.dropdown-menu').contains('Navigation').click()
})
it('cy.go() - go back or forward in the browser\'s history', () => {
// https://on.cypress.io/go
cy.location('pathname').should('include', 'navigation')
cy.go('back')
cy.location('pathname').should('not.include', 'navigation')
cy.go('forward')
cy.location('pathname').should('include', 'navigation')
// clicking back
cy.go(-1)
cy.location('pathname').should('not.include', 'navigation')
// clicking forward
cy.go(1)
cy.location('pathname').should('include', 'navigation')
})
it('cy.reload() - reload the page', () => {
// https://on.cypress.io/reload
cy.reload()
// reload the page without using the cache
cy.reload(true)
})
it('cy.visit() - visit a remote url', () => {
// https://on.cypress.io/visit
// Visit any sub-domain of your current domain
// Pass options to the visit
cy.visit('https://example.cypress.io/commands/navigation', {
timeout: 50000, // increase total time for the visit to resolve
onBeforeLoad (contentWindow) {
// contentWindow is the remote page's window object
expect(typeof contentWindow === 'object').to.be.true
},
onLoad (contentWindow) {
// contentWindow is the remote page's window object
expect(typeof contentWindow === 'object').to.be.true
},
})
})
})

View File

@ -1,194 +0,0 @@
/// <reference types="Cypress" />
context('Network Requests', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/network-requests')
})
// Manage AJAX / XHR requests in your app
it('cy.server() - control behavior of network requests and responses', () => {
// https://on.cypress.io/server
cy.server().should((server) => {
// the default options on server
// you can override any of these options
expect(server.delay).to.eq(0)
expect(server.method).to.eq('GET')
expect(server.status).to.eq(200)
expect(server.headers).to.be.null
expect(server.response).to.be.null
expect(server.onRequest).to.be.undefined
expect(server.onResponse).to.be.undefined
expect(server.onAbort).to.be.undefined
// These options control the server behavior
// affecting all requests
// pass false to disable existing route stubs
expect(server.enable).to.be.true
// forces requests that don't match your routes to 404
expect(server.force404).to.be.false
// whitelists requests from ever being logged or stubbed
expect(server.whitelist).to.be.a('function')
})
cy.server({
method: 'POST',
delay: 1000,
status: 422,
response: {},
})
// any route commands will now inherit the above options
// from the server. anything we pass specifically
// to route will override the defaults though.
})
it('cy.request() - make an XHR request', () => {
// https://on.cypress.io/request
cy.request('https://jsonplaceholder.cypress.io/comments')
.should((response) => {
expect(response.status).to.eq(200)
expect(response.body).to.have.length(500)
expect(response).to.have.property('headers')
expect(response).to.have.property('duration')
})
})
it('cy.request() - verify response using BDD syntax', () => {
cy.request('https://jsonplaceholder.cypress.io/comments')
.then((response) => {
// https://on.cypress.io/assertions
expect(response).property('status').to.equal(200)
expect(response).property('body').to.have.length(500)
expect(response).to.include.keys('headers', 'duration')
})
})
it('cy.request() with query parameters', () => {
// will execute request
// https://jsonplaceholder.cypress.io/comments?postId=1&id=3
cy.request({
url: 'https://jsonplaceholder.cypress.io/comments',
qs: {
postId: 1,
id: 3,
},
})
.its('body')
.should('be.an', 'array')
.and('have.length', 1)
.its('0') // yields first element of the array
.should('contain', {
postId: 1,
id: 3,
})
})
it('cy.request() - pass result to the second request', () => {
// first, let's find out the userId of the first user we have
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
.its('body.0') // yields the first element of the returned list
.then((user) => {
expect(user).property('id').to.be.a('number')
// make a new post on behalf of the user
cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
userId: user.id,
title: 'Cypress Test Runner',
body: 'Fast, easy and reliable testing for anything that runs in a browser.',
})
})
// note that the value here is the returned value of the 2nd request
// which is the new post object
.then((response) => {
expect(response).property('status').to.equal(201) // new entity created
expect(response).property('body').to.contain({
id: 101, // there are already 100 posts, so new entity gets id 101
title: 'Cypress Test Runner',
})
// we don't know the user id here - since it was in above closure
// so in this test just confirm that the property is there
expect(response.body).property('userId').to.be.a('number')
})
})
it('cy.request() - save response in the shared test context', () => {
// https://on.cypress.io/variables-and-aliases
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
.its('body.0') // yields the first element of the returned list
.as('user') // saves the object in the test context
.then(function () {
// NOTE 👀
// By the time this callback runs the "as('user')" command
// has saved the user object in the test context.
// To access the test context we need to use
// the "function () { ... }" callback form,
// otherwise "this" points at a wrong or undefined object!
cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
userId: this.user.id,
title: 'Cypress Test Runner',
body: 'Fast, easy and reliable testing for anything that runs in a browser.',
})
.its('body').as('post') // save the new post from the response
})
.then(function () {
// When this callback runs, both "cy.request" API commands have finished
// and the test context has "user" and "post" objects set.
// Let's verify them.
expect(this.post, 'post has the right user id').property('userId').to.equal(this.user.id)
})
})
it('cy.route() - route responses to matching requests', () => {
// https://on.cypress.io/route
let message = 'whoa, this comment does not exist'
cy.server()
// Listen to GET to comments/1
cy.route('GET', 'comments/*').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click()
// https://on.cypress.io/wait
cy.wait('@getComment').its('status').should('eq', 200)
// Listen to POST to comments
cy.route('POST', '/comments').as('postComment')
// we have code that posts a comment when
// the button is clicked in scripts.js
cy.get('.network-post').click()
cy.wait('@postComment')
// get the route
cy.get('@postComment').should((xhr) => {
expect(xhr.requestBody).to.include('email')
expect(xhr.requestHeaders).to.have.property('Content-Type')
expect(xhr.responseBody).to.have.property('name', 'Using POST in cy.route()')
})
// Stub a response to PUT comments/ ****
cy.route({
method: 'PUT',
url: 'comments/*',
status: 404,
response: { error: message },
delay: 500,
}).as('putComment')
// we have code that puts a comment when
// the button is clicked in scripts.js
cy.get('.network-put').click()
cy.wait('@putComment')
// our 404 statusCode logic in scripts.js executed
cy.get('.network-put-comment').should('contain', message)
})
})

View File

@ -1,87 +0,0 @@
/// <reference types="Cypress" />
context('Querying', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/querying')
})
// The most commonly used query is 'cy.get()', you can
// think of this like the '$' in jQuery
it('cy.get() - query DOM elements', () => {
// https://on.cypress.io/get
cy.get('#query-btn').should('contain', 'Button')
cy.get('.query-btn').should('contain', 'Button')
cy.get('#querying .well>button:first').should('contain', 'Button')
// ↲
// Use CSS selectors just like jQuery
cy.get('[data-test-id="test-example"]').should('have.class', 'example')
// 'cy.get()' yields jQuery object, you can get its attribute
// by invoking `.attr()` method
cy.get('[data-test-id="test-example"]')
.invoke('attr', 'data-test-id')
.should('equal', 'test-example')
// or you can get element's CSS property
cy.get('[data-test-id="test-example"]')
.invoke('css', 'position')
.should('equal', 'static')
// or use assertions directly during 'cy.get()'
// https://on.cypress.io/assertions
cy.get('[data-test-id="test-example"]')
.should('have.attr', 'data-test-id', 'test-example')
.and('have.css', 'position', 'static')
})
it('cy.contains() - query DOM elements with matching content', () => {
// https://on.cypress.io/contains
cy.get('.query-list')
.contains('bananas')
.should('have.class', 'third')
// we can pass a regexp to `.contains()`
cy.get('.query-list')
.contains(/^b\w+/)
.should('have.class', 'third')
cy.get('.query-list')
.contains('apples')
.should('have.class', 'first')
// passing a selector to contains will
// yield the selector containing the text
cy.get('#querying')
.contains('ul', 'oranges')
.should('have.class', 'query-list')
cy.get('.query-button')
.contains('Save Form')
.should('have.class', 'btn')
})
it('.within() - query DOM elements within a specific element', () => {
// https://on.cypress.io/within
cy.get('.query-form').within(() => {
cy.get('input:first').should('have.attr', 'placeholder', 'Email')
cy.get('input:last').should('have.attr', 'placeholder', 'Password')
})
})
it('cy.root() - query the root DOM element', () => {
// https://on.cypress.io/root
// By default, root is the document
cy.root().should('match', 'html')
cy.get('.query-ul').within(() => {
// In this within, the root is now the ul DOM element
cy.root().should('have.class', 'query-ul')
})
})
})

View File

@ -1,95 +0,0 @@
/// <reference types="Cypress" />
context('Spies, Stubs, and Clock', () => {
it('cy.spy() - wrap a method in a spy', () => {
// https://on.cypress.io/spy
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
const obj = {
foo () {},
}
const spy = cy.spy(obj, 'foo').as('anyArgs')
obj.foo()
expect(spy).to.be.called
})
it('cy.spy() retries until assertions pass', () => {
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
const obj = {
/**
* Prints the argument passed
* @param x {any}
*/
foo (x) {
console.log('obj.foo called with', x)
},
}
cy.spy(obj, 'foo').as('foo')
setTimeout(() => {
obj.foo('first')
}, 500)
setTimeout(() => {
obj.foo('second')
}, 2500)
cy.get('@foo').should('have.been.calledTwice')
})
it('cy.stub() - create a stub and/or replace a function with stub', () => {
// https://on.cypress.io/stub
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
const obj = {
/**
* prints both arguments to the console
* @param a {string}
* @param b {string}
*/
foo (a, b) {
console.log('a', a, 'b', b)
},
}
const stub = cy.stub(obj, 'foo').as('foo')
obj.foo('foo', 'bar')
expect(stub).to.be.called
})
it('cy.clock() - control time in the browser', () => {
// https://on.cypress.io/clock
// create the date in UTC so its always the same
// no matter what local timezone the browser is running in
const now = new Date(Date.UTC(2017, 2, 14)).getTime()
cy.clock(now)
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
cy.get('#clock-div').click()
.should('have.text', '1489449600')
})
it('cy.tick() - move time in the browser', () => {
// https://on.cypress.io/tick
// create the date in UTC so its always the same
// no matter what local timezone the browser is running in
const now = new Date(Date.UTC(2017, 2, 14)).getTime()
cy.clock(now)
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
cy.get('#tick-div').click()
.should('have.text', '1489449600')
cy.tick(10000) // 10 seconds passed
cy.get('#tick-div').click()
.should('have.text', '1489449610')
})
})

View File

@ -1,121 +0,0 @@
/// <reference types="Cypress" />
context('Traversal', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/traversal')
})
it('.children() - get child DOM elements', () => {
// https://on.cypress.io/children
cy.get('.traversal-breadcrumb')
.children('.active')
.should('contain', 'Data')
})
it('.closest() - get closest ancestor DOM element', () => {
// https://on.cypress.io/closest
cy.get('.traversal-badge')
.closest('ul')
.should('have.class', 'list-group')
})
it('.eq() - get a DOM element at a specific index', () => {
// https://on.cypress.io/eq
cy.get('.traversal-list>li')
.eq(1).should('contain', 'siamese')
})
it('.filter() - get DOM elements that match the selector', () => {
// https://on.cypress.io/filter
cy.get('.traversal-nav>li')
.filter('.active').should('contain', 'About')
})
it('.find() - get descendant DOM elements of the selector', () => {
// https://on.cypress.io/find
cy.get('.traversal-pagination')
.find('li').find('a')
.should('have.length', 7)
})
it('.first() - get first DOM element', () => {
// https://on.cypress.io/first
cy.get('.traversal-table td')
.first().should('contain', '1')
})
it('.last() - get last DOM element', () => {
// https://on.cypress.io/last
cy.get('.traversal-buttons .btn')
.last().should('contain', 'Submit')
})
it('.next() - get next sibling DOM element', () => {
// https://on.cypress.io/next
cy.get('.traversal-ul')
.contains('apples').next().should('contain', 'oranges')
})
it('.nextAll() - get all next sibling DOM elements', () => {
// https://on.cypress.io/nextall
cy.get('.traversal-next-all')
.contains('oranges')
.nextAll().should('have.length', 3)
})
it('.nextUntil() - get next sibling DOM elements until next el', () => {
// https://on.cypress.io/nextuntil
cy.get('#veggies')
.nextUntil('#nuts').should('have.length', 3)
})
it('.not() - remove DOM elements from set of DOM elements', () => {
// https://on.cypress.io/not
cy.get('.traversal-disabled .btn')
.not('[disabled]').should('not.contain', 'Disabled')
})
it('.parent() - get parent DOM element from DOM elements', () => {
// https://on.cypress.io/parent
cy.get('.traversal-mark')
.parent().should('contain', 'Morbi leo risus')
})
it('.parents() - get parent DOM elements from DOM elements', () => {
// https://on.cypress.io/parents
cy.get('.traversal-cite')
.parents().should('match', 'blockquote')
})
it('.parentsUntil() - get parent DOM elements from DOM elements until el', () => {
// https://on.cypress.io/parentsuntil
cy.get('.clothes-nav')
.find('.active')
.parentsUntil('.clothes-nav')
.should('have.length', 2)
})
it('.prev() - get previous sibling DOM element', () => {
// https://on.cypress.io/prev
cy.get('.birds').find('.active')
.prev().should('contain', 'Lorikeets')
})
it('.prevAll() - get all previous sibling DOM elements', () => {
// https://on.cypress.io/prevAll
cy.get('.fruits-list').find('.third')
.prevAll().should('have.length', 2)
})
it('.prevUntil() - get all previous sibling DOM elements until el', () => {
// https://on.cypress.io/prevUntil
cy.get('.foods-list').find('#nuts')
.prevUntil('#veggies').should('have.length', 3)
})
it('.siblings() - get all sibling DOM elements', () => {
// https://on.cypress.io/siblings
cy.get('.traversal-pills .active')
.siblings().should('have.length', 2)
})
})

View File

@ -1,133 +0,0 @@
/// <reference types="Cypress" />
context('Utilities', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/utilities')
})
it('Cypress._ - call a lodash method', () => {
// https://on.cypress.io/_
cy.request('https://jsonplaceholder.cypress.io/users')
.then((response) => {
let ids = Cypress._.chain(response.body).map('id').take(3).value()
expect(ids).to.deep.eq([1, 2, 3])
})
})
it('Cypress.$ - call a jQuery method', () => {
// https://on.cypress.io/$
let $li = Cypress.$('.utility-jquery li:first')
cy.wrap($li)
.should('not.have.class', 'active')
.click()
.should('have.class', 'active')
})
it('Cypress.Blob - blob utilities and base64 string conversion', () => {
// https://on.cypress.io/blob
cy.get('.utility-blob').then(($div) =>
// https://github.com/nolanlawson/blob-util#imgSrcToDataURL
// get the dataUrl string for the javascript-logo
Cypress.Blob.imgSrcToDataURL('https://example.cypress.io/assets/img/javascript-logo.png', undefined, 'anonymous')
.then((dataUrl) => {
// create an <img> element and set its src to the dataUrl
let img = Cypress.$('<img />', { src: dataUrl })
// need to explicitly return cy here since we are initially returning
// the Cypress.Blob.imgSrcToDataURL promise to our test
// append the image
$div.append(img)
cy.get('.utility-blob img').click()
.should('have.attr', 'src', dataUrl)
}))
})
it('Cypress.minimatch - test out glob patterns against strings', () => {
// https://on.cypress.io/minimatch
let matching = Cypress.minimatch('/users/1/comments', '/users/*/comments', {
matchBase: true,
})
expect(matching, 'matching wildcard').to.be.true
matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', {
matchBase: true,
})
expect(matching, 'comments').to.be.false
// ** matches against all downstream path segments
matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/**', {
matchBase: true,
})
expect(matching, 'comments').to.be.true
// whereas * matches only the next path segment
matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/*', {
matchBase: false,
})
expect(matching, 'comments').to.be.false
})
it('Cypress.moment() - format or parse dates using a moment method', () => {
// https://on.cypress.io/moment
const time = Cypress.moment().utc('2014-04-25T19:38:53.196Z').format('h:mm A')
expect(time).to.be.a('string')
cy.get('.utility-moment').contains('3:38 PM')
.should('have.class', 'badge')
// the time in the element should be between 3pm and 5pm
const start = Cypress.moment('3:00 PM', 'LT')
const end = Cypress.moment('5:00 PM', 'LT')
cy.get('.utility-moment .badge')
.should(($el) => {
// parse American time like "3:38 PM"
const m = Cypress.moment($el.text().trim(), 'LT')
// display hours + minutes + AM|PM
const f = 'h:mm A'
expect(m.isBetween(start, end),
`${m.format(f)} should be between ${start.format(f)} and ${end.format(f)}`).to.be.true
})
})
it('Cypress.Promise - instantiate a bluebird promise', () => {
// https://on.cypress.io/promise
let waited = false
/**
* @return Bluebird<string>
*/
function waitOneSecond () {
// return a promise that resolves after 1 second
// @ts-ignore TS2351 (new Cypress.Promise)
return new Cypress.Promise((resolve, reject) => {
setTimeout(() => {
// set waited to true
waited = true
// resolve with 'foo' string
resolve('foo')
}, 1000)
})
}
cy.then(() =>
// return a promise to cy.then() that
// is awaited until it resolves
// @ts-ignore TS7006
waitOneSecond().then((str) => {
expect(str).to.eq('foo')
expect(waited).to.be.true
}))
})
})

View File

@ -1,59 +0,0 @@
/// <reference types="Cypress" />
context('Viewport', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/viewport')
})
it('cy.viewport() - set the viewport size and dimension', () => {
// https://on.cypress.io/viewport
cy.get('#navbar').should('be.visible')
cy.viewport(320, 480)
// the navbar should have collapse since our screen is smaller
cy.get('#navbar').should('not.be.visible')
cy.get('.navbar-toggle').should('be.visible').click()
cy.get('.nav').find('a').should('be.visible')
// lets see what our app looks like on a super large screen
cy.viewport(2999, 2999)
// cy.viewport() accepts a set of preset sizes
// to easily set the screen to a device's width and height
// We added a cy.wait() between each viewport change so you can see
// the change otherwise it is a little too fast to see :)
cy.viewport('macbook-15')
cy.wait(200)
cy.viewport('macbook-13')
cy.wait(200)
cy.viewport('macbook-11')
cy.wait(200)
cy.viewport('ipad-2')
cy.wait(200)
cy.viewport('ipad-mini')
cy.wait(200)
cy.viewport('iphone-6+')
cy.wait(200)
cy.viewport('iphone-6')
cy.wait(200)
cy.viewport('iphone-5')
cy.wait(200)
cy.viewport('iphone-4')
cy.wait(200)
cy.viewport('iphone-3')
cy.wait(200)
// cy.viewport() accepts an orientation for all presets
// the default orientation is 'portrait'
cy.viewport('ipad-2', 'portrait')
cy.wait(200)
cy.viewport('iphone-4', 'landscape')
cy.wait(200)
// The viewport will be reset back to the default dimensions
// in between tests (the default can be set in cypress.json)
})
})

View File

@ -1,34 +0,0 @@
/// <reference types="Cypress" />
context('Waiting', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/waiting')
})
// BE CAREFUL of adding unnecessary wait times.
// https://on.cypress.io/best-practices#Unnecessary-Waiting
// https://on.cypress.io/wait
it('cy.wait() - wait for a specific amount of time', () => {
cy.get('.wait-input1').type('Wait 1000ms after typing')
cy.wait(1000)
cy.get('.wait-input2').type('Wait 1000ms after typing')
cy.wait(1000)
cy.get('.wait-input3').type('Wait 1000ms after typing')
cy.wait(1000)
})
it('cy.wait() - wait for a specific route', () => {
cy.server()
// Listen to GET to comments/1
cy.route('GET', 'comments/*').as('getComment')
// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click()
// wait for GET comments/1
cy.wait('@getComment').its('status').should('eq', 200)
})
})

View File

@ -1,22 +0,0 @@
/// <reference types="Cypress" />
context('Window', () => {
beforeEach(() => {
cy.visit('https://example.cypress.io/commands/window')
})
it('cy.window() - get the global window object', () => {
// https://on.cypress.io/window
cy.window().should('have.property', 'top')
})
it('cy.document() - get the document object', () => {
// https://on.cypress.io/document
cy.document().should('have.property', 'charset').and('eq', 'UTF-8')
})
it('cy.title() - get the title', () => {
// https://on.cypress.io/title
cy.title().should('include', 'Kitchen Sink')
})
})

View File

@ -1,23 +0,0 @@
// / <reference types="Cypress" />
context('Header', () => {
before(() => {
cy.visit('/');
cy.login();
});
after(() => {
cy.logout();
});
it('has username on header', () => {
cy.get('[data-cy=header-user-button]').click();
cy.fixture('defaults').then(defaults => {
cy.get('[data-cy=header-username]').should(
'have.text',
defaults.auth.username
);
});
});
});

View File

@ -1,35 +0,0 @@
// / <reference types="Cypress" />
context('Login', () => {
before(() => {
cy.visit('/');
});
after(() => {
cy.logout();
});
/* it('OpenNebula logo', () => {
}); */
/* it('requires email', () => {
cy.get('form').contains('SignIn').click()
cy.get('.error-email').should('contain', 'email error')
}); */
/* it('requires password', () => {
cy.get('[data-test=email]').type('')
cy.get('form').contains('SignIn').click()
cy.get('.error-password').should('contain', 'email error')
}); */
/* it('requires valid email and password', () => {
}); */
it('navigates to dashboard on successfull login', () => {
cy.login();
cy.get('[data-cy=header]').should('be.visible');
});
});

View File

@ -0,0 +1,16 @@
// / <reference types="Cypress" />
context('Dashboard', () => {
before(() => {
cy.visit('/')
cy.login()
})
after(() => {
cy.logout()
})
it('validate items', () => {
})
})

View File

@ -0,0 +1,31 @@
// const { internalLog } = require('../../../support/utils')
// / <reference types="Cypress" />
context('Login', () => {
before(() => {
cy.goToIndex(__dirname, () => {
cy.login()
})
})
after(() => {
cy.logout()
})
it('has successfull login', () => {
cy.getJWT((JWT) => {
if (JWT && cy.wrap(JWT).should('exist')) {
cy.get('[data-cy=header]').should('be.visible')
}
})
})
it('has username on header', () => {
cy.get('[data-cy=header-user-button]').click()
cy.fixture('defaults').then(defaults => {
cy.get('[data-cy=header-username]').should(
'have.text',
defaults.auth.username
)
})
})
})

View File

@ -0,0 +1,218 @@
const { createIntercept, waitIntercept } = require('../../../support/utils')
const testType = 'Provider'
const reloadProviderComponent = () => {
// for reload the provider react-component this update the provider list
cy.navigateMenu('dashboard')
}
const interceptList = {
method: 'GET',
url: '/provider/list'
}
const interceptCreate = {
method: 'POST',
url: '/provider/create'
}
const interceptConfigure = {
method: 'PUT',
url: '/provider/update'
}
const interceptDelete = {
method: 'DELETE',
url: '/provider/delete'
}
let defaultSettings = {}
context(testType, () => {
before(() => {
// fill settings
cy.fixture('defaults').then(defaults => {
defaultSettings = defaults.provision
})
// go to index app
cy.visit('/')
cy.login()
})
after(() => {
cy.logout()
})
it('Create a Provider', () => {
cy.navigateMenu(`${testType}s`, () => {
cy.get('[data-cy=create-provider]').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptList), () => {
cy.get('[data-cy=select-provision-type]').select(defaultSettings.provision || '')
cy.get('[data-cy=select-provider-type]').select(defaultSettings.provider || '')
let brk = true
// expect test
const validateTest = request => {
expect(request).to.be.a('object')
expect(request).to.nested.include({ 'response.body.id': 200 })
}
// fill form "Configure Connection" tab
const fillFormConfigureConnection = () => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.get('[data-cy=form-provider-access_key]').clear().type(defaultSettings.key || '')
cy.get('[data-cy=form-provider-secret_key]').clear().type(defaultSettings.secretKey || '')
const intercept = createIntercept(interceptCreate)
cy.wrap($button).click({ force: true })
waitIntercept(intercept, validateTest)
})
}
// fill form "Provider Overview" tab
const fillFormProviderOverview = () => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.get('[data-cy=form-provider-name]').clear().type(defaultSettings.nameProvider || '')
cy.get('[data-cy=form-provider-description]').clear().type(defaultSettings.descriptionProvider || '')
cy.wrap($button).click({ force: true })
fillFormConfigureConnection()
})
}
// select template in "Provider template" tab
const selectTemplate = $el => {
brk = false
cy.wrap($el).find('>button').click({ force: true }).then(() => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.wrap($button).click({ force: true })
fillFormProviderOverview()
})
})
}
// find provider template in "Provider template" tab
cy.get('[data-cy=providers-templates]').find('[data-cy=provider-template-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvider && $el.find('[data-cy=provider-template-card-title]').text() === defaultSettings.nameProvider) {
selectTemplate($el)
}
return brk
})
})
})
})
})
it('Check information a Provider', () => {
reloadProviderComponent()
cy.navigateMenu(`${testType}s`, () => {
waitIntercept(createIntercept(interceptList), () => {
let brk = true
// select provider
const selectProvider = $el => {
brk = false
cy.wrap($el).find('>button').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptList), info => {
cy.get('[data-cy=provider-name]').should('have.text', defaultSettings.nameProvider)
cy.get('[data-cy=provider-description]').should('have.text', defaultSettings.descriptionProvider)
cy.get('[data-cy=provider-type]').should('have.text', defaultSettings.provider)
cy.get('[data-cy=provider-access_key]').should('have.text', defaultSettings.key)
cy.get('[data-cy=provider-secret_key]').should('have.text', defaultSettings.secretKey)
cy.get('[data-cy=dg-cancel-button]').click({ force: true })
})
})
}
// find provider
cy.get('[data-cy=providers]').find('[data-cy=provider-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvider && $el.find('[data-cy=provider-card-title]').text() === defaultSettings.nameProvider) {
selectProvider($el)
}
return brk
})
})
})
})
it('Configure', () => {
reloadProviderComponent()
cy.navigateMenu(`${testType}s`, () => {
waitIntercept(createIntercept(interceptList), () => {
let brk = true
// expect test
const validateTest = request => {
expect(request).to.be.a('object')
expect(request).to.nested.include({ 'response.body.id': 200 })
}
// fill "Configure connection" tab
const fillConfigureConnection = $button => {
const intercept = createIntercept(interceptConfigure)
cy.get('[data-cy=form-provider-access_key]').clear().type(defaultSettings.keyEdited || '')
cy.get('[data-cy=form-provider-secret_key]').clear().type(defaultSettings.secretKeyEdited || '')
cy.wrap($button).click({ force: true })
waitIntercept(intercept, validateTest)
}
// fill "Provider overview" tab
const fillProviderOverview = $button => {
cy.get('[data-cy=form-provider-description]').clear().type(defaultSettings.descriptionProviderEdited || '')
cy.wrap($button).click({ force: true })
cy.get('[data-cy=stepper-next-button]').then(fillConfigureConnection)
}
// select provider
const selectProvider = $el => {
brk = false
cy.wrap($el).find('[data-cy=provider-edit]').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptList), () => {
cy.get('[data-cy=stepper-next-button]').then(fillProviderOverview)
})
})
}
// find provider
cy.get('[data-cy=providers]').find('[data-cy=provider-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvider && $el.find('[data-cy=provider-card-title]').text() === defaultSettings.nameProvider) {
selectProvider($el)
}
return brk
})
})
})
})
it('Delete', () => {
reloadProviderComponent()
cy.navigateMenu(`${testType}s`, () => {
waitIntercept(createIntercept(interceptList), () => {
let brk = true
// expect test
const validateTest = request => {
expect(request).to.be.a('object')
expect(request).to.nested.include({ 'response.body.id': 202 })
}
// select provider
const selectProvider = $el => {
brk = false
cy.wrap($el).find('[data-cy=provider-delete]').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptList), () => {
const intercept = createIntercept(interceptDelete)
cy.get('[data-cy=dg-accept-button]').click({ force: true }).then(() => {
waitIntercept(intercept, validateTest)
})
})
})
}
// find provider
cy.get('[data-cy=providers]').find('[data-cy=provider-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvider && $el.find('[data-cy=provider-card-title]').text() === defaultSettings.nameProvider) {
selectProvider($el)
}
return brk
})
})
})
})
})

View File

@ -0,0 +1,221 @@
const { createIntercept, waitIntercept } = require('../../../support/utils')
const testType = 'Provision'
const reloadProvisionComponent = () => {
// for reload the provision react-component this update the provider list
cy.navigateMenu('dashboard')
}
const interceptProviderList = {
method: 'GET',
url: '/provider/list'
}
const interceptList = {
method: 'GET',
url: '/provision/list'
}
const interceptCreate = {
method: 'POST',
url: '/provision/create'
}
const interceptConfigure = {
method: 'PUT',
url: '/provision/configure'
}
const interceptDelete = {
method: 'DELETE',
url: '/provision/delete'
}
let defaultSettings = {}
context(testType, () => {
before(() => {
// fill settings
cy.fixture('defaults').then(defaults => {
defaultSettings = defaults.provision
})
//go to index app
cy.visit('/')
cy.login()
})
after(() => {
cy.logout()
})
it('Create', () => {
cy.navigateMenu(`${testType}s`, () => {
cy.get('[data-cy=create-provision]').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptProviderList), () => {
cy.get('[data-cy=select-provision-type]').select(defaultSettings.provision || '')
cy.get('[data-cy=select-provider-type]').select(defaultSettings.provider || '')
let brkProvisionTemplate = true
let brkProvider = true
// expect test
const validateTest = request => {
expect(request).to.be.a('object')
expect(request).to.nested.include({ 'response.body.id': 202 })
}
// fill form "Configure inputs" tab
const fillFormConfigureInputs = () => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.get('[data-cy=form-provision-number_hosts]').clear().type(defaultSettings.numberInstances || '')
const intercept = createIntercept(interceptCreate)
cy.wrap($button).click({ force: true })
waitIntercept(intercept, validateTest)
})
}
// fill form "Provider overview" tab
const fillFormProvision = () => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.get('[data-cy=form-provision-name]').clear().type(defaultSettings.nameProvision || '')
cy.get('[data-cy=form-provision-description]').clear().type(defaultSettings.descriptionProvision || '')
cy.wrap($button).click({ force: true })
fillFormConfigureInputs()
})
}
// find provider in "Provider" tab
const selectProvider = $el => {
brkProvider = false
cy.wrap($el).find('>button').click({ force: true }).then(() => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.wrap($button).click({ force: true })
fillFormProvision()
})
})
}
// find provider in "Provider" tab
const findProvider = () => {
cy.get('[data-cy=stepper-next-button]').then($button => {
cy.wrap($button).click({ force: true })
cy.get('[data-cy=providers]').find('[data-cy=provider-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvision && $el.find('[data-cy=provider-card-title]').text().includes(defaultSettings.nameProvider)) {
selectProvider($el)
}
return brkProvider
})
})
}
// select provision template in "Provision template" tab
const selectProvisionTemplate = $el => {
brkProvisionTemplate = false
cy.wrap($el).find('>button').click({ force: true }).then(findProvider)
}
// find provision template in "Provision template" tab
cy.get('[data-cy=provisions-templates]').find('[data-cy=provision-template-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvision && $el.find('[data-cy=provision-template-card-title]').text() === defaultSettings.nameProvision) {
selectProvisionTemplate($el)
}
return brkProvisionTemplate
})
})
})
})
})
it('Check information', () => {
reloadProvisionComponent()
cy.navigateMenu(`${testType}s`, () => {
waitIntercept(createIntercept(interceptList), () => {
let brk = true
//select provider
const selectProvider = $el => {
brk = false
cy.wrap($el).find('>button').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptList), info => {
cy.get('[data-cy=provision-name]').should('have.text', defaultSettings.nameProvision)
cy.get('[data-cy=provision-description]').should('have.text', defaultSettings.descriptionProvision)
cy.get('[data-cy=provider-provider-name]').should('have.text', defaultSettings.nameProvider)
cy.get('[data-cy=provider-cluster]').should('contain', defaultSettings.nameProvision)
})
})
}
//find provider
cy.get('[data-cy=provisions]').find('[data-cy=provision-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvider && $el.find('[data-cy=provision-card-title]').text() === defaultSettings.nameProvision) {
selectProvider($el)
}
return brk
})
})
})
})
it('Configure', () => {
reloadProvisionComponent()
cy.navigateMenu(`${testType}s`, () => {
waitIntercept(createIntercept(interceptList), () => {
let brk = true
// expect test
const validateTest = request => {
expect(request).to.be.a('object')
expect(request).to.nested.include({ 'response.body.id': 202})
}
// select provider
const selectProvider = $el => {
brk = false
cy.wrap($el).find('[data-cy=provision-configure]').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptConfigure), validateTest)
})
}
// find provider
cy.get('[data-cy=provisions]').find('[data-cy=provision-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvision && $el.find('[data-cy=provision-card-title]').text() === defaultSettings.nameProvision) {
selectProvider($el)
}
return brk
})
})
})
})
it('Delete', () => {
reloadProvisionComponent()
cy.navigateMenu(`${testType}s`, () => {
waitIntercept(createIntercept(interceptList), () => {
let brk = true
// expect test
const validateTest = request => {
expect(request).to.be.a('object')
expect(request).to.nested.include({ 'response.body.id': 202})
}
// select provider
const selectProvider = $el => {
brk = false
cy.wrap($el).find('[data-cy=provision-delete]').click({ force: true }).then(() => {
waitIntercept(createIntercept(interceptList), ()=>{
const intercept = createIntercept(interceptDelete)
cy.get('[data-cy=dg-accept-button]').click({force:true}).then(()=>{
waitIntercept(intercept, validateTest)
})
})
})
}
// find provider
cy.get('[data-cy=provisions]').find('[data-cy=provision-card]').each($el => {
if (defaultSettings && defaultSettings.nameProvision && $el.find('[data-cy=provision-card-title]').text() === defaultSettings.nameProvision) {
selectProvider($el)
}
return brk
})
})
})
})
})

View File

@ -1,31 +1,89 @@
const { internalLog } = require('./utils')
const { sep } = require('path')
Cypress.Commands.add('login', () => {
cy.fixture('defaults').then(defaults => {
cy.get('[data-cy=login-username]').type(defaults.auth.username);
cy.get('[data-cy=login-password]').type(defaults.auth.password);
});
cy.get('[data-cy=login-user]').clear().type(defaults.auth.username)
cy.get('[data-cy=login-token]').clear().type(defaults.auth.password)
})
cy.get('[data-cy=login-button]').then(($btn) => {
cy.wrap($btn).click()
})
})
cy.get('[data-cy=login-button]').click();
});
Cypress.Commands.add('openUserModal', (callback = () => undefined) => {
cy.get('[data-cy=header-user-button]').then(($btn) => {
if ($btn) {
cy.wrap($btn).click({ force: true })
}
callback()
})
})
Cypress.Commands.add('logout', () => {
cy.get('[data-cy=header-user-button]').click();
cy.get('[data-cy=header-logout-button]').click();
// cy.fixture('defaults').then(defaults => {
// cy.window()
// .its('sessionStorage')
// .invoke('removeItem', defaults.auth.jwtName);
// });
});
cy.openUserModal(
() => {
cy.get('[data-cy=header-logout-button]').then(($btn) => {
if ($btn) {
cy.wrap($btn).click({ force: true })
cy.fixture('defaults').then(defaults => {
cy.window().its('sessionStorage').invoke('removeItem', defaults.auth.jwtName)
})
}
})
}
)
})
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
Cypress.Commands.add('getJWT', (callback = () => undefined) => {
cy.fixture('defaults').then(defaults => {
cy.window().then(win => {
callback(win.sessionStorage.getItem(defaults.auth.jwtName))
})
})
})
Cypress.Commands.add('navigateMenu', (contentText = '', callback = () => undefined) => {
if (contentText) {
let rtn = true
cy.get('[data-cy=main-menu]').find('li').each($li => {
if ($li && $li.text && typeof $li.text === 'function' && $li.text().toLowerCase() === contentText.toLowerCase()) {
rtn = false
cy.wrap($li).click({ force: true }).then(() => {
callback()
})
}
return rtn
})
}
})
Cypress.Commands.add('goToIndex', (path = '', callback = () => undefined) => {
if (expect(path).to.not.be.empty) {
const folders = path.split(sep)
cy.fixture('defaults').then(defaults => {
if (expect(defaults.apps).to.be.a('object')) {
const apps = Object.keys(defaults.apps)
let selectApp = ''
apps.forEach(app => {
if (folders.includes(app)) {
selectApp = app
}
})
if (expect(apps).to.be.a('array') && expect(apps).to.include(selectApp)) {
cy.visit(`/${selectApp}`, { timeout: 30000 })
cy.getJWT((JWT) => {
if (!JWT) {
cy.get('[data-cy=opennebula-logo]').then($window => {
if ($window) {
cy.wait(1500)
}
})
}
callback()
})
}
}
})
}
})

View File

@ -0,0 +1,41 @@
const { v4 } = require('uuid')
const createIntercept = (data = {}) => {
const uuidv4 = v4()
cy.intercept({
method: data.method || 'GET',
url: data.url || ''
}).as(uuidv4)
return uuidv4
}
const waitIntercept = (intercept = '', callback = () => undefined) => {
if (intercept) {
cy.wait(`@${intercept}`).then(interception => {
if (interception && interception.state && interception.state === 'Complete' && typeof callback === 'function') {
callback(interception)
}
})
}
}
const internalLog = (command = '', message = '') => {
Cypress.log({
name: command,
displayName: command,
consoleProps: () => {
return {
error: message
}
}
})
}
const utils = {
internalLog,
createIntercept,
waitIntercept
}
module.exports = utils

View File

@ -1176,18 +1176,18 @@
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
}
}
@ -1793,9 +1793,9 @@
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"arch": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz",
"integrity": "sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
"integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
"dev": true
},
"are-we-there-yet": {
@ -2005,9 +2005,9 @@
"dev": true
},
"aws4": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"dev": true
},
"axios": {
@ -3305,9 +3305,9 @@
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk="
},
"cypress": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-5.4.0.tgz",
"integrity": "sha512-BJR+u3DRSYMqaBS1a3l1rbh5AkMRHugbxcYYzkl+xYlO6dzcJVE8uAhghzVI/hxijCyBg1iuSe4TRp/g1PUg8Q==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-6.2.1.tgz",
"integrity": "sha512-OYkSgzA4J4Q7eMjZvNf5qWpBLR4RXrkqjL3UZ1UzGGLAskO0nFTi/RomNTG6TKvL3Zp4tw4zFY1gp5MtmkCZrA==",
"dev": true,
"requires": {
"@cypress/listr-verbose-renderer": "^0.4.1",
@ -3322,7 +3322,7 @@
"chalk": "^4.1.0",
"check-more-types": "^2.24.0",
"cli-table3": "~0.6.0",
"commander": "^4.1.1",
"commander": "^5.1.0",
"common-tags": "^1.8.0",
"debug": "^4.1.1",
"eventemitter2": "^6.4.2",
@ -3340,10 +3340,10 @@
"minimist": "^1.2.5",
"moment": "^2.27.0",
"ospath": "^1.2.2",
"pretty-bytes": "^5.3.0",
"pretty-bytes": "^5.4.1",
"ramda": "~0.26.1",
"request-progress": "^3.0.0",
"supports-color": "^7.1.0",
"supports-color": "^7.2.0",
"tmp": "~0.2.1",
"untildify": "^4.0.0",
"url": "^0.11.0",
@ -3384,10 +3384,16 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"commander": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"dev": true
},
"debug": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
@ -3506,6 +3512,12 @@
"integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==",
"dev": true
},
"dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
"integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
"dev": true
},
"debounce": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz",
@ -3633,6 +3645,12 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"diff-match-patch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
@ -4595,9 +4613,9 @@
}
},
"execa": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz",
"integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@ -5206,6 +5224,12 @@
"nan": "^2.12.1"
}
},
"fsu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/fsu/-/fsu-1.1.1.tgz",
"integrity": "sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A==",
"dev": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@ -5334,12 +5358,20 @@
}
},
"global-dirs": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz",
"integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz",
"integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==",
"dev": true,
"requires": {
"ini": "^1.3.5"
"ini": "1.3.7"
},
"dependencies": {
"ini": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
"integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==",
"dev": true
}
}
},
"global-modules": {
@ -5626,7 +5658,8 @@
"html-entities": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
"integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA=="
"integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==",
"dev": true
},
"http": {
"version": "0.0.1-security",
@ -6620,11 +6653,23 @@
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
},
"lodash.isempty": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
"integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=",
"dev": true
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
},
"lodash.isfunction": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
"integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==",
"dev": true
},
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
@ -6635,6 +6680,12 @@
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
},
"lodash.isobject": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=",
"dev": true
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
@ -7094,6 +7145,337 @@
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
},
"mochawesome": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/mochawesome/-/mochawesome-6.2.1.tgz",
"integrity": "sha512-zew/N1Gb4JYCTl3scu9i8OW0ay7b0ZOGczCrSW/P+XdBrLntqI5/JlJiYV1/Nn/SY4qahddsIE+qWL8ACNerPA==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"diff": "^4.0.1",
"json-stringify-safe": "^5.0.1",
"lodash.isempty": "^4.4.0",
"lodash.isfunction": "^3.0.9",
"lodash.isobject": "^3.0.2",
"lodash.isstring": "^4.0.1",
"mochawesome-report-generator": "^5.1.0",
"strip-ansi": "^6.0.0",
"uuid": "^7.0.3"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"uuid": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
"dev": true
}
}
},
"mochawesome-merge": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/mochawesome-merge/-/mochawesome-merge-4.2.0.tgz",
"integrity": "sha512-FSMzagh+8hTShhFXdBLE4/zS2WALcDruoD0bmtiwHEjfyQszR/iEGFTgbuM5ewA5At3qeSGwGsT0k2Stt64NdQ==",
"dev": true,
"requires": {
"fs-extra": "^7.0.1",
"glob": "^7.1.6",
"uuid": "^3.3.2",
"yargs": "^15.3.1"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"fs-extra": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"mochawesome-report-generator": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/mochawesome-report-generator/-/mochawesome-report-generator-5.1.0.tgz",
"integrity": "sha512-5cI4Jh+sD+jIxc7q94961vnm/6VKDI7TFUPt9dps6oAc4y4WMpEeeOlmgKKM81q2eGaviNUYw+acFalGK6EJ9g==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"dateformat": "^3.0.2",
"escape-html": "^1.0.3",
"fs-extra": "^7.0.0",
"fsu": "^1.0.2",
"lodash.isfunction": "^3.0.8",
"opener": "^1.4.2",
"prop-types": "^15.7.2",
"tcomb": "^3.2.17",
"tcomb-validation": "^3.3.0",
"validator": "^10.11.0",
"yargs": "^13.2.2"
},
"dependencies": {
"fs-extra": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
}
}
},
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
@ -7644,6 +8026,12 @@
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
"dev": true
},
"opener": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
"dev": true
},
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@ -7950,9 +8338,9 @@
"dev": true
},
"pretty-bytes": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz",
"integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.5.0.tgz",
"integrity": "sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==",
"dev": true
},
"process": {
@ -9667,6 +10055,21 @@
}
}
},
"tcomb": {
"version": "3.2.29",
"resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.29.tgz",
"integrity": "sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ==",
"dev": true
},
"tcomb-validation": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/tcomb-validation/-/tcomb-validation-3.4.1.tgz",
"integrity": "sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA==",
"dev": true,
"requires": {
"tcomb": "^3.0.0"
}
},
"terser": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
@ -10197,6 +10600,12 @@
"spdx-expression-parse": "^3.0.0"
}
},
"validator": {
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
"integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==",
"dev": true
},
"value-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",

View File

@ -10,7 +10,7 @@
"build": "npm run build-front && npm run build-server",
"start": "cross-env NODE_ENV=production babel-node ./dist/index.js",
"cypress:open": "cypress open",
"cypress:run": "cypress run --headless --browser chrome --spec \"cypress/integration/**/*.spec.js\"",
"cypress:run": "rimraf cypress/results/* && node cypress/command/index.js",
"pot": "node potfile.js",
"po2json": "node po2json.js",
"lint": "eslint ./src/client/",
@ -42,6 +42,9 @@
"eslint-plugin-standard": "^4.0.1",
"fireedge-genpotfile": "^1.0.0",
"fireedge-pojson": "^1.0.2",
"mochawesome": "^6.2.1",
"mochawesome-merge": "^4.2.0",
"mochawesome-report-generator": "^5.1.0",
"react-hot-loader": "^4.13.0",
"webpack-dev-middleware": "^3.7.2",
"webpack-hot-middleware": "^2.25.0"
@ -129,4 +132,4 @@
"yup": "^0.29.3",
"zeromq": "^5.2.0"
}
}
}

View File

@ -35,7 +35,7 @@ const ProvisionCard = memo(
const imgSource = useMemo(() => (
isExternalURL(image) ? image : `${IMAGES_URL}/${image}`
), [image])
const dataCy = isProvider ? 'provider' : 'provision'
return (
<SelectCard
title={NAME}
@ -54,6 +54,8 @@ const ProvisionCard = memo(
</StatusBadge>
)
}
cardProps={{ 'data-cy': `${dataCy}-card` }}
cardHeaderProps={{ titleTypographyProps: { 'data-cy': `${dataCy}-card-title` } }}
mediaProps={{
component: 'img',
image: imgSource,

View File

@ -24,7 +24,7 @@ const ProvisionTemplateCard = React.memo(
const imgSource = React.useMemo(() =>
isExternalURL(image) ? image : `${IMAGES_URL}/${image}`
, [image])
const dataCy = isProvider ? 'provider' : 'provision'
return (
<SelectCard
title={name}
@ -38,6 +38,8 @@ const ProvisionTemplateCard = React.memo(
draggable: false,
onError
}}
cardProps={{ 'data-cy': `${dataCy}-template-card` }}
cardHeaderProps={{ titleTypographyProps: { 'data-cy': `${dataCy}-template-card-title` } }}
/>
)
},

View File

@ -86,7 +86,7 @@ const CustomStepper = ({
))}
</Stepper>
<Box marginY={2} textAlign='end'>
<Button onClick={handleBack} disabled={disabledBack}>
<Button onClick={handleBack} disabled={disabledBack} data-cy='stepper-back-button'>
{Tr(T.Back)}
</Button>
<SubmitButton

View File

@ -21,7 +21,8 @@ const ListCards = ({
cardsProps,
EmptyComponent,
displayEmpty,
isLoading
isLoading,
gridProps
}) => {
const classes = listCardsStyles()
const isMobile = useMediaQuery(theme => theme.breakpoints.only('xs'))
@ -31,7 +32,7 @@ const ListCards = ({
}
return (
<Grid container spacing={3}>
<Grid container spacing={3} {...gridProps}>
{/* CREATE CARD COMPONENT */}
{handleCreate && (ButtonCreateComponent ? (
<ButtonCreateComponent onClick={handleCreate} />
@ -110,7 +111,10 @@ ListCards.propTypes = {
PropTypes.element
]),
displayEmpty: PropTypes.bool,
isLoading: PropTypes.bool
isLoading: PropTypes.bool,
gridProps: PropTypes.shape({
'data-cy': PropTypes.string
})
}
ListCards.defaultProps = {
@ -123,7 +127,8 @@ ListCards.defaultProps = {
cardsProps: () => undefined,
EmptyComponent: undefined,
displayEmpty: false,
isLoading: false
isLoading: false,
gridProps: {}
}
ListCards.displayName = 'ListCards'

View File

@ -80,7 +80,7 @@ const Template = () => ({
<Breadcrumbs separator={<ArrowIcon color="secondary" />}>
<Select
color='secondary'
data-cy='select-provision-type'
inputProps = {{ 'data-cy': 'select-provision-type' }}
native
style={{ minWidth: '8em' }}
onChange={handleChangeProvision}
@ -92,7 +92,7 @@ const Template = () => ({
</Select>
{provisionSelected && <Select
color='secondary'
data-cy='select-provider-type'
inputProps = {{ 'data-cy': 'select-provider-type' }}
native
style={{ minWidth: '8em' }}
onChange={handleChangeProvider}
@ -124,6 +124,7 @@ const Template = () => ({
: 'Your providers templates list is empty'
} />
}
gridProps={{ 'data-cy': 'providers-templates' }}
CardComponent={ProvisionTemplateCard}
cardsProps={({ value = {} }) => {
const isSelected = data?.some(selected =>

View File

@ -37,15 +37,15 @@ const Info = memo(({ data }) => {
</ListItem>
<ListItem>
<Typography>{Tr(T.Name)}</Typography>
<Typography>{NAME}</Typography>
<Typography data-cy="provider-name">{NAME}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Description)}</Typography>
<Typography noWrap>{description}</Typography>
<Typography data-cy="provider-description" noWrap>{description}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Provider)}</Typography>
<Typography>{providerName}</Typography>
<Typography data-cy="provider-type">{providerName}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.RegistrationTime)}</Typography>
@ -57,7 +57,7 @@ const Info = memo(({ data }) => {
typeof value === 'string' && (
<ListItem key={key}>
<Typography>{key}</Typography>
<Typography>{value}</Typography>
<Typography data-cy={`provider-${key}`}>{value}</Typography>
</ListItem>
))}
</List>

View File

@ -39,7 +39,7 @@ function Providers () {
onClick: () => fetchRequest(undefined, { reload: true }),
isSubmitting: Boolean(loading || reloading)
}}
addButtonProps={{ onClick: () => history.push(PATH.PROVIDERS.CREATE) }}
addButtonProps={{ 'data-cy': 'create-provider', onClick: () => history.push(PATH.PROVIDERS.CREATE) }}
searchProps={{ handleChange }}
/>
<Box p={3}>
@ -49,6 +49,7 @@ function Providers () {
<ListCards
list={result ?? providers}
isLoading={providers.length === 0 && loading}
gridProps={{ 'data-cy': 'providers' }}
CardComponent={ProvisionCard}
cardsProps={({ value: { ID, NAME } }) => ({
isProvider: true,
@ -62,7 +63,7 @@ function Providers () {
handleClick: () =>
history.push(PATH.PROVIDERS.EDIT.replace(':id', ID)),
icon: <EditIcon />,
cy: `provider-edit-${ID}`
cy: 'provider-edit'
},
{
handleClick: () => setShowDialog({
@ -74,7 +75,7 @@ function Providers () {
}
}),
icon: <DeleteIcon color='error' />,
cy: `provider-delete-${ID}`
cy: 'provider-delete'
}
]
})}

View File

@ -43,19 +43,19 @@ const Info = memo(({ data }) => {
</ListItem>
<ListItem>
<Typography>{Tr(T.Name)}</Typography>
<Typography>{name}</Typography>
<Typography data-cy="provision-name">{name}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Description)}</Typography>
<Typography noWrap>{description}</Typography>
<Typography data-cy="provision-description" noWrap>{description}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Provider)}</Typography>
<Typography>{providerName}</Typography>
<Typography data-cy="provider-provider-name">{providerName}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Cluster)}</Typography>
<Typography>{`${clusterId} - ${clusterName}`}</Typography>
<Typography data-cy="provider-cluster">{`${clusterId} - ${clusterName}`}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.StartTime)}</Typography>

View File

@ -50,6 +50,7 @@ const Provider = () => ({
list={providersByTypeAndService}
EmptyComponent={<EmptyCard title={'Your providers list is empty'} />}
CardComponent={ProvisionCard}
gridProps={{ 'data-cy': 'providers' }}
cardsProps={({ value: { ID } }) => {
const isSelected = data?.some(selected => selected === ID)

View File

@ -87,7 +87,7 @@ const Template = () => ({
<Breadcrumbs separator={<ArrowIcon color="secondary" />}>
<Select
color='secondary'
data-cy='select-provision-type'
inputProps = {{ 'data-cy': 'select-provision-type' }}
native
style={{ minWidth: '8em' }}
onChange={handleChangeProvision}
@ -99,7 +99,7 @@ const Template = () => ({
</Select>
{provisionSelected && <Select
color='secondary'
data-cy='select-provider-type'
inputProps = {{ 'data-cy': 'select-provider-type' }}
native
style={{ minWidth: '8em' }}
onChange={handleChangeProvider}
@ -131,6 +131,7 @@ const Template = () => ({
: 'Your provisions templates list is empty'
} />
}
gridProps={{ 'data-cy': 'provisions-templates' }}
CardComponent={ProvisionTemplateCard}
cardsProps={({ value = {} }) => {
const isSelected = data?.some(selected =>

View File

@ -45,7 +45,7 @@ function Provisions () {
onClick: () => fetchRequest(undefined, { reload: true }),
isSubmitting: Boolean(loading || reloading)
}}
addButtonProps={{ onClick: () => history.push(PATH.PROVISIONS.CREATE) }}
addButtonProps={{ 'data-cy': 'create-provision', onClick: () => history.push(PATH.PROVISIONS.CREATE) }}
searchProps={{ handleChange }}
/>
<Box p={3}>
@ -55,6 +55,7 @@ function Provisions () {
<ListCards
list={result ?? provisions}
isLoading={provisions.length === 0 && loading}
gridProps={{ 'data-cy': 'provisions' }}
CardComponent={ProvisionCard}
cardsProps={({ value: { ID, NAME } }) => ({
handleClick: () => setShowDialog({
@ -67,7 +68,7 @@ function Provisions () {
{
handleClick: () => configureProvision({ id: ID }),
icon: <EditIcon />,
cy: `provision-configure-${ID}`
cy: 'provision-configure'
},
{
handleClick: () => setShowDialog({
@ -80,7 +81,7 @@ function Provisions () {
content: DialogInfo
}),
icon: <DeleteIcon color='error' />,
cy: `provision-delete-${ID}`
cy: 'provision-delete'
}
]
})}