[Tests] Rewrite search aggregator specs

This commit is contained in:
Pete Richards 2015-10-16 17:06:23 -07:00
parent 12efb47be7
commit 0f63e4dde9
2 changed files with 230 additions and 84 deletions

View File

@ -76,7 +76,6 @@ define([
) { ) {
var aggregator = this, var aggregator = this,
timestamp = Date.now(),
resultPromises; resultPromises;
if (!maxResults) { if (!maxResults) {
@ -95,18 +94,18 @@ define([
.then(function (providerResults) { .then(function (providerResults) {
var modelResults = { var modelResults = {
hits: [], hits: [],
totals: 0 total: 0
}; };
providerResults.forEach(function (providerResult) { providerResults.forEach(function (providerResult) {
modelResults.hits = modelResults.hits =
modelResults.hits.concat(providerResult.hits); modelResults.hits.concat(providerResult.hits);
modelResults.totals += providerResult.totals; modelResults.total += providerResult.total;
}); });
aggregator.orderByScore(modelResults); modelResults = aggregator.orderByScore(modelResults);
aggregator.applyFilter(modelResults, filter); modelResults = aggregator.applyFilter(modelResults, filter);
aggregator.removeDuplicates(modelResults); modelResults = aggregator.removeDuplicates(modelResults);
return aggregator.asObjectResults(modelResults); return aggregator.asObjectResults(modelResults);
}); });
@ -144,15 +143,15 @@ define([
return filter(hit.model); return filter(hit.model);
}); });
finalLength = modelResults.hits; finalLength = modelResults.hits.length;
removedByFilter = initialLength - finalLength; removedByFilter = initialLength - finalLength;
modelResults.totals -= removedByFilter; modelResults.total -= removedByFilter;
return modelResults; return modelResults;
}; };
/** /**
* Remove duplicate hits in a modelResults object, and decrement `totals` * Remove duplicate hits in a modelResults object, and decrement `total`
* each time a duplicate is removed. * each time a duplicate is removed.
*/ */
SearchAggregator.prototype.removeDuplicates = function (modelResults) { SearchAggregator.prototype.removeDuplicates = function (modelResults) {
@ -162,7 +161,7 @@ define([
.hits .hits
.filter(function alreadyInResults(hit) { .filter(function alreadyInResults(hit) {
if (includedIds[hit.id]) { if (includedIds[hit.id]) {
modelResults.totals -= 1; modelResults.total -= 1;
return false; return false;
} }
includedIds[hit.id] = true; includedIds[hit.id] = true;
@ -189,7 +188,7 @@ define([
.then(function (objects) { .then(function (objects) {
var objectResults = { var objectResults = {
totals: modelResults.totals total: modelResults.total
}; };
objectResults.hits = modelResults objectResults.hits = modelResults

View File

@ -19,83 +19,230 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global define,describe,it,expect,beforeEach,jasmine*/ /*global define,describe,it,expect,beforeEach,jasmine,Promise,waitsFor,spyOn*/
/** /**
* SearchSpec. Created by shale on 07/31/2015. * SearchSpec. Created by shale on 07/31/2015.
*/ */
define( define([
["../../src/services/SearchAggregator"], "../../src/services/SearchAggregator"
function (SearchAggregator) { ], function (SearchAggregator) {
"use strict"; "use strict";
describe("The search aggregator ", function () { describe("SearchAggregator", function () {
var mockQ, var $q,
mockPromise, objectService,
mockProviders = [], providers,
aggregator, aggregator;
mockProviderResults = [],
mockAggregatorResults,
i;
beforeEach(function () { beforeEach(function () {
mockQ = jasmine.createSpyObj( $q = jasmine.createSpyObj(
"$q", '$q',
[ "all" ] ['all']
); );
mockPromise = jasmine.createSpyObj( $q.all.andReturn(Promise.resolve([]));
"promise", objectService = jasmine.createSpyObj(
[ "then" ] 'objectService',
); ['getObjects']
for (i = 0; i < 3; i += 1) { );
mockProviders.push( providers = [],
jasmine.createSpyObj( aggregator = new SearchAggregator($q, objectService, providers);
"mockProvider" + i,
[ "query" ]
)
);
mockProviders[i].query.andReturn(mockPromise);
}
mockQ.all.andReturn(mockPromise);
aggregator = new SearchAggregator(mockQ, mockProviders);
aggregator.query();
for (i = 0; i < mockProviders.length; i += 1) {
mockProviderResults.push({
hits: [
{
id: i,
score: 42 - i
},
{
id: i + 1,
score: 42 - (2 * i)
}
]
});
}
mockAggregatorResults = mockPromise.then.mostRecentCall.args[0](mockProviderResults);
});
it("sends queries to all providers", function () {
for (i = 0; i < mockProviders.length; i += 1) {
expect(mockProviders[i].query).toHaveBeenCalled();
}
});
it("filters out duplicate objects", function () {
expect(mockAggregatorResults.hits.length).toEqual(mockProviders.length + 1);
expect(mockAggregatorResults.total).not.toBeLessThan(mockAggregatorResults.hits.length);
});
it("orders results by score", function () {
for (i = 1; i < mockAggregatorResults.hits.length; i += 1) {
expect(mockAggregatorResults.hits[i].score)
.not.toBeGreaterThan(mockAggregatorResults.hits[i - 1].score);
}
});
}); });
}
);
it("can order model results by score", function () {
var modelResults = {
hits: [
{score: 1},
{score: 23},
{score: 11}
]
},
sorted = aggregator.orderByScore(modelResults);
expect(sorted.hits).toEqual([
{score: 23},
{score: 11},
{score: 1}
]);
});
it('filters results without a function', function () {
var modelResults = {
hits: [
{thing: 1},
{thing: 2}
],
total: 2
},
filtered = aggregator.applyFilter(modelResults);
expect(filtered.hits).toEqual([
{thing: 1},
{thing: 2}
]);
expect(filtered.total).toBe(2);
});
it('filters results with a function', function () {
var modelResults = {
hits: [
{model: {thing: 1}},
{model: {thing: 2}},
{model: {thing: 3}}
],
total: 3
},
filterFunc = function (model) {
return model.thing < 2;
},
filtered = aggregator.applyFilter(modelResults, filterFunc);
expect(filtered.hits).toEqual([
{model: {thing: 1}}
]);
expect(filtered.total).toBe(1);
});
it('can remove duplicates', function () {
var modelResults = {
hits: [
{id: 15},
{id: 23},
{id: 14},
{id: 23}
],
total: 4
},
deduped = aggregator.removeDuplicates(modelResults);
expect(deduped.hits).toEqual([
{id: 15},
{id: 23},
{id: 14}
]);
expect(deduped.total).toBe(3);
});
it('can convert model results to object results', function () {
var modelResults = {
hits: [
{id: 123, score: 5},
{id: 234, score: 1}
],
total: 2
},
objects = {
123: '123-object-hey',
234: '234-object-hello'
},
promiseChainComplete = false;
objectService.getObjects.andReturn(Promise.resolve(objects));
aggregator
.asObjectResults(modelResults)
.then(function (objectResults) {
expect(objectResults).toEqual({
hits: [
{id: 123, score: 5, object: '123-object-hey'},
{id: 234, score: 1, object: '234-object-hello'}
],
total: 2
});
})
.then(function () {
promiseChainComplete = true;
});
waitsFor(function () {
return promiseChainComplete;
});
});
it('can send queries to providers', function () {
var provider = jasmine.createSpyObj(
'provider',
['query']
);
provider.query.andReturn('i prooomise!');
providers.push(provider);
aggregator.query('find me', 123, 'filter');
expect(provider.query).toHaveBeenCalledWith('find me', 123);
expect($q.all).toHaveBeenCalledWith(['i prooomise!']);
});
it('supplies max results when none is provided', function () {
var provider = jasmine.createSpyObj(
'provider',
['query']
);
providers.push(provider);
aggregator.query('find me');
expect(provider.query).toHaveBeenCalledWith('find me', 100);
});
it('can combine responses from multiple providers', function () {
var providerResponses = [
{
hits: [
'oneHit',
'twoHit'
],
total: 2
},
{
hits: [
'redHit',
'blueHit',
'by',
'Pete'
],
total: 4
}
],
promiseChainResolved = false;
$q.all.andReturn(Promise.resolve(providerResponses));
spyOn(aggregator, 'orderByScore').andReturn('orderedByScore!');
spyOn(aggregator, 'applyFilter').andReturn('filterApplied!');
spyOn(aggregator, 'removeDuplicates')
.andReturn('duplicatesRemoved!');
spyOn(aggregator, 'asObjectResults').andReturn('objectResults');
aggregator
.query('something', 10, 'filter')
.then(function (objectResults) {
expect(aggregator.orderByScore).toHaveBeenCalledWith({
hits: [
'oneHit',
'twoHit',
'redHit',
'blueHit',
'by',
'Pete'
],
total: 6
});
expect(aggregator.applyFilter)
.toHaveBeenCalledWith('orderedByScore!', 'filter');
expect(aggregator.removeDuplicates)
.toHaveBeenCalledWith('filterApplied!');
expect(aggregator.asObjectResults)
.toHaveBeenCalledWith('duplicatesRemoved!');
expect(objectResults).toBe('objectResults');
})
.then(function () {
promiseChainResolved = true;
});
waitsFor(function () {
return promiseChainResolved;
});
});
});
});