aboutsummaryrefslogtreecommitdiffstats
path: root/test/widget/selectSpec.js
diff options
context:
space:
mode:
authorMisko Hevery2011-09-08 13:56:29 -0700
committerIgor Minar2011-10-11 11:01:45 -0700
commit4f78fd692c0ec51241476e6be9a4df06cd62fdd6 (patch)
tree91f70bb89b9c095126fbc093f51cedbac5cb0c78 /test/widget/selectSpec.js
parentdf6d2ba3266de405ad6c2f270f24569355706e76 (diff)
downloadangular.js-4f78fd692c0ec51241476e6be9a4df06cd62fdd6.tar.bz2
feat(forms): new and improved forms
Diffstat (limited to 'test/widget/selectSpec.js')
-rw-r--r--test/widget/selectSpec.js510
1 files changed, 510 insertions, 0 deletions
diff --git a/test/widget/selectSpec.js b/test/widget/selectSpec.js
new file mode 100644
index 00000000..6adf8b93
--- /dev/null
+++ b/test/widget/selectSpec.js
@@ -0,0 +1,510 @@
+'use strict';
+
+describe('select', function(){
+ var compile = null, element = null, scope = null, $formFactory = null;
+
+ beforeEach(function() {
+ scope = null;
+ element = null;
+ compile = function(html, parent) {
+ if (parent) {
+ parent.html(html);
+ element = parent.children();
+ } else {
+ element = jqLite(html);
+ }
+ scope = angular.compile(element)();
+ scope.$apply();
+ $formFactory = scope.$service('$formFactory');
+ return scope;
+ };
+ });
+
+ afterEach(function(){
+ dealoc(element);
+ });
+
+
+ describe('select-one', function(){
+
+ it('should compile children of a select without a name, but not create a model for it',
+ function() {
+ compile('<select>' +
+ '<option selected="true">{{a}}</option>' +
+ '<option value="">{{b}}</option>' +
+ '<option>C</option>' +
+ '</select>');
+ scope.a = 'foo';
+ scope.b = 'bar';
+ scope.$digest();
+
+ expect(scope.$element.text()).toBe('foobarC');
+ });
+
+ it('should require', function(){
+ compile('<select name="select" ng:model="selection" required ng:change="log=log+\'change;\'">' +
+ '<option value=""></option>' +
+ '<option value="c">C</option>' +
+ '</select>');
+ scope.log = '';
+ scope.selection = 'c';
+ scope.$digest();
+ expect($formFactory.forElement(element).select.$error.REQUIRED).toEqual(undefined);
+ expect(element).toBeValid();
+ expect(element).toBePristine();
+
+ scope.selection = '';
+ scope.$digest();
+ expect($formFactory.forElement(element).select.$error.REQUIRED).toEqual(true);
+ expect(element).toBeInvalid();
+ expect(element).toBePristine();
+ expect(scope.log).toEqual('');
+
+ element[0].value = 'c';
+ browserTrigger(element, 'change');
+ expect(element).toBeValid();
+ expect(element).toBeDirty();
+ expect(scope.log).toEqual('change;');
+ });
+
+ it('should not be invalid if no require', function(){
+ compile('<select name="select" ng:model="selection">' +
+ '<option value=""></option>' +
+ '<option value="c">C</option>' +
+ '</select>');
+
+ expect(element).toBeValid();
+ expect(element).toBePristine();
+ });
+
+ });
+
+
+ describe('select-multiple', function(){
+ it('should support type="select-multiple"', function(){
+ compile('<select ng:model="selection" multiple>' +
+ '<option>A</option>' +
+ '<option>B</option>' +
+ '</select>');
+ scope.selection = ['A'];
+ scope.$digest();
+ expect(element[0].childNodes[0].selected).toEqual(true);
+ });
+
+ it('should require', function(){
+ compile('<select name="select" ng:model="selection" multiple required>' +
+ '<option>A</option>' +
+ '<option>B</option>' +
+ '</select>');
+
+ scope.selection = [];
+ scope.$digest();
+ expect($formFactory.forElement(element).select.$error.REQUIRED).toEqual(true);
+ expect(element).toBeInvalid();
+ expect(element).toBePristine();
+
+ scope.selection = ['A'];
+ scope.$digest();
+ expect(element).toBeValid();
+ expect(element).toBePristine();
+
+ element[0].value = 'B';
+ browserTrigger(element, 'change');
+ expect(element).toBeValid();
+ expect(element).toBeDirty();
+ });
+
+ });
+
+
+ describe('ng:options', function(){
+ var select, scope;
+
+ function createSelect(attrs, blank, unknown){
+ var html = '<select';
+ forEach(attrs, function(value, key){
+ if (isBoolean(value)) {
+ if (value) html += ' ' + key;
+ } else {
+ html += ' ' + key + '="' + value + '"';
+ }
+ });
+ html += '>' +
+ (blank ? '<option value="">blank</option>' : '') +
+ (unknown ? '<option value="?">unknown</option>' : '') +
+ '</select>';
+ select = jqLite(html);
+ scope = compile(select);
+ }
+
+ function createSingleSelect(blank, unknown){
+ createSelect({
+ 'ng:model':'selected',
+ 'ng:options':'value.name for value in values'
+ }, blank, unknown);
+ }
+
+ function createMultiSelect(blank, unknown){
+ createSelect({
+ 'ng:model':'selected',
+ 'multiple':true,
+ 'ng:options':'value.name for value in values'
+ }, blank, unknown);
+ }
+
+ afterEach(function(){
+ dealoc(select);
+ dealoc(scope);
+ });
+
+ it('should throw when not formated "? for ? in ?"', function(){
+ expect(function(){
+ compile('<select ng:model="selected" ng:options="i dont parse"></select>');
+ }).toThrow("Expected ng:options in form of '_select_ (as _label_)? for (_key_,)?_value_ in" +
+ " _collection_' but got 'i dont parse'.");
+ });
+
+ it('should render a list', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}, {name:'B'}, {name:'C'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ var options = select.find('option');
+ expect(options.length).toEqual(3);
+ expect(sortedHtml(options[0])).toEqual('<option value="0">A</option>');
+ expect(sortedHtml(options[1])).toEqual('<option value="1">B</option>');
+ expect(sortedHtml(options[2])).toEqual('<option value="2">C</option>');
+ });
+
+ it('should render an object', function(){
+ createSelect({
+ 'ng:model':'selected',
+ 'ng:options': 'value as key for (key, value) in object'
+ });
+ scope.object = {'red':'FF0000', 'green':'00FF00', 'blue':'0000FF'};
+ scope.selected = scope.object.red;
+ scope.$digest();
+ var options = select.find('option');
+ expect(options.length).toEqual(3);
+ expect(sortedHtml(options[0])).toEqual('<option value="blue">blue</option>');
+ expect(sortedHtml(options[1])).toEqual('<option value="green">green</option>');
+ expect(sortedHtml(options[2])).toEqual('<option value="red">red</option>');
+ expect(options[2].selected).toEqual(true);
+
+ scope.object.azur = '8888FF';
+ scope.$digest();
+ options = select.find('option');
+ expect(options[3].selected).toEqual(true);
+ });
+
+ it('should grow list', function(){
+ createSingleSelect();
+ scope.values = [];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(1); // because we add special empty option
+ expect(sortedHtml(select.find('option')[0])).toEqual('<option value="?"></option>');
+
+ scope.values.push({name:'A'});
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(1);
+ expect(sortedHtml(select.find('option')[0])).toEqual('<option value="0">A</option>');
+
+ scope.values.push({name:'B'});
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(sortedHtml(select.find('option')[0])).toEqual('<option value="0">A</option>');
+ expect(sortedHtml(select.find('option')[1])).toEqual('<option value="1">B</option>');
+ });
+
+ it('should shrink list', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}, {name:'B'}, {name:'C'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(3);
+
+ scope.values.pop();
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(sortedHtml(select.find('option')[0])).toEqual('<option value="0">A</option>');
+ expect(sortedHtml(select.find('option')[1])).toEqual('<option value="1">B</option>');
+
+ scope.values.pop();
+ scope.$digest();
+ expect(select.find('option').length).toEqual(1);
+ expect(sortedHtml(select.find('option')[0])).toEqual('<option value="0">A</option>');
+
+ scope.values.pop();
+ scope.selected = null;
+ scope.$digest();
+ expect(select.find('option').length).toEqual(1); // we add back the special empty option
+ });
+
+ it('should shrink and then grow list', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}, {name:'B'}, {name:'C'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(3);
+
+ scope.values = [{name:'1'}, {name:'2'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+
+ scope.values = [{name:'A'}, {name:'B'}, {name:'C'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(3);
+ });
+
+ it('should update list', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}, {name:'B'}, {name:'C'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+
+ scope.values = [{name:'B'}, {name:'C'}, {name:'D'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ var options = select.find('option');
+ expect(options.length).toEqual(3);
+ expect(sortedHtml(options[0])).toEqual('<option value="0">B</option>');
+ expect(sortedHtml(options[1])).toEqual('<option value="1">C</option>');
+ expect(sortedHtml(options[2])).toEqual('<option value="2">D</option>');
+ });
+
+ it('should preserve existing options', function(){
+ createSingleSelect(true);
+
+ scope.values = [];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(1);
+
+ scope.values = [{name:'A'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(jqLite(select.find('option')[0]).text()).toEqual('blank');
+ expect(jqLite(select.find('option')[1]).text()).toEqual('A');
+
+ scope.values = [];
+ scope.selected = null;
+ scope.$digest();
+ expect(select.find('option').length).toEqual(1);
+ expect(jqLite(select.find('option')[0]).text()).toEqual('blank');
+ });
+
+ describe('binding', function(){
+ it('should bind to scope value', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}, {name:'B'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+
+ scope.selected = scope.values[1];
+ scope.$digest();
+ expect(select.val()).toEqual('1');
+ });
+
+ it('should bind to scope value and group', function(){
+ createSelect({
+ 'ng:model':'selected',
+ 'ng:options':'item.name group by item.group for item in values'
+ });
+ scope.values = [{name:'A'},
+ {name:'B', group:'first'},
+ {name:'C', group:'second'},
+ {name:'D', group:'first'},
+ {name:'E', group:'second'}];
+ scope.selected = scope.values[3];
+ scope.$digest();
+ expect(select.val()).toEqual('3');
+
+ var first = jqLite(select.find('optgroup')[0]);
+ var b = jqLite(first.find('option')[0]);
+ var d = jqLite(first.find('option')[1]);
+ expect(first.attr('label')).toEqual('first');
+ expect(b.text()).toEqual('B');
+ expect(d.text()).toEqual('D');
+
+ var second = jqLite(select.find('optgroup')[1]);
+ var c = jqLite(second.find('option')[0]);
+ var e = jqLite(second.find('option')[1]);
+ expect(second.attr('label')).toEqual('second');
+ expect(c.text()).toEqual('C');
+ expect(e.text()).toEqual('E');
+
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+ });
+
+ it('should bind to scope value through experession', function(){
+ createSelect({'ng:model':'selected', 'ng:options':'item.id as item.name for item in values'});
+ scope.values = [{id:10, name:'A'}, {id:20, name:'B'}];
+ scope.selected = scope.values[0].id;
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+
+ scope.selected = scope.values[1].id;
+ scope.$digest();
+ expect(select.val()).toEqual('1');
+ });
+
+ it('should bind to object key', function(){
+ createSelect({
+ 'ng:model':'selected',
+ 'ng:options':'key as value for (key, value) in object'
+ });
+ scope.object = {'red':'FF0000', 'green':'00FF00', 'blue':'0000FF'};
+ scope.selected = 'green';
+ scope.$digest();
+ expect(select.val()).toEqual('green');
+
+ scope.selected = 'blue';
+ scope.$digest();
+ expect(select.val()).toEqual('blue');
+ });
+
+ it('should bind to object value', function(){
+ createSelect({
+ 'ng:model':'selected',
+ 'ng:options':'value as key for (key, value) in object'
+ });
+ scope.object = {'red':'FF0000', 'green':'00FF00', 'blue':'0000FF'};
+ scope.selected = '00FF00';
+ scope.$digest();
+ expect(select.val()).toEqual('green');
+
+ scope.selected = '0000FF';
+ scope.$digest();
+ expect(select.val()).toEqual('blue');
+ });
+
+ it('should insert a blank option if bound to null', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}];
+ scope.selected = null;
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(select.val()).toEqual('');
+ expect(jqLite(select.find('option')[0]).val()).toEqual('');
+
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+ expect(select.find('option').length).toEqual(1);
+ });
+
+ it('should reuse blank option if bound to null', function(){
+ createSingleSelect(true);
+ scope.values = [{name:'A'}];
+ scope.selected = null;
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(select.val()).toEqual('');
+ expect(jqLite(select.find('option')[0]).val()).toEqual('');
+
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+ expect(select.find('option').length).toEqual(2);
+ });
+
+ it('should insert a unknown option if bound to something not in the list', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}];
+ scope.selected = {};
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(select.val()).toEqual('?');
+ expect(jqLite(select.find('option')[0]).val()).toEqual('?');
+
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+ expect(select.find('option').length).toEqual(1);
+ });
+ });
+
+ describe('on change', function(){
+ it('should update model on change', function(){
+ createSingleSelect();
+ scope.values = [{name:'A'}, {name:'B'}];
+ scope.selected = scope.values[0];
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+
+ select.val('1');
+ browserTrigger(select, 'change');
+ expect(scope.selected).toEqual(scope.values[1]);
+ });
+
+ it('should update model on change through expression', function(){
+ createSelect({'ng:model':'selected', 'ng:options':'item.id as item.name for item in values'});
+ scope.values = [{id:10, name:'A'}, {id:20, name:'B'}];
+ scope.selected = scope.values[0].id;
+ scope.$digest();
+ expect(select.val()).toEqual('0');
+
+ select.val('1');
+ browserTrigger(select, 'change');
+ expect(scope.selected).toEqual(scope.values[1].id);
+ });
+
+ it('should update model to null on change', function(){
+ createSingleSelect(true);
+ scope.values = [{name:'A'}, {name:'B'}];
+ scope.selected = scope.values[0];
+ select.val('0');
+ scope.$digest();
+
+ select.val('');
+ browserTrigger(select, 'change');
+ expect(scope.selected).toEqual(null);
+ });
+ });
+
+ describe('select-many', function(){
+ it('should read multiple selection', function(){
+ createMultiSelect();
+ scope.values = [{name:'A'}, {name:'B'}];
+
+ scope.selected = [];
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(jqLite(select.find('option')[0]).attr('selected')).toBeFalsy();
+ expect(jqLite(select.find('option')[1]).attr('selected')).toBeFalsy();
+
+ scope.selected.push(scope.values[1]);
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(select.find('option')[0].selected).toEqual(false);
+ expect(select.find('option')[1].selected).toEqual(true);
+
+ scope.selected.push(scope.values[0]);
+ scope.$digest();
+ expect(select.find('option').length).toEqual(2);
+ expect(select.find('option')[0].selected).toEqual(true);
+ expect(select.find('option')[1].selected).toEqual(true);
+ });
+
+ it('should update model on change', function(){
+ createMultiSelect();
+ scope.values = [{name:'A'}, {name:'B'}];
+
+ scope.selected = [];
+ scope.$digest();
+ select.find('option')[0].selected = true;
+
+ browserTrigger(select, 'change');
+ expect(scope.selected).toEqual([scope.values[0]]);
+ });
+ });
+
+ });
+
+});