diff --git a/karma-jqlite.conf.js b/karma-jqlite.conf.js
index 6cb9811428cc..3eee66ccd552 100644
--- a/karma-jqlite.conf.js
+++ b/karma-jqlite.conf.js
@@ -7,6 +7,7 @@ autoWatch = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
+urlRoot = "/karma/tests/"
junitReporter = {
outputFile: 'test_out/jqlite.xml',
diff --git a/karma-jquery.conf.js b/karma-jquery.conf.js
index 7b527a15cbb9..bafcd10c2832 100644
--- a/karma-jquery.conf.js
+++ b/karma-jquery.conf.js
@@ -7,6 +7,7 @@ autoWatch = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
+urlRoot = "/karma/tests/"
junitReporter = {
outputFile: 'test_out/jquery.xml',
diff --git a/karma-modules.conf.js b/karma-modules.conf.js
index 9fea7d5853ef..a205a56464a2 100644
--- a/karma-modules.conf.js
+++ b/karma-modules.conf.js
@@ -7,6 +7,7 @@ autoWatch = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
+urlRoot = "/karma/tests/"
junitReporter = {
outputFile: 'test_out/modules.xml',
diff --git a/src/ng/browser.js b/src/ng/browser.js
index 7a32993f8b2d..efef5886c295 100644
--- a/src/ng/browser.js
+++ b/src/ng/browser.js
@@ -245,7 +245,6 @@ function Browser(window, document, $log, $sniffer) {
//////////////////////////////////////////////////////////////
var lastCookies = {};
var lastCookieString = '';
- var cookiePath = self.baseHref();
/**
* @name ng.$browser#cookies
@@ -253,7 +252,12 @@ function Browser(window, document, $log, $sniffer) {
*
* @param {string=} name Cookie name
* @param {string=} value Cookie value
- *
+ * @param {object} options Object allowing additional control on how a cookie is created
+ * - **expires** - `{date}` - date for cookie to expire.
+ * If not passed, the object is not a date or the date is in the past, the cookie expiration
+ * date will not be set, so that the cookie will expire at the end of the session.
+ * - **path** - `{string}` - the path to set the cookie on.
+ * Defaults to {@link #baseHref baseHref}
* @description
* The cookies method provides a 'private' low level access to browser cookies.
* It is not meant to be used directly, use the $cookie service instead.
@@ -262,55 +266,115 @@ function Browser(window, document, $log, $sniffer) {
*
*
cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it
*
cookies(name, value) -> set name to value, if value is undefined delete the cookie
+ *
cookies(name, value,options) -> same as (name, value), but allows more granular control of the cookie
+ *
cookies(name,undefined,options) -> deletes a cookie. allows passing path in options to delete only
+ * cookie under that path
*
cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)
*
*
* @returns {Object} Hash of all cookies (if called without any parameter)
- */
- self.cookies = function(name, value) {
- var cookieLength, cookieArray, cookie, i, index;
-
- if (name) {
- if (value === undefined) {
- rawDocument.cookie = escape(name) + "=;path=" + cookiePath + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
- } else {
- if (isString(value)) {
- cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
-
- // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
- // - 300 cookies
- // - 20 cookies per unique domain
- // - 4096 bytes per cookie
- if (cookieLength > 4096) {
- $log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
- cookieLength + " > 4096 bytes)!");
- }
- }
- }
- } else {
- if (rawDocument.cookie !== lastCookieString) {
- lastCookieString = rawDocument.cookie;
- cookieArray = lastCookieString.split("; ");
- lastCookies = {};
-
- for (i = 0; i < cookieArray.length; i++) {
- cookie = cookieArray[i];
- index = cookie.indexOf('=');
- if (index > 0) { //ignore nameless cookies
- var name = unescape(cookie.substring(0, index));
- // the first value that is seen for a cookie is the most
- // specific one. values for the same cookie name that
- // follow are for less specific paths.
- if (lastCookies[name] === undefined) {
- lastCookies[name] = unescape(cookie.substring(index + 1));
- }
- }
- }
- }
- return lastCookies;
- }
- };
-
+ */
+ self.cookies = (function() {
+ var cookies = function(name, value, options) {
+ if (!angular.isDefined(options) || options == null) options = {};
+ if (name) {
+ if (value === undefined) {
+ deleteCookie(name, options);
+ } else {
+ if (isString(value)) {
+ setCookie(name, value, options);
+ }
+ }
+ } else {
+ return getAllCookies();
+ }
+ }
+
+ var defaultPath = self.baseHref;
+
+ function deleteCookie(name, options) {
+ if (options.path) {
+ rawDocument.cookie = escape(name) + "=;path=" + options.path + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ } else {
+ rawDocument.cookie = escape(name) + "=;path=" + defaultPath() + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ var path = location.pathname;
+ //delete cookies under different paths
+ while (rawDocument.cookie.indexOf(name + "=") >= 0 && angular.isDefined(path)) {
+ rawDocument.cookie = escape(name) + "=;path=" + path + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ if (path == '') break;
+ path = path.replace(/\/$|[^\/]*[^\/]$/, "");
+ }
+ }
+ }
+ function setCookie(name, value, options) {
+ var newCookie = escape(name) + '=' + escape(value)
+ + resolvePathString(name, options)
+ + resolveExpirationString(name, options);
+
+ rawDocument.cookie = newCookie;
+ alertOnLength(name, newCookie);
+ }
+ function resolvePathString(name, options) {
+ var path = defaultPath();
+ if (options.path) {
+ if (angular.isString(options.path) && location.pathname.indexOf(options.path) >= 0) {
+ path = options.path;
+ } else {
+ $log.warn("Cookie '" + name + "' was not set with requested path '" + options.path +
+ "' since path is not a String or not partial to window.location, which is " + location.pathname)
+ }
+ }
+ return ";path=" + path;
+ }
+ function resolveExpirationString(name, options) {
+ if (options.expires) {
+ if (angular.isDate(options.expires) && options.expires > new Date()) {
+ return ";expires=" + options.expires.toUTCString();
+ } else {
+ $log.warn("Cookie '" + name + "' was not set with requested expiration '" + options.expires +
+ "' since date is in the past or object is not a date")
+ }
+ }
+ return "";
+ }
+ function alertOnLength(name, cookieString) {
+ var cookieLength = (cookieString).length + 1;
+
+ // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
+ // - 300 cookies
+ // - 20 cookies per unique domain
+ // - 4096 bytes per cookie
+ if (cookieLength > 4096) {
+ $log.warn("Cookie '" + name + "' possibly not set or overflowed because it was too large (" +
+ cookieLength + " > 4096 bytes)!");
+ }
+ }
+ function getAllCookies() {
+ if (rawDocument.cookie !== lastCookieString) {
+ lastCookieString = rawDocument.cookie;
+ var cookieArray = lastCookieString.split("; ");
+ lastCookies = {};
+ var cookie, i, index;
+ for (i = 0; i < cookieArray.length; i++) {
+ cookie = cookieArray[i];
+ index = cookie.indexOf('=');
+ if (index > 0) {
+ var name = unescape(cookie.substring(0, index));
+ // the first value that is seen for a cookie is the most
+ // specific one. values for the same cookie name that
+ // follow are for less specific paths.
+ if (lastCookies[name] === undefined) {
+ lastCookies[name] = unescape(cookie.substring(index + 1));
+ }
+ } else if (index <0) {
+ lastCookies[unescape(cookie)] = ''; // IE saves cookie= as cookie, which require special care
+ } //ignore nameless cookies where index ==0
+ }
+ }
+ return lastCookies;
+ }
+ return cookies;
+ })();
/**
* @name ng.$browser#defer
diff --git a/src/ngCookies/cookies.js b/src/ngCookies/cookies.js
index 683557077688..b7d64d9de819 100644
--- a/src/ngCookies/cookies.js
+++ b/src/ngCookies/cookies.js
@@ -3,8 +3,9 @@
/**
* @ngdoc overview
* @name ngCookies
- */
-
+ */
+
+var $cookieOptionsHash = {};
angular.module('ngCookies', ['ng']).
/**
@@ -13,26 +14,64 @@ angular.module('ngCookies', ['ng']).
* @requires $browser
*
* @description
- * Provides read/write access to browser's cookies.
+ * The '$cookies' service exposes the browser's cookies as a simple Object (I.E. dictionary/hashmap).
+ * Allowing read/write operations on cookies to work similar to changing an object's variables
+ * where each variable is a different cookie.
*
- * Only a simple Object is exposed and by adding or removing properties to/from
- * this object, new cookies are created/deleted at the end of current $eval.
+ * The $cookies object acts as a cache for the actual cookies, which flushes at the end of the current $eval.
+ * That is, if you change a value of a cookie in $cookie, it will be written to the browser at the end of the $eval.
*
- * @example
-
-
-
-
-
+
+
+ * # Cookie defaults
+ * when using the $cookie service, any cookies added/updated will be created with the following options:
+ * - if a base tag exists, then the path will be set to the base tag's href path. otherwise the path will be /.
+ * - no expiration date is passed, so all cookies set using $cookies will expire at end of session. *
+ * # Interoperability Considerations
+ * It is not advised to access or modify the browsers cookies directly when using the $cookies service
+ * on the same cookie, since the $cookie service caches changes and only flushes them at the end of the current $eval,
+ * interdependency is not predictable.
+ * Also note that changes made directly to the cookie will only appear in the $cookie cache after 100ms and not at
+ * the end of the current $eval (as opposed to changes made through the $cookie service)
*/
- factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
+ factory('$cookies', ['$rootScope', '$browser', function($rootScope, $browser) {
var cookies = {},
lastCookies = {},
lastBrowserCookies,
@@ -73,7 +112,9 @@ angular.module('ngCookies', ['ng']).
//delete any cookies deleted in $cookies
for (name in lastCookies) {
if (isUndefined(cookies[name])) {
- $browser.cookies(name, undefined);
+ updated = true;
+ $browser.cookies(name, undefined,$cookieOptionsHash[name]);
+ delete $cookieOptionsHash[name];
}
}
@@ -84,10 +125,12 @@ angular.module('ngCookies', ['ng']).
if (angular.isDefined(lastCookies[name])) {
cookies[name] = lastCookies[name];
} else {
+ //delete cookie who value was put as undefined, $browser already updated
delete cookies[name];
}
- } else if (value !== lastCookies[name]) {
- $browser.cookies(name, value);
+ } else if (value !== lastCookies[name] || $cookieOptionsHash[name]) {
+ $browser.cookies(name, value,$cookieOptionsHash[name]);
+ delete $cookieOptionsHash[name];
updated = true;
}
}
@@ -108,6 +151,7 @@ angular.module('ngCookies', ['ng']).
updated = true;
}
}
+ copy(browserCookies, lastCookies);
}
}
}]).
@@ -122,7 +166,49 @@ angular.module('ngCookies', ['ng']).
* Provides a key-value (string-object) storage, that is backed by session cookies.
* Objects put or retrieved from this storage are automatically serialized or
* deserialized by angular's toJson/fromJson.
- * @example
+ *
+ * The service uses the $cookies service internally, so anything that applies to that service, applies here
+ * unless otherwise mentioned.
+ * Unlike the $cookies service, the $cookieStore service allows custom Path and expirationDate settions for cookies.
+ * @example
+
+
+
+
+
User info
+
+
first name:
+
+
+
+
last name:
+
+
+
+ Click to reset cookie in :
+ milliseconds.
+
+
+
+ function CookieCtrl($scope,$cookieStore,$cookies) {
+ $scope.details = $cookieStore.get("details") || {firstName:"hugo",lastName:"gogo"};
+ $scope.cookieTimeout = 1000;
+ $scope.$watch("details",function(newValue){
+ $cookieStore.put("details",newValue);
+ },true);
+ $scope.setExpire = function() {
+ $cookieStore.put("details",$cookieStore.get("details"),{expires: calcDate($scope)});
+ setTimeout(function(){
+ $scope.details = $cookieStore.get("details") || {firstName:"hugo",lastName:"gogo"};
+ $scope.$apply()
+ }, +$scope.cookieTimeout + 50);
+ }
+ }
+ function calcDate($scope) {
+ return new Date(new Date().getTime() + +$scope.cookieTimeout);
+ }
+
+
*/
factory('$cookieStore', ['$cookies', function($cookies) {
@@ -153,8 +239,15 @@ angular.module('ngCookies', ['ng']).
*
* @param {string} key Id for the `value`.
* @param {Object} value Value to be stored.
+ * @param {object} options Options for the cookie stored, if not passed uses default.
+ * - **expires** - `{date}` - date for cookie to expire.
+ * If not passed, the object is not a date or the date is in the past, the cookie expiration
+ * date will not be set, so that the cookie will expire at the end of the session.
+ * - **path** - `{string}` - the path to set the cookie on.
+ * Defaults to / (or base tag's href attribute, if base tag exists)
*/
- put: function(key, value) {
+ put: function(key, value,options) {
+ $cookieOptionsHash[key] = options;
$cookies[key] = angular.toJson(value);
},
@@ -167,8 +260,12 @@ angular.module('ngCookies', ['ng']).
* Remove given cookie
*
* @param {string} key Id of the key-value pair to delete.
+ * @param {object} options Options for the cookie to be deleted.
+ * - **path** - `{string}` - the path to delete the cookie
+ * If not passed, all cookies that matche the key are deleted.
*/
- remove: function(key) {
+ remove: function(key,options) {
+ $cookieOptionsHash[key] = options;
delete $cookies[key];
}
};
diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js
index a35e0f2fd473..67ba3506b12e 100644
--- a/src/ngMock/angular-mocks.js
+++ b/src/ngMock/angular-mocks.js
@@ -63,6 +63,7 @@ angular.mock.$Browser = function() {
};
self.cookieHash = {};
+ self.cookieOptionHash = {};
self.lastCookieHash = {};
self.deferredFns = [];
self.deferredNextId = 0;
@@ -160,13 +161,15 @@ angular.mock.$Browser.prototype = {
return this.$$url;
},
- cookies: function(name, value) {
+ cookies: function(name, value,options) {
if (name) {
if (value == undefined) {
+ if (options) this.cookieOptionHash[name] = options;
delete this.cookieHash[name];
} else {
if (angular.isString(value) && //strings only
value.length <= 4096) { //strict cookie storage limits
+ if (options) this.cookieOptionHash[name] = options;
this.cookieHash[name] = value;
}
}
diff --git a/test/ng/browserSpecs.js b/test/ng/browserSpecs.js
old mode 100755
new mode 100644
index 3ec78e615341..8c980ede4542
--- a/test/ng/browserSpecs.js
+++ b/test/ng/browserSpecs.js
@@ -37,7 +37,8 @@ function MockWindow() {
this.location = {
href: 'http://server',
- replace: noop
+ replace: noop,
+ pathname: window.location.pathname
};
this.history = {
@@ -49,7 +50,19 @@ function MockWindow() {
function MockDocument() {
var self = this;
- this[0] = window.document
+ //IE8 allows defineProperty only on dom elements
+ var fakeDocument = document.createElement('br');
+ Object.defineProperty(fakeDocument,"cookie",{
+ set: function(value) {
+ self.lastCookieSet = value;
+ window.document.cookie = value;
+ },
+ get: function() {
+ return window.document.cookie;
+ }
+ });
+
+ this[0] = fakeDocument
this.basePath = '/';
this.find = function(name) {
@@ -67,524 +80,662 @@ function MockDocument() {
throw new Error(name);
}
}
-}
-
-describe('browser', function() {
-
- var browser, fakeWindow, fakeDocument, logs, scripts, removedScripts, sniffer;
-
- beforeEach(function() {
- scripts = [];
- removedScripts = [];
- sniffer = {history: true, hashchange: true};
- fakeWindow = new MockWindow();
- fakeDocument = new MockDocument();
-
- var fakeBody = [{appendChild: function(node){scripts.push(node);},
- removeChild: function(node){removedScripts.push(node);}}];
-
- logs = {log:[], warn:[], info:[], error:[]};
-
- var fakeLog = {log: function() { logs.log.push(slice.call(arguments)); },
- warn: function() { logs.warn.push(slice.call(arguments)); },
- info: function() { logs.info.push(slice.call(arguments)); },
- error: function() { logs.error.push(slice.call(arguments)); }};
-
- browser = new Browser(fakeWindow, fakeDocument, fakeLog, sniffer);
- });
-
- it('should contain cookie cruncher', function() {
- expect(browser.cookies).toBeDefined();
- });
-
- describe('outstading requests', function() {
- it('should process callbacks immedietly with no outstanding requests', function() {
- var callback = jasmine.createSpy('callback');
- browser.notifyWhenNoOutstandingRequests(callback);
- expect(callback).toHaveBeenCalled();
- });
- });
-
-
- describe('defer', function() {
- it('should execute fn asynchroniously via setTimeout', function() {
- var callback = jasmine.createSpy('deferred');
-
- browser.defer(callback);
- expect(callback).not.toHaveBeenCalled();
-
- fakeWindow.setTimeout.flush();
- expect(callback).toHaveBeenCalledOnce();
- });
-
-
- it('should update outstandingRequests counter', function() {
- var callback = jasmine.createSpy('deferred');
-
- browser.defer(callback);
- expect(callback).not.toHaveBeenCalled();
-
- fakeWindow.setTimeout.flush();
- expect(callback).toHaveBeenCalledOnce();
+}
+
+describe('browser', function() {
+ var browser, fakeWindow, fakeDocument, logs, scripts, removedScripts, sniffer;
+
+ beforeEach(function() {
+ scripts = [];
+ removedScripts = [];
+ sniffer = { history: true, hashchange: true };
+ fakeWindow = new MockWindow();
+ fakeDocument = new MockDocument();
+
+ var fakeBody = [{ appendChild: function(node) { scripts.push(node); },
+ removeChild: function(node) { removedScripts.push(node); }
+ }];
+
+ logs = { log: [], warn: [], info: [], error: [] };
+
+ var fakeLog = { log: function() { logs.log.push(slice.call(arguments)); },
+ warn: function() { logs.warn.push(slice.call(arguments)); },
+ info: function() { logs.info.push(slice.call(arguments)); },
+ error: function() { logs.error.push(slice.call(arguments)); }
+ };
+
+ browser = new Browser(fakeWindow, fakeDocument, fakeLog, sniffer);
+ });
+
+ it('should contain cookie cruncher', function() {
+ expect(browser.cookies).toBeDefined();
+ });
+
+ describe('outstading requests', function() {
+ it('should process callbacks immedietly with no outstanding requests', function() {
+ var callback = jasmine.createSpy('callback');
+ browser.notifyWhenNoOutstandingRequests(callback);
+ expect(callback).toHaveBeenCalled();
+ });
+ });
+
+
+ describe('defer', function() {
+ it('should execute fn asynchroniously via setTimeout', function() {
+ var callback = jasmine.createSpy('deferred');
+
+ browser.defer(callback);
+ expect(callback).not.toHaveBeenCalled();
+
+ fakeWindow.setTimeout.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+
+ it('should update outstandingRequests counter', function() {
+ var callback = jasmine.createSpy('deferred');
+
+ browser.defer(callback);
+ expect(callback).not.toHaveBeenCalled();
+
+ fakeWindow.setTimeout.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+
+ 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([]);
+ expect(browser.defer.cancel(deferId1)).toBe(true);
+ expect(browser.defer.cancel(deferId3)).toBe(true);
+ fakeWindow.setTimeout.flush();
+ expect(log).toEqual(['ok']);
+ expect(browser.defer.cancel(deferId2)).toBe(false);
+ });
+ });
+ });
+
+
+ describe('cookies', function() {
+ function deleteAllCookies() {
+ var cookies = document.cookie.split(";");
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = cookies[i];
+ var path = location.pathname;
+ var eqPos = cookie.indexOf("=");
+ var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
+ //delete all possible paths
+ while (path && path != '') {
+ document.cookie = name + "=;path=" + path + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ path = path.replace(/\/$|[^\/]*[^\/]$/, "");
+ }
+ document.cookie = name + "=;path=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ }
+ }
+
+ beforeEach(function() {
+ deleteAllCookies();
+ expect(document.cookie).toEqual('');
+ });
+
+
+ afterEach(function() {
+ deleteAllCookies();
+ expect(document.cookie).toEqual('');
+ });
+
+
+ describe('remove all via (null)', function() {
+
+ it('should do nothing when no cookies are set', function() {
+ browser.cookies(null);
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ });
+
+ });
+
+ describe('remove via cookies(cookieName, undefined)', function() {
+
+ it('should remove a cookie when it is present', function() {
+ document.cookie = 'foo=bar;path=/';
+
+ browser.cookies('foo', undefined);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ });
+
+
+ it('should do nothing when an nonexisting cookie is being removed', function() {
+ browser.cookies('doesntexist', undefined);
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ });
+ it('should remove cookie with file path', function() {
+ document.cookie = 'foo=bar;path=/karma';
+ browser.cookies('foo', undefined);
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ it('should remove cookie with directory path', function() {
+ document.cookie = 'foo=bar;path=/karma/';
+ browser.cookies('foo', undefined);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ it('should remove cookie with nested path', function() {
+ document.cookie = 'foo=bar;path=/karma/tests';
+ browser.cookies('foo', undefined);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ it('should remove all named cookies with different paths', function() {
+ document.cookie = 'foo=first;path=/';
+ document.cookie = 'foo=second;path=/karma';
+ browser.cookies('foo', undefined);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ });
+ describe('remove via cookies(cookieName, undefined,options)',function(){
+ it('should work with null in options argument',function() {
+ document.cookie = 'foo=bar;path=/';
+
+ browser.cookies('foo', undefined,null);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ it('should work with array in options argument',function() {
+ document.cookie = 'foo=bar;path=/';
+
+ browser.cookies('foo', undefined,[]);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ it('should not delete path not requested',function() {
+ document.cookie = 'foo=bar;path=/';
+
+ browser.cookies('foo', undefined,{path:"/karma"});
+
+ expect(document.cookie).toEqual('foo=bar');
+ expect(browser.cookies()).toEqual({'foo':'bar'});
+ })
+ it('should delete requested path',function() {
+ document.cookie = 'foo=bar;path=/karma';
+
+ browser.cookies('foo', undefined,{path:"/karma"});
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ })
+ it('should delete only requested path',function() {
+ document.cookie = 'foo=first;path=/';
+ document.cookie = 'foo=second;path=/karma';
+
+ browser.cookies('foo', undefined,{path:"/"});
+
+ expect(document.cookie).toEqual('foo=second');
+ expect(browser.cookies()).toEqual({'foo':'second'});
+ })
+ })
+
+ describe('put via cookies(cookieName, string)', function() {
+
+ it('should create and store a cookie', function() {
+ browser.cookies('cookieName', 'cookie=Value');
+ expect(document.cookie).toMatch(/cookieName=cookie%3DValue;? ?/);
+ expect(browser.cookies()).toEqual({ 'cookieName': 'cookie=Value' });
+ expect(fakeDocument.lastCookieSet).toEqual("cookieName=cookie%3DValue;path=/")
+ });
+
+
+ it('should overwrite an existing unsynced cookie', function() {
+ document.cookie = "cookie=new;path=/";
+
+ var oldVal = browser.cookies('cookie', 'newer');
+
+ expect(document.cookie).toEqual('cookie=newer');
+ expect(browser.cookies()).toEqual({ 'cookie': 'newer' });
+ expect(oldVal).not.toBeDefined();
+ });
+
+ it('should escape both name and value', function() {
+ browser.cookies('cookie1=', 'val;ue');
+ browser.cookies('cookie2=bar;baz', 'val=ue');
+
+ var rawCookies = document.cookie.split("; "); //order is not guaranteed, so we need to parse
+ expect(rawCookies.length).toEqual(2);
+ expect(rawCookies).toContain('cookie1%3D=val%3Bue');
+ expect(rawCookies).toContain('cookie2%3Dbar%3Bbaz=val%3Due');
+ });
+
+ it('should log warnings when 4kb per cookie storage limit is reached', function() {
+ var i, longVal = '', cookieStr;
+
+ for (i = 0; i < 4083; i++) {
+ longVal += '+';
+ }
+
+ cookieStr = document.cookie;
+ browser.cookies('x', longVal); //total size 4093-4096, so it should go through
+ expect(document.cookie).not.toEqual(cookieStr);
+ expect(browser.cookies()['x']).toEqual(longVal);
+ expect(logs.warn).toEqual([]);
+
+ browser.cookies('x', longVal + 'xxxx'); //total size 4097-4099, a warning should be logged
+ expect(logs.warn).toEqual(
+ [["Cookie 'x' possibly not set or overflowed because it was too large (4097 > 4096 " +
+ "bytes)!"]]);
+
+ //force browser to dropped a cookie and make sure that the cache is not out of sync
+ browser.cookies('x', 'shortVal');
+ expect(browser.cookies().x).toEqual('shortVal'); //needed to prime the cache
+ cookieStr = document.cookie;
+ browser.cookies('x', longVal + longVal + longVal); //should be too long for all browsers
+
+ if (document.cookie !== cookieStr) {
+ fail("browser didn't drop long cookie when it was expected. make the cookie in this " +
+ "test longer");
+ }
+
+ expect(browser.cookies().x).toEqual('shortVal');
+ });
+ it('should allow empty values', function() {
+ browser.cookies('cookieName', '');
+ expect(document.cookie).toMatch(/cookieName=?/)
+ expect(browser.cookies().cookieName).toEqual('');
+ })
+ });
+
+ describe('put via cookies(cookieName, string), if no ', function() {
+ beforeEach(function() {
+ fakeDocument.basePath = undefined;
+ });
+
+ it('should default path in cookie to "" (empty string)', function() {
+ browser.cookies('cookie', 'bender');
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=")
+ });
+ });
+ describe('put via cookies(cookieName, string), with complex ', function() {
+ beforeEach(function() {
+ fakeDocument.basePath = "http://location/karma/";
+ });
+
+ it('should set path in cookie to uri path', function() {
+ browser.cookies('cookie', 'bender');
+ //TODO: change test to run in URI /inner/path, so that the cookies will be saved
+ // and we can query them.
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/karma/")
+ });
+ });
+ describe('put via cookies(cookieName,string,options) with no options', function() {
+ it('should not throw exception when passing null', function() {
+ browser.cookies('cookie', 'bender', null);
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/");
+ })
+ it('should not throw exception when passing array', function() {
+ browser.cookies('cookie', 'bender', []);
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/");
+ })
+ })
+ describe('put via cookies(cookieName, string,options) with different path', function() {
+ it('should set path in cookie to desired path', function() {
+ browser.cookies('cookie', 'bender', { path: "/karma/tests" });
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/karma/tests")
+ })
+ it('shuld ignore path if path is not part of location', function() {
+ browser.cookies('cookie', 'bender', { path: "/something" });
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/")
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(logs.warn).toEqual(
+ [["Cookie 'cookie' was not set with requested path '/something'" +
+ " since path is not a String or not partial to window.location, which is /karma/tests/context.html"]]);
+ })
+ })
+ describe('put via cookies(cookieName, string,options) with expiration', function() {
+ it('should set expiration if passed', function() {
+ browser.cookies('cookie', 'bender', { expires: new Date(2050, 1, 1) });
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/;expires=" + new Date(2050, 1, 1).toUTCString())
+ })
+ it('should ignore if not a date object', function() {
+ browser.cookies('cookie', 'bender', { expires: [] });
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/")
+ expect(logs.warn).toEqual(
+ [["Cookie 'cookie' was not set with requested expiration ''" +
+ " since date is in the past or object is not a date"]]);
+ })
+ it('should ignore if date in the past', function() {
+ browser.cookies('cookie', 'bender', { expires: new Date(1999, 1, 1) });
+ expect(document.cookie).toEqual('cookie=bender');
+ expect(fakeDocument.lastCookieSet).toEqual("cookie=bender;path=/")
+ expect(logs.warn).toEqual(
+ [["Cookie 'cookie' was not set with requested expiration '" + (new Date(1999, 1, 1)) +
+ "' since date is in the past or object is not a date"]]);
+ })
+ })
+ describe('get via cookies()[cookieName]', function() {
+
+ it('should return undefined for nonexistent cookie', function() {
+ expect(browser.cookies().nonexistent).not.toBeDefined();
+ });
+
+
+ it('should return a value for an existing cookie', function() {
+ document.cookie = "foo=bar=baz;path=/";
+ expect(browser.cookies().foo).toEqual('bar=baz');
+ });
+ it('should return the the first value provided for a cookie', function() {
+ // For a cookie that has different values that differ by path, the
+ // value for the most specific path appears first. browser.cookies()
+ // should provide that value for the cookie.
+ document.cookie = 'foo="first"; foo="second"';
+ expect(browser.cookies()['foo']).toBe('"first"');
+ });
+ it('should unescape cookie values that were escaped by puts', function() {
+ document.cookie = "cookie2%3Dbar%3Bbaz=val%3Due;path=/";
+ expect(browser.cookies()['cookie2=bar;baz']).toEqual('val=ue');
+ });
+
+
+ it('should preserve leading & trailing spaces in names and values', function() {
+ browser.cookies(' cookie name ', ' cookie value ');
+ expect(browser.cookies()[' cookie name ']).toEqual(' cookie value ');
+ expect(browser.cookies()['cookie name']).not.toBeDefined();
+ });
+ it('should read empty values', function() {
+ document.cookie = "cookie=;path=/";
+ expect(browser.cookies()['cookie']).toEqual('');
+ })
+ });
+
+ describe('getAll via cookies()', function() {
+
+ it('should return cookies as hash', function() {
+ document.cookie = "foo1=bar1;path=/";
+ document.cookie = "foo2=bar2;path=/";
+ expect(browser.cookies()).toEqual({ 'foo1': 'bar1', 'foo2': 'bar2' });
+ });
+
+
+ it('should return empty hash if no cookies exist', function() {
+ expect(browser.cookies()).toEqual({});
+ });
+ });
+
+
+ it('should pick up external changes made to browser cookies', function() {
+ browser.cookies('oatmealCookie', 'drool');
+ expect(browser.cookies()).toEqual({ 'oatmealCookie': 'drool' });
+
+ document.cookie = 'oatmealCookie=changed;path=/';
+ expect(browser.cookies().oatmealCookie).toEqual('changed');
+ });
+
+
+ it('should initialize cookie cache with existing cookies', function() {
+ document.cookie = "existingCookie=existingValue;path=/";
+ expect(browser.cookies()).toEqual({ 'existingCookie': 'existingValue' });
+ });
+
+ });
+
+ describe('poller', function() {
+
+ it('should call functions in pollFns in regular intervals', function() {
+ var log = '';
+ browser.addPollFn(function() { log += 'a'; });
+ browser.addPollFn(function() { log += 'b'; });
+ expect(log).toEqual('');
+ fakeWindow.setTimeout.flush();
+ expect(log).toEqual('ab');
+ fakeWindow.setTimeout.flush();
+ expect(log).toEqual('abab');
+ });
+
+ it('should startPoller', function() {
+ expect(fakeWindow.timeouts.length).toEqual(0);
+
+ browser.addPollFn(function() { });
+ expect(fakeWindow.timeouts.length).toEqual(1);
+
+ //should remain 1 as it is the check fn
+ browser.addPollFn(function() { });
+ expect(fakeWindow.timeouts.length).toEqual(1);
+ });
+
+ it('should return fn that was passed into addPollFn', function() {
+ var fn = function() { return 1; };
+ var returnedFn = browser.addPollFn(fn);
+ expect(returnedFn).toBe(fn);
+ });
+ });
+
+ describe('url', function() {
+ var pushState, replaceState, locationReplace;
+
+ beforeEach(function() {
+ pushState = spyOn(fakeWindow.history, 'pushState');
+ replaceState = spyOn(fakeWindow.history, 'replaceState');
+ locationReplace = spyOn(fakeWindow.location, 'replace');
+ });
+
+ it('should return current location.href', function() {
+ fakeWindow.location.href = 'http://test.com';
+ expect(browser.url()).toEqual('http://test.com');
+
+ fakeWindow.location.href = 'https://another.com';
+ expect(browser.url()).toEqual('https://another.com');
+ });
+
+ it('should use history.pushState when available', function() {
+ sniffer.history = true;
+ browser.url('http://new.org');
+
+ expect(pushState).toHaveBeenCalledOnce();
+ expect(pushState.argsForCall[0][2]).toEqual('http://new.org');
+
+ expect(replaceState).not.toHaveBeenCalled();
+ expect(locationReplace).not.toHaveBeenCalled();
+ expect(fakeWindow.location.href).toEqual('http://server');
+ });
+
+ it('should use history.replaceState when available', function() {
+ sniffer.history = true;
+ browser.url('http://new.org', true);
+
+ expect(replaceState).toHaveBeenCalledOnce();
+ expect(replaceState.argsForCall[0][2]).toEqual('http://new.org');
+
+ expect(pushState).not.toHaveBeenCalled();
+ expect(locationReplace).not.toHaveBeenCalled();
+ expect(fakeWindow.location.href).toEqual('http://server');
+ });
+
+ it('should set location.href when pushState not available', function() {
+ sniffer.history = false;
+ browser.url('http://new.org');
+
+ expect(fakeWindow.location.href).toEqual('http://new.org');
+
+ expect(pushState).not.toHaveBeenCalled();
+ expect(replaceState).not.toHaveBeenCalled();
+ expect(locationReplace).not.toHaveBeenCalled();
+ });
+
+ it('should use location.replace when history.replaceState not available', function() {
+ sniffer.history = false;
+ browser.url('http://new.org', true);
+
+ expect(locationReplace).toHaveBeenCalledWith('http://new.org');
+
+ expect(pushState).not.toHaveBeenCalled();
+ expect(replaceState).not.toHaveBeenCalled();
+ expect(fakeWindow.location.href).toEqual('http://server');
+ });
+
+ it('should return $browser to allow chaining', function() {
+ expect(browser.url('http://any.com')).toBe(browser);
+ });
+
+
+ it('should decode single quotes to work around FF bug 407273', function() {
+ fakeWindow.location.href = "http://ff-bug/?single%27quote";
+ expect(browser.url()).toBe("http://ff-bug/?single'quote");
+ });
+
+ it('should not set URL when the URL is already set', function() {
+ var current = fakeWindow.location.href;
+ sniffer.history = false;
+ fakeWindow.location.href = 'dontchange';
+ browser.url(current);
+ expect(fakeWindow.location.href).toBe('dontchange');
+ });
+ });
+
+ describe('urlChange', function() {
+ var callback;
+
+ beforeEach(function() {
+ callback = jasmine.createSpy('onUrlChange');
+ });
+
+ afterEach(function() {
+ if (!jQuery) jqLite(fakeWindow).dealoc();
+ });
+
+ it('should return registered callback', function() {
+ expect(browser.onUrlChange(callback)).toBe(callback);
+ });
+
+ it('should forward popstate event with new url when history supported', function() {
+ sniffer.history = true;
+ browser.onUrlChange(callback);
+ fakeWindow.location.href = 'http://server/new';
+
+ fakeWindow.fire('popstate');
+ expect(callback).toHaveBeenCalledWith('http://server/new');
+
+ fakeWindow.fire('hashchange');
+ fakeWindow.setTimeout.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+ it('should forward only popstate event when both history and hashchange supported', function() {
+ sniffer.history = true;
+ sniffer.hashchange = true;
+ browser.onUrlChange(callback);
+ fakeWindow.location.href = 'http://server/new';
+
+ fakeWindow.fire('popstate');
+ expect(callback).toHaveBeenCalledWith('http://server/new');
+
+ fakeWindow.fire('hashchange');
+ fakeWindow.setTimeout.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+ it('should forward hashchange event with new url when only hashchange supported', function() {
+ sniffer.history = false;
+ sniffer.hashchange = true;
+ browser.onUrlChange(callback);
+ fakeWindow.location.href = 'http://server/new';
+
+ fakeWindow.fire('hashchange');
+ expect(callback).toHaveBeenCalledWith('http://server/new');
+
+ fakeWindow.fire('popstate');
+ fakeWindow.setTimeout.flush();
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+ it('should use polling when neither history nor hashchange supported', function() {
+ sniffer.history = false;
+ sniffer.hashchange = false;
+ browser.onUrlChange(callback);
+
+ fakeWindow.location.href = 'http://server.new';
+ fakeWindow.setTimeout.flush();
+ expect(callback).toHaveBeenCalledWith('http://server.new');
+
+ fakeWindow.fire('popstate');
+ fakeWindow.fire('hashchange');
+ expect(callback).toHaveBeenCalledOnce();
+ });
+
+ it('should not fire urlChange if changed by browser.url method (polling)', function() {
+ sniffer.history = false;
+ sniffer.hashchange = false;
+ browser.onUrlChange(callback);
+ browser.url('http://new.com');
+
+ fakeWindow.setTimeout.flush();
+ expect(callback).not.toHaveBeenCalled();
+ });
+
+ it('should not fire urlChange if changed by browser.url method (hashchange)', function() {
+ sniffer.history = false;
+ sniffer.hashchange = true;
+ browser.onUrlChange(callback);
+ browser.url('http://new.com');
+
+ fakeWindow.fire('hashchange');
+ expect(callback).not.toHaveBeenCalled();
+ });
+ });
+
+
+ describe('baseHref', function() {
+ var jqDocHead;
+
+ beforeEach(function() {
+ jqDocHead = jqLite(document).find('head');
+ });
+
+ it('should return value from ', function() {
+ fakeDocument.basePath = '/base/path/';
+ expect(browser.baseHref()).toEqual('/base/path/');
+ });
+
+ it('should return \'\' (empty string) if no ', function() {
+ fakeDocument.basePath = undefined;
+ expect(browser.baseHref()).toEqual('');
+ });
+
+ it('should remove domain from ', function() {
+ fakeDocument.basePath = 'http://host.com/base/path/';
+ expect(browser.baseHref()).toEqual('/base/path/');
+
+ fakeDocument.basePath = 'http://host.com/base/path/index.html';
+ expect(browser.baseHref()).toEqual('/base/path/index.html');
+ });
});
-
-
- 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([]);
- expect(browser.defer.cancel(deferId1)).toBe(true);
- expect(browser.defer.cancel(deferId3)).toBe(true);
- fakeWindow.setTimeout.flush();
- expect(log).toEqual(['ok']);
- expect(browser.defer.cancel(deferId2)).toBe(false);
- });
- });
- });
-
-
- describe('cookies', function() {
-
- function deleteAllCookies() {
- var cookies = document.cookie.split(";");
- var path = location.pathname;
-
- for (var i = 0; i < cookies.length; i++) {
- var cookie = cookies[i];
- var eqPos = cookie.indexOf("=");
- var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
- var parts = path.split('/');
- while (parts.length) {
- document.cookie = name + "=;path=" + (parts.join('/') || '/') + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
- parts.pop();
- }
- }
- }
-
- beforeEach(function() {
- deleteAllCookies();
- expect(document.cookie).toEqual('');
- });
-
-
- afterEach(function() {
- deleteAllCookies();
- expect(document.cookie).toEqual('');
- });
-
-
- describe('remove all via (null)', function() {
-
- it('should do nothing when no cookies are set', function() {
- browser.cookies(null);
- expect(document.cookie).toEqual('');
- expect(browser.cookies()).toEqual({});
- });
-
- });
-
- describe('remove via cookies(cookieName, undefined)', function() {
-
- it('should remove a cookie when it is present', function() {
- document.cookie = 'foo=bar;path=/';
-
- browser.cookies('foo', undefined);
-
- expect(document.cookie).toEqual('');
- expect(browser.cookies()).toEqual({});
- });
-
-
- it('should do nothing when an nonexisting cookie is being removed', function() {
- browser.cookies('doesntexist', undefined);
- expect(document.cookie).toEqual('');
- expect(browser.cookies()).toEqual({});
- });
- });
-
-
- describe('put via cookies(cookieName, string)', function() {
-
- it('should create and store a cookie', function() {
- browser.cookies('cookieName', 'cookie=Value');
- expect(document.cookie).toMatch(/cookieName=cookie%3DValue;? ?/);
- expect(browser.cookies()).toEqual({'cookieName':'cookie=Value'});
- });
-
-
- it('should overwrite an existing unsynced cookie', function() {
- document.cookie = "cookie=new;path=/";
-
- var oldVal = browser.cookies('cookie', 'newer');
-
- expect(document.cookie).toEqual('cookie=newer');
- expect(browser.cookies()).toEqual({'cookie':'newer'});
- expect(oldVal).not.toBeDefined();
- });
-
- it('should escape both name and value', function() {
- browser.cookies('cookie1=', 'val;ue');
- browser.cookies('cookie2=bar;baz', 'val=ue');
-
- var rawCookies = document.cookie.split("; "); //order is not guaranteed, so we need to parse
- expect(rawCookies.length).toEqual(2);
- expect(rawCookies).toContain('cookie1%3D=val%3Bue');
- expect(rawCookies).toContain('cookie2%3Dbar%3Bbaz=val%3Due');
- });
-
- it('should log warnings when 4kb per cookie storage limit is reached', function() {
- var i, longVal = '', cookieStr;
-
- for(i=0; i<4083; i++) {
- longVal += '+';
- }
-
- cookieStr = document.cookie;
- browser.cookies('x', longVal); //total size 4093-4096, so it should go through
- expect(document.cookie).not.toEqual(cookieStr);
- expect(browser.cookies()['x']).toEqual(longVal);
- expect(logs.warn).toEqual([]);
-
- browser.cookies('x', longVal + 'xxxx'); //total size 4097-4099, a warning should be logged
- expect(logs.warn).toEqual(
- [[ "Cookie 'x' possibly not set or overflowed because it was too large (4097 > 4096 " +
- "bytes)!" ]]);
-
- //force browser to dropped a cookie and make sure that the cache is not out of sync
- browser.cookies('x', 'shortVal');
- expect(browser.cookies().x).toEqual('shortVal'); //needed to prime the cache
- cookieStr = document.cookie;
- browser.cookies('x', longVal + longVal + longVal); //should be too long for all browsers
-
- if (document.cookie !== cookieStr) {
- this.fail(new Error("browser didn't drop long cookie when it was expected. make the " +
- "cookie in this test longer"));
- }
-
- expect(browser.cookies().x).toEqual('shortVal');
- });
- });
-
- describe('put via cookies(cookieName, string), if no ', function () {
- beforeEach(function () {
- fakeDocument.basePath = undefined;
- });
-
- it('should default path in cookie to "" (empty string)', function () {
- browser.cookies('cookie', 'bender');
- // This only fails in Safari and IE when cookiePath returns undefined
- // Where it now succeeds since baseHref return '' instead of undefined
- expect(document.cookie).toEqual('cookie=bender');
- });
- });
-
- describe('get via cookies()[cookieName]', function() {
-
- it('should return undefined for nonexistent cookie', function() {
- expect(browser.cookies().nonexistent).not.toBeDefined();
- });
-
-
- it ('should return a value for an existing cookie', function() {
- document.cookie = "foo=bar=baz;path=/";
- expect(browser.cookies().foo).toEqual('bar=baz');
- });
-
- it('should return the the first value provided for a cookie', function() {
- // For a cookie that has different values that differ by path, the
- // value for the most specific path appears first. browser.cookies()
- // should provide that value for the cookie.
- document.cookie = 'foo="first"; foo="second"';
- expect(browser.cookies()['foo']).toBe('"first"');
- });
-
- it ('should unescape cookie values that were escaped by puts', function() {
- document.cookie = "cookie2%3Dbar%3Bbaz=val%3Due;path=/";
- expect(browser.cookies()['cookie2=bar;baz']).toEqual('val=ue');
- });
-
-
- it('should preserve leading & trailing spaces in names and values', function() {
- browser.cookies(' cookie name ', ' cookie value ');
- expect(browser.cookies()[' cookie name ']).toEqual(' cookie value ');
- expect(browser.cookies()['cookie name']).not.toBeDefined();
- });
- });
-
-
- describe('getAll via cookies()', function() {
-
- it('should return cookies as hash', function() {
- document.cookie = "foo1=bar1;path=/";
- document.cookie = "foo2=bar2;path=/";
- expect(browser.cookies()).toEqual({'foo1':'bar1', 'foo2':'bar2'});
- });
-
-
- it('should return empty hash if no cookies exist', function() {
- expect(browser.cookies()).toEqual({});
- });
- });
-
-
- it('should pick up external changes made to browser cookies', function() {
- browser.cookies('oatmealCookie', 'drool');
- expect(browser.cookies()).toEqual({'oatmealCookie':'drool'});
-
- document.cookie = 'oatmealCookie=changed;path=/';
- expect(browser.cookies().oatmealCookie).toEqual('changed');
- });
-
-
- it('should initialize cookie cache with existing cookies', function() {
- document.cookie = "existingCookie=existingValue;path=/";
- expect(browser.cookies()).toEqual({'existingCookie':'existingValue'});
- });
-
- });
-
- describe('poller', function() {
-
- it('should call functions in pollFns in regular intervals', function() {
- var log = '';
- browser.addPollFn(function() {log+='a';});
- browser.addPollFn(function() {log+='b';});
- expect(log).toEqual('');
- fakeWindow.setTimeout.flush();
- expect(log).toEqual('ab');
- fakeWindow.setTimeout.flush();
- expect(log).toEqual('abab');
- });
-
- it('should startPoller', function() {
- expect(fakeWindow.timeouts.length).toEqual(0);
-
- browser.addPollFn(function() {});
- expect(fakeWindow.timeouts.length).toEqual(1);
-
- //should remain 1 as it is the check fn
- browser.addPollFn(function() {});
- expect(fakeWindow.timeouts.length).toEqual(1);
- });
-
- it('should return fn that was passed into addPollFn', function() {
- var fn = function() { return 1; };
- var returnedFn = browser.addPollFn(fn);
- expect(returnedFn).toBe(fn);
- });
- });
-
- describe('url', function() {
- var pushState, replaceState, locationReplace;
-
- beforeEach(function() {
- pushState = spyOn(fakeWindow.history, 'pushState');
- replaceState = spyOn(fakeWindow.history, 'replaceState');
- locationReplace = spyOn(fakeWindow.location, 'replace');
- });
-
- it('should return current location.href', function() {
- fakeWindow.location.href = 'http://test.com';
- expect(browser.url()).toEqual('http://test.com');
-
- fakeWindow.location.href = 'https://another.com';
- expect(browser.url()).toEqual('https://another.com');
- });
-
- it('should use history.pushState when available', function() {
- sniffer.history = true;
- browser.url('http://new.org');
-
- expect(pushState).toHaveBeenCalledOnce();
- expect(pushState.argsForCall[0][2]).toEqual('http://new.org');
-
- expect(replaceState).not.toHaveBeenCalled();
- expect(locationReplace).not.toHaveBeenCalled();
- expect(fakeWindow.location.href).toEqual('http://server');
- });
-
- it('should use history.replaceState when available', function() {
- sniffer.history = true;
- browser.url('http://new.org', true);
-
- expect(replaceState).toHaveBeenCalledOnce();
- expect(replaceState.argsForCall[0][2]).toEqual('http://new.org');
-
- expect(pushState).not.toHaveBeenCalled();
- expect(locationReplace).not.toHaveBeenCalled();
- expect(fakeWindow.location.href).toEqual('http://server');
- });
-
- it('should set location.href when pushState not available', function() {
- sniffer.history = false;
- browser.url('http://new.org');
-
- expect(fakeWindow.location.href).toEqual('http://new.org');
-
- expect(pushState).not.toHaveBeenCalled();
- expect(replaceState).not.toHaveBeenCalled();
- expect(locationReplace).not.toHaveBeenCalled();
- });
-
- it('should use location.replace when history.replaceState not available', function() {
- sniffer.history = false;
- browser.url('http://new.org', true);
-
- expect(locationReplace).toHaveBeenCalledWith('http://new.org');
-
- expect(pushState).not.toHaveBeenCalled();
- expect(replaceState).not.toHaveBeenCalled();
- expect(fakeWindow.location.href).toEqual('http://server');
- });
-
- it('should return $browser to allow chaining', function() {
- expect(browser.url('http://any.com')).toBe(browser);
- });
-
-
- it('should decode single quotes to work around FF bug 407273', function() {
- fakeWindow.location.href = "http://ff-bug/?single%27quote";
- expect(browser.url()).toBe("http://ff-bug/?single'quote");
- });
-
- it('should not set URL when the URL is already set', function() {
- var current = fakeWindow.location.href;
- sniffer.history = false;
- fakeWindow.location.href = 'dontchange';
- browser.url(current);
- expect(fakeWindow.location.href).toBe('dontchange');
- });
- });
-
- describe('urlChange', function() {
- var callback;
-
- beforeEach(function() {
- callback = jasmine.createSpy('onUrlChange');
- });
-
- afterEach(function() {
- if (!jQuery) jqLite(fakeWindow).dealoc();
- });
-
- it('should return registered callback', function() {
- expect(browser.onUrlChange(callback)).toBe(callback);
- });
-
- it('should forward popstate event with new url when history supported', function() {
- sniffer.history = true;
- browser.onUrlChange(callback);
- fakeWindow.location.href = 'http://server/new';
-
- fakeWindow.fire('popstate');
- expect(callback).toHaveBeenCalledWith('http://server/new');
-
- fakeWindow.fire('hashchange');
- fakeWindow.setTimeout.flush();
- expect(callback).toHaveBeenCalledOnce();
- });
-
- it('should forward only popstate event when both history and hashchange supported', function() {
- sniffer.history = true;
- sniffer.hashchange = true;
- browser.onUrlChange(callback);
- fakeWindow.location.href = 'http://server/new';
-
- fakeWindow.fire('popstate');
- expect(callback).toHaveBeenCalledWith('http://server/new');
-
- fakeWindow.fire('hashchange');
- fakeWindow.setTimeout.flush();
- expect(callback).toHaveBeenCalledOnce();
- });
-
- it('should forward hashchange event with new url when only hashchange supported', function() {
- sniffer.history = false;
- sniffer.hashchange = true;
- browser.onUrlChange(callback);
- fakeWindow.location.href = 'http://server/new';
-
- fakeWindow.fire('hashchange');
- expect(callback).toHaveBeenCalledWith('http://server/new');
-
- fakeWindow.fire('popstate');
- fakeWindow.setTimeout.flush();
- expect(callback).toHaveBeenCalledOnce();
- });
-
- it('should use polling when neither history nor hashchange supported', function() {
- sniffer.history = false;
- sniffer.hashchange = false;
- browser.onUrlChange(callback);
-
- fakeWindow.location.href = 'http://server.new';
- fakeWindow.setTimeout.flush();
- expect(callback).toHaveBeenCalledWith('http://server.new');
-
- fakeWindow.fire('popstate');
- fakeWindow.fire('hashchange');
- expect(callback).toHaveBeenCalledOnce();
- });
-
- it('should not fire urlChange if changed by browser.url method (polling)', function() {
- sniffer.history = false;
- sniffer.hashchange = false;
- browser.onUrlChange(callback);
- browser.url('http://new.com');
-
- fakeWindow.setTimeout.flush();
- expect(callback).not.toHaveBeenCalled();
- });
-
- it('should not fire urlChange if changed by browser.url method (hashchange)', function() {
- sniffer.history = false;
- sniffer.hashchange = true;
- browser.onUrlChange(callback);
- browser.url('http://new.com');
-
- fakeWindow.fire('hashchange');
- expect(callback).not.toHaveBeenCalled();
- });
- });
-
-
- describe('baseHref', function() {
- var jqDocHead;
-
- beforeEach(function() {
- jqDocHead = jqLite(document).find('head');
- });
-
- it('should return value from ', function() {
- fakeDocument.basePath = '/base/path/';
- expect(browser.baseHref()).toEqual('/base/path/');
- });
-
- it('should return \'\' (empty string) if no ', function() {
- fakeDocument.basePath = undefined;
- expect(browser.baseHref()).toEqual('');
- });
-
- it('should remove domain from ', function() {
- fakeDocument.basePath = 'http://host.com/base/path/';
- expect(browser.baseHref()).toEqual('/base/path/');
-
- fakeDocument.basePath = 'http://host.com/base/path/index.html';
- expect(browser.baseHref()).toEqual('/base/path/index.html');
- });
- });
});
diff --git a/test/ngCookies/cookiesSpec.js b/test/ngCookies/cookiesSpec.js
index 674c27748f11..91343546f434 100644
--- a/test/ngCookies/cookiesSpec.js
+++ b/test/ngCookies/cookiesSpec.js
@@ -1,99 +1,109 @@
-'use strict';
-
-describe('$cookies', function() {
- beforeEach(module('ngCookies', function($provide) {
- $provide.factory('$browser', function(){
- return angular.extend(new angular.mock.$Browser(), {cookieHash: {preexisting:'oldCookie'}});
- });
- }));
-
-
- it('should provide access to existing cookies via object properties and keep them in sync',
- inject(function($cookies, $browser, $rootScope) {
- expect($cookies).toEqual({'preexisting': 'oldCookie'});
-
- // access internal cookie storage of the browser mock directly to simulate behavior of
- // document.cookie
- $browser.cookieHash['brandNew'] = 'cookie';
- $browser.poll();
-
- expect($cookies).toEqual({'preexisting': 'oldCookie', 'brandNew':'cookie'});
-
- $browser.cookieHash['brandNew'] = 'cookie2';
- $browser.poll();
- expect($cookies).toEqual({'preexisting': 'oldCookie', 'brandNew':'cookie2'});
-
- delete $browser.cookieHash['brandNew'];
- $browser.poll();
- expect($cookies).toEqual({'preexisting': 'oldCookie'});
- }));
-
-
- it('should create or update a cookie when a value is assigned to a property',
- inject(function($cookies, $browser, $rootScope) {
- $cookies.oatmealCookie = 'nom nom';
- $rootScope.$digest();
-
- expect($browser.cookies()).
- toEqual({'preexisting': 'oldCookie', 'oatmealCookie':'nom nom'});
-
- $cookies.oatmealCookie = 'gone';
- $rootScope.$digest();
-
- expect($browser.cookies()).
- toEqual({'preexisting': 'oldCookie', 'oatmealCookie': 'gone'});
- }));
-
-
- it('should drop or reset any cookie that was set to a non-string value',
- inject(function($cookies, $browser, $rootScope) {
- $cookies.nonString = [1, 2, 3];
- $cookies.nullVal = null;
- $cookies.undefVal = undefined;
- $cookies.preexisting = function() {};
- $rootScope.$digest();
- expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'});
- expect($cookies).toEqual({'preexisting': 'oldCookie'});
- }));
-
-
- it('should remove a cookie when a $cookies property is deleted',
- inject(function($cookies, $browser, $rootScope) {
- $cookies.oatmealCookie = 'nom nom';
- $rootScope.$digest();
- $browser.poll();
- expect($browser.cookies()).
- toEqual({'preexisting': 'oldCookie', 'oatmealCookie':'nom nom'});
-
- delete $cookies.oatmealCookie;
- $rootScope.$digest();
-
- expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'});
- }));
-
-
- it('should drop or reset cookies that browser refused to store',
- inject(function($cookies, $browser, $rootScope) {
- var i, longVal;
-
- for (i=0; i<5000; i++) {
- longVal += '*';
- }
-
- //drop if no previous value
- $cookies.longCookie = longVal;
- $rootScope.$digest();
- expect($cookies).toEqual({'preexisting': 'oldCookie'});
-
-
- //reset if previous value existed
- $cookies.longCookie = 'shortVal';
- $rootScope.$digest();
- expect($cookies).toEqual({'preexisting': 'oldCookie', 'longCookie': 'shortVal'});
- $cookies.longCookie = longVal;
- $rootScope.$digest();
- expect($cookies).toEqual({'preexisting': 'oldCookie', 'longCookie': 'shortVal'});
- }));
+'use strict';
+
+describe('$cookies', function() {
+ beforeEach(module('ngCookies', function($provide) {
+ $provide.factory('$browser', function() {
+ return angular.extend(new angular.mock.$Browser(), { cookieHash: { preexisting: 'oldCookie'} });
+ });
+ }));
+
+
+ it('should provide access to existing cookies via object properties and keep them in sync',
+ inject(function($cookies, $browser, $rootScope) {
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie' });
+
+ // access internal cookie storage of the browser mock directly to simulate behavior of
+ // document.cookie
+ $browser.cookieHash['brandNew'] = 'cookie';
+ $browser.poll();
+
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie', 'brandNew': 'cookie' });
+
+ $browser.cookieHash['brandNew'] = 'cookie2';
+ $browser.poll();
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie', 'brandNew': 'cookie2' });
+
+ delete $browser.cookieHash['brandNew'];
+ $browser.poll();
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie' });
+ }));
+
+
+ it('should create or update a cookie when a value is assigned to a property',
+ inject(function($cookies, $browser, $rootScope) {
+ $cookies.oatmealCookie = 'nom nom';
+ $rootScope.$digest();
+
+ expect($browser.cookies()).
+ toEqual({ 'preexisting': 'oldCookie', 'oatmealCookie': 'nom nom' });
+
+ $cookies.oatmealCookie = 'gone';
+ $rootScope.$digest();
+
+ expect($browser.cookies()).
+ toEqual({ 'preexisting': 'oldCookie', 'oatmealCookie': 'gone' });
+ }));
+
+
+ it('should drop or reset any cookie that was set to a non-string value',
+ inject(function($cookies, $browser, $rootScope) {
+ $cookies.nonString = [1, 2, 3];
+ $cookies.nullVal = null;
+ $cookies.undefVal = undefined;
+ $cookies.preexisting = function() { };
+ $rootScope.$digest();
+ expect($browser.cookies()).toEqual({ 'preexisting': 'oldCookie' });
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie' });
+ }));
+ it('should handle empty string value cookies', inject(function($cookies, $browser, $rootScope) {
+ $cookies.emptyCookie = '';
+ $rootScope.$digest();
+ expect($browser.cookies()).
+ toEqual({ 'preexisting': 'oldCookie', 'emptyCookie': '' });
+
+ $browser.cookieHash['blankCookie'] = '';
+ $browser.poll();
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie', 'emptyCookie': '', 'blankCookie': '' });
+
+ }))
+
+ it('should remove a cookie when a $cookies property is deleted',
+ inject(function($cookies, $browser, $rootScope) {
+ $cookies.oatmealCookie = 'nom nom';
+ $rootScope.$digest();
+ $browser.poll();
+ expect($browser.cookies()).
+ toEqual({ 'preexisting': 'oldCookie', 'oatmealCookie': 'nom nom' });
+
+ delete $cookies.oatmealCookie;
+ $rootScope.$digest();
+
+ expect($browser.cookies()).toEqual({ 'preexisting': 'oldCookie' });
+ }));
+
+
+ it('should drop or reset cookies that browser refused to store',
+ inject(function($cookies, $browser, $rootScope) {
+ var i, longVal;
+
+ for (i = 0; i < 5000; i++) {
+ longVal += '*';
+ }
+
+ //drop if no previous value
+ $cookies.longCookie = longVal;
+ $rootScope.$digest();
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie' });
+
+
+ //reset if previous value existed
+ $cookies.longCookie = 'shortVal';
+ $rootScope.$digest();
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie', 'longCookie': 'shortVal' });
+ $cookies.longCookie = longVal;
+ $rootScope.$digest();
+ expect($cookies).toEqual({ 'preexisting': 'oldCookie', 'longCookie': 'shortVal' });
+ }));
});
@@ -125,15 +135,32 @@ describe('$cookieStore', function() {
$rootScope.$digest();
expect($browser.cookies()).toEqual({});
}));
- it('should handle empty string value cookies', inject(function ($cookieStore, $browser, $rootScope) {
- $cookieStore.put("emptyCookie",'');
- $rootScope.$digest();
- expect($browser.cookies()).
- toEqual({ 'emptyCookie': '""' });
- expect($cookieStore.get("emptyCookie")).toEqual('');
-
- $browser.cookieHash['blankCookie'] = '';
- $browser.poll();
- expect($cookieStore.get("blankCookie")).toEqual('');
+ it('should handle empty string value cookies', inject(function($cookieStore, $browser, $rootScope) {
+ $cookieStore.put("emptyCookie",'');
+ $rootScope.$digest();
+ expect($browser.cookies()).
+ toEqual({ 'emptyCookie': '""' });
+ expect($cookieStore.get("emptyCookie")).toEqual('');
+
+ $browser.cookieHash['blankCookie'] = '';
+ $browser.poll();
+ expect($cookieStore.get("blankCookie")).toEqual('');
+ }))
+ it('should send options to cookies on put',
+ inject(function($cookieStore, $browser, $rootScope) {
+ $cookieStore.put("optionCookie","someVal","the option")
+ $rootScope.$digest();
+ expect($browser.cookieOptionHash["optionCookie"]).toEqual("the option");
+ expect($browser.cookies()).toEqual({'optionCookie': '"someVal"' })
+ }))
+ it('should send options to cookies on delete',
+ inject(function($cookieStore, $browser, $rootScope) {
+ $cookieStore.put("optionCookie","someValue")
+ $rootScope.$digest();
+ $browser.poll();
+ $cookieStore.remove("optionCookie","the option");
+ $rootScope.$digest();
+ expect($browser.cookieOptionHash["optionCookie"]).toEqual("the option");
+ expect($browser.cookies()).toEqual({})
}))
});