Successfully reported this slideshow.

Advanced Javascript Unit Testing

3

Share

1 of 13
1 of 13

Advanced Javascript Unit Testing

3

Share

Download to read offline

A lot of applications these days have a substantial, if not a major, part written in JavaScript. And not only for the front-end part, as Node.js is gaining popularity on the back-end. You might already have started doing some unit testing for your JavaScript code, but JavaScript has a quite a few concepts where it differs from traditional back-end programming languages like C# or Ruby. This fast-paced talk will show best practices for unit testing code involving 7 of those concepts. We will cover:
- Asynchronous code, both with callbacks and with promises
- Time and timers
- Ajax requests
- DOM manipulation
- Responsive design with CSS media queries
- Cross browser compatibility
- Leak detection

A lot of applications these days have a substantial, if not a major, part written in JavaScript. And not only for the front-end part, as Node.js is gaining popularity on the back-end. You might already have started doing some unit testing for your JavaScript code, but JavaScript has a quite a few concepts where it differs from traditional back-end programming languages like C# or Ruby. This fast-paced talk will show best practices for unit testing code involving 7 of those concepts. We will cover:
- Asynchronous code, both with callbacks and with promises
- Time and timers
- Ajax requests
- DOM manipulation
- Responsive design with CSS media queries
- Cross browser compatibility
- Leak detection

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

Advanced Javascript Unit Testing

  1. 1. Advanced JavaScript Unit Testing Lars Thorup ZeaLake Software Consulting April, 2015
  2. 2. Who is Lars Thorup? ● Software developer/architect ● JavaScript, C# ● Test Driven Development ● Continuous Integration ● Coach: Teaching TDD and continuous integration ● Founder of ZeaLake ● @larsthorup
  3. 3. Best practices for JavaScript unit testing ● Asynchronous code: callbacks and promises ● Time and timers ● The DOM ● Ajax ● Cross-browser testing ● Leak detection ● Continuous testing
  4. 4. Asynchronous code: callbacks ● How to wait for the callback? ● Call done() when done! [Mocha, Jasmine] https://github.com/larsthorup/mha2015-demo it('should eventually return a+b', function () { code.addSlow(4, 5, function (result) { result.should.equal(9); }); }); it('should eventually return a+b', function (done) { code.addSlow(4, 5, function (result) { result.should.equal(9); done(); }); }); When this is called the test has already ended
  5. 5. Asynchronous code: promises ● Return a promise from the test [Mocha] ● Use promise matchers [chai-as-promised] it('should eventually return a+b', function () { return code.adding(4, 5).should.become(9); }); https://github.com/larsthorup/mha2015-demo
  6. 6. Time and timers ● How to test delayed behavior fast? ● Fake the built-in timer! [Sinon, Jasmine] beforeEach(function () { this.sinon = sinon.sandbox.create(); this.sinon.useFakeTimers(); }); afterEach(function () { this.sinon.restore(); }); it('should eventually return a+b', function () { var adding = code.adding(4, 5); this.sinon.clock.tick(500); return adding.should.become(9); }); https://github.com/larsthorup/mha2015-demo
  7. 7. The DOM ● Don't copy real markup ● Use the real thing if fast+easy (client side templating, RequireJS) ● Else inject minimal fake markup ● Use a fragment, or insert a fixture, don't use document https://github.com/larsthorup/jsdevenv-mocha-require/blob/master/src/test/js/page/weather.test.js it('listens', function () { var context = $('<div><input type="text" id="city" /></div>'); weather.listen(context); var city = context.find('#city'); city.val('San Francisco'); city.trigger('change'); expect(weather.fetch.calledWith('San Francisco')).to.equal(true); });
  8. 8. CSS / responsive design ● Render into an iframe, then adjust size [quixote] beforeEach(function () { iframe = $('<iframe></iframe>').appendTo(fixture); context = $(iframe.get(0).contentDocument); $('<style></style>').text(menuCss).appendTo(context.find('head')); var menu = $(multiline(function () {/* <ul class="menu"> <li>Item 1</li> <li>Item 2</li> </ul> */})).appendTo(context.find('body')); items = menu.find('li'); }); it('should turn horizontal when wide', function () { iframe.attr('width', '401px'); expect(items.eq(0).offset().left).to.be.below(items.eq(1).offset().left); expect(items.eq(0).offset().top).to.equal(items.eq(1).offset().top); }); https://github.com/larsthorup/jsdevenv-mocha-require/blob/master/src/test/js/style/menu-responsive.test.js
  9. 9. Ajax ● Don't call any services ● Slow, fragile, setup heavy ● Mock or fake server responses [Sinon, mockjax] https://github.com/larsthorup/jsdevenv-mocha-require/blob/master/src/test/js/page/weather.test.js it('fetches', function (done) { $.mockjax({ url: 'http://api.openweathermap.org/data/2.5/weather', data: {q: 'Denver'}, responseText: { weather: [{ description: 'sun' }] }, responseTime: 1 }); var fetching = weather.fetch('Denver'); fetching.then(function (data) { expect(data.text).to.equal('sun'); done(); }); });
  10. 10. Ajax - generate mocks from real responses ● zealake.com/2015/01/05/unit-test-your-service-integration-layer/ https://github.com/larsthorup/mars/blob/master/test/util/api.proxy.js https://github.com/larsthorup/mars/tree/master/demo/test/api-faker.js
  11. 11. Cross-browser testing ● Use Karma to run your tests in real browsers ● Also valuable for debugging ● Use browser services for continuous integration ● BrowserStack ● SauceLabs https://github.com/larsthorup/jsdevenv-mocha-require/blob/master/Gruntfile.js
  12. 12. Leak detection ● To ensure that tests don't influence each other ● To make our code more reusable ● Use global beforeEach() and afterEach() [Mocha, Jasmine] ● Sample before, verify after ● window / global properties ● DOM elements ● localstorage keys
  13. 13. Wallaby.js ● Continuous Testing ● For JetBrains IDE's ● Visual Studio is in progress ● wallabyjs.com

×