'use strict'; describe('select', function() { var scope, formElement, element, $compile; function compile(html) { formElement = jqLite('
' + html + '
'); element = formElement.find('select'); $compile(formElement)(scope); scope.$apply(); } beforeEach(inject(function($rootScope, _$compile_) { scope = $rootScope.$new(); //create a child scope because the root scope can't be $destroy-ed $compile = _$compile_; formElement = element = null; })); afterEach(function() { scope.$destroy(); //disables unknown option work during destruction dealoc(formElement); }); beforeEach(function() { this.addMatchers({ toEqualSelect: function(expected){ var actualValues = [], expectedValues = [].slice.call(arguments); forEach(this.actual.find('option'), function(option) { actualValues.push(option.selected ? [option.value] : option.value); }); this.message = function() { return 'Expected ' + toJson(actualValues) + ' to equal ' + toJson(expectedValues) + '.'; }; return equals(expectedValues, actualValues); } }); }); describe('select-one', function() { it('should compile children of a select without a ngModel, but not create a model for it', function() { compile(''); scope.$apply(function() { scope.a = 'foo'; scope.b = 'bar'; }); expect(element.text()).toBe('foobarC'); }); it('should not interfere with selection via selected attr if ngModel directive is not present', function() { compile(''); expect(element).toEqualSelect('not me', ['me!'], 'nah'); }); it('should require', function() { compile( ''); scope.change = function() { scope.log += 'change;'; }; scope.$apply(function() { scope.log = ''; scope.selection = 'c'; }); expect(scope.form.select.$error.required).toBeFalsy(); expect(element).toBeValid(); expect(element).toBePristine(); scope.$apply(function() { scope.selection = ''; }); expect(scope.form.select.$error.required).toBeTruthy(); 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( ''); expect(element).toBeValid(); expect(element).toBePristine(); }); it('should work with repeated value options', function() { scope.robots = ['c3p0', 'r2d2']; scope.robot = 'r2d2'; compile(''); expect(element).toEqualSelect('c3p0', ['r2d2']); browserTrigger(element.find('option').eq(0)); expect(element).toEqualSelect(['c3p0'], 'r2d2'); expect(scope.robot).toBe('c3p0'); scope.$apply(function() { scope.robots.unshift('wallee'); }); expect(element).toEqualSelect('wallee', ['c3p0'], 'r2d2'); expect(scope.robot).toBe('c3p0'); scope.$apply(function() { scope.robots = ['c3p0+', 'r2d2+']; scope.robot = 'r2d2+'; }); expect(element).toEqualSelect('c3p0+', ['r2d2+']); expect(scope.robot).toBe('r2d2+'); }); describe('empty option', function() { it('should select the empty option when model is undefined', function() { compile(''); expect(element).toEqualSelect([''], 'x', 'y'); }); it('should support defining an empty option anywhere in the option list', function() { compile(''); expect(element).toEqualSelect('x', [''], 'y'); }); it('should set the model to empty string when empty option is selected', function() { scope.robot = 'x'; compile(''); expect(element).toEqualSelect('', ['x'], 'y'); browserTrigger(element.find('option').eq(0)); expect(element).toEqualSelect([''], 'x', 'y'); expect(scope.robot).toBe(''); }); describe('interactions with repeated options', function() { it('should select empty option when model is undefined', function() { scope.robots = ['c3p0', 'r2d2']; compile(''); expect(element).toEqualSelect([''], 'c3p0', 'r2d2'); }); it('should set model to empty string when selected', function() { scope.robots = ['c3p0', 'r2d2']; compile(''); browserTrigger(element.find('option').eq(1)); expect(element).toEqualSelect('', ['c3p0'], 'r2d2'); expect(scope.robot).toBe('c3p0'); browserTrigger(element.find('option').eq(0)); expect(element).toEqualSelect([''], 'c3p0', 'r2d2'); expect(scope.robot).toBe(''); }); it('should not break if both the select and repeater models change at once', function() { scope.robots = ['c3p0', 'r2d2']; scope.robot = 'c3p0' compile(''); expect(element).toEqualSelect('', ['c3p0'], 'r2d2'); scope.$apply(function() { scope.robots = ['wallee']; scope.robot = ''; }); expect(element).toEqualSelect([''], 'wallee'); }); }); }); describe('unknown option', function() { it("should insert&select temporary unknown option when no options-model match", function() { compile(''); expect(element).toEqualSelect(['? undefined:undefined ?'], 'c3p0', 'r2d2'); scope.$apply(function() { scope.robot = 'r2d2'; }); expect(element).toEqualSelect('c3p0', ['r2d2']); scope.$apply(function() { scope.robot = "wallee"; }); expect(element).toEqualSelect(['? string:wallee ?'], 'c3p0', 'r2d2'); }); it("should NOT insert temporary unknown option when model is undefined and empty options " + "is present", function() { compile(''); expect(element).toEqualSelect([''], 'c3p0', 'r2d2'); expect(scope.robot).toBeUndefined(); scope.$apply(function() { scope.robot = null; }); expect(element).toEqualSelect(['? object:null ?'], '', 'c3p0', 'r2d2'); scope.$apply(function() { scope.robot = 'r2d2'; }); expect(element).toEqualSelect('', 'c3p0', ['r2d2']); scope.$apply(function() { delete scope.robot; }); expect(element).toEqualSelect([''], 'c3p0', 'r2d2'); }); it("should insert&select temporary unknown option when no options-model match, empty " + "option is present and model is defined", function() { scope.robot = 'wallee'; compile(''); expect(element).toEqualSelect(['? string:wallee ?'], '', 'c3p0', 'r2d2'); scope.$apply(function() { scope.robot = 'r2d2'; }); expect(element).toEqualSelect('', 'c3p0', ['r2d2']); }); describe('interactions with repeated options', function() { it('should work with repeated options', function() { compile(''); expect(element).toEqualSelect(['? undefined:undefined ?']); expect(scope.robot).toBeUndefined(); scope.$apply(function() { scope.robot = 'r2d2'; }); expect(element).toEqualSelect(['? string:r2d2 ?']); expect(scope.robot).toBe('r2d2'); scope.$apply(function() { scope.robots = ['c3p0', 'r2d2']; }); expect(element).toEqualSelect('c3p0', ['r2d2']); expect(scope.robot).toBe('r2d2'); }); it('should work with empty option and repeated options', function() { compile(''); expect(element).toEqualSelect(['']); expect(scope.robot).toBeUndefined(); scope.$apply(function() { scope.robot = 'r2d2'; }); expect(element).toEqualSelect(['? string:r2d2 ?'], ''); expect(scope.robot).toBe('r2d2'); scope.$apply(function() { scope.robots = ['c3p0', 'r2d2']; }); expect(element).toEqualSelect('', 'c3p0', ['r2d2']); expect(scope.robot).toBe('r2d2'); }); it('should insert unknown element when repeater shrinks and selected option is unavailable', function() { scope.robots = ['c3p0', 'r2d2']; scope.robot = 'r2d2'; compile(''); expect(element).toEqualSelect('c3p0', ['r2d2']); expect(scope.robot).toBe('r2d2'); scope.$apply(function() { scope.robots.pop(); }); expect(element).toEqualSelect(['? string:r2d2 ?'], 'c3p0'); expect(scope.robot).toBe('r2d2'); scope.$apply(function() { scope.robots.unshift('r2d2'); }); expect(element).toEqualSelect(['r2d2'], 'c3p0'); expect(scope.robot).toBe('r2d2'); scope.$apply(function() { delete scope.robots; }); expect(element).toEqualSelect(['? string:r2d2 ?']); expect(scope.robot).toBe('r2d2'); }); }); }); }); describe('select-multiple', function() { it('should support type="select-multiple"', function() { compile( ''); scope.$apply(function() { scope.selection = ['A']; }); expect(element).toEqualSelect(['A'], 'B'); scope.$apply(function() { scope.selection.push('B'); }); expect(element).toEqualSelect(['A'], ['B']); }); it('should work with optgroups', function() { compile(''); expect(element).toEqualSelect('A', 'B'); expect(scope.selection).toBeUndefined(); scope.$apply(function() { scope.selection = ['A']; }); expect(element).toEqualSelect(['A'], 'B'); scope.$apply(function() { scope.selection.push('B'); }); expect(element).toEqualSelect(['A'], ['B']); }); it('should require', function() { compile( ''); scope.$apply(function() { scope.selection = []; }); expect(scope.form.select.$error.required).toBeTruthy(); expect(element).toBeInvalid(); expect(element).toBePristine(); scope.$apply(function() { scope.selection = ['A']; }); expect(element).toBeValid(); expect(element).toBePristine(); element[0].value = 'B'; browserTrigger(element, 'change'); expect(element).toBeValid(); expect(element).toBeDirty(); }); }); describe('ngOptions', function() { function createSelect(attrs, blank, unknown) { var html = 'blank') : '') + (unknown ? (isString(unknown) ? unknown : '') : '') + ''; compile(html); } 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); } it('should throw when not formated "? for ? in ?"', function() { expect(function() { compile(''); }).toThrow("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in" + " _collection_' but got 'i dont parse'."); }); it('should render a list', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}, {name: 'C'}]; scope.selected = scope.values[0]; }); var options = element.find('option'); expect(options.length).toEqual(3); expect(sortedHtml(options[0])).toEqual(''); expect(sortedHtml(options[1])).toEqual(''); expect(sortedHtml(options[2])).toEqual(''); }); it('should render zero as a valid display value', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 0}, {name: 1}, {name: 2}]; scope.selected = scope.values[0]; }); var options = element.find('option'); expect(options.length).toEqual(3); expect(sortedHtml(options[0])).toEqual(''); expect(sortedHtml(options[1])).toEqual(''); expect(sortedHtml(options[2])).toEqual(''); }); it('should render an object', function() { createSelect({ 'ng-model': 'selected', 'ng-options': 'value as key for (key, value) in object' }); scope.$apply(function() { scope.object = {'red': 'FF0000', 'green': '00FF00', 'blue': '0000FF'}; scope.selected = scope.object.red; }); var options = element.find('option'); expect(options.length).toEqual(3); expect(sortedHtml(options[0])).toEqual(''); expect(sortedHtml(options[1])).toEqual(''); expect(sortedHtml(options[2])).toEqual(''); expect(options[2].selected).toEqual(true); scope.$apply(function() { scope.object.azur = '8888FF'; }); options = element.find('option'); expect(options[3].selected).toEqual(true); }); it('should grow list', function() { createSingleSelect(); scope.$apply(function() { scope.values = []; }); expect(element.find('option').length).toEqual(1); // because we add special empty option expect(sortedHtml(element.find('option')[0])).toEqual(''); scope.$apply(function() { scope.values.push({name:'A'}); scope.selected = scope.values[0]; }); expect(element.find('option').length).toEqual(1); expect(sortedHtml(element.find('option')[0])).toEqual(''); scope.$apply(function() { scope.values.push({name:'B'}); }); expect(element.find('option').length).toEqual(2); expect(sortedHtml(element.find('option')[0])).toEqual(''); expect(sortedHtml(element.find('option')[1])).toEqual(''); }); it('should shrink list', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name:'A'}, {name:'B'}, {name:'C'}]; scope.selected = scope.values[0]; }); expect(element.find('option').length).toEqual(3); scope.$apply(function() { scope.values.pop(); }); expect(element.find('option').length).toEqual(2); expect(sortedHtml(element.find('option')[0])).toEqual(''); expect(sortedHtml(element.find('option')[1])).toEqual(''); scope.$apply(function() { scope.values.pop(); }); expect(element.find('option').length).toEqual(1); expect(sortedHtml(element.find('option')[0])).toEqual(''); scope.$apply(function() { scope.values.pop(); scope.selected = null; }); expect(element.find('option').length).toEqual(1); // we add back the special empty option }); it('should shrink and then grow list', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name:'A'}, {name:'B'}, {name:'C'}]; scope.selected = scope.values[0]; }); expect(element.find('option').length).toEqual(3); scope.$apply(function() { scope.values = [{name: '1'}, {name: '2'}]; scope.selected = scope.values[0]; }); expect(element.find('option').length).toEqual(2); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}, {name: 'C'}]; scope.selected = scope.values[0]; }); expect(element.find('option').length).toEqual(3); }); it('should update list', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}, {name: 'C'}]; scope.selected = scope.values[0]; }); scope.$apply(function() { scope.values = [{name: 'B'}, {name: 'C'}, {name: 'D'}]; scope.selected = scope.values[0]; }); var options = element.find('option'); expect(options.length).toEqual(3); expect(sortedHtml(options[0])).toEqual(''); expect(sortedHtml(options[1])).toEqual(''); expect(sortedHtml(options[2])).toEqual(''); }); it('should preserve existing options', function() { createSingleSelect(true); scope.$apply(function() { scope.values = []; }); expect(element.find('option').length).toEqual(1); scope.$apply(function() { scope.values = [{name: 'A'}]; scope.selected = scope.values[0]; }); expect(element.find('option').length).toEqual(2); expect(jqLite(element.find('option')[0]).text()).toEqual('blank'); expect(jqLite(element.find('option')[1]).text()).toEqual('A'); scope.$apply(function() { scope.values = []; scope.selected = null; }); expect(element.find('option').length).toEqual(1); expect(jqLite(element.find('option')[0]).text()).toEqual('blank'); }); it('should ignore $ and $$ properties', function() { createSelect({ 'ng-options': 'key as value for (key, value) in object', 'ng-model': 'selected' }); scope.$apply(function() { scope.object = {'regularProperty': 'visible', '$$private': 'invisible', '$property': 'invisible'}; scope.selected = 'regularProperty'; }); var options = element.find('option'); expect(options.length).toEqual(1); expect(sortedHtml(options[0])).toEqual(''); }); describe('binding', function() { it('should bind to scope value', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = scope.values[0]; }); expect(element.val()).toEqual('0'); scope.$apply(function() { scope.selected = scope.values[1]; }); expect(element.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.$apply(function() { 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]; }); expect(element.val()).toEqual('3'); var first = jqLite(element.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(element.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.$apply(function() { scope.selected = scope.values[0]; }); expect(element.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.$apply(function() { scope.values = [{id: 10, name: 'A'}, {id: 20, name: 'B'}]; scope.selected = scope.values[0].id; }); expect(element.val()).toEqual('0'); scope.$apply(function() { scope.selected = scope.values[1].id; }); expect(element.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.$apply(function() { scope.object = {red: 'FF0000', green: '00FF00', blue: '0000FF'}; scope.selected = 'green'; }); expect(element.val()).toEqual('green'); scope.$apply(function() { scope.selected = 'blue'; }); expect(element.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.$apply(function() { scope.object = {red: 'FF0000', green: '00FF00', blue:'0000FF'}; scope.selected = '00FF00'; }); expect(element.val()).toEqual('green'); scope.$apply(function() { scope.selected = '0000FF'; }); expect(element.val()).toEqual('blue'); }); it('should insert a blank option if bound to null', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}]; scope.selected = null; }); expect(element.find('option').length).toEqual(2); expect(element.val()).toEqual(''); expect(jqLite(element.find('option')[0]).val()).toEqual(''); scope.$apply(function() { scope.selected = scope.values[0]; }); expect(element.val()).toEqual('0'); expect(element.find('option').length).toEqual(1); }); it('should reuse blank option if bound to null', function() { createSingleSelect(true); scope.$apply(function() { scope.values = [{name: 'A'}]; scope.selected = null; }); expect(element.find('option').length).toEqual(2); expect(element.val()).toEqual(''); expect(jqLite(element.find('option')[0]).val()).toEqual(''); scope.$apply(function() { scope.selected = scope.values[0]; }); expect(element.val()).toEqual('0'); expect(element.find('option').length).toEqual(2); }); it('should insert a unknown option if bound to something not in the list', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}]; scope.selected = {}; }); expect(element.find('option').length).toEqual(2); expect(element.val()).toEqual('?'); expect(jqLite(element.find('option')[0]).val()).toEqual('?'); scope.$apply(function() { scope.selected = scope.values[0]; }); expect(element.val()).toEqual('0'); expect(element.find('option').length).toEqual(1); }); it('should select correct input if previously selected option was "?"', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = {}; }); expect(element.find('option').length).toEqual(3); expect(element.val()).toEqual('?'); expect(element.find('option').eq(0).val()).toEqual('?'); browserTrigger(element.find('option').eq(1)); expect(element.val()).toEqual('0'); expect(element.find('option').eq(0).prop('selected')).toBeTruthy(); expect(element.find('option').length).toEqual(2); }); }); describe('blank option', function () { it('should be compiled as template, be watched and updated', function () { var option; createSingleSelect(''); scope.$apply(function() { scope.blankVal = 'so blank'; scope.values = [{name: 'A'}]; }); // check blank option is first and is compiled expect(element.find('option').length).toBe(2); option = element.find('option').eq(0); expect(option.val()).toBe(''); expect(option.text()).toBe('blank is so blank'); scope.$apply(function() { scope.blankVal = 'not so blank'; }); // check blank option is first and is compiled expect(element.find('option').length).toBe(2); option = element.find('option').eq(0); expect(option.val()).toBe(''); expect(option.text()).toBe('blank is not so blank'); }); it('should support binding via ngBindTemplate directive', function () { var option; createSingleSelect(''); scope.$apply(function() { scope.blankVal = 'so blank'; scope.values = [{name: 'A'}]; }); // check blank option is first and is compiled expect(element.find('option').length).toBe(2); option = element.find('option').eq(0); expect(option.val()).toBe(''); expect(option.text()).toBe('blank is so blank'); }); it('should support biding via ngBind attribute', function () { var option; createSingleSelect(''); scope.$apply(function() { scope.blankVal = 'is blank'; scope.values = [{name: 'A'}]; }); // check blank option is first and is compiled expect(element.find('option').length).toBe(2); option = element.find('option').eq(0); expect(option.val()).toBe(''); expect(option.text()).toBe('is blank'); }); it('should be rendered with the attributes preserved', function () { var option; createSingleSelect(''); scope.$apply(function() { scope.blankVal = 'is blank'; }); // check blank option is first and is compiled option = element.find('option').eq(0); expect(option.hasClass('coyote')).toBeTruthy(); expect(option.attr('id')).toBe('road-runner'); expect(option.attr('custom-attr')).toBe('custom-attr'); }); it('should be selected, if it is available and no other option is selected', function() { // selectedIndex is used here because jqLite incorrectly reports element.val() scope.$apply(function() { scope.values = [{name: 'A'}]; }); createSingleSelect(true); // ensure the first option (the blank option) is selected expect(element[0].selectedIndex).toEqual(0); scope.$digest(); // ensure the option has not changed following the digest expect(element[0].selectedIndex).toEqual(0); }); }); describe('on change', function() { it('should update model on change', function() { createSingleSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = scope.values[0]; }); expect(element.val()).toEqual('0'); element.val('1'); browserTrigger(element, '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.$apply(function() { scope.values = [{id: 10, name: 'A'}, {id: 20, name: 'B'}]; scope.selected = scope.values[0].id; }); expect(element.val()).toEqual('0'); element.val('1'); browserTrigger(element, 'change'); expect(scope.selected).toEqual(scope.values[1].id); }); it('should update model to null on change', function() { createSingleSelect(true); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = scope.values[0]; element.val('0'); }); element.val(''); browserTrigger(element, 'change'); expect(scope.selected).toEqual(null); }); }); describe('select-many', function() { it('should read multiple selection', function() { createMultiSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = []; }); expect(element.find('option').length).toEqual(2); expect(element.find('option')[0].selected).toBeFalsy(); expect(element.find('option')[1].selected).toBeFalsy(); scope.$apply(function() { scope.selected.push(scope.values[1]); }); expect(element.find('option').length).toEqual(2); expect(element.find('option')[0].selected).toBeFalsy(); expect(element.find('option')[1].selected).toBeTruthy(); scope.$apply(function() { scope.selected.push(scope.values[0]); }); expect(element.find('option').length).toEqual(2); expect(element.find('option')[0].selected).toBeTruthy(); expect(element.find('option')[1].selected).toBeTruthy(); }); it('should update model on change', function() { createMultiSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = []; }); element.find('option')[0].selected = true; browserTrigger(element, 'change'); expect(scope.selected).toEqual([scope.values[0]]); }); it('should select from object', function() { createSelect({ 'ng-model':'selected', 'multiple':true, 'ng-options':'key as value for (key,value) in values' }); scope.values = {'0':'A', '1':'B'}; scope.selected = ['1']; scope.$digest(); expect(element.find('option')[1].selected).toBe(true); element.find('option')[0].selected = true; browserTrigger(element, 'change'); expect(scope.selected).toEqual(['0', '1']); element.find('option')[1].selected = false; browserTrigger(element, 'change'); expect(scope.selected).toEqual(['0']); }); it('should deselect all options when model is emptied', function() { createMultiSelect(); scope.$apply(function() { scope.values = [{name: 'A'}, {name: 'B'}]; scope.selected = [scope.values[0]]; }); expect(element.find('option')[0].selected).toEqual(true); scope.$apply(function() { scope.selected.pop(); }); expect(element.find('option')[0].selected).toEqual(false); }) }); describe('ngRequired', function() { it('should allow bindings on ngRequired', function() { createSelect({ 'ng-model': 'value', 'ng-options': 'item.name for item in values', 'ng-required': 'required' }, true); scope.$apply(function() { scope.values = [{name: 'A', id: 1}, {name: 'B', id: 2}]; scope.required = false; }); element.val(''); browserTrigger(element, 'change'); expect(element).toBeValid(); scope.$apply(function() { scope.required = true; }); expect(element).toBeInvalid(); scope.$apply(function() { scope.value = scope.values[0]; }); expect(element).toBeValid(); element.val(''); browserTrigger(element, 'change'); expect(element).toBeInvalid(); scope.$apply(function() { scope.required = false; }); expect(element).toBeValid(); }); }); }); describe('option', function() { it('should populate value attribute on OPTION', function() { compile(''); expect(element).toEqualSelect(['? undefined:undefined ?'], 'abc'); }); it('should ignore value if already exists', function() { compile(''); expect(element).toEqualSelect(['? undefined:undefined ?'], 'abc'); }); it('should set value even if self closing HTML', function() { scope.x = 'hello' compile(''); expect(element).toEqualSelect(['hello']); }); it('should not blow up when option directive is found inside of a datalist', inject(function($compile, $rootScope) { var element = $compile('
' + '' + '{{foo}}' + '
')($rootScope); $rootScope.foo = 'success'; $rootScope.$digest(); expect(element.find('span').text()).toBe('success'); dealoc(element); })); }); });