TESTER SON JAVASCRIPT*
DANS LA JOIE ET LA BONNE HUMEUR
💥💥💥
*FRONT-END
Nicolas Payot
Lead Front-End Developer [ Dawex ]
FRONT-END APPS ARE MORE AND MORE COMPLICATED 😣
THE MORE COMPLICATED, THE MORE AUTOMATED TESTS WE NEED
⚙️⚙️⚙️
TESTS SHOULD NOT BE A BURDEN TO WRITE!
OTHERWISE WE DON'T WRITE THEM... 🤕
TESTING EXPERIENCE IS BETTER THANKS TO MODERN FRAMEWORKS
MOCHA
CHAI
SINON
KARMA
PHANTOMJS
JASMINE
TAPE
AVA
ENZYME
JSDOM
ISTANBUL
JEST 😍
NOWADAYS
UNIT TESTS AT
JASMINE / KARMA / PHANTOMJS
JEST
👇👇👇
Delightful JavaScript Testing 😋
MEET JEST
GETTING STARTED WITH JEST
npm install --save-dev jest
yarn add --dev jest
*.test.js
*.spec.js
__tests__/**/*.js
jest
ASSERTIONS WITH JEST
🍴
expect(something)
.toBe(value)
.toEqual(value)
.toContain(item)
.toMatch(regexOrString)
.toHaveProperty(string)
...
.not.toBe / toEqual / ...
AND
CUSTOM
MATCHERS
ERROR FEEDBACK
HERE'S WHAT YOU GOT
BUT HERE'S WHAT YOU EXPECTED
TESTING ASYNC CODE IS YAY!
Callbacks, Promises, async / await
🤘
jest --watch
INTERACTIVE WATCH MODE 🔎
RUNS TESTS ONLY ON CHANGED FILES SINCE LAST COMMIT
INTERACTIVE WATCH MODE 🔎
MANUAL MOCKS
api.js __mocks__/api.js
jest.mock('./path/to/api');
// imported api is mocked version
import { api } from './path/to/api';
SNAPSHOT TESTING 📸
expect(serializedComponent)
.toMatchSnapshot();
HelloWorld.vue HelloWorld.spec.js __snapshots__/HelloWorld.spec.js.snap
BUILT-IN CODE COVERAGE
AND ALSO...
PERFORMANCES 💪💪💪
TESTS RUN IN PARALLEL BY DEFAULT
DEMO TIME
🤞
NOW, LET'S TALK ABOUT E2E TESTING
🤐
SELENIUM WEBDRIVER API
😝
JavaScript code
(Tests / WebDriver client API)
ChromeDriver
HTTP server
Commands to control Chrome
(WebDriver protocol)
SELENIUM 2.0
BUT SELENIUM...
👉 HARD TO DEBUG
👉 FLAKY TESTS
😭
SELENIUM FRIENDS
(AND COMPETITORS)
WEBDRIVER.IO
CYPRESS 😍
PUPPETEER 😎
PROTRACTOR
NIGHTWATCH
CASPERJS
Fast, easy and reliable testing for anything that runs in a browser
MEET CYPRESS
E2E TESTS AT
PROTRACTOR / CUCUMBERJS 🥒
CYPRESS
👇👇👇
NO DEPENDENCY
DIRECTLY RUNS IN THE BROWSER
DESKTOP GUI (REACT, ELECTRON)
RUNS IN CI ENVIRONMENTS
VIDEO RECORDS (CI)
GETTING STARTED WITH CYPRESS
npm install --save-dev cypress
yarn add --dev cypress
cypress open
cypress run
CYPRESS SCAFFOLDING
CYPRESS API
describe()
it()
beforeEach()
.only()
.skip()
// ...
MOCHA
cy.stub()
cy.spy()
SINON
CHAI
expect(something)
.to.be.true
.to.equal(value)
.to.contain(value)
// ...
INTERACTING WITH DOM
cy.get('selector').find(node)
cy.get('nav a').first()
cy.get('nav').children()
cy.get('nav').parents()
// ...
SELECTORS
INTERACTING WITH DOM
.type('something') // {enter}, {backspace}
.click()
.dblclick()
.check() / .uncheck()
.select()
.focus() / .blur()
// ...
EVENTS
cy.get('#header a')
.should('have.class', 'active')
.and('have.attr', 'href', '/users');
ASSERTIONS WITH CYPRESS
IMPLICIT SUBJECTS
Pretty handy, right?
cy.get('#header a')
.should($a => {
// perform some logic before assertions
expect($a).to.have.class('active');
expect($a).to.have.attr('href', '/users');
});
ASSERTIONS WITH CYPRESS
EXPLICIT SUBJECTS
A bit less handy...
USE CUSTOM COMMANDS FOR BETTER CODE
Cypress.Commands.add('login', (username, password) => {
// command logic
});
it('should login', () => {
cy.login('john', '1234');
// ...
});
WAIT FOR XHR REQUESTS
// ...
cy.route('POST', '/api/login').as('login');
cy.get('button[type="submit"]')
.click();
cy.wait('@login');
PREVENTS TEST FLAKE
SPY / STUB XHR REQUESTS
cy.route({
method: 'POST',
url: '/checkout',
response: {
items: ['product1', 'product2']
}
});
PREVENTS TEST FLAKE, ALSO.
DEBUGGING?
LOGS FROM RUNNER
debugger / .debug()
BROWSER DEVTOOLS
DEMO TIME
🤞🤞
THANK YOU!
Tester son JavaScript dans la joie et la bonne humeur [snowcamp]
By Nicolas Payot
Tester son JavaScript dans la joie et la bonne humeur [snowcamp]
- 1,700