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 jestyarn add --dev jest
*.test.js
*.spec.js
__tests__/**/*.js
jestASSERTIONS 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 --watchINTERACTIVE 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 cypressyarn add --dev cypresscypress opencypress runCYPRESS 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,901