diff --git a/package.json b/package.json index 7f028a1ce8..dff64dc546 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "gulp dev", "test": "npm run unitTests", + "test:watch": "gulp devTest", "unitTests": "gulp unitTests && gulp coverage", "accessibilityTests": "gulp accessibilityTests", "testChunks": "node chunkTesters/chunk.tester.js", diff --git a/pages/index.html b/pages/index.html index 7a948afdf2..a2f35051ef 100644 --- a/pages/index.html +++ b/pages/index.html @@ -10,7 +10,7 @@ diff --git a/src/ui/MissingTerm/MissingTerms.ts b/src/ui/MissingTerm/MissingTerms.ts index bb1ccce4ea..59b3823ee5 100644 --- a/src/ui/MissingTerm/MissingTerms.ts +++ b/src/ui/MissingTerm/MissingTerms.ts @@ -9,6 +9,7 @@ import { IComponentBindings } from '../Base/ComponentBindings'; import { ComponentOptions } from '../Base/ComponentOptions'; import { MissingTermManager } from './MissingTermManager'; import XRegExp = require('xregexp'); +import { intersection } from 'underscore'; export interface IMissingTermsOptions { caption?: string; @@ -46,8 +47,8 @@ export class MissingTerms extends Component { /** * The maximum number of missing term to be displayed * - * **Default:** `5` - * **Minimum value:** `1` + * **Default:** `5` + * **Minimum value:** `1` */ numberOfTerms: ComponentOptions.buildNumberOption({ defaultValue: 5, @@ -81,13 +82,32 @@ export class MissingTerms extends Component { this.options = ComponentOptions.initComponentOptions(element, MissingTerms, options); this.addMissingTerms(); } + + private get absentTerms() { + let absentTerms = this.result.absentTerms; + + if (this.result.attachments) { + absentTerms = this.intersectAbsentTerms(absentTerms, this.result.attachments); + } + + if (this.result.childResults) { + absentTerms = this.intersectAbsentTerms(absentTerms, this.result.childResults); + } + + return absentTerms; + } + + private intersectAbsentTerms(absentTerms: string[], results: IQueryResult[]) { + return intersection(absentTerms, ...results.map(result => result.absentTerms)); + } + /** - *Returns all original basic query expression terms that were not matched by the result item the component instance is associated with. + * Returns all original basic query expression terms that were not matched by the result item the component instance is associated with. */ public get missingTerms(): string[] { const terms = []; - for (const term of this.result.absentTerms) { + for (const term of this.absentTerms) { const regex = this.createWordBoundaryDelimitedRegex(term); const query = this.queryStateModel.get('q'); const result = regex.exec(query); diff --git a/unitTests/ui/MissingTermsTest.ts b/unitTests/ui/MissingTermsTest.ts index 00bba27e99..effe72c775 100644 --- a/unitTests/ui/MissingTermsTest.ts +++ b/unitTests/ui/MissingTermsTest.ts @@ -5,7 +5,7 @@ import { FakeResults } from '../Fake'; import { IQueryResult } from '../../src/rest/QueryResult'; export function MissingTermsTest() { - describe('MissingTerm', () => { + describe('MissingTerms', () => { let test: Mock.IBasicComponentSetup; let fakeResult: IQueryResult; @@ -13,10 +13,14 @@ export function MissingTermsTest() { const test = Mock.advancedResultComponentSetup( MissingTerms, fakeResult, - new Mock.AdvancedComponentSetupOptions(null, option, (env: Mock.MockEnvironmentBuilder): Mock.MockEnvironmentBuilder => { - env.withLiveQueryStateModel().queryStateModel.set('q', query); - return env; - }) + new Mock.AdvancedComponentSetupOptions( + null, + option, + (env: Mock.MockEnvironmentBuilder): Mock.MockEnvironmentBuilder => { + env.withLiveQueryStateModel().queryStateModel.set('q', query); + return env; + } + ) ); const analyticsElement = $$('div', { className: 'CoveoAnalytics' @@ -52,7 +56,7 @@ export function MissingTermsTest() { }); it(`true, - it should log a addMissingTerm event when it is clicked`, function() { + it should log a addMissingTerm event when it is clicked`, function () { const query = 'This is my query'; fakeResult.absentTerms = ['This']; test = mockComponent(query); @@ -106,9 +110,7 @@ export function MissingTermsTest() { }); it('when the show more button is clicked, show all the missing terms', () => { - $$(test.cmp.element) - .find('.coveo-missing-term-show-more') - .click(); + $$(test.cmp.element).find('.coveo-missing-term-show-more').click(); const visibleMissingTerm = $$(test.cmp.element) .findAll('.coveo-missing-term') .filter(element => { @@ -118,6 +120,7 @@ export function MissingTermsTest() { }); }); }); + describe('when the langage is', () => { const getMissingTerms = () => { return test.cmp.queryStateModel.get('missingTerms'); @@ -289,5 +292,43 @@ export function MissingTermsTest() { }); }); }); + + describe('with attachments & child results', () => { + it('should only display missing terms that are returned both by the result & its attachments', () => { + const attachment = FakeResults.createFakeResult(); + attachment.absentTerms = ['hello', 'bye']; + + fakeResult.absentTerms = ['hello', 'world']; + fakeResult.attachments = [attachment]; + + test = mockComponent('hello world bye'); + expect(test.cmp.missingTerms).toEqual(['hello']); + }); + + it('should only display missing terms that are returned both by the result & its child results', () => { + const childResult = FakeResults.createFakeResult(); + childResult.absentTerms = ['hello', 'bye']; + + fakeResult.absentTerms = ['hello', 'world']; + fakeResult.childResults = [childResult]; + + test = mockComponent('hello world bye'); + expect(test.cmp.missingTerms).toEqual(['hello']); + }); + + it('should only display missing terms that are returned by the result, its attachments & its child results', () => { + const childResult = FakeResults.createFakeResult(); + childResult.absentTerms = ['hello', 'world', 'forever']; + const attachment = FakeResults.createFakeResult(); + attachment.absentTerms = ['hello', 'world', 'bye']; + + fakeResult.absentTerms = ['hello', 'world', 'bye']; + fakeResult.attachments = [attachment]; + fakeResult.childResults = [childResult]; + + test = mockComponent('hello world bye forever'); + expect(test.cmp.missingTerms).toEqual(['hello', 'world']); + }); + }); }); }