diff options
| -rw-r--r-- | test/FiltersSpec.js | 28 | ||||
| -rw-r--r-- | test/angular-mocks.js | 102 |
2 files changed, 113 insertions, 17 deletions
diff --git a/test/FiltersSpec.js b/test/FiltersSpec.js index 6bbc09ae..4dd108ac 100644 --- a/test/FiltersSpec.js +++ b/test/FiltersSpec.js @@ -87,18 +87,11 @@ describe('filter', function(){ }); describe('date', function(){ - var morning = angular.String.toDate('2010-09-03T23:05:08Z'); - var midnight = angular.String.toDate('2010-09-03T23:05:08Z'); - var noon = angular.String.toDate('2010-09-03T23:05:08Z'); - morning.setHours(7); - noon.setHours(12); - midnight.setHours(0); - - //butt-ugly hack: force the date to be 2pm PDT for locale testing - morning.getTimezoneOffset = - noon.getTimezoneOffset = - midnight.getTimezoneOffset = - function() {return 7 * 60;}; + + var morning = new TzDate(+5, '2010-09-03T12:05:08Z'); //7am + var noon = new TzDate(+5, '2010-09-03T17:05:08Z'); //12pm + var midnight = new TzDate(+5, '2010-09-03T05:05:08Z'); //12am + it('should ignore falsy inputs', function() { expect(filter.date(null)).toEqual(null); @@ -116,16 +109,17 @@ describe('filter', function(){ }); it('should accept format', function() { + expect(filter.date(morning, "yy-MM-dd HH:mm:ss")). + toEqual('10-09-03 07:05:08'); + expect(filter.date(midnight, "yyyy-M-d h=H:m:saZ")). - toEqual('2010-9-3 12=0:5:8am0700'); + toEqual('2010-9-3 12=0:5:8am0500'); expect(filter.date(midnight, "yyyy-MM-dd hh=HH:mm:ssaZ")). - toEqual('2010-09-03 12=00:05:08am0700'); + toEqual('2010-09-03 12=00:05:08am0500'); expect(filter.date(noon, "yyyy-MM-dd hh=HH:mm:ssaZ")). - toEqual('2010-09-03 12=12:05:08pm0700'); - + toEqual('2010-09-03 12=12:05:08pm0500'); }); }); }); - diff --git a/test/angular-mocks.js b/test/angular-mocks.js index efe5b5b3..a090f0e8 100644 --- a/test/angular-mocks.js +++ b/test/angular-mocks.js @@ -162,3 +162,105 @@ MockBrowser.prototype = { angular.service('$browser', function(){ return new MockBrowser(); }); + + +/** + * Mock of the Date type which has its timezone specified via constroctor arg. + * + * The main purpose is to create Date-like instances with timezone fixed to the specified timezone + * offset, so that we can test code that depends on local timezone settings without dependency on + * the time zone settings of the machine where the code is running. + * + * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored) + * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* + * + * @example + * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z'); + * newYearInBratislava.getTimezoneOffset() => -60; + * newYearInBratislava.getFullYear() => 2010; + * newYearInBratislava.getMonth() => 0; + * newYearInBratislava.getDate() => 1; + * newYearInBratislava.getHours() => 0; + * newYearInBratislava.getMinutes() => 0; + * + * + * !!!! WARNING !!!!! + * This is not a complete Date object so only methods that were implemented can be called safely. + * To make matters worse, TzDate instances inherit stuff from Date via a prototype. + * + * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is + * incomplete we might be missing some non-standard methods. This can result in errors like: + * "Date.prototype.foo called on incompatible Object". + */ +function TzDate(offset, timestamp) { + if (angular.isString(timestamp)) { + var tsStr = timestamp; + timestamp = new Date(timestamp).getTime(); + if (isNaN(timestamp)) + throw { + name: "Illegal Argument", + message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string" + }; + } + + var localOffset = new Date(timestamp).getTimezoneOffset(); + this.offsetDiff = localOffset*60*1000 - offset*1000*60*60; + this.date = new Date(timestamp + this.offsetDiff); + + this.getTime = function() { + return this.date.getTime() - this.offsetDiff; + }; + + this.toLocaleDateString = function() { + return this.date.toLocaleDateString(); + }; + + this.getFullYear = function() { + return this.date.getFullYear(); + }; + + this.getMonth = function() { + return this.date.getMonth(); + }; + + this.getDate = function() { + return this.date.getDate(); + }; + + this.getHours = function() { + return this.date.getHours(); + }; + + this.getMinutes = function() { + return this.date.getMinutes(); + }; + + this.getSeconds = function() { + return this.date.getSeconds(); + }; + + this.getTimezoneOffset = function() { + return offset * 60; + }; + + //hide all methods not implemented in this mock that the Date prototype exposes + var unimplementedMethods = ['getDay', 'getMilliseconds', 'getTime', 'getUTCDate', 'getUTCDay', + 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', + 'getUTCSeconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', + 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', + 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', + 'setYear', 'toDateString', 'toJSON', 'toGMTString', 'toLocaleFormat', 'toLocaleString', + 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf']; + + angular.foreach(unimplementedMethods, function(methodName) { + this[methodName] = function() { + throw { + name: "MethodNotImplemented", + message: "Method '" + methodName + "' is not implemented in the TzDate mock" + }; + }; + }); +} + +//make "tzDateInstance instanceof Date" return true +TzDate.prototype = Date.prototype; |
