Slide 1

Slide 1 text

Next-Generation Web Application Testing Amir Rustamzadeh @amirrustam REFACTR.TECH 2019

Slide 2

Slide 2 text

Sr. Engineer @amirrustam Amir Rustamzadeh [email protected]

Slide 3

Slide 3 text

@amirrustam ! E2E testing? I spend hours chasing flaky tests! " # Too expensive for project budget. In our last project, E2E tests slowed down development.

Slide 4

Slide 4 text

E2E Integration Unit Visit The Testing Pyramid @amirrustam

Slide 5

Slide 5 text

E2E Integration Unit Visit The Testing Pyramid Easy, developers really like to write these. @amirrustam

Slide 6

Slide 6 text

E2E Integration Unit Visit The Testing Pyramid Easy, developers really like to write these. More Difficult, costly, slower… Often completely ignored @amirrustam

Slide 7

Slide 7 text

E2E Integration Unit Visit The Testing Pyramid Best for users & business @amirrustam

Slide 8

Slide 8 text

Don’t let your users be your first E2E testers. @amirrustam

Slide 9

Slide 9 text

Renaissance of the Web 2005 2006 2014 2013 @amirrustam 2010

Slide 10

Slide 10 text

Renaissance of the Web 2005 2006 2014 2013 More complexity moved from backend to frontend. @amirrustam 2010

Slide 11

Slide 11 text

Stateless Stateful @amirrustam

Slide 12

Slide 12 text

2005 2006 2014 2013 Renaissance of the Web + Testing Automation 2004 @amirrustam 2010

Slide 13

Slide 13 text

✋ JSDOM or DOM Emulation JSDOM is not a real browser. Your users don’t run your app with JSDOM. One of the primary reasons for E2E is to simulate real user actions. @amirrustam

Slide 14

Slide 14 text

Fast, easy and reliable testing for anything that runs in a browser. Free. Open Source. MIT License @amirrustam

Slide 15

Slide 15 text

$ npm install -D cypress ☝ All-in-one tool You get everything you need ❤ Familiar tools underneath Mocha, Chia, Sinon @amirrustam

Slide 16

Slide 16 text

@amirrustam

Slide 17

Slide 17 text

@amirrustam

Slide 18

Slide 18 text

@amirrustam Let’s see it in action…. https://github.com/cypress-io/cypress-example-todomvc

Slide 19

Slide 19 text

* Fast Test Runs @amirrustam

Slide 20

Slide 20 text

Cypress Architecture Cypress Test Runner Your App @amirrustam Browser

Slide 21

Slide 21 text

⚡ Native-access to the DOM and your app. @amirrustam

Slide 22

Slide 22 text

@amirrustam Username Password Login You can mutate state programmatically. There is no need to always manipulate the UI to create the desired state.

Slide 23

Slide 23 text

⚙ Component Testing cypress-react-unit-testing vue angular angularjs hyper-app svelte cycle https://github.com/bahmutov/cypress-vue-unit-test#test-adapters-for-other-frameworks @amirrustam

Slide 24

Slide 24 text

Component Mounting Cypress Test Runner My Component My Component @amirrustam Browser

Slide 25

Slide 25 text

@amirrustam import mount from 'cypress-vue-unit-test' import MyComponent from './app/components/MyComponent.vue' describe('My Component', () => { beforeEach(mount(MyComponent)) it('loads', () => { cy.get('button').should('be.visible') }) })

Slide 26

Slide 26 text

⏳ Automatic Waiting Demo @amirrustam

Slide 27

Slide 27 text

1 Easy stubbing, mocking, and spying. @amirrustam

Slide 28

Slide 28 text

@amirrustam it('starts with zero items', () => { // start Cypress network server // spy on route `GET /todos` // THEN visit the page cy.server() cy.route('GET', '/todos').as('todos') cy.visit('/') cy .wait('@todos') // wait for `GET /todos` response // inspect the server's response .its('response.body') .should('have.length', 0) // then check the DOM cy.get('li.todo').should('have.length', 0) })

Slide 29

Slide 29 text

@amirrustam it('posts new item to the server', () => { cy.server() cy.route('POST', '/todos').as('new-item') cy.visit('/') cy.get(‘.new-todo').type('buy cookies{enter}') cy.wait('@new-item').its('request.body').should('have.contain', { title: 'buy cookies', completed: false }) })

Slide 30

Slide 30 text

@amirrustam it('starts with zero items (stubbed response)', () => { // start Cypress network server // spy on route `GET /todos` // THEN visit the page cy.server() cy.route('GET', '/todos', []).as('todos') cy.visit('/') cy .wait('@todos') // wait for `GET /todos` response // inspect the server's response .its('response.body') .should('have.length', 0) // then check the DOM cy.get('li.todo').should('have.length', 0) })

Slide 31

Slide 31 text

@amirrustam it('starts with zero items (fixture)', () => { // start Cypress network server // stub route `GET /todos`, return data from fixture file // THEN visit the page cy.server() cy.route('GET', '/todos', ‘fixture:sample-todos').as('todos') cy.visit('/') cy .wait('@todos') // wait for `GET /todos` response // inspect the server's response .its('response.body') .should('have.length', 0) // then check the DOM cy.get('li.todo').should('have.length', 0) })

Slide 32

Slide 32 text

Flake-free, consistent, and reliable. @amirrustam

Slide 33

Slide 33 text

@amirrustam How are commands executed? cy.get('.todo-list li’).should(‘not.exist') cy.get(‘.main’).should('not.exist') cy.get('.footer').should('not.exist') 1 2 3 4 5 6

Slide 34

Slide 34 text

Debuggability @amirrustam

Slide 35

Slide 35 text

@amirrustam

Slide 36

Slide 36 text

Cypress Architecture Cypress Test Runner Your App @amirrustam ⚙ Cypress Node Backend Browser

Slide 37

Slide 37 text

@amirrustam Browser Node Backend cy.exec(…) Execute system commands outside of the scope of Cypress. ✅ Seed a database ✅ Running build scripts ✅ Start and kill processes

Slide 38

Slide 38 text

@amirrustam Browser Node Backend cy.exec(…) cy.exec('rake db:seed').its('code').should('eq', 0) cy.exec('npm run my-script’) .its(‘stdout') .should('contain', 'Done running the script')

Slide 39

Slide 39 text

@amirrustam Browser Node Backend cy.task(…) // in test describe('e2e', () => { beforeEach(() => { cy.task('defaults:db') cy.visit('/') }) it('displays article values', () => { cy.get('.article-list') .should('have.length', 10) }) })

Slide 40

Slide 40 text

@amirrustam Browser Node Backend cy.task(…) // in plugins/index.js file // we require some code in our app that // is responsible for seeding our database const db = require('../../server/src/db') module.exports = (on, config) => { on('task', { 'defaults:db': () => { return db.seed('defaults') } }) }

Slide 41

Slide 41 text

5 cypress open Great for everyday development workflow Cypress + Editor Side-by-Side TDD Nirvana cypress run Testing in CI/CD Pipeline Headless More efficient for running all your tests @amirrustam

Slide 42

Slide 42 text

5 cypress open Great for everyday development workflow Cypress + Editor Side-by-Side TDD Nirvana w/ Realtime Reloading cypress run --record Record to Cypress Dashboard @amirrustam

Slide 43

Slide 43 text

Dashboard @amirrustam

Slide 44

Slide 44 text

cypress run --record --parallel Parallelization Now available in Cypress 3.1 @amirrustam

Slide 45

Slide 45 text

cypress run --parallel cypress run --parallel cypress run --parallel Your CI Machines 3x parallelism Ready for work signup.spec.js login.spec.js widget.spec.js @amirrustam

Slide 46

Slide 46 text

Previous Spec Test Runs Spec Test Duration History Test Duration (seconds) The Future Automatic Load Balancing of Test Specs Duration Forecast @amirrustam

Slide 47

Slide 47 text

Automatic Load Balancing of Test Specs login.spec.js signup.spec.js widget.spec.js @amirrustam

Slide 48

Slide 48 text

@amirrustam cypress-example-kitchensink

Slide 49

Slide 49 text

@amirrustam cypress-dashboard 83%

Slide 50

Slide 50 text

@amirrustam Parallelization Tips Do not write all tests in one file. Break them up so they can be load balanced on CI machines. Do not write tests that are dependent on each other. Tests should pass in isolation.

Slide 51

Slide 51 text

Cypress Parallelization Easily optimize your CI usage You save a lot of ⏳ time and money @amirrustam

Slide 52

Slide 52 text

cypress run --group frontend Test Run Grouping Now available in Cypress 3.1

Slide 53

Slide 53 text

@amirrustam cypress-example-kitchensink

Slide 54

Slide 54 text

Documentation docs.cypress.io

Slide 55

Slide 55 text

Best Practices docs.cypress.io @amirrustam

Slide 56

Slide 56 text

Roadmap docs.cypress.io @amirrustam

Slide 57

Slide 57 text

@amirrustam Mobile Desktop Cross Browser Support

Slide 58

Slide 58 text

@amirrustam Test Retries ✅ 999 Tests Pass ❌ 1 Test Fails Might just be a CI mishap

Slide 59

Slide 59 text

docs.cypress.io/examples/examples/tutorials.html Tutorial Videos

Slide 60

Slide 60 text

Testing Workshop docs.cypress.io/examples/examples/workshop.html

Slide 61

Slide 61 text

We are trying to drastically improve the status quo of testing on the web. @amirrustam

Slide 62

Slide 62 text

Thank You npm install -D cypress Free. Open Source. MIT License Follow @amirrustam for link to slides.