layout: true
class: middle .center[# Modern Testing in Javascript World ]
name: agenda
Agile Testing @Munich - Meetup | Oct. 26, 2018 Munich
class: center
Robert Hostlowsky
Consultant at codecentric AG, Germany, since 2020: working at instana
web-dev-ops-qa-guy
– because Agile is about testing" https://www.slideshare.net/tumma72/keynote-agile-testing
“Testing is an attitude which brings us to trust results based on the fact that we can validate them.”
class: .center[ Two sides of the same medal, different focus
Ice-cone of testing: user / business values
Testing-pyramid: developer fast feedback + confidence
class: middle
–
All usual matchers we know from chai are already built-in –
Extensible: Expect API
npm install -g -D jest
jest --init
babel-jest
ts-jest
describe('Test Code with Jest', () => { it('should have Test runner expect("Jest based on Jasmine").toContain('jasmine'); }); });
// async/await can be used. it('works with async/await', async () => { expect.assertions(1); const data = await user.getUserName(4); expect(data).toEqual('Mark'); });
or
it('works with promises', () => { return user.getUserName(4) .then(data => expect(data) .toEqual('Mark')); });
[https://jestjs.io/docs/en/mock-functions]
[https://jestjs.io/docs/en/expect]
class: center,middle
Full coverage with “the Testing trophy” by Kent C. Dodds:
.right[]
Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol.
Puppeteer runs headless by default
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser => { const page = await browser.newPage(); await page.goto('https://google.com'); const inputElement = await page.$('input[type=submit]'); await inputElement.click(); // ... });
[https://github.com/transitive-bullshit/awesome-puppeteer]
class: middle,center
🎁 Extra: Automatically starts a server as part of test suite
{ "preset": "jest-puppeteer" }``` ``` js describe('Google', () => { beforeAll(async () => { await page.goto('https://google.com') }) it('should display "google" text on page', async () => { await expect(page).toMatch('google') }) })
// Assert that a button containing text "Home" will be clicked await expect(page).toClick('button', { text: 'Home' })
// Assert that current page contains 'Text in the page' await expect(page).toMatch('Text in the page')
// submit a form const inputElement = await page.$('input[type=submit]'); await inputElement.click();
and more on https://github.com/smooth-code/jest-puppeteer
class: middle.
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ devtools: false, slowMo: 0, headless: false }) const page = await browser.newPage() await page.goto('https://www.coolboard.fun/') const boards = '.sc-bdVaJa > .ui > .ui > p > a:nth-child(2)'; await page.waitForSelector(boards) await page.click(boards) await page.waitForSelector('.App > .sc-bdVaJa > .ui > p > a') await page.click('.App > .sc-bdVaJa > .ui > p > a') const auth0LockInputEmail = 'div > div > .auth0-lock-input-email > .auth0-lock-input-wrap > .auth0-lock-input'; await page.waitForSelector(auth0LockInputEmail) await page.click(auth0LockInputEmail) await page.type(auth0LockInputEmail, Email_Adress) let auth0LockInputPassword = 'div > div > .auth0-lock-input-password > .auth0-lock-input-wrap > .auth0-lock-input'; // ...
👍 easy to start quickly 👍 slow-motion mode helps to analyse 👎 hard to maintain, because of "cryptic" _ selectors 👎 one long test plan hard to debug
class: inverse,middle
A free, open source, locally installed Test Runner + Dashboard Service for recording your tests.
Git: 1st commit Jun 5, 2014
Public beta: Oct 9, 2017
https://www.cypress.io/how-it-works/
https://docs.cypress.io/examples/examples/recipes.html
function gotoBoards () { return cy.get('.sc-bdVaJa > .ui > .ui > p > a:nth-child(2)').click() } function clickLogin() { return cy.get('.App > .sc-bdVaJa > .ui > p > a').click(); } describe('Checkout cypress', () => { it('tests coolboard', () => { cy.visit('https://www.coolboard.fun/'); gotoBoards(); clickLogin(); cy.get(auth0LockInputEmail).type('MyEmail.com'); cy.get(auth0LockInputPassword).type(password, {log: false}); cy.get('#auth0-lock-container-1 form button') .click() .wait(2000); // workaround for loading new data from server. gotoBoards(); const New_Board_button = '.App > .sc-bdVaJa .ui'; cy.get(New_Board_button).click(); //... } }
More on Upcoming-Features:
More control and better insights than with Jest/Puppeteer:
In the protocol you can additionally see the XHR requests and even all navigation! That has been a problem with Puppeteer, but was easy to detect!
For even better experience:
Write unit tests with Jest
🎁 Best for Fast Feedback for development / TDD
Have end-to-end tests with Cypress
🎁 Best for check meeting of the business needs
Cypress for the important (happy path) use cases Small number of additional *UI browser* tests for some edge cases on other browsers