UNPKG

angucomplete-alt

Version:

Awesome Autocompleteness for AngularJS

1,283 lines (1,090 loc) 71.5 kB
'use strict'; describe('angucomplete-alt', function() { var $compile, $scope, $timeout; var KEY_DW = 40, KEY_UP = 38, KEY_ES = 27, KEY_EN = 13, KEY_DEL = 46, KEY_TAB = 9, KEY_BS = 8; beforeEach(module('angucomplete-alt')); beforeEach(inject(function(_$compile_, $rootScope, _$timeout_) { $compile = _$compile_; $scope = $rootScope.$new(); $timeout = _$timeout_; })); describe('Render', function() { it('should render input element with given id plus _value', function() { var element = angular.element('<div angucomplete-alt id="ex1" selected-object="selectedCountry" title-field="name"></div>'); $scope.selectedCountry = null; $compile(element)($scope); $scope.$digest(); expect(element.find('#ex1_value').length).toBe(1); }); it('should render planceholder string', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name"/>'); $scope.selectedCountry = null; $compile(element)($scope); $scope.$digest(); expect(element.find('#ex1_value').attr('placeholder')).toEqual('Search countries'); }); it('should render maxlength string', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" maxlength="25" />'); $scope.selectedCountry = null; $compile(element)($scope); $scope.$digest(); expect(element.find('#ex1_value').attr('maxlength')).toEqual('25'); }); it('should render default type attribute for input element if not explicitly specified', function() { var element = angular.element('<div angucomplete-alt id="ex1" selected-object="selectedCountry" title-field="name"></div>'); $scope.selectedCountry = null; $compile(element)($scope); $scope.$digest(); expect(element.find('#ex1_value').attr('type')).toEqual('text'); }); }); describe('Local data', function() { it('should show search results after 3 letter is entered', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); expect(element.find('.angucomplete-row').length).toBe(0); e.which = 108; // letter: l inputField.val('al'); inputField.trigger('input'); inputField.trigger(e); expect(element.find('.angucomplete-row').length).toBe(0); e.which = 98; // letter: b inputField.val('alb'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('.angucomplete-row').length).toBeGreaterThan(0); }); it('should show search results after 1 letter is entered with minlength being set to 1', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('.angucomplete-row').length).toBeGreaterThan(0); }); it('should show search results after 2 letters are entered and hide results when a letter is deleted', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="2"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); expect(element.find('.angucomplete-row').length).toBe(0); e.which = 108; // letter: l inputField.val('al'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('.angucomplete-row').length).toBe(2); // delete a char e.which = KEY_DEL; inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); expect(element.find('.angucomplete-row').length).toBe(0); }); it('should reset selectedObject to undefined when input changes', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_DW; inputField.trigger(eKeydown); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect($scope.selectedCountry.originalObject).toEqual({name: 'Afghanistan', code: 'AF'}); inputField.focus(); inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect($scope.selectedCountry).toBeUndefined(); }); describe('incomplete local data', function() { it('should not throw errors', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.countrySelected = null; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {code: 'AX'}, {name: 'Albania'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); expect(function() { $timeout.flush(); }).not.toThrow(); }); }); }); describe('Set results', function() { it('should set scope.results[0].title', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="name" title-field="name" minlength="1"/>'); $scope.names = [ {name: 'John'}, {name: 'Tim'}, {name: 'Wanda'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].title).toBe('John'); }); it('should set scope.results[0].title for two title fields', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="firstName" title-field="firstName,lastName" minlength="1"/>'); var lastName = 'Doe', firstName = 'John'; $scope.names = [ {firstName: 'John', lastName: 'Doe'}, {firstName: 'Tim', lastName: 'Doe'}, {firstName: 'Wanda', lastName: 'Doe'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].title).toBe(firstName + ' ' + lastName); }); it('should set scope.results[0].title to dotted attribute', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="name.first" title-field="name.first,name.last" minlength="1"/>'); var first = 'John'; var last = 'Doe'; $scope.names = [ { name: { first: first, last: last } } ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].title).toBe(first + ' ' + last); }); it('should set scope.results[0].description', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="name" title-field="name" description-field="desc" minlength="1"/>'); var description = 'blah blah blah'; $scope.names = [ {name: 'John', desc: description} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].description).toBe(description); }); it('should set scope.results[0].description to dotted attribute', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="name" title-field="name" description-field="desc.short" minlength="1"/>'); var desc = 'short desc...'; $scope.names = [ { name: 'John', desc: { long: 'very very long description...', short: desc } } ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].description).toBe(desc); }); it('should set scope.results[0].image', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="name" title-field="name" image-field="pic" minlength="1"/>'); var image = 'some pic'; $scope.names = [ {name: 'John', pic: image} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].image).toBe(image); }); it('should set scope.results[0].image to dotted attribute', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" local-data="names" search-fields="name" title-field="name" image-field="pic.small" minlength="1"/>'); var image = 'small pic'; $scope.names = [ { name: 'John', pic: { large: 'large pic', mid: 'medium pic', small: image } } ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'j'.charCodeAt(0); inputField.val('j'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.isolateScope().results[0].image).toBe(image); }); }); describe('Local Data', function() { it('should set $scope.searching to false', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'a'.charCodeAt(0); inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); expect(element.isolateScope().searching).toBe(true); $timeout.flush(); expect(element.isolateScope().searching).toBe(false); }); }); describe('Remote API', function() { var $httpBackend; beforeEach(inject(function(_$httpBackend_) { $httpBackend = _$httpBackend_; })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); it('should process via custom handler', inject(function($http) { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-api-handler="postFn" search-fields="name" title-field="name" remote-url-data-field="data" minlength="1"/>'); var url = '/api'; $scope.postFn = function(str, timeout) { return $http.post(url, {q: str}, {timeout: timeout}); }; $compile(element)($scope); $scope.$digest(); var queryTerm = 'j'; var results = {data: [{name: 'john'}]}; $httpBackend.expectPOST('/api', {q: queryTerm}).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = queryTerm.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); expect(element.isolateScope().searching).toBe(true); $timeout.flush(); $httpBackend.flush(); expect(element.find('.angucomplete-row').length).toBe(1); })); it('should url encode input string', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" remote-url-error-callback="errorCB" minlength="1"/>'); $scope.errorCB = jasmine.createSpy('errorCB'); $compile(element)($scope); $scope.$digest(); var queryTerm = '//'; var results = {data: [{name: 'john'}]}; var encodedQueryTerm = encodeURIComponent(queryTerm); $httpBackend.expectGET('names?q=' + encodedQueryTerm).respond(0); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = '/'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); expect(element.isolateScope().searching).toBe(true); $timeout.flush(); $httpBackend.flush(); }); it('should not do anything when request is canceled', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" remote-url-error-callback="errorCB" minlength="1"/>'); $scope.errorCB = jasmine.createSpy('errorCB'); $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{name: 'john'}]}; $httpBackend.expectGET('names?q=' + queryTerm).respond(0); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); expect(element.isolateScope().searching).toBe(true); $timeout.flush(); $httpBackend.flush(); expect($scope.errorCB).not.toHaveBeenCalled(); }); it('should call $http with given url and param', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" minlength="1"/>'); $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{name: 'john'}]}; $httpBackend.expectGET('names?q=' + queryTerm).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); expect(element.isolateScope().searching).toBe(true); $timeout.flush(); $httpBackend.flush(); }); it('should set $scope.searching to false after success', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" minlength="1"/>'); $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{name: 'john'}]}; $httpBackend.expectGET('names?q=' + queryTerm).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); expect(element.isolateScope().searching).toBe(true); $timeout.flush(); $httpBackend.flush(); expect(element.isolateScope().searching).toBe(false); }); it('should process dotted data attribute', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="search.data" title-field="name" minlength="1"/>'); $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = { meta: { offset: 0, total: 1 }, search: { seq_id: 1234567890, data: [ {name: 'john'} ] } }; $httpBackend.expectGET('names?q=' + queryTerm).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); $httpBackend.flush(); expect(element.isolateScope().results[0].originalObject).toEqual(results.search.data[0]); }); it('should not throw an exception when match-class is set and remote api returns bogus results (issue #2)', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" description="type" minlength="1" match-class="highlight"/>'); $compile(element)($scope); $scope.$digest(); var results = {data: [{name: 'tim', type: 'A'}]}; $httpBackend.expectGET('names?q=a').respond(200, results); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); $httpBackend.flush(); expect(element.isolateScope().searching).toBe(false); }); it('should call error callback when it is given', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" remote-url-error-callback="errorCallback" title-field="name" minlength="1"/>'); $scope.errorCallback = jasmine.createSpy('errorCallback'); $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{name: 'john'}]}; $httpBackend.expectGET('names?q=' + queryTerm).respond(500, 'Internal server error'); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); $httpBackend.flush(); expect($scope.errorCallback).toHaveBeenCalled(); }); }); describe('request formatter function for ajax request', function() { it('should process the request with the given function', inject(function($httpBackend) { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names" search-fields="name" remote-url-data-field="data" remote-url-request-formatter="dataFormatFn" title-field="name" minlength="1"/>'); var sequenceNum = 1234567890; $scope.dataFormatFn = function(str) { return {q: str, sequence: sequenceNum}; }; $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{name: 'john'}]}; $httpBackend.expectGET('names?q=' + queryTerm + '&sequence=' + sequenceNum).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); $httpBackend.flush(); $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); })); }); describe('custom data formatter function for ajax response', function() { var $httpBackend; beforeEach(inject(function(_$httpBackend_) { $httpBackend = _$httpBackend_; })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); it('should process normarlly if not given', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="first" remote-url-data-field="data" title-field="name" minlength="1"/>'); $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{first: 'John', last: 'Doe'}]}; $httpBackend.expectGET('names?q=' + queryTerm).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); $httpBackend.flush(); expect(element.isolateScope().results[0].originalObject).toEqual(results.data[0]); }); it('should run response data through formatter if given', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url-response-formatter="dataConverter" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" minlength="1"/>'); $scope.dataConverter = function(rawData) { var data = rawData.data; for (var i = 0; i < data.length; i++) { data[i].name = data[i].last + ', ' + data[i].first; } return rawData; }; $compile(element)($scope); $scope.$digest(); var queryTerm = 'john'; var results = {data: [{first: 'John', last: 'Doe'}]}; $httpBackend.expectGET('names?q=' + queryTerm).respond(200, results); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 'n'.charCodeAt(0); inputField.val(queryTerm); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); $httpBackend.flush(); expect(element.isolateScope().results[0].originalObject).toEqual({first: 'John', last: 'Doe', name: 'Doe, John'}); }); }); describe('clear result', function() { it('should clear input when clear-selected is true', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" clear-selected="true"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_DW; inputField.trigger(eKeydown); expect(element.isolateScope().currentIndex).toBe(0); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect($scope.selectedCountry.originalObject).toEqual({name: 'Afghanistan', code: 'AF'}); expect(element.isolateScope().searchStr).toBe(null); }); }); describe('blur', function() { it('should hide dropdown when focus is lost', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" clear-selected="true"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeFalsy(); inputField.blur(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeFalsy(); $timeout.flush(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeTruthy(); }); it('should cancel hiding the dropdown if it happens within pause period', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" clear-selected="true"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeFalsy(); inputField.blur(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeFalsy(); inputField.focus(); $timeout.flush(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeTruthy(); }); }); describe('TAB for selecting', function() { it('should select the selected suggestion when TAB is pressed', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_DW; inputField.trigger(eKeydown); expect(element.isolateScope().currentIndex).toBe(0); eKeydown.which = KEY_TAB; inputField.trigger(eKeydown); $scope.$digest(); expect($scope.selectedCountry.originalObject).toEqual($scope.countries[0]); }); it('should select the first suggestion when TAB is pressed', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_TAB; inputField.trigger(eKeydown); $scope.$digest(); expect($scope.selectedCountry.originalObject).toEqual($scope.countries[0]); }); it('should take the input field value when TAB is pressed when there is no selection', function() { var element = angular.element('<form><div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" override-suggestions="true"/></form>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('z'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('.angucomplete-row').length).toBe(0); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_TAB; inputField.trigger(eKeydown); inputField.blur(); expect($scope.selectedCountry.originalObject).toEqual('z'); }); it('should not select the first suggestion when TAB is pressed when override-suggestions is set', function() { var element = angular.element('<form><div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" override-suggestions="true"/></form>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_TAB; inputField.trigger(eKeydown); inputField.blur(); expect($scope.selectedCountry.originalObject).toEqual('a'); }); }); describe('override suggestions', function() { it('should override suggestions when enter is pressed but no suggestion is selected', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" override-suggestions="true"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('abc'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeFalsy(); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect($scope.selectedCountry.originalObject).toEqual('abc'); inputField.blur(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeTruthy(); }); it('should override suggestions when enter is pressed but no suggestion is selected also incorporate with clear-selected if it is set', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" override-suggestions="true" clear-selected="true"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('abc'); inputField.trigger('input'); inputField.trigger(e); $timeout.flush(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeFalsy(); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect($scope.selectedCountry.originalObject).toEqual('abc'); inputField.blur(); expect(element.find('#ex1_dropdown').hasClass('ng-hide')).toBeTruthy(); expect(element.isolateScope().searchStr).toBe(null); }); }); describe('selectedObject callback', function() { it('should call selectedObject callback if given', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); var selected = false; $scope.countrySelected = function(value) { selected = true; }; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); expect(selected).toBe(false); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_DW; inputField.trigger(eKeydown); expect(element.isolateScope().currentIndex).toBe(0); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect(selected).toBe(true); }); }); describe('selectedObject callback with extra paramater', function() { it('should call selectedObject callback if given', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" selected-object-data="\'test\'" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); var selected = false; $scope.countrySelected = function(value, row) { selected = row; }; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); expect(selected).toBe(false); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.find('#ex1_dropdown').length).toBe(1); var eKeydown = $.Event('keydown'); eKeydown.which = KEY_DW; inputField.trigger(eKeydown); expect(element.isolateScope().currentIndex).toBe(0); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect(selected).toBe('test'); }); }); describe('initial value', function() { it('should set initial value from string', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1" initial-value="initialValue"/>'); $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); $scope.initialValue = 'Japan'; $scope.$digest(); expect(element.isolateScope().searchStr).toBe('Japan'); }); it('should set initial value from object', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="grabCountryCode" local-data="countries" search-fields="name" title-field="name" minlength="1" initial-value="initialValue"/>'); $scope.countryCode = null; $scope.grabCountryCode = function(value) { $scope.countryCode = value.originalObject.code; }; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); $scope.initialValue = {name: 'Aland Islands', code: 'AX'}; $scope.$digest(); expect(element.isolateScope().searchStr).toBe('Aland Islands'); expect($scope.countryCode).toBe('AX'); }); it('should set validity to true', function() { var element = angular.element('<form name="form"><div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1" initial-value="initialValue" field-required="true"/></form>'); $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); $scope.initialValue = 'Japan'; $scope.$digest(); expect(element.find('#ex1').isolateScope().searchStr).toBe('Japan'); expect(element.hasClass('ng-valid')).toBe(true); }); }); describe('require field', function() { it('should add a class ng-invalid-autocomplete-required when initialized', function() { var element = angular.element('<form name="form"><div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1" field-required="required" input-name="country"/></form>'); $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $scope.required = true; $compile(element)($scope); $scope.$digest(); expect(element.hasClass('ng-invalid')).toBe(true); }); it('should add a class ng-invalid-autocomplete-required when selection is made', function() { var element = angular.element('<form name="form"><div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1" field-required="required" input-name="country"/></form>'); $scope.countrySelected = null; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $scope.required = true; $compile(element)($scope); $scope.$digest(); expect(element.hasClass('ng-invalid')).toBe(true); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.find('.angucomplete-row').length).toBe(3); // make a selection var eKeydown = $.Event('keydown'); eKeydown.which = KEY_DW; inputField.trigger(eKeydown); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect(element.hasClass('ng-invalid')).toBe(false); expect($scope.countrySelected).toBeDefined(); // delete a char inputField.focus(); eKeyup.which = KEY_DEL; inputField.val('Afghanista'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.hasClass('ng-invalid')).toBe(true); expect(element.find('.angucomplete-row').length).toBe(1); expect($scope.countrySelected).toBeUndefined(); // make a selection again eKeydown.which = KEY_DW; inputField.trigger(eKeydown); eKeydown.which = KEY_EN; inputField.trigger(eKeydown); expect(element.hasClass('ng-invalid')).toBe(false); expect($scope.countrySelected).toBeDefined(); }); }); describe('Input changed callback', function() { it('should call input changed callback when input is changed', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" input-changed="inputChanged"/>'); $scope.selectedCountry = undefined; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $scope.inputChanged = jasmine.createSpy('inputChanged'); $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var e = $.Event('keyup'); e.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(e); expect($scope.inputChanged).toHaveBeenCalledWith('a'); }); }); describe('Auto Selecting', function() { it('should not select a suggestion when there are multiple matches', function() { var element = angular.element('<div angucomplete-alt auto-match="true" id="ex1" placeholder="Search people" selected-object="selectedPerson" local-data="people" search-fields="name" title-field="name" minlength="2"/>'); $scope.selectedPerson = undefined; $scope.people = [ {name: 'Jim Beam', email: 'jbeam@example.com'}, {name: 'Elvis Presly', email: 'theking@example.com'}, {name: 'John Elway', email: 'elway1@example.com'}, {name: 'John Elway', email: 'elway2@example.com'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var y = $.Event('keyup'); y.which = 121; inputField.val('john elway'); inputField.trigger('input'); inputField.trigger(y); $timeout.flush(); expect($scope.selectedPerson).toBeUndefined(); }); it('should select the first suggestion when the search text fully matches any of the attributes', function() { var element = angular.element('<div angucomplete-alt auto-match="true" id="ex1" placeholder="Search people" selected-object="selectedPerson" local-data="people" search-fields="name" title-field="name" minlength="2"/>'); $scope.selectedPerson = undefined; $scope.people = [ {name: 'Jim Beam', email: 'jbeam@example.com'}, {name: 'Elvis Presly', email: 'theking@example.com'}, {name: 'John Elway', email: 'elway@example.com'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var y = $.Event('keyup'); y.which = 121; inputField.val('john elway'); inputField.trigger('input'); inputField.trigger(y); $timeout.flush(); expect($scope.selectedPerson.originalObject).toEqual($scope.people[2]); }); it('should not throw an error when description is not defined', function() { var element = angular.element('<div angucomplete-alt auto-match="true" id="ex1" placeholder="Search people" selected-object="selectedPerson" local-data="people" search-fields="name,email" title-field="name" description-field="email" minlength="1"/>'); $scope.selectedPerson = undefined; $scope.people = [ {name: 'Jim Beam', email: 'jbeam@example.com'}, {name: 'Elvis Presly'}, {name: 'John Elway', email: 'elway@example.com'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var y = $.Event('keyup'); y.which = 121; inputField.val('e'); inputField.trigger('input'); inputField.trigger(y); expect(function() { $timeout.flush(); }).not.toThrow(); }); }); describe('key event handling', function() { it('should query again when down arrow key is pressed', function() { var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search countries" selected-object="countrySelected" local-data="countries" search-fields="name" title-field="name" minlength="1"/>'); $scope.countrySelected = null; $scope.countries = [ {name: 'Afghanistan', code: 'AF'}, {name: 'Aland Islands', code: 'AX'}, {name: 'Albania', code: 'AL'} ]; $compile(element)($scope); $scope.$digest(); var inputField = element.find('#ex1_value'); var eKeyup = $.Event('keyup'); eKeyup.which = 97; // letter: a inputField.val('a'); inputField.trigger('input'); inputField.trigger(eKeyup); $timeout.flush(); expect(element.find('.angucomplete-row').length).toBe(3); // ESC once eKeyup.which = KEY_ES; inputField.trigger(eKeyup); expect(element.find('.angucomplete-row').lengt