Gleb Bahmutov PRO
JavaScript ninja, image processing expert, software quality fanatic
these slides
C / C++ / C# / Java / CoffeeScript / JavaScript / Node / Angular / Vue / Cycle.js / functional / testing
24 people. Atlanta, Philly, Boston, NYC, Nashville,
Myanmar, Colombia, Ukraine
Fast, easy and reliable testing for anything that runs in a browser
npm i -D cypress
docker run cypress/included
or download Cypress application
1
example project: https://github.com/cypress-io/jsnation-example
or use Docker image
2
it('adds and completes todos', () => {
cy.visit('/')
cy.get('.new-todo')
.type('write code{enter}')
.type('write tests{enter}')
.type('deploy{enter}')
cy.get('.todo').should('have.length', 3)
cy.get('.todo').first().find('.toggle')
.check()
cy.get('.todo').first()
.should('have.class', 'completed')
})
it('changes the URL when "awesome" is clicked', () => {
cy.visit('/my/resource/path')
cy.get('.awesome-selector')
.click()
cy.url()
.should('include',
'/my/resource/path#awesomeness')
})
there are no async / awaits or promise chains
Tests should read naturally
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();
test('My Test', async t => {
await t
.setNativeDialogHandler(() => true)
.click('#populate')
.click('#submit-button');
const location = await t.eval(() => window.location);
await t.expect(location.pathname)
.eql('/testcafe/example/thank-you.html');
});
it('changes the URL when "awesome" is clicked', () => {
const user = cy
user.visit('/my/resource/path')
user.get('.awesome-selector')
.click()
user.url()
.should('include',
'/my/resource/path#awesomeness')
})
Kent C Dodds https://testingjavascript.com/
Dear user,
more details: "End-to-end Testing Is Hard - But It Doesn't Have to Be" ReactiveConf 2018 https://www.youtube.com/watch?v=swpz0H0u13k
3
version: 2.1
orbs:
cypress: cypress-io/cypress@1
workflows:
build:
jobs:
- cypress/run:
# we need to start the web application
start: npm start
{
"scripts": {
"test": "cypress:run",
"start": "parcel serve public/index.html",
"e2e": "start-test 1234"
}
}
Do I need more end-to-end tests?
But do not let 100% code coverage be the only goal
import '@cypress/code-coverage/support'
cypress/support/index.js file
module.exports = (on, config) => {
on('task', require('@cypress/code-coverage/task'))
}
cypress/plugins/index.js file
A single end-to-end test can be very effective at covering a lot of code
The missed lines in the business logic code are targets for more end-to-end tests
Cannot reach the edge case from the end-to-end test
import {getVisibleTodos} from '../../src/selectors'
describe('getVisibleTodos', () => {
it('throws an error for unknown visibility filter', () => {
expect(() => {
getVisibleTodos({
todos: [],
visibilityFilter: 'unknown-filter'
})
}).to.throw()
})
})
cypress/integration/selectors-spec.js
and get a perfect 100%
Does the app work on different screens?
;['macbook-15', 'iphone-6'].forEach(viewport => {
it(`works on ${viewport}`, () => {
cy.viewport(viewport)
cy.visit('/')
cy.get('.new-todo')
.type('write code{enter}')
.type('write tests{enter}')
.type('deploy{enter}')
cy.get('.todo').should('have.length', 3)
cy.get('.todo')
.first()
.find('.toggle')
.check()
cy.get('.todo')
.first()
.should('have.class', 'completed')
cy.get('.clear-completed').click()
cy.get('.todo').should('have.length', 2)
})
})
// import 'todomvc-app-css/index.css'
functional tests still pass!
don't try assert visual look
baseline image
new image
visual diff
🙁 Hard to test complex app states
😍 — but not with Cypress!
😵 Performance
😡 Consistent & deterministic rendering
😬 Day-to-day review process & approval workflow.
Do-It-Yourself vs 3rd party service
Disclaimer: PhD in Computer Vision and Image Processing
runs first
added async
Cypress GitHub integration is coming soon
By Gleb Bahmutov
In this talk, I will use code coverage to guide end-to-end tests writing and visual regression testing to avoid style regressions. I will also explain how asynchronous tests can be made to look synchronous. Presented at BostonJS meetup, June 2019
JavaScript ninja, image processing expert, software quality fanatic