Reputation: 31
I'm new to unit testing, and I need to test a function that measures the time elapsed since a reddit post was created. Hard coding the arguments works right now, but the tests will fail as time moves along.
For instance, a test that outputs "1 day ago" with a hard-coded argument will pass today, but won't pass tomorrow, as it then will have been 2 days since the post. Same concept applies when measuring hours.
Here's my function that converts the created_utc
timestamp (a number like 1488420682
) to a human-readable amount of time elapsed:
PostCluster.js
getElapsedHours(created_utc) {
const seconds = created_utc;
const epoch = new Date(1970, 0, 1);
const timeStamp = new Date(epoch.setSeconds(seconds));
const now = new Date();
const delta = timeStamp - now;
const currentTimeZoneOffsetInHours = now.getTimezoneOffset() / 60;
const hoursElapsed = Math.floor(Math.abs((delta / 1000) / 3600) + currentTimeZoneOffsetInHours);
if (hoursElapsed > 24) {
const days = Math.floor(hoursElapsed / 24);
if (hoursElapsed > 48) {
return `${days} days`;
} return '1 day';
} else {
if (hoursElapsed === 1) {
return '1 hour';
} else if (hoursElapsed < 1) {
return 'less than 1 hour';
} else {
return `${hoursElapsed} hours`;
}
}
}
Here's an example of the outputs displayed in action
The test below passes as is, because the time elapsed since that timestamp will always be greater than 48 hours. BUT... how would I write the tests to check for the outputs "1 day, 1 hour, x hours, less than 1 hour" and have them pass every time they run in the future?
postcluster.spec.js
describe('<PostCluster />', () => {
it("ensures getElapsedHours returns 'x days' when greater than 48 hours", () => {
const days = PostCluster.prototype.getElapsedHours(1488420682).split(' ')[1];
expect(days).to.equal('days');
});
});
I've seen MockDate used, but not sure how that can apply here.
Upvotes: 3
Views: 6461
Reputation: 2387
Ok...I may have commented prematurely, but the below may work for you
function demo(created_utc) {
var elapsed_seconds = (new Date() - (created_utc * 1000) ) / 1000
if (elapsed_seconds >= 172800) return Math.floor(elapsed_seconds /86400).toString() + " days ago";
else if(elapsed_seconds >= 86400) return "about 1 day ago"
else if(elapsed_seconds >= 7200) return Math.floor(elapsed_seconds /3600).toString() + " hours ago";
else if(elapsed_seconds >= 3600) return "about an hour ago"
else return "less than an hour ago"
};
To test this function I would probably data drive this always with the current time. So, I would need to figure out created_utc
to properly test each scenario correctly.
To do this, In my expect statement, i would have something like
var epoch_hour = (new Date() / 1000) - 3600
expect(demo(epoch_hour)).to.contain("about an hour");
Upvotes: 0
Reputation: 2087
You should create some mock data for every case:
1 day
x days
1 hour
less than 1 hour
x hours
For example for x days
you generate a new date that is older with x days than today:
it("ensures getElapsedHours returns 'x days' when greater than 48 hours", () => {
var days = 3;
var moreThanThreeDaysInMillisecs = 1000 * 3601 * days * 24;
var dateMoreThanThreeDays = Date.now() - moreThanThreeDaysInMillisecs;
...
})
and test against that.
You should not test with live data as it is volatile and your tests could fail because of that. Create some mock data and test each public function/method in isolation.
Upvotes: 1