'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('');
scope.a = 'foo';
scope.b = 'bar';
scope.$digest();
expect(scope.$element.text()).toBe('foobarC');
});
it('should require', function() {
compile('');
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('');
expect(element).toBeValid();
expect(element).toBePristine();
});
});
describe('select-multiple', function() {
it('should support type="select-multiple"', function() {
compile('');
scope.selection = ['A'];
scope.$digest();
expect(element[0].childNodes[0].selected).toEqual(true);
});
it('should require', function() {
compile('');
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 = 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('');
}).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('');
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.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('');
expect(sortedHtml(options[1])).toEqual('');
expect(sortedHtml(options[2])).toEqual('');
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('');
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('');
scope.values.push({name:'B'});
scope.$digest();
expect(select.find('option').length).toEqual(2);
expect(sortedHtml(select.find('option')[0])).toEqual('');
expect(sortedHtml(select.find('option')[1])).toEqual('');
});
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('');
expect(sortedHtml(select.find('option')[1])).toEqual('');
scope.values.pop();
scope.$digest();
expect(select.find('option').length).toEqual(1);
expect(sortedHtml(select.find('option')[0])).toEqual('');
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('');
expect(sortedHtml(options[1])).toEqual('');
expect(sortedHtml(options[2])).toEqual('');
});
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);
});
it('should select correct input if previously selected option was "?"', function() {
createSingleSelect();
scope.values = [{name:'A'},{name:'B'}];
scope.selected = {};
scope.$digest();
expect(select.find('option').length).toEqual(3);
expect(select.val()).toEqual('?');
expect(select.find('option').eq(0).val()).toEqual('?');
browserTrigger(select.find('option').eq(1));
expect(select.val()).toEqual('0');
expect(select.find('option').eq(0).prop('selected')).toBeTruthy();
expect(select.find('option').length).toEqual(2);
});
});
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]).prop('selected')).toBeFalsy();
expect(jqLite(select.find('option')[1]).prop('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]]);
});
});
});
});