From 347be5ae9aa6829427e1e8e1b1e58afdf2a36c0a Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 13 Jan 2011 10:35:26 -0800 Subject: fixed select with ng:format select (one/multiple) could not chose from a list of objects, since DOM requires string ids. Solved by adding index formatter, which exposed incorrect handling of formatters in select widgets. --- test/FormattersSpec.js | 15 ++++++++ test/JsonSpec.js | 17 ++++++--- test/ParserSpec.js | 25 +++++++++++++ test/directivesSpec.js | 15 +++++--- test/widgetsSpec.js | 98 ++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 142 insertions(+), 28 deletions(-) (limited to 'test') diff --git a/test/FormattersSpec.js b/test/FormattersSpec.js index af50f384..1ebd8e22 100644 --- a/test/FormattersSpec.js +++ b/test/FormattersSpec.js @@ -33,5 +33,20 @@ describe("formatter", function(){ assertEquals('a', angular.formatter.trim.format(" a ")); assertEquals('a', angular.formatter.trim.parse(' a ')); }); + + describe('json', function(){ + it('should treat empty string as null', function(){ + expect(angular.formatter.json.parse('')).toEqual(null); + }); + }); + + describe('index', function(){ + it('should parse an object from array', function(){ + expect(angular.formatter.index.parse('1', ['A', 'B', 'C'])).toEqual('B'); + }); + it('should format an index from array', function(){ + expect(angular.formatter.index.format('B', ['A', 'B', 'C'])).toEqual('1'); + }); + }); }); diff --git a/test/JsonSpec.js b/test/JsonSpec.js index 6d8a40e4..4a160905 100644 --- a/test/JsonSpec.js +++ b/test/JsonSpec.js @@ -92,11 +92,11 @@ describe('json', function(){ it('should not serialize undefined values', function() { expect(angular.toJson({A:undefined})).toEqual('{}'); }); - + it('should not serialize $window object', function() { expect(toJson(window)).toEqual('WINDOW'); }); - + it('should not serialize $document object', function() { expect(toJson(document)).toEqual('DOCUMENT'); }); @@ -116,6 +116,13 @@ describe('json', function(){ expect(fromJson("{exp:1.2e-10}")).toEqual({exp:1.2E-10}); }); + it('should ignore non-strings', function(){ + expect(fromJson([])).toEqual([]); + expect(fromJson({})).toEqual({}); + expect(fromJson(null)).toEqual(null); + expect(fromJson(undefined)).toEqual(undefined); + }); + //run these tests only in browsers that have native JSON parser if (JSON && JSON.parse) { @@ -187,18 +194,18 @@ describe('json', function(){ expect(function(){fromJson('[].constructor');}). toThrow(new Error("Parse Error: Token '.' is not valid json at column 3 of expression [[].constructor] starting at [.constructor].")); }); - + it('should not allow object dereference', function(){ expect(function(){fromJson('{a:1, b: $location, c:1}');}).toThrow(); expect(function(){fromJson("{a:1, b:[1]['__parent__']['location'], c:1}");}).toThrow(); }); - + it('should not allow assignments', function(){ expect(function(){fromJson("{a:1, b:[1]=1, c:1}");}).toThrow(); expect(function(){fromJson("{a:1, b:=1, c:1}");}).toThrow(); expect(function(){fromJson("{a:1, b:x=1, c:1}");}).toThrow(); }); - + }); }); diff --git a/test/ParserSpec.js b/test/ParserSpec.js index c237aa40..4d0e14dc 100644 --- a/test/ParserSpec.js +++ b/test/ParserSpec.js @@ -396,4 +396,29 @@ describe('parser', function() { expect(scope.obj.name).toBeUndefined(); expect(scope.obj[0].name).toEqual(1); }); + + describe('formatter', function(){ + it('should return no argument function', function() { + var noop = parser('noop').formatter()(); + expect(noop.format(null, 'abc')).toEqual('abc'); + expect(noop.parse(null, '123')).toEqual('123'); + }); + + it('should delegate arguments', function(){ + var index = parser('index:objs').formatter()(); + expect(index.format({objs:['A','B']}, 'B')).toEqual('1'); + expect(index.parse({objs:['A','B']}, '1')).toEqual('B'); + }); + }); + + describe('assignable', function(){ + it('should expose assignment function', function(){ + var fn = parser('a').assignable(); + expect(fn.assign).toBeTruthy(); + var scope = {}; + fn.assign(scope, 123); + expect(scope).toEqual({a:123}); + }); + }); + }); diff --git a/test/directivesSpec.js b/test/directivesSpec.js index ab1813c3..ef8241f1 100644 --- a/test/directivesSpec.js +++ b/test/directivesSpec.js @@ -104,10 +104,17 @@ describe("directive", function(){ }); - it('should ng:bind-attr', function(){ - var scope = compile(''); - expect(element.attr('src')).toEqual('http://localhost/mysrc'); - expect(element.attr('alt')).toEqual('myalt'); + describe('ng:bind-attr', function(){ + it('should bind attributes', function(){ + var scope = compile(''); + expect(element.attr('src')).toEqual('http://localhost/mysrc'); + expect(element.attr('alt')).toEqual('myalt'); + }); + + it('should not pretty print JSON in attributes', function(){ + var scope = compile('{{ {a:1} }}'); + expect(element.attr('alt')).toEqual('{"a":1}'); + }); }); it('should remove special attributes on false', function(){ diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index 8dab4630..946c433f 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -44,7 +44,7 @@ describe("widget", function(){ expect(scope.$get('name')).toEqual('Kai'); expect(scope.$get('count')).toEqual(2); }); - + it('should not trigger eval if value does not change', function(){ compile(''); expect(scope.name).toEqual("Misko"); @@ -53,7 +53,7 @@ describe("widget", function(){ expect(scope.name).toEqual("Misko"); expect(scope.count).toEqual(0); }); - + it('should allow complex refernce binding', function(){ compile('
'+ ''+ @@ -416,7 +416,7 @@ describe("widget", function(){ scope.$eval(); expect(element[0].childNodes[1].selected).toEqual(true); }); - + it('should select default option on repeater', function(){ compile( ''); expect(scope.selection).toEqual('1'); }); - + it('should select selected option on repeater', function(){ compile( ''); expect(scope.selection).toEqual('ABC'); }); - + it('should select dynamically selected option on repeater', function(){ compile( ''); expect(scope.selection).toEqual('2'); }); - + + it('should allow binding to objects through JSON', function(){ + compile( + ''); + scope.objs = [{name:'A'}, {name:'B'}]; + scope.$eval(); + expect(scope.selection).toEqual({name:'A'}); + }); + + it('should allow binding to objects through index', function(){ + compile( + ''); + scope.objs = [{name:'A'}, {name:'B'}]; + scope.$eval(); + expect(scope.selection).toBe(scope.objs[0]); + }); + }); - it('should support type="select-multiple"', function(){ - compile( - ''); - expect(scope.selection).toEqual(['B']); - scope.selection = ['A']; - scope.$eval(); - expect(element[0].childNodes[0].selected).toEqual(true); + describe('select-multiple', function(){ + it('should support type="select-multiple"', function(){ + compile(''); + expect(scope.selection).toEqual(['B']); + scope.selection = ['A']; + scope.$eval(); + expect(element[0].childNodes[0].selected).toEqual(true); + }); + + it('should allow binding to objects through index', function(){ + compile('', + function(){ + scope.list = [{name:'A'}, {name:'B'}, {name:'C'}]; + }); + scope.$eval(); + expect(scope.selection).toEqual([{name:'A'}, {name:'B'}]); + }); + + it('should be empty array when no items are selected', function(){ + compile( + ''); + scope.list = [{name:'A'}, {name:'B'}, {name:'C'}]; + scope.$eval(); + expect(scope.selection).toEqual([]); + }); + + it('should be contain the selected object', function(){ + compile('', + function(){ + scope.list = [{name:'A'}, {name:'B'}, {name:'C'}]; + }); + scope.$eval(); + expect(scope.selection).toEqual([{name:'B'}]); + }); + }); - + it('should ignore text widget which have no name', function(){ compile(''); expect(scope.$element.attr('ng-exception')).toBeFalsy(); @@ -504,7 +564,7 @@ describe("widget", function(){ scope.$eval(); expect(element.text()).toEqual('true:misko'); }); - + it("should compare stringified versions", function(){ var switchWidget = angular.widget('ng:switch'); expect(switchWidget.equals(true, 'true')).toEqual(true); @@ -521,7 +581,7 @@ describe("widget", function(){ scope.$eval(); expect(element.text()).toEqual('one'); }); - + it("should match urls", function(){ var scope = angular.compile('
{{params.name}}
'); scope.url = '/Book/Moby'; -- cgit v1.2.3