UNPKG

typeahead-addresspicker

Version:

Example of adding google map API to typeahead jquery plugin to display address autocomplete suggestions.

593 lines (462 loc) 16.4 kB
describe('Bloodhound', function() { beforeEach(function() { jasmine.Ajax.useMock(); jasmine.Transport.useMock(); jasmine.PersistentStorage.useMock(); }); afterEach(function() { clearAjaxRequests(); }); describe('#initialize', function() { beforeEach(function() { this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, local: fixtures.data.simple }); spyOn(this.bloodhound, '_initialize').andCallThrough(); }); it('should not support reinitialization by default', function() { var p1, p2; p1 = this.bloodhound.initialize(); p2 = this.bloodhound.initialize(); expect(p1).toBe(p2); expect(this.bloodhound._initialize.callCount).toBe(1); }); it('should reinitialize if reintialize flag is true', function() { var p1, p2; p1 = this.bloodhound.initialize(); p2 = this.bloodhound.initialize(true); expect(p1).not.toBe(p2); expect(this.bloodhound._initialize.callCount).toBe(2); }); }); describe('#add', function() { it('should add datums to search index', function() { var spy = jasmine.createSpy(); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, local: [] }); this.bloodhound.initialize(); this.bloodhound.add(fixtures.data.simple); this.bloodhound.get('big', spy); expect(spy).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); }); }); describe('#clear', function() { it('should remove all datums to search index', function() { var spy = jasmine.createSpy(); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, local: fixtures.data.simple }); this.bloodhound.initialize(); this.bloodhound.clear(); this.bloodhound.get('big', spy); expect(spy).toHaveBeenCalledWith([]); }); }); describe('#clearPrefetchCache', function() { it('should clear persistent storage', function() { this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: '/test' }); this.bloodhound.initialize(); this.bloodhound.clearPrefetchCache(); expect(this.bloodhound.storage.clear).toHaveBeenCalled(); }); }); describe('#clearRemoteCache', function() { it('should clear remote request cache', function() { spyOn(Transport, 'resetCache'); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: '/test' }); this.bloodhound.initialize(); this.bloodhound.clearRemoteCache(); expect(Transport.resetCache).toHaveBeenCalled(); }); }); describe('local', function() { describe('when local is an array', function() { beforeEach(function() { this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, local: fixtures.data.simple }); this.bloodhound.initialize(); }); it('should hydrate the bloodhound', function() { var spy = jasmine.createSpy(); this.bloodhound.get('big', spy); expect(spy).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); }); }); describe('when local is a function that returns an array', function() { beforeEach(function() { var localFn = function() { return fixtures.data.simple; }; this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, local: localFn }); this.bloodhound.initialize(); }); it('should hydrate the bloodhound', function() { var spy = jasmine.createSpy(); this.bloodhound.get('big', spy); expect(spy).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); }); }); }); describe('prefetch', function() { it('should throw error if url is not set', function() { expect(test).toThrow(); function test() { var d = new Bloodhound({ prefetch: {} }); } }); it('should use url or cacheKey to store data locally', function() { var ttl = 100; this.bloodhound1 = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: { url: '/test1', cacheKey: 'woah' } }); expect(PersistentStorage).toHaveBeenCalledWith('woah'); this.bloodhound2 = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: { url: '/test2', ttl: ttl, thumbprint: '!' } }); expect(PersistentStorage).toHaveBeenCalledWith('/test2'); this.bloodhound2.initialize(); ajaxRequests[0].response(fixtures.ajaxResps.ok); expect(this.bloodhound2.storage.set) .toHaveBeenCalledWith('data', fixtures.serialized.simple, ttl); expect(this.bloodhound2.storage.set) .toHaveBeenCalledWith('protocol', 'http:', ttl); expect(this.bloodhound2.storage.set) .toHaveBeenCalledWith('thumbprint', '%VERSION%!', ttl); }); it('should load data from provided url', function() { var spy1, spy2; spy1 = jasmine.createSpy(); spy2 = jasmine.createSpy(); this.bloodhound1 = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: '/test1' }); this.bloodhound2 = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: { url: '/test2' } }); this.bloodhound1.initialize(); this.bloodhound2.initialize(); ajaxRequests[0].response(fixtures.ajaxResps.ok); ajaxRequests[1].response(fixtures.ajaxResps.ok); expect(ajaxRequests[0].url).toBe('/test1'); expect(ajaxRequests[1].url).toBe('/test2'); this.bloodhound1.get('big', spy1); this.bloodhound2.get('big', spy2); expect(spy1).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); expect(spy2).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); }); it('should clear preexisting data', function() { this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: '/test' }); spyOn(this.bloodhound, 'clear'); this.bloodhound.initialize(); mostRecentAjaxRequest().response(fixtures.ajaxResps.ok); expect(this.bloodhound.clear).toHaveBeenCalled(); }); it('should filter data if filter is provided', function() { var filterSpy, spy; filterSpy = jasmine.createSpy().andCallFake(fakeFilter); spy = jasmine.createSpy(); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: { url: '/test', filter: filterSpy } }); this.bloodhound.initialize(); mostRecentAjaxRequest().response(fixtures.ajaxResps.ok); expect(filterSpy).toHaveBeenCalled(); this.bloodhound.get('big', spy); expect(spy).toHaveBeenCalledWith([ { value: 'BIG' }, { value: 'BIGGER' }, { value: 'BIGGEST' } ]); function fakeFilter(resp) { return [{ value: 'BIG' }, { value: 'BIGGER' }, { value: 'BIGGEST' }]; } }); it('should not make a request if data is available in storage', function() { var that = this, spy = jasmine.createSpy(); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, prefetch: '/test' }); this.bloodhound.storage.get.andCallFake(fakeGet); this.bloodhound.initialize(); expect(mostRecentAjaxRequest()).toBeNull(); this.bloodhound.get('big', spy); expect(spy).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); function fakeGet(key) { var val; switch (key) { case 'data': val = fixtures.serialized.simple; break; case 'protocol': val = 'http:'; break; case 'thumbprint': val = that.bloodhound.prefetch.thumbprint; break; } return val; } }); }); describe('remote', function() { it('should perform query substitution on the provided url', function() { this.bloodhound1 = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: { url: '/test?q=$$', wildcard: '$$' } }); this.bloodhound2 = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: { url: '/test?q=%QUERY', replace: function(str, query) {return str.replace('%QUERY', query); } } }); this.bloodhound1.initialize(); this.bloodhound2.initialize(); this.bloodhound1.get('one two', $.noop); this.bloodhound2.get('one two', $.noop); expect(this.bloodhound1.transport.get).toHaveBeenCalledWith( '/test?q=one%20two', { type: 'GET', dataType: 'json' }, jasmine.any(Function) ); expect(this.bloodhound2.transport.get).toHaveBeenCalledWith( '/test?q=one two', { type: 'GET', dataType: 'json' }, jasmine.any(Function) ); }); it('should filter the response if a filter is provided', function() { var filterSpy, spy; spy = jasmine.createSpy(); filterSpy = jasmine.createSpy().andCallFake(fakeFilter); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: { url: '/test', filter: filterSpy } }); this.bloodhound.initialize(); this.bloodhound.transport.get.andCallFake(fakeGet); this.bloodhound.get('big', spy); waitsFor(function() { return spy.callCount; }); runs(function() { expect(filterSpy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith([ { value: 'BIG' }, { value: 'BIGGER' }, { value: 'BIGGEST' } ]); }); function fakeFilter(resp) { return [{ value: 'BIG' }, { value: 'BIGGER' }, { value: 'BIGGEST' }]; } function fakeGet(url, o, cb) { cb(null, fixtures.data.simple); } }); describe('when there is not matching data in the search index', function() { beforeEach(function() { this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: '/test?q=%QUERY', local: { value: 'not an animal' } }); this.bloodhound.initialize(); }); it('should call #get callback once if there is a cache hit', function() { var spy = jasmine.createSpy(); this.bloodhound.transport.get.andCallFake(fakeGetWithCacheHit); this.bloodhound.get('dog', spy); expect(spy.callCount).toBe(1); function fakeGetWithCacheHit(url, o, cb) { cb(null, fixtures.data.animals); return true; } }); it('should call #get callback once if there is a cache miss', function() { var spy = jasmine.createSpy(); this.bloodhound.transport.get.andCallFake(fakeGetWithCacheMiss); this.bloodhound.get('dog', spy); expect(spy.callCount).toBe(1); function fakeGetWithCacheMiss(url, o, cb) { cb(null, fixtures.data.animals); return false; } }); }); describe('when there is matching data in the search index', function() { beforeEach(function() { this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: '/test?q=%QUERY', local: { value: 'dog' } }); this.bloodhound.initialize(); }); it('should call the #get callback twice if there is a cache miss', function() { var spy = jasmine.createSpy(); this.bloodhound.transport.get.andCallFake(fakeGetWithCacheMiss); this.bloodhound.get('dog', spy); expect(spy.callCount).toBe(2); function fakeGetWithCacheMiss(url, o, cb) { cb(null, fixtures.data.animals); return false; } }); it('should call the #get callback once if there is a cache hit', function() { var spy = jasmine.createSpy(); this.bloodhound.transport.get.andCallFake(fakeGetWithCacheHit); this.bloodhound.get('dog', spy); expect(spy.callCount).toBe(1); function fakeGetWithCacheHit(url, o, cb) { cb(null, fixtures.data.animals); return true; } }); }); it('should should treat failures as empty suggestion sets', function() { var spy = jasmine.createSpy(); this.bloodhound = new Bloodhound({ datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, remote: '/test?q=%QUERY' }); this.bloodhound.initialize(); this.bloodhound.transport.get.andCallFake(fakeGet); this.bloodhound.get('dog', spy); expect(spy).toHaveBeenCalledWith([]); function fakeGet(url, o, cb) { cb(true); } }); }); describe('local/prefetch/remote integration', function() { it('duplicates should be removed if dupDetector is provided', function() { var spy; spy = jasmine.createSpy(); this.bloodhound = new Bloodhound({ limit: 6, datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, dupDetector: function(d1, d2) { return d1.value === d2.value; }, local: fixtures.data.animals, remote: { url: '/test?q=%QUERY' } }); this.bloodhound.initialize(); this.bloodhound.transport.get.andCallFake(fakeGet); this.bloodhound.get('dog', spy); expect(spy).toHaveBeenCalledWith([{ value: 'dog' }]); waitsFor(function() { return spy.callCount === 2; }); runs(function() { expect(spy).toHaveBeenCalledWith(fixtures.data.animals); }); function fakeGet(url, o, cb) { setTimeout(function() { cb(null, fixtures.data.animals); }, 0); } }); it('remote should backfill local/prefetch', function() { var spy1, spy2; spy1 = jasmine.createSpy(); spy2 = jasmine.createSpy(); this.bloodhound = new Bloodhound({ limit: 3, datumTokenizer: datumTokenizer, queryTokenizer: queryTokenizer, local: fixtures.data.simple, remote: { url: '/test?q=%QUERY' } }); this.bloodhound.initialize(); this.bloodhound.transport.get.andCallFake(fakeGet); this.bloodhound.get('big', spy1); this.bloodhound.get('bigg', spy2); expect(spy1.callCount).toBe(1); expect(spy2.callCount).toBe(1); expect(spy1).toHaveBeenCalledWith([ { value: 'big' }, { value: 'bigger' }, { value: 'biggest' } ]); expect(spy2).toHaveBeenCalledWith([ { value: 'bigger' }, { value: 'biggest' } ]); waitsFor(function() { return spy2.callCount === 2; }); runs(function() { expect(spy2).toHaveBeenCalledWith([ { value: 'bigger' }, { value: 'biggest' }, { value: 'dog' } ]); }); function fakeGet(url, o, cb) { setTimeout(function() { cb(null, fixtures.data.animals); }, 0); } }); }); // helper functions // ---------------- function datumTokenizer(d) { return $.trim(d.value).split(/\s+/); } function queryTokenizer(s) { return $.trim(s).split(/\s+/); } });