@bahmutov
Ask Questions at Sli.do
event code #cy-ansible
Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.
New
"Classic"
Automation Analytics
Nightwatch.js | jest-puppeteer | Cypress | |
---|---|---|---|
Multi-browser | Selenium! | No* | No* |
OSS Bus Factor | Low | Medium | Medium* |
Visual Testing | Yes | Yes | Yes* |
Triage-ability | Medium* | Low | Off the Charts |
Network Mocks | No | Yes* | Yes |
Parallelization | Yes | No | Yes* |
Documentation | Medium | Low | Off the Charts |
Native .todo() | No | Yes | No |
(what we had before)
Nightwatch.js | jest-puppeteer | Cypress | |
---|---|---|---|
Multi-browser | Selenium! | No* | No* |
OS Bus Factor | Low | Medium | Medium* |
Visual Testing | Yes | Yes | Yes* |
Triage-ability | Medium* | Low | Off the Charts |
Network Stubs/Mocks | No | Yes* | Yes |
Parallelization | Yes | No | Yes* |
Documentation | Medium | Low | Off the Charts |
Native .todo() | No | Yes | No |
(what we had before)
//commands.js
Cypress.Commands.add('createOrReplace', (resource, name) => {
const options = `--resource="${resource}" --name="${name}"`
const command = `python akit_client.py create_or_replace ${options} "${Cypress.config().baseUrl}"`
console.log(`Calling awxkit create_or_replace(): ${options}`)
cy.exec(command, { timeout: Cypress.config('akit_wait') }).then((ret) => {
expect(ret.stderr).to.be.empty
return JSON.parse(ret.stdout)
})
})
//commands.js
Cypress.Commands.add('createOrReplace', (resource, name) => {
const options = `--resource="${resource}" --name="${name}"`
const command = `python akit_client.py create_or_replace ${options} "${Cypress.config().baseUrl}"`
console.log(`Calling awxkit create_or_replace(): ${options}`)
cy.exec(command, { timeout: Cypress.config('akit_wait') }).then((ret) => {
expect(ret.stderr).to.be.empty
return JSON.parse(ret.stdout)
})
})
beforeEach(function () {
cy.createOrReplace('credentials', `credential-name`).as('cred')
})
it('can copy a credential', function () {
cy.visit(`/#/credentials?credential.name__icontains=${this.cred.name}`)
cy.server()
cy.route('POST', `/api/v2/credentials/${this.cred.id}/copy/`).as('copy')
cy.route('OPTIONS', `/api/v2/credentials/`).as('getCredentials')
cy.get('#credential-list-copy-button').click()
cy.wait(['@copy', '@getCredentials'])
cy.get('tbody').find('tr').should('have.length', 2)
})
beforeEach(function () {
cy.createOrReplace('credentials', `credential-name`).as('cred')
})
it('can copy a credential', function () {
cy.visit(`/#/credentials?credential.name__icontains=${this.cred.name}`)
cy.server()
cy.route('POST', `/api/v2/credentials/${this.cred.id}/copy/`).as('copy')
cy.route('OPTIONS', `/api/v2/credentials/`).as('getCredentials')
cy.get('#credential-list-copy-button').click()
cy.wait(['@copy', '@getCredentials'])
cy.get('tbody').find('tr').should('have.length', 2)
})
Object was created via Python SDK
beforeEach(function () {
cy.createOrReplace('credentials', `credential-name`).as('cred')
})
it('can copy a credential', function () {
cy.visit(`/#/credentials?credential.name__icontains=${this.cred.name}`)
cy.server()
cy.route('POST', `/api/v2/credentials/${this.cred.id}/copy/`).as('copy')
cy.route('OPTIONS', `/api/v2/credentials/`).as('getCredentials')
cy.get('#credential-list-copy-button').click()
cy.wait(['@copy', '@getCredentials'])
cy.get('tbody').find('tr').should('have.length', 2)
})
cy.intercept() on the timestamps
Fixture data for timeseries plots
UI is often the bearer of bad news
Run all tests every 3 hours for a baseline
Reduce Triage Time
context('Testsuite Example', function () {
it('a real test', function () {
cy.get('#the-thing').click()
})
it.skip('a stubbed test', function () {})
it.skip('a test which cannot be implemented', function () {}) // TBI /awx/issues/9122
})
We have spent 0 time optimizing our runs
Test the UI, not through it
beforeEach(function () {
cy.createOrReplace('credentials', `credential-name`).as('cred')
})
it('can copy a credential', function () {
cy.visit(`/#/credentials?credential.name__icontains=${this.cred.name}`)
cy.server()
cy.route('POST', `/api/v2/credentials/${this.cred.id}/copy/`).as('copy')
cy.route('OPTIONS', `/api/v2/credentials/`).as('getCredentials')
cy.get('#credential-list-copy-button').click()
cy.wait(['@copy', '@getCredentials'])
cy.get('tbody').find('tr').should('have.length', 2)
})
Object was created via Python SDK
Cypress.on('window:before:load', (window) => {
switch (Cypress.env('BROWSER_LANGUAGE')) {
case 'japanese':
console.log('Loading Japanese...')
Object.defineProperty(
window.navigator, 'language',
{ value: 'ja-JP' })
Object.defineProperty(
window.navigator,
'languages', ['jp']
)
break
case 'french':
console.log('Loading French...')
Object.defineProperty(
window.navigator,
'language', { value: 'fr-FR' }
)
Object.defineProperty(
window.navigator,
'languages', ['fr'])
break
}
})
@bahmutov