Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

An Introduction to the World of Testing for Front-End Developers

210 views

Published on

Presented at Web Unleashed 2017. More info at www.fitc.ca/webu

Presented by Haris Mahmood, Shopify

Overview

As front-end developers become more and more capable of building web applications, the value of testing front-end code is now more valuable than ever. Unfortunately, the testing ecosystem can be confusing, and daunting to those just getting started with the vast number of libraries and testing frameworks offering various tools and capabilities.

This talk aims to navigate the world of testing front-end code, and provide steps for front-end developers to incorporate testing into their work and projects quickly and with ease!

Objective

Provide an introduction and overview of the world of testing for front-end development, and tips and steps to get started today.

Target Audience

Front-end developers with no or little experience with testing.

Five Things Audience Members Will Learn

Understanding on why testing is important
What options exist for testing today
What type of tests are best for what scenario
How to assess what frameworks and libraries to use
Steps on getting started with testing

Published in: Technology
  • Be the first to comment

  • Be the first to like this

An Introduction to the World of Testing for Front-End Developers

  1. 1. engineer at shopify. haris —
  2. 2. instructor at hackeryou. haris —
  3. 3. tech apparel + pins at repitsupply.com haris — FITC2017
  4. 4. @harismahmood89 @repitsupply haris —
  5. 5. WORLD OF TESTINGfo r F r o n t -E n d D e v e l o p e r s A n I n t r o d u c t i o n t o t h e
  6. 6. a brief intro.
  7. 7. i didn’t know where to start.
  8. 8. testing seemed hard.
  9. 9. testing seemed confusing.
  10. 10. front-end has evolved incredibly.
  11. 11. ridiculous amount of libraries, tools, frameworks to choose from.
  12. 12. explore various aspects of the testing world to help you begin.
  13. 13. won’t explore every option.
  14. 14. the most commonly used.
  15. 15. why test?
  16. 16. faster than manual testing in the long run.
  17. 17. verify previously tested code still works as the app/product evolves.
  18. 18. tests act like self-updating documentation.
  19. 19. test all edge/weird cases.
  20. 20. build rock-solid apps.
  21. 21. a couple stories.
  22. 22. nest - smart thermostat.
  23. 23. drained entire battery after software update.
  24. 24. no heat during one of the coldest times in 2016.
  25. 25. nissan airbag sensor software.
  26. 26. washington state’s prison sentence reduction.
  27. 27. update released in 2002.
  28. 28. more then 3,000 prisoners released early.
  29. 29. 600 days.
  30. 30. people would potentially have to go back to prison.
  31. 31. 13 years.
  32. 32. cool, so what first?
  33. 33. linting — the first line of defence.
  34. 34. linting tools enforce defined style rules.
  35. 35. ensures better readability.
  36. 36. highlights issues (particularly syntax errors) before execution.
  37. 37. eslint.
  38. 38. companies share their eslint configs that you can use as a starting point.
  39. 39. test tools + concepts.
  40. 40. tonnes of different types of test tools.
  41. 41. various functionalities.
  42. 42. some tools provide more than one functionality.
  43. 43. develop an ideal combination of tools as per your preference / project requirement.
  44. 44. i. test frameworks. provides the foundation to test your code.
  45. 45. ii. testing structure. test code organization. usually organized in a behaviour-driven-development (bdd) structure.
  46. 46. describe('calculator', function() { // describes a module with nested "describe" functions describe('add', function() { // specify the expected behaviour it('should add 2 numbers', function() { // test assertions go here }) }) })
  47. 47. ii. assertions. functions that ensure test results are as expected.
  48. 48. // Jasmine expect(houseName).toBeString() expect(houseName).toEqual(‘Targaryen’)
  49. 49. // Chai expect(houseName).to.be.a(‘string’) expect(houseName).to.equal(‘Targaryen’)
  50. 50. iii. spies. gather info about function calls. help verify functions are called or not.
  51. 51. var user = { ... setName: function(name) { this.name = name; } } //Create spy var setNameSpy = sinon.spy(user, ‘setName'); user.setName(‘Jon Snow’); console.log(setNameSpy.callCount); //output: 1
  52. 52. super helpful to test callbacks.
  53. 53. function myFunction(condition, callback) { if(condition) { callback(); } }
  54. 54. function myFunction(condition, callback) { if(condition) { callback(); } } describe('myFunction', function() { it('should call the callback function', function() { var callback = sinon.spy(); myFunction(true, callback); assert(callback.calledOnce); // true }); });
  55. 55. iv. stubs. allow you to replace functions with our own to ensure a behaviour.
  56. 56. var account = { ... isActive: function() { ... } } sinon.stub(account, ‘isActive').returns(true)
  57. 57. v. code coverage. determines whether our test cases are covering the entirety of an app’s codebase.
  58. 58. vi. generate + display tests. display our tests and results.
  59. 59. test types.
  60. 60. unit tests.
  61. 61. unit tests. test individual functions / classes. pass in inputs and ensure expected output is returned.
  62. 62. integration tests.
  63. 63. integration tests. test several functions/modules/components to ensure they work together as expected.
  64. 64. functional tests.
  65. 65. functional tests. test a scenario on the app/product.
  66. 66. snapshot tests.
  67. 67. snapshot tests. compare resulting data to an expected one. super useful for component structure testing.
  68. 68. tips + things to keep in mind.
  69. 69. start with unit tests. they are quite often easier to write.
  70. 70. use a coverage tool to ensure unit tests cover everything.
  71. 71. have unit, and integration tests at least.
  72. 72. snapshot tests can be an alternative to ui-based integration tests.
  73. 73. use the same tools for all your tests if possible. testing structure, syntax, assertion functions, result reporting, etc.
  74. 74. choosing a framework.
  75. 75. the first thing you’ll want to do is to pick a testing framework.
  76. 76. let’s examine some of the most popular ones today.
  77. 77. jasmine. provides everything you need out of box - running environment, reporting, mocking tools, assertion functions.
  78. 78. ready out of the box. you can still switch/add features if needed. jasmine.
  79. 79. extremely popular in the angular world. jasmine.
  80. 80. relies on third party libraries and tools for assertions, mocks, spies etc. mocha.
  81. 81. a little harder to setup, but more flexible. mocha.
  82. 82. built and recommended by facebook. jest.
  83. 83. wraps jasmine, and adds features on top. jest.
  84. 84. super impressive speeds and convenience. jest.
  85. 85. mainly used for react apps, but can be used elsewhere too. jest.
  86. 86. other tools.
  87. 87. code coverage tool. istanbul.
  88. 88. lets you run tests in browsers - real, headless, and legacy. karma.
  89. 89. the most popular assertion library. chai.
  90. 90. testing utility for react apps built by airbnb. allows for super easy asserts, traversing the component outputs, etc. enzyme.
  91. 91. provides spies, stubs and mocks. sinon.
  92. 92. how should i start?
  93. 93. super quick to set up + get going, provides tonnes of tooling built right in (due to jasmine wrapping). start with jest.
  94. 94. just write some tests.
  95. 95. you may end up changing to a different framework + tools.
  96. 96. the basic concepts are the same across them all.
  97. 97. quick example.
  98. 98. silly movie theatre app. let’s check it out, setup jest and start testing!
  99. 99. var list = [ { name: 'Jurassic World 2', showTime: '7:00pm', ticketsRemaining: 47, }, { name: 'Star Wars: The Last Jedi', showTime: '10:00pm', ticketsRemaining: 22, } ]
  100. 100. app-folder !"" app.js !"" yarn.lock #"" package.json
  101. 101. app-folder !"" app.js !"" yarn.lock #"" package.json
  102. 102. function listMovies(list) { return list.reduce((acc, item) => { return `${acc} ${item.name} at ${item.showTime} has $ {item.ticketsRemaining} tickets left n`; }, ''); }
  103. 103. function listMovies(list) { return list.reduce((acc, item) => { return `${acc} ${item.name} at ${item.showTime} has $ {item.ticketsRemaining} tickets left n`; }, ''); } Jurassic World 2 at 7:00pm has 47 tickets left Star Wars: The Last Jedi at 10:00pm has 22 tickets left
  104. 104. function ticketsLeft(movie) { return movie.ticketsRemaining > 0; }
  105. 105. function addMovieToList(list, name, showTime) { let newList = list.slice(); newList.push({ name, showTime, ticketsRemaining: 100 }); return newList; }
  106. 106. function buyTickets(movie, quantity) { const newRemaining = movie.ticketsRemaining - quantity; if (newRemaining >= 0) { return Object.assign(movie, {ticketsRemaining: movie.ticketsRemaining - quantity}); } else { return 'Error'; } }
  107. 107. module.exports = { listMovies, ticketsLeft, buyTickets, addMovieToList }
  108. 108. let’s setup jest!
  109. 109. yarn add --dev jest npm install --save-dev jest
  110. 110. update package.json
  111. 111. { "name": "example-1", "version": "1.0.0", "main": "app.js", "license": "MIT", "devDependencies": { "jest": "^21.1.0" }, "scripts": { "test": "jest" } }
  112. 112. npm test
  113. 113. and that is literally it.
  114. 114. let’s write some tests!
  115. 115. two main ways to have jest run your tests.
  116. 116. i. files with *.test.js
  117. 117. ii. files in a folder named __test__
  118. 118. function ticketsLeft(movie) { return movie.ticketsRemaining > 0; }
  119. 119. const app = require('./app.js'); describe('the movie app', () => { describe('ticketsLeft', () => { it('should return false when no tickets available', () => { }); }); });
  120. 120. const app = require('./app.js'); describe('the movie app', () => { describe('ticketsLeft', () => { it('should return false when no tickets available', () => { }); }); });
  121. 121. it('should return false when no tickets available', () => { const testMovie = { ticketsRemaining: 0, }; });
  122. 122. it('should return false when no tickets available', () => { const testMovie = { ticketsRemaining: 0, }; const result = app.ticketsLeft(testMovie); const expected = false; });
  123. 123. it('should return false when no tickets available', () => { const testMovie = { ticketsRemaining: 0, }; const result = app.ticketsLeft(testMovie); const expected = false; expect(result).toEqual(expected); });
  124. 124. ‘expect’ and ‘toBe’ are called matchers.
  125. 125. npm test
  126. 126. 🎉
  127. 127. it('should return true when tickets are available', () => { const testMovie = { ticketsRemaining: 27, }; const result = app.ticketsLeft(testMovie); const expected = true; expect(result).toEqual(expected); });
  128. 128. function listMovies(list) { return list.reduce((acc, item) => { return `${acc} ${item.name} at ${item.showTime} has $ {item.ticketsRemaining} tickets left n`; }, ''); }
  129. 129. describe('listMovies', () => { it('should list movies, showtimes and tickets', () => { var list = [ { name: 'Jurassic World 2’, showTime: ‘7:00pm', ticketsRemaining: 47, }, { name: 'Star Wars: The Last Jedi’, showTime: ’10:00pm', ticketsRemaining: 22, } ]; const result = app.listMovies(list); const expected = 'Jurassic World 2 at 7:00pm has 47 tickets left nStar Wars: The Last Jedi at 10:00pm has 22 tickets left n'; expect(result).toEqual(expected); }); });
  130. 130. Difference: - Expected + Received - Jurassic World 2 at 7:00pm has 47 tickets left - Star Wars: The Last Jedi at 10:00pm has 22 tickets left + Jurassic World 2 at 7:00pm has 47 tickets left + Star Wars: The Last Jedi at 10:00pm has 22 tickets left
  131. 131. Difference: - Expected + Received - Jurassic World 2 at 7:00pm has 47 tickets left - Star Wars: The Last Jedi at 10:00pm has 22 tickets left + Jurassic World 2 at 7:00pm has 47 tickets left + Star Wars: The Last Jedi at 10:00pm has 22 tickets left
  132. 132. function listMovies(list) { return list.reduce((acc, item) => { return `${acc} ${item.name} at ${item.showTime} has $ {item.ticketsRemaining} tickets left n`; }, ''); }
  133. 133. function listMovies(list) { return list.reduce((acc, item) => { return `${acc}${item.name} at ${item.showTime} has $ {item.ticketsRemaining} tickets left n`; }, ''); }
  134. 134. describe('addMovieToList', () => { it('adds a movie to the movie list', () => { const list = [ { name: 'Jurassic World 2’, showTime: ‘7:00pm', ticketsRemaining: 47 } ]; const results = app.addMovieToList(list, 'Thor', '4:30pm'); const expected = [ { name: 'Jurassic World 2’, showTime: ‘7:00pm’, ticketsRemaining: 47 }, { name: ‘Thor', showTime: ‘4:30pm', ticketsRemaining: 100 } ]; expect(results).toBe(expected); }); });
  135. 135. Expected value to be (using ===):
  136. 136. Compared values have no visual difference. Looks like you wanted to test for object/array equality with strict `toBe` matcher. You probably need to use `toEqual` instead.
  137. 137. describe('addMovieToList', () => { it('adds a movie to the movie list', () => { const list = [ { name: 'Jurassic World 2’, showTime: ‘7:00pm', ticketsRemaining: 47 } ]; const results = app.addMovieToList(list, 'Thor', '4:30pm'); const expected = [ { name: 'Jurassic World 2’, showTime: ‘7:00pm’, ticketsRemaining: 47 }, { name: ‘Thor', showTime: ‘4:30pm', ticketsRemaining: 100 } ]; expect(results).toBe(expected); expect(results).toEqual(expected); }); });
  138. 138. other matchers.
  139. 139. toBeNull, toBeUndefined, toBeDefined, toBeTruthy, toBeFalsy, toBeGreaterThan, toBeGreaterThanOrEqual, toBeLessThan, toMatch, toContain ...
  140. 140. all done! i think?
  141. 141. let’s setup some code coverage!
  142. 142. update our test script.
  143. 143. "scripts": { "test": "jest --coverage" }
  144. 144. buyTickets()
  145. 145. add a watcher for continuous testing runs.
  146. 146. "scripts": { "test": "jest --coverage --watch" }
  147. 147. in conclusion.
  148. 148. the value of testing is immense.
  149. 149. the ecosystem is vast with tonnes of options to choose from.
  150. 150. many options provide tooling for specific requirements.
  151. 151. a few that are all-encompassing.
  152. 152. start simple.
  153. 153. customize + modify as you go.
  154. 154. most importantly —
  155. 155. most importantly — start.
  156. 156. thank-you!
  157. 157. thank-you! #beKind
  158. 158. thank-you! #beKind #repItSupply

×