Test-driven Client-side JS

Fe6b81005d1553accd6b2a28f6a2bef1?s=47 Pete Hodgson
February 04, 2015

Test-driven Client-side JS

Presented at ForwardJS, Feb 2015
VIDEO: https://forwardjs.com/lectures/33

Writing high quality, maintainable client-side code is becoming increasingly important as we continue to move more logic into the browser. This talk will show how unit-testing and test-driven development helps you build better quality code, faster.

We'll see examples of building a React app test-first, then look at techniques and tools to solve the trickier parts of unit-testing in JavaScript. You'll see how TDD guides us towards cleaner and more maintainable code, with clear separation between your application logic and the browser's 'ideosnycractic' APIs.

Fe6b81005d1553accd6b2a28f6a2bef1?s=128

Pete Hodgson

February 04, 2015
Tweet

Transcript

  1. TEST-DRIVEN CLIENT-SIDE APPS Pete Hodgson @ph1 | phodgson@thoughtworks.com

  2. UNIT
 TESTING

  3. TEST DRIVEN DEVELOPMENT

  4. me me me Pete Hodgson Consultant at ThoughtWorks @ph1 blog.thepete.net

  5. WRITE A
 FAILING TEST GET THE TEST TO PASS REFACTOR

  6. WRITE A
 FAILING TEST GET THE TEST TO PASS REFACTOR

  7. FEEDBACK

  8. NXTBRT.COM

  9. the
 backend the
 browser <html> single-page javascript app REACT {JSON}

  10. { dest_name: “Richmond”, etd: 8, … } Departure Domain Object

    { destination: “Richmond”, departing: “8 mins” } View Object presenter function
  11. var presentDeparture = function(departure){ return { destination: departure.dest_name }; };

  12. var departurePresenter = require('../../js/departure_presenter'); ! describe( 'Departure presenter', function(){ it('presents

    the destination', function(){ // Given var departure = { dest_name: "Ontario", etd: 10 }; // When var viewModel = departurePresenter(departure); // Then expect(viewModel).to.have.property('destination','Ontario'); }); });
  13. var departurePresenter = require('../../js/departure_presenter'); ! describe( 'Departure presenter', function(){ it('presents

    the destination', function(){ // Given var departure = { dest_name: "Ontario", etd: 10 }; // When var viewModel = departurePresenter(departure); // Then expect(viewModel).to.have.property('destination','Ontario'); }); });
  14. { dest_name: “Richmond”, etd: 8, … } Departure Domain Object

    { destination: “Richmond”, departing: “8 mins” } View Object
  15. { dest_name: “Richmond”, etd: 8, … } Departure Domain Object

    { destination: “Richmond”, departing: “8 mins” } View Object
  16. FEEDBACK

  17. RAPID FOCUSED ACCURATE FEEDBACK

  18. 25

  19. 26

  20. 27

  21. 27 TEST SCOPE

  22. TEST SCOPE DOM HTTP 28

  23. 29

  24. 30 ISOLATION

  25. 30 ISOLATION test code

  26. presenter function test code ✓ ISOLATION

  27. departures gateway controller AJAX function “station-id” GET
 http://blah/station-id LIST OF

    DEPARTURE OBJECTS BIG BLOB
 OF JSON
  28. 34

  29. HTTP 35 ajax function

  30. 36 fake ajax function

  31. 36 fake ajax function

  32. departures gateway test code mock
 ajax fn

  33. departures gateway test code “station-id” “http://blah/station-id” mock
 ajax fn

  34. departures gateway test code CORRECTLY-PARSED DOMAIN OBJECT SOME JSON mock


    ajax fn
  35. it( 'parses the AJAX response as JSON', function(){ // Given

    var fakeJson = '{ "some":"json" }'; var fakeAjaxResponse = Q(fakeJson); var fakeAjaxFn = function(){ return fakeAjaxResponse; }; ! var departuresGateway = createDeparturesGateway(fakeAjaxFn); ! // When var departuresPromise = departuresGateway.fetchDeparturesFor('blah'); ! // Then return expect(departuresPromise) .to.eventually .deep.equal({some:"json"}); });
  36. RAPID FOCUSED ACCURATE FEEDBACK

  37. 42 ISOLATION

  38. mocha test runner chai assertion library gulp task runner, file

    watcher testem browser manager sinon stubbing/mocking chai-as-promised …
  39. 45 github.com/moredip/test-driven-react @ph1 | phodgson@thoughtworks.com http://slides.thepete.net