aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Browser.js42
-rw-r--r--src/angular-mocks.js19
-rw-r--r--test/BrowserSpecs.js36
3 files changed, 86 insertions, 11 deletions
diff --git a/src/Browser.js b/src/Browser.js
index 55b65471..58ad22c8 100644
--- a/src/Browser.js
+++ b/src/Browser.js
@@ -40,6 +40,8 @@ function Browser(window, document, body, XHR, $log) {
rawDocument = document[0],
location = window.location,
setTimeout = window.setTimeout,
+ clearTimeout = window.clearTimeout,
+ pendingDeferIds = {},
lastLocationUrl;
self.isMock = false;
@@ -163,15 +165,12 @@ function Browser(window, document, body, XHR, $log) {
* @returns {function()} the added function
*/
self.addPollFn = function(fn) {
- if (!pollTimeout) startPoller(100, setTimeout);
+ if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
pollFns.push(fn);
return fn;
};
/**
- * @name angular.service.$browser#startPoller
- * @methodOf angular.service.$browser
- *
* @param {number} interval How often should browser call poll functions (ms)
* @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
*
@@ -339,20 +338,49 @@ function Browser(window, document, body, XHR, $log) {
* @methodOf angular.service.$browser
* @param {function()} fn A function, who's execution should be defered.
* @param {number=} [delay=0] of milliseconds to defer the function execution.
+ * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
*
* @description
* Executes a fn asynchroniously via `setTimeout(fn, delay)`.
*
* Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
- * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed via
- * `$browser.defer.flush()`.
+ * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
+ * via `$browser.defer.flush()`.
*
*/
self.defer = function(fn, delay) {
+ var timeoutId;
outstandingRequestCount++;
- setTimeout(function() { completeOutstandingRequest(fn); }, delay || 0);
+ timeoutId = setTimeout(function() {
+ delete pendingDeferIds[timeoutId];
+ completeOutstandingRequest(fn);
+ }, delay || 0);
+ pendingDeferIds[timeoutId] = true;
+ return timeoutId;
};
+
+ /**
+ * @workInProgress
+ * @ngdoc method
+ * @name angular.service.$browser.defer#cancel
+ * @methodOf angular.service.$browser.defer
+ * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled.
+ *
+ * @description
+ * Cancels a defered task identified with `deferId`.
+ */
+
+ self.defer.cancel = function(deferId) {
+ if (pendingDeferIds[deferId]) {
+ delete pendingDeferIds[deferId];
+ clearTimeout(deferId);
+ completeOutstandingRequest(noop);
+ return true;
+ }
+ };
+
+
//////////////////////////////////////////////////////////////
// Misc API
//////////////////////////////////////////////////////////////
diff --git a/src/angular-mocks.js b/src/angular-mocks.js
index a4941288..20423f05 100644
--- a/src/angular-mocks.js
+++ b/src/angular-mocks.js
@@ -281,15 +281,32 @@ function MockBrowser() {
self.cookieHash = {};
self.lastCookieHash = {};
self.deferredFns = [];
+ self.deferredNextId = 0;
self.defer = function(fn, delay) {
delay = delay || 0;
- self.deferredFns.push({time:(self.defer.now + delay), fn:fn});
+ self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
self.deferredFns.sort(function(a,b){ return a.time - b.time;});
+ return self.deferredNextId++;
};
+
self.defer.now = 0;
+
+ self.defer.cancel = function(deferId) {
+ var fnIndex;
+
+ forEach(self.deferredFns, function(fn, index) {
+ if (fn.id === deferId) fnIndex = index;
+ });
+
+ if (fnIndex) {
+ self.deferredFns.splice(fnIndex, 1);
+ }
+ }
+
+
self.defer.flush = function(delay) {
if (angular.isDefined(delay)) {
self.defer.now += delay;
diff --git a/test/BrowserSpecs.js b/test/BrowserSpecs.js
index b4ad688b..40e983da 100644
--- a/test/BrowserSpecs.js
+++ b/test/BrowserSpecs.js
@@ -5,8 +5,11 @@ describe('browser', function(){
var browser, fakeWindow, xhr, logs, scripts, removedScripts, setTimeoutQueue;
function fakeSetTimeout(fn) {
- setTimeoutQueue.push(fn);
- return Math.random();
+ return setTimeoutQueue.push(fn) - 1; //return position in the queue
+ }
+
+ function fakeClearTimeout(deferId) {
+ setTimeoutQueue[deferId] = noop; //replace fn with noop to preserve other deferId indexes
}
fakeSetTimeout.flush = function() {
@@ -25,7 +28,8 @@ describe('browser', function(){
xhr = null;
fakeWindow = {
location: {href:"http://server"},
- setTimeout: fakeSetTimeout
+ setTimeout: fakeSetTimeout,
+ clearTimeout: fakeClearTimeout
};
var fakeBody = [{appendChild: function(node){scripts.push(node);},
@@ -161,6 +165,32 @@ describe('browser', function(){
fakeSetTimeout.flush();
expect(callback).toHaveBeenCalled();
});
+
+
+ it('should return unique deferId', function() {
+ var deferId1 = browser.defer(noop),
+ deferId2 = browser.defer(noop);
+
+ expect(deferId1).toBeDefined();
+ expect(deferId2).toBeDefined();
+ expect(deferId1).not.toEqual(deferId2);
+ })
+
+
+ describe('cancel', function() {
+ it('should allow tasks to be canceled with returned deferId', function() {
+ var log = [],
+ deferId1 = browser.defer(function() { log.push('cancel me') }),
+ deferId2 = browser.defer(function() { log.push('ok') }),
+ deferId3 = browser.defer(function() { log.push('cancel me, now!') });
+
+ expect(log).toEqual([]);
+ browser.defer.cancel(deferId1);
+ browser.defer.cancel(deferId3);
+ fakeSetTimeout.flush();
+ expect(log).toEqual(['ok']);
+ });
+ });
});