I'm new to mocha, and I wanted to try using a for loop to create test cases. I want to test a function that I've made that takes an input of standard 12 hour time, and outputs it into 24 hour military time. This is what it looks like.
exports.main = function(time) {
var hr = parseInt(time.substr(0,2));
var period = time.substr(8,10);
if (period == 'AM' && hr == 12) {
hr = '0';
}
if (period == 'PM' && hr < 12) {
hr += 12;
}
hr.toString();
if (hr < 10) {
hr = '0' + hr;
}
return time = time.replace(/^\d{2}/g, hr).substr(0,8);
}
To test my function in mocha, I have two arrays, one array holds the standard times and the other holds the corresponding expected output. I want to iterate through them and produce a test case for each iteration and test my function.
test_array = ["12:00:00AM", "01:00:00AM", "02:00:00AM", "03:00:00AM", "04:00:00AM",
"05:00:00AM", "06:00:00AM", "07:00:00AM", "08:00:00AM", "09:00:00AM",
"10:00:00AM", "11:00:00AM", "12:00:00PM", "01:00:00PM", "02:00:00PM",
"03:00:00PM", "04:00:00PM", "05:00:00PM", "06:00:00PM", "07:00:00PM",
"08:00:00PM", "09:00:00PM", "10:00:00PM", "11:00:00PM"];
against = ["00:00:00", "01:00:00", "02:00:00", "03:00:00", "04:00:00",
"05:00:00", "06:00:00", "07:00:00", "08:00:00", "09:00:00", "10:00:00",
"11:00:00", "12:00:00", "13:00:00", "14:00:00", "15:00:00", "16:00:00",
"17:00:00", "18:00:00", "19:00:00", "20:00:00", "21:00:00", "22:00:00",
"23:00:00"]
This is what my test script looks like:
var converter = require('../modules/time.js');
describe('Time Converter', function() {
describe('main()', function() {
for(i = 0; i < 24; i++) {
it(test_array[i] + ' should convert to ' + against[i], function() {
var test = converter.main(test_array[i]);
assert.equal(test, against[i]);
});
}
});
});
The following is the results of the tests:
0 passing (23ms)
24 failing
1) Time Converter main() 12:00:00AM should convert to 00:00:00:
TypeError: Cannot read property 'substr' of undefined
at Object.exports.main (app/modules/time.js:43:27)
at Context.<anonymous> (app/test/test.js:35:26)
2) - 24) has the same result:
24) Time Converter main() 11:00:00PM should convert to 23:00:00:
TypeError: Cannot read property 'substr' of undefined
at Object.exports.main (app/modules/time.js:43:27)
at Context.<anonymous> (app/test/test.js:35:26)
However when I change the for loop to
for(i = 0; i < 23; i++)
All the tests pass except, naturally it doesn't test the last test case.
Time Converter
main()
✓ 12:00:00AM should convert to 00:00:00
✓ 01:00:00AM should convert to 01:00:00
✓ 02:00:00AM should convert to 02:00:00
✓ 03:00:00AM should convert to 03:00:00
✓ 04:00:00AM should convert to 04:00:00
✓ 05:00:00AM should convert to 05:00:00
✓ 06:00:00AM should convert to 06:00:00
✓ 07:00:00AM should convert to 07:00:00
✓ 08:00:00AM should convert to 08:00:00
✓ 09:00:00AM should convert to 09:00:00
✓ 10:00:00AM should convert to 10:00:00
✓ 11:00:00AM should convert to 11:00:00
✓ 12:00:00PM should convert to 12:00:00
✓ 01:00:00PM should convert to 13:00:00
✓ 02:00:00PM should convert to 14:00:00
✓ 03:00:00PM should convert to 15:00:00
✓ 04:00:00PM should convert to 16:00:00
✓ 05:00:00PM should convert to 17:00:00
✓ 06:00:00PM should convert to 18:00:00
✓ 07:00:00PM should convert to 19:00:00
✓ 08:00:00PM should convert to 20:00:00
✓ 09:00:00PM should convert to 21:00:00
✓ 10:00:00PM should convert to 22:00:00
23 passing (14ms)
However when I test the last test case by itself, it passes.
✓ 11:00:00PMshould convert to 23:00:00
So, I'm confused as to why all the tests don't work if the for loop iterates through the whole array, but works if I iterate up until the last index. Can someone clear this up for me?
Your code may be sync, but mocha calls it it async. Means: your it descriptions are parsed sync, mocha stores this information and runs every test in it's own context. This is async. To make this work, you have to create a closure with a function:
var converter = require('../modules/time.js');
// outside the loop:
function itShouldTestArray(i) {
// i is now within the function scope and won't change anymore
it(test_array[i] + ' should convert to ' + against[i], function() {
var test = converter.main(test_array[i]);
assert.equal(test, against[i]);
}
describe('Time Converter', function() {
describe('main()', function() {
for(i = 0; i < 24; i++) {
itShouldTestArray(i);
});
}
});
});
So, I'm confused as to why all the tests don't work if the for loop iterates through the whole array, but works if I iterate up until the last index. Can someone clear this up for me?
This is probably a very-hard-to-debug-problem caused by the asynchronous testing conducted by Mocha. It seems like that changing i
from 23 to 24 somehow results in your arrays being deleted before the tests are conducted, confer the error message:
TypeError: Cannot read property 'substr' of undefined
You can avoid this deletion of the arrays before testing time by assigning their values inside a closure:
var converter = require('../modules/time.js');
describe('Time Converter', function() {
describe('main()', function() {
test_array = // insert array inside closure;
against = //insert array inside closure;
callback = function () {
var test = converter.main (test_array[i]);
assert.equal(test, against[i]);
}
for(i = 0; i < 24; i++) {
it(test_array[i] + ' should convert to ' + against[i], callback);
}
})
})
This way each callback
passed to it()
will have access to the arrays without any possibility of them being deleted or altered before testing time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With