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