Reputation: 1895
I'm new to writing unit tests.
My function looks like this:
getData() {
return this.parameters.map(p => {
return {
name: p.name,
items: p.items.map(item => {
const toTime = item.hasOwnProperty('end') ? moment.utc(item.end._d).unix() : null;
const fromTime = item.hasOwnProperty('start') ? moment.utc(item.start._d).unix() : null;
return {
id: item.id,
fromTime: fromTime,
toTime: toTime,
};
}),
};
});
}
and so far my Jasmine test looks like this:
describe('getData()', function() {
it('should return json data', function() {
$ctrl.parameters = [{
name: 'test',
items: [{
id: 1,
fromTime: null,
toTime: null
}, {
id: 13,
fromTime: null,
toTime: null
}]
}];
expect($ctrl.getData()).toEqual([{
name: 'test',
items: [{
id: 1,
fromTime: null,
toTime: null
}, {
id: 13,
fromTime: null,
toTime: null
}]
}]);
});
});
This test is working/passing, but as you can see I am not testing the ternary if/else that uses Moment.js. Basically what the ternary does is check if items contains a property called start
/ end
and if it does, convert that value to a epoch/Unix timestamp and assign it to either toTime
or fromTime
.
So if items had a property called end with a value of 'Sat Oct 31 2015 00:00:00 GMT+0000 (GMT)'
, then it would be converted to '1446249600'
and assigned to toTime
.
How can I write a test for it?
Upvotes: 14
Views: 6388
Reputation: 5758
The simplest option is to just construct a couple example dates manually for the input. For example:
$ctrl.parameters = [{
name: 'test',
items: [{
id: 1,
start: moment.utc('2017-01-01T01:00:00'),
end: moment.utc('2017-01-01T06:00:00')
}, {
id: 13,
start: moment.utc('2017-01-02T08:00:00'),
end: null
}]
}];
(Note in the above example, I changed fromTime
and toTime
to start
and end
, respectively, since that is what getData
is expecting for the input.)
Then figure out their unix timestamps. You can do this part externally - for example, I just opened up the browser developer tools (F12) on the moment.js website, evaluated the following statements in the console, and grabbed the timestamp values:
moment.utc('2017-01-01T01:00:00').unix()
moment.utc('2017-01-01T06:00:00').unix()
moment.utc('2017-01-02T08:00:00').unix()
Finally, back in the unit test, just verify that the timestamps match the expected values:
expect($ctrl.getData()).toEqual([{
name: 'test',
items: [{
id: 1,
fromTime: 1483232400,
toTime: 1483250400
}, {
id: 13,
fromTime: 1483344000,
toTime: null
}]
}]);
Alternatively, if you would rather not have hardcoded timestamps in your unit tests, you can instead store each example date in its own variable (e.g., start1
, end1
), and then compare to, e.g., start1.unix()
:
// Arrange
const start1 = moment.utc('2017-01-01T01:00:00');
const end1 = moment.utc('2017-01-01T06:00:00');
const start2 = moment.utc('2017-01-02T08:00:00');
$ctrl.parameters = [{
name: 'test',
items: [{
id: 1,
start: start1,
end: end1
}, {
id: 13,
start: start2,
end: null
}]
}];
// Act
const result = $ctrl.getData();
// Assert
expect(result).toEqual([{
name: 'test',
items: [{
id: 1,
fromTime: start1.unix(),
toTime: end1.unix()
}, {
id: 13,
fromTime: start2.unix(),
toTime: null
}]
}]);
That's perfectly fine, since the unit test is meant to test your code, not moment.js. It's up to you.
Note also that I am using the Arrange-Act-Assert pattern for organizing the test. Again, up to you, but once your unit tests start to get complicated, that tends to keep things easier to follow.
Either way, you will need to change how you compute toTime
and fromTime
in your getData
method, since the code as written will not work if you pass in null
for either start
or end
. In particular, item.hasOwnProperty('start')
will return true if you pass in a null
value for start
, but it will error out because it tries to evaluate item.start._d
.
Instead, I recommend changing those 2 lines to the following:
const toTime = item.end ? moment.utc(item.end._d).unix() : null;
const fromTime = item.start ? moment.utc(item.start._d).unix() : null;
I would also advise against using the _d
property of the moment object, since that is an internal (private) variable. Since start
and end
are already moment objects, you may instead be able to just do this:
const toTime = item.end ? item.end.unix() : null;
const fromTime = item.start ? item.start.unix() : null;
A complete jsbin example containing all of the above recommended changes is available here:
https://jsbin.com/xuruwuzive/edit?js,output
Note that some tweaks had to be made so it runs outside the context of AngularJS (make getData a standalone function that accepts its parameters directly, rather than via $ctrl
).
Upvotes: 7