In one of my the previous posts I wrote about unit testing in JavaScript (you can find it here: https://42coders.com/unit-testing-javascript-with-jasmine/). When doing tdd (test driven development) or bdd (behaviour driven development), it is necessary to mock the the input of the tested methods. If the code is clean enough it should be pretty straightforward to do, but in some cases things get complicated. In this article I’ll show some tricks how to deal with these scenarios.

Datetime

When a function uses the built in datetime object, we’d need to find a way to mock the built in time object. It could also be solved by refactoring the function to take the datetime object as an argument, which would make the mocking trivial, but it is a subject for another article. Let’s see how can we solve the problem described above. I’ve used sinon.js https://sinonjs.org/ a cool library which is capable to fake timers, xhr requests and much more.

Install sinon using npm:

npm install sinon 1 npm install sinon

Require it before usage:

let sinon = require('sinon'); 1 let sinon = require ( 'sinon' ) ;

Create a date object to use a fake timer:

let fakeDate = new Date(2019, 5, 11, 12, 0, 0); 1 let fakeDate = new Date ( 2019 , 5 , 11 , 12 , 0 , 0 ) ;

Use the fake timers:

let clock = sinon.useFakeTimers(fakeDate); 1 let clock = sinon . useFakeTimers ( fakeDate ) ;

When the desired test has run, restore the timers with:

clock.restore(); 1 clock . restore ( ) ;

Geolocation

Geolocation enabled apps are not easy for testing, especially because good quality GPS signal can be captured only outside. From fitness and health viewpoint it would be good to write some code and walk a bit outside for testing, but the productivity won’t be so good 🙂

You can mock the HTML5 geolocation with the geomock library: https://github.com/daniel-werner/GeoMock. I’ve forked this repository from https://github.com/janmonschke/GeoMock, and only added one feature, to send the predefined coordinates only once, without repeating them.

First of all require geomock

require('geomock/geomock'); 1 require ( 'geomock/geomock' ) ;

Set up the time interval to send the coordinates (in milliseconds)

navigator.geolocation.delay = 1000; 1 navigator . geolocation . delay = 1000 ;

Set up if it should repeat the coordinates or just “play” them once.

navigator.geolocation.repeat = true; 1 navigator . geolocation . repeat = true ;

Add the predefined coordinates

var startTime = 1551018055000; navigator.geolocation.waypoints = [ {coords : {latitude : 45.8849114, longitude : 19.2545559, accuracy: 65 }, timestamp: startTime}, {coords : {latitude : 45.8856601, longitude : 19.2553514, accuracy: 65 }, timestamp: startTime + 30000}, {coords : {latitude : 45.8849114, longitude : 19.2545559, accuracy: 65 }, timestamp: startTime + 55000}, {coords : {latitude : 45.8856601, longitude : 19.2553514, accuracy: 65 }, timestamp: startTime + 75000}, {coords : {latitude : 45.8849114, longitude : 19.2545559, accuracy: 65 }, timestamp: startTime + 90000}, ]; 1 2 3 4 5 6 7 8 var startTime = 1551018055000 ; navigator . geolocation . waypoints = [ { coords : { latitude : 45.8849114 , longitude : 19.2545559 , accuracy : 65 } , timestamp : startTime } , { coords : { latitude : 45.8856601 , longitude : 19.2553514 , accuracy : 65 } , timestamp : startTime + 30000 } , { coords : { latitude : 45.8849114 , longitude : 19.2545559 , accuracy : 65 } , timestamp : startTime + 55000 } , { coords : { latitude : 45.8856601 , longitude : 19.2553514 , accuracy : 65 } , timestamp : startTime + 75000 } , { coords : { latitude : 45.8849114 , longitude : 19.2545559 , accuracy : 65 } , timestamp : startTime + 90000 } , ] ;

When the tested code uses the geolocation feature, it will get the fake coordinates, and you’d be able to test it easily. Using this library can be beneficial for creating integration tests or feature tests of the application.

Writing tests for existing code

In some cases you might write tests for existing, working code. This is not considered as test driven development, but it is much better than not having tests at all, and the tests can ensure you won’t break existing functionality when modifying the code. But writing tests is boring, writing mocks are even more boring, and we developers are lazy :), so we’d use tricks to avoid doing boring things. My favourite trick in these situations is to test the code manually and copy the function’s arguments during this test. It is easy to do with the Chrome developer console, the following way:

Add console.log(argument1) to the function.

Open the console in the DevTools, right click on the logged data, and select Store as global variable

It would store it as a temporary variable, e.g temp1. You can copy the value to the clipboard with the copy(temp1) command in the console, and paste it to your test. It is especially useful when the arguments are objects with many fields, or arrays with multiple elements.

Conclusion

Using built in browser/language features in our code should not stop us writing unit/feature tests for the application to ensure we produce clean code and high quality software!