351 lines
10 KiB
JavaScript
351 lines
10 KiB
JavaScript
describe('Bloodhound', function() {
|
||
|
||
function build(o) {
|
||
return new Bloodhound(_.mixin({
|
||
datumTokenizer: datumTokenizer,
|
||
queryTokenizer: queryTokenizer
|
||
}, o || {}));
|
||
}
|
||
|
||
beforeEach(function() {
|
||
jasmine.Remote.useMock();
|
||
jasmine.Prefetch.useMock();
|
||
jasmine.Transport.useMock();
|
||
jasmine.PersistentStorage.useMock();
|
||
});
|
||
|
||
afterEach(function() {
|
||
clearAjaxRequests();
|
||
});
|
||
|
||
describe('#initialize', function() {
|
||
beforeEach(function() {
|
||
this.bloodhound = build({ initialize: false });
|
||
spyOn(this.bloodhound, '_initialize').andCallThrough();
|
||
});
|
||
|
||
it('should not initialize if intialize option is false', function() {
|
||
expect(this.bloodhound._initialize).not.toHaveBeenCalled();
|
||
});
|
||
|
||
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);
|
||
});
|
||
|
||
it('should clear the index', function() {
|
||
this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
|
||
spyOn(this.bloodhound, 'clear');
|
||
this.bloodhound.initialize();
|
||
|
||
expect(this.bloodhound.clear).toHaveBeenCalled();
|
||
});
|
||
|
||
it('should load data from prefetch cache if available', function() {
|
||
this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
|
||
this.bloodhound.prefetch.fromCache.andReturn(fixtures.serialized.simple);
|
||
this.bloodhound.initialize();
|
||
|
||
expect(this.bloodhound.all()).toEqual(fixtures.data.simple);
|
||
expect(this.bloodhound.prefetch.fromNetwork).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it('should load data from prefetch network as fallback', function() {
|
||
this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
|
||
this.bloodhound.prefetch.fromCache.andReturn(null);
|
||
this.bloodhound.prefetch.fromNetwork.andCallFake(fakeFromNetwork);
|
||
this.bloodhound.initialize();
|
||
|
||
expect(this.bloodhound.all()).toEqual(fixtures.data.simple);
|
||
|
||
function fakeFromNetwork(cb) { cb(null, fixtures.data.simple); }
|
||
});
|
||
|
||
it('should store prefetch network data in the prefetch cache', function() {
|
||
this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
|
||
this.bloodhound.prefetch.fromCache.andReturn(null);
|
||
this.bloodhound.prefetch.fromNetwork.andCallFake(fakeFromNetwork);
|
||
this.bloodhound.initialize();
|
||
|
||
expect(this.bloodhound.prefetch.store)
|
||
.toHaveBeenCalledWith(fixtures.serialized.simple);
|
||
|
||
function fakeFromNetwork(cb) { cb(null, fixtures.data.simple); }
|
||
});
|
||
|
||
it('should add local after prefetch is loaded', function() {
|
||
this.bloodhound = build({
|
||
initialize: false,
|
||
local: [{ foo: 'bar' }],
|
||
prefetch: '/prefetch'
|
||
});
|
||
this.bloodhound.prefetch.fromNetwork.andCallFake(fakeFromNetwork);
|
||
|
||
expect(this.bloodhound.all()).toEqual([]);
|
||
this.bloodhound.initialize();
|
||
expect(this.bloodhound.all()).toEqual([{ foo: 'bar' }]);
|
||
|
||
function fakeFromNetwork(cb) { cb(null, []); }
|
||
});
|
||
});
|
||
|
||
describe('#add', function() {
|
||
it('should add datums to search index', function() {
|
||
var spy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build().add(fixtures.data.simple);
|
||
|
||
this.bloodhound.search('big', spy);
|
||
|
||
expect(spy).toHaveBeenCalledWith([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' },
|
||
{ value: 'biggest' }
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('#get', function() {
|
||
beforeEach(function() {
|
||
this.bloodhound = build({
|
||
identify: function(d) { return d.value; },
|
||
local: fixtures.data.simple
|
||
});
|
||
});
|
||
|
||
it('should support array signature', function() {
|
||
expect(this.bloodhound.get(['big', 'bigger'])).toEqual([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' }
|
||
]);
|
||
});
|
||
|
||
it('should support splat signature', function() {
|
||
expect(this.bloodhound.get('big', 'bigger')).toEqual([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' }
|
||
]);
|
||
});
|
||
|
||
it('should return nothing for unknown ids', function() {
|
||
expect(this.bloodhound.get('big', 'foo', 'bigger')).toEqual([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' }
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('#clear', function() {
|
||
it('should remove all datums to search index', function() {
|
||
var spy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build({ local: fixtures.data.simple }).clear();
|
||
|
||
this.bloodhound.search('big', spy);
|
||
|
||
expect(spy).toHaveBeenCalledWith([]);
|
||
});
|
||
});
|
||
|
||
describe('#clearPrefetchCache', function() {
|
||
it('should clear persistent storage', function() {
|
||
this.bloodhound = build({ prefetch: '/prefetch' }).clearPrefetchCache();
|
||
expect(this.bloodhound.prefetch.clear).toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe('#clearRemoteCache', function() {
|
||
it('should clear remote request cache', function() {
|
||
spyOn(Transport, 'resetCache');
|
||
this.bloodhound = build({ remote: '/remote' }).clearRemoteCache();
|
||
expect(Transport.resetCache).toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe('#all', function() {
|
||
it('should return all local results', function() {
|
||
this.bloodhound = build({ local: fixtures.data.simple });
|
||
expect(this.bloodhound.all()).toEqual(fixtures.data.simple);
|
||
});
|
||
});
|
||
|
||
describe('#search – local', function() {
|
||
it('should return sync matches', function() {
|
||
var spy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build({ local: fixtures.data.simple });
|
||
|
||
this.bloodhound.search('big', spy);
|
||
|
||
expect(spy).toHaveBeenCalledWith([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' },
|
||
{ value: 'biggest' }
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('#search – prefetch', function() {
|
||
it('should return sync matches', function() {
|
||
var spy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build({ initialize: false, prefetch: '/prefetch' });
|
||
this.bloodhound.prefetch.fromCache.andReturn(fixtures.serialized.simple);
|
||
this.bloodhound.initialize();
|
||
|
||
this.bloodhound.search('big', spy);
|
||
|
||
expect(spy).toHaveBeenCalledWith([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' },
|
||
{ value: 'biggest' }
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('#search – remote', function() {
|
||
it('should return async matches', function() {
|
||
var spy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build({ remote: '/remote' });
|
||
this.bloodhound.remote.get.andCallFake(fakeGet);
|
||
this.bloodhound.search('dog', $.noop, spy);
|
||
|
||
expect(spy.callCount).toBe(1);
|
||
|
||
function fakeGet(o, cb) { cb(fixtures.data.animals); }
|
||
});
|
||
});
|
||
|
||
describe('#search – integration', function() {
|
||
it('should backfill when local/prefetch is not sufficient', function() {
|
||
var syncSpy, asyncSpy;
|
||
|
||
syncSpy = jasmine.createSpy();
|
||
asyncSpy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build({
|
||
sufficient: 3,
|
||
local: fixtures.data.simple,
|
||
remote: '/remote'
|
||
});
|
||
this.bloodhound.remote.get.andCallFake(fakeGet);
|
||
|
||
this.bloodhound.search('big', syncSpy, asyncSpy);
|
||
|
||
expect(syncSpy).toHaveBeenCalledWith([
|
||
{ value: 'big' },
|
||
{ value: 'bigger' },
|
||
{ value: 'biggest' }
|
||
]);
|
||
expect(asyncSpy).not.toHaveBeenCalled();
|
||
|
||
this.bloodhound.search('bigg', syncSpy, asyncSpy);
|
||
|
||
expect(syncSpy).toHaveBeenCalledWith([
|
||
{ value: 'bigger' },
|
||
{ value: 'biggest' }
|
||
]);
|
||
expect(asyncSpy).toHaveBeenCalledWith(fixtures.data.animals);
|
||
|
||
function fakeGet(o, cb) { cb(fixtures.data.animals); }
|
||
});
|
||
|
||
it('should remove duplicates from backfill', function() {
|
||
var syncSpy, asyncSpy;
|
||
|
||
syncSpy = jasmine.createSpy();
|
||
asyncSpy = jasmine.createSpy();
|
||
|
||
this.bloodhound = build({
|
||
identify: function(d) { return d.value; },
|
||
local: fixtures.data.animals,
|
||
remote: '/remote'
|
||
});
|
||
this.bloodhound.remote.get.andCallFake(fakeGet);
|
||
|
||
this.bloodhound.search('dog', syncSpy, asyncSpy);
|
||
|
||
expect(syncSpy).toHaveBeenCalledWith([{ value: 'dog' }]);
|
||
expect(asyncSpy).toHaveBeenCalledWith([
|
||
{ value: 'cat' },
|
||
{ value: 'moose' }
|
||
]);
|
||
|
||
function fakeGet(o, cb) { cb(fixtures.data.animals); }
|
||
});
|
||
|
||
it('should not add remote data to index if indexRemote is false', function() {
|
||
this.bloodhound = build({
|
||
identify: function(d) { return d.value; },
|
||
remote: '/remote'
|
||
});
|
||
this.bloodhound.remote.get.andCallFake(fakeGet);
|
||
|
||
spyOn(this.bloodhound, 'add');
|
||
this.bloodhound.search('dog');
|
||
|
||
expect(this.bloodhound.add).not.toHaveBeenCalled();
|
||
|
||
function fakeGet(o, cb) { cb(fixtures.data.animals); }
|
||
});
|
||
|
||
it('should add remote data to index if indexRemote is true', function() {
|
||
this.bloodhound = build({
|
||
identify: function(d) { return d.value; },
|
||
indexRemote: true,
|
||
remote: '/remote'
|
||
});
|
||
this.bloodhound.remote.get.andCallFake(fakeGet);
|
||
|
||
spyOn(this.bloodhound, 'add');
|
||
this.bloodhound.search('dog');
|
||
|
||
expect(this.bloodhound.add).toHaveBeenCalledWith(fixtures.data.animals);
|
||
|
||
function fakeGet(o, cb) { cb(fixtures.data.animals); }
|
||
});
|
||
|
||
it('should not add duplicates from remote to index', function() {
|
||
this.bloodhound = build({
|
||
identify: function(d) { return d.value; },
|
||
indexRemote: true,
|
||
local: fixtures.data.animals,
|
||
remote: '/remote'
|
||
});
|
||
this.bloodhound.remote.get.andCallFake(fakeGet);
|
||
|
||
spyOn(this.bloodhound, 'add');
|
||
this.bloodhound.search('dog');
|
||
|
||
expect(this.bloodhound.add).toHaveBeenCalledWith([
|
||
{ value: 'cat' },
|
||
{ value: 'moose' }
|
||
]);
|
||
|
||
function fakeGet(o, cb) { cb(fixtures.data.animals); }
|
||
});
|
||
});
|
||
|
||
// helper functions
|
||
// ----------------
|
||
|
||
function datumTokenizer(d) { return $.trim(d.value).split(/\s+/); }
|
||
function queryTokenizer(s) { return $.trim(s).split(/\s+/); }
|
||
});
|