From 9be0ba895540adb36f536bc48f33b094063ec8c9 Mon Sep 17 00:00:00 2001 From: Brian Ford Date: Fri, 20 Dec 2013 15:18:21 -0800 Subject: [PATCH] fix(lib/throttle): fix bugs, add tests --- content-scripts/lib/throttle.js | 6 +- content-scripts/lib/throttle.spec.js | 100 +++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 content-scripts/lib/throttle.spec.js diff --git a/content-scripts/lib/throttle.js b/content-scripts/lib/throttle.js index 39a6614..af4ca63 100644 --- a/content-scripts/lib/throttle.js +++ b/content-scripts/lib/throttle.js @@ -26,8 +26,8 @@ module.exports = function (func, wait) { var argsString = Array.prototype.slice.call(args).join(';'); - var now = new Date(); - var remaining = wait - (now - lastCalled[argsString]); + var now = Date.now(); + var remaining = wait - (now - (lastCalled[argsString] || 0)); if (remaining <= 0) { clearTimeout(timeoutId[argsString]); @@ -37,7 +37,7 @@ module.exports = function (func, wait) { } else if (!timeoutId[argsString]) { timeoutId[argsString] = setTimeout(function () { - lastCalled[argsString] = new Date(); + lastCalled[argsString] = Date.now(); timeoutId[argsString] = null; func.apply(thisArg, args); }, remaining); diff --git a/content-scripts/lib/throttle.spec.js b/content-scripts/lib/throttle.spec.js new file mode 100644 index 0000000..492e7ae --- /dev/null +++ b/content-scripts/lib/throttle.spec.js @@ -0,0 +1,100 @@ +// these tests run in node even though +// that's kind of a silly thing to do ¯\_(ツ)_/¯ + +var throttle = require('./throttle'); + +// TOOD: solve this like a real engineer +// cuz jasmine doesn't patch Date.now +var temporalPatchification = (function () { + var dateConst = Date.now(); + var originalDateNow = Date.now; + var originalJasmineTick = jasmine.Clock.tick; + function dateNowPatchify () { + Date.now = function () { + return dateConst; + }; + jasmine.Clock.tick = function (ticks) { + dateConst += ticks; + return originalJasmineTick(ticks); + }; + } + + function dateNowDepatchify () { + Date.now = originalDateNow; + jasmine.Clock.tick = originalJasmineTick; + } + + return function patchify (fn) { + return function () { + var returns; + dateNowPatchify(); + returns = fn(); + dateNowDepatchify(); + return returns; + }; + }; +}()); + +describe('throttle', function() { + + var delegate; + + beforeEach(function () { + jasmine.Clock.useMock(); + delegate = jasmine.createSpy('delegate'); + }); + + describe('when the timeout is zero', function () { + var wrapped; + + beforeEach(function () { + wrapped = throttle(delegate, 0); + }); + + it('should return the delegate when timeout is zero', function() { + expect(wrapped).toBe(delegate); + }); + + it('should immediately call the delegate when timeout is zero', function() { + wrapped(); + expect(delegate).toHaveBeenCalled(); + }); + }); + + describe('when the timeout is non-zero', function () { + var wrapped; + + beforeEach(function () { + wrapped = throttle(delegate, 100); + }); + + it('should call the delegate immediately', function() { + wrapped(); + expect(delegate).toHaveBeenCalled(); + }); + + it('should call the delegate once with the same args', function() { + wrapped(1); + wrapped(1); + expect(delegate.callCount).toBe(1); + }); + + it('should call the delegate again after the timeout', temporalPatchification(function() { + wrapped(1); + expect(delegate.callCount).toBe(1); + + jasmine.Clock.tick(101); + wrapped(1); + expect(delegate.callCount).toBe(2); + })); + + it('should call the delegate immediately with different args', function() { + wrapped(1); + expect(delegate).toHaveBeenCalledWith(1); + wrapped(2); + expect(delegate).toHaveBeenCalledWith(2); + }); + }); + + +});