From b3eafd83d4ed2c0ec43da65c95ba50055caafb92 Mon Sep 17 00:00:00 2001 From: Louis Bompart Date: Tue, 28 Jul 2020 02:06:27 -0400 Subject: [PATCH] test(SFINT-3353): Test cleaning --- package-lock.json | 198 +++++++- package.json | 2 +- .../UserActions/ClickedDocumentList.spec.ts | 178 ++++--- .../UserActions/ExpandableList.spec.ts | 99 ++-- .../components/UserActions/QueryList.spec.ts | 195 ++++---- .../UserActions/ResponsiveUserActions.spec.ts | 12 +- .../UserActions/UserActions.spec.ts | 358 ++++++-------- .../UserActions/UserActivity.spec.ts | 442 ++++++++---------- .../ViewedByCustomer/ViewedByCustomer.spec.ts | 4 +- tests/models/UserProfilingModel.spec.ts | 26 +- tests/utils.ts | 6 +- 11 files changed, 802 insertions(+), 718 deletions(-) diff --git a/package-lock.json b/package-lock.json index eab93b99..c8fc4de9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3003,6 +3003,22 @@ "integrity": "sha1-+CjC0yFb/WbFgHJwm0JgxkElOQo=", "dev": true }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, "@samverschueren/stream-to-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", @@ -4587,6 +4603,12 @@ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -7134,6 +7156,152 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -7810,6 +7978,12 @@ "is-glob": "^4.0.1" } }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, "global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", @@ -9084,13 +9258,21 @@ } }, "jasmine": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.5.0.tgz", - "integrity": "sha512-DYypSryORqzsGoMazemIHUfMkXM7I7easFaxAvNM3Mr6Xz3Fy36TupTrAOxZWN8MVKEU5xECv22J4tUQf3uBzQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.6.1.tgz", + "integrity": "sha512-Jqp8P6ZWkTVFGmJwBK46p+kJNrZCdqkQ4GL+PGuBXZwK1fM4ST9BizkYgIwCFqYYqnTizAy6+XG2Ej5dFrej9Q==", "dev": true, "requires": { - "glob": "^7.1.4", - "jasmine-core": "~3.5.0" + "fast-glob": "^2.2.6", + "jasmine-core": "~3.6.0" + }, + "dependencies": { + "jasmine-core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.6.0.tgz", + "integrity": "sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw==", + "dev": true + } } }, "jasmine-core": { @@ -9912,6 +10094,12 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", diff --git a/package.json b/package.json index 329b19b4..de27de6a 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "coveralls": "^3.0.3", "cypress": "^4.0.2", "istanbul-instrumenter-loader": "^3.0.1", - "jasmine": "^3.3.1", + "jasmine": "3.6.1", "karma": "^4.4.1", "karma-chrome-launcher": "^3.1.0", "karma-coverage-istanbul-reporter": "^2.0.5", diff --git a/tests/components/UserActions/ClickedDocumentList.spec.ts b/tests/components/UserActions/ClickedDocumentList.spec.ts index 32d04464..1d6637f3 100644 --- a/tests/components/UserActions/ClickedDocumentList.spec.ts +++ b/tests/components/UserActions/ClickedDocumentList.spec.ts @@ -3,7 +3,7 @@ import { Mock, Fake } from 'coveo-search-ui-tests'; import { ClickedDocumentList } from '../../../src/components/UserActions/ClickedDocumentList'; import { UserProfileModel, UserAction } from '../../../src/models/UserProfileModel'; import { Logger, Initialization } from 'coveo-search-ui'; -import { delay, generate, fakeUserProfileModel } from '../../utils'; +import { generate, fakeUserProfileModel, waitForPromiseCompletion } from '../../utils'; import { UserActionType } from '../../../src/rest/UserProfilingEndpoint'; describe('ClickedDocumentList', () => { @@ -35,131 +35,124 @@ describe('ClickedDocumentList', () => { Logger.enable(); }); - it('should show a text when there is no document clicked', () => { + it('should show a text when there is no document clicked', async () => { const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve([])); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - const emptyElement = mock.cmp.element.querySelector('.coveo-empty'); - expect(emptyElement).not.toBeNull(); - expect(emptyElement.innerText).toBe('No document clicked by this user'); - }); + const emptyElement = mock.cmp.element.querySelector('.coveo-empty'); + expect(emptyElement).not.toBeNull(); + expect(emptyElement.innerText).toBe('No document clicked by this user'); }); - it('should show "Documents Clicked" as title', () => { + it('should show "Documents Clicked" as title', async () => { const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-title').innerHTML).toMatch('Recent Clicked Documents'); - }); + expect(mock.cmp.element.querySelector('.coveo-title').innerHTML).toMatch('Recent Clicked Documents'); }); - it('should show the title specified in "listLabel" option', () => { + it('should show the title specified in "listLabel" option', async () => { const customTitle = 'Custom Title'; const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', listLabel: customTitle }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-title').innerHTML).toMatch(customTitle); - }); + expect(mock.cmp.element.querySelector('.coveo-title').innerHTML).toMatch(customTitle); }); - it('should show 4 documents by default', () => { + it('should show 4 documents by default', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + const list = mock.env.element.querySelector('.coveo-list'); - expect(list.childElementCount).toBe(4); - }); + expect(list.childElementCount).toBe(4); }); - it('should show a number of documents equal to the "numberOfItems" option', () => { + it('should show a number of documents equal to the "numberOfItems" option', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + const list = mock.env.element.querySelector('.coveo-list'); - expect(list.childElementCount).toBe(10); - }); + expect(list.childElementCount).toBe(10); }); - it('should display an icon beside every list item', () => { + it('should display an icon beside every list item', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + const list = mock.env.element.querySelector('.coveo-list'); - for (let i = 0; i < 4; i++) { - const icon = list.children.item(i).querySelector('svg'); - expect(icon).toBeDefined; - } - }); + for (let i = 0; i < 4; i++) { + const icon = list.children.item(i).querySelector('svg'); + expect(icon).toBeDefined; + } }); - it('should show all documents when expanded', () => { + it('should show all documents when expanded', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); - const button = mock.env.element.querySelector('.coveo-more-less'); - button.click(); + const list = mock.env.element.querySelector('.coveo-list'); + const button = mock.env.element.querySelector('.coveo-more-less'); + button.click(); - return delay(() => { - expect(list.childElementCount).toBe(TEST_CLICKS.length); - }); - }); + await waitForPromiseCompletion(); + + expect(list.childElementCount).toBe(TEST_CLICKS.length); }); - it('should not show the same query twice', () => { + it('should not show the same query twice', async () => { // Setup. const createComponentInsideStub = sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); @@ -176,80 +169,78 @@ describe('ClickedDocumentList', () => { const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(CLICK_EVENTS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(CLICK_EVENTS)); return env; }) ); + await waitForPromiseCompletion(); // Validation. - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); - expect(list.childElementCount).toBe(SORTED_AND_TRIMMED_CLICK_EVENTS.length); - - // Check that the order is respected. - list.childNodes.forEach((node: HTMLElement, i) => { - expect(node.innerHTML).toMatch('CoveoResultLink'); - expect(createComponentInsideStub.calledWith(node.firstChild as HTMLElement, SORTED_AND_TRIMMED_CLICK_EVENTS[i].document)).toBe(true); - }); + const list = mock.env.element.querySelector('.coveo-list'); + expect(list.childElementCount).toBe(SORTED_AND_TRIMMED_CLICK_EVENTS.length); + + // Check that the order is respected. + list.childNodes.forEach((node: HTMLElement, i) => { + expect(node.innerHTML).toMatch('CoveoResultLink'); + expect(createComponentInsideStub.calledWith(node.firstChild as HTMLElement, SORTED_AND_TRIMMED_CLICK_EVENTS[i].document)).toBe(true); }); }); - it('should render the a list of document clicked by a user as a list of ResultLink and put the most recent document click on top', () => { + it('should render the a list of document clicked by a user as a list of ResultLink and put the most recent document click on top', async () => { const createComponentInside = sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); const sortedClick = TEST_CLICKS.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()).reverse(); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + const list = mock.env.element.querySelector('.coveo-list'); - list.childNodes.forEach((node: HTMLElement, i) => { - expect(node.innerHTML).toMatch('CoveoResultLink'); - expect(createComponentInside.calledWith(node.firstChild as HTMLElement, sortedClick[i].document)).toBe(true); - }); + list.childNodes.forEach((node: HTMLElement, i) => { + expect(node.innerHTML).toMatch('CoveoResultLink'); + expect(createComponentInside.calledWith(node.firstChild as HTMLElement, sortedClick[i].document)).toBe(true); }); }); - it('should fetch the list of document clicked by a user from the model', () => { + it('should fetch the list of document clicked by a user from the model', async () => { let model = sandbox.createStubInstance(UserProfileModel); Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { model = fakeUserProfileModel(env.root, sandbox); - model.getActions.returns(Promise.resolve(TEST_CLICKS)); + model.getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; }) ); + await waitForPromiseCompletion(); expect(model.getActions.called).toBe(true); }); - it("should log an error message when the component can't fetch the list of document clicked by a user from the model", () => { + it("should log an error message when the component can't fetch the list of document clicked by a user from the model", async () => { const errorLoggerStub = sandbox.stub(Logger.prototype, 'error'); const mock = Mock.advancedComponentSetup( ClickedDocumentList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - expect(mock.cmp.element.childElementCount).toBe(0); - expect(errorLoggerStub.called).toBe(true); - }); + expect(mock.cmp.element.childElementCount).toBe(0); + expect(errorLoggerStub.called).toBe(true); }); - it('Should disable itself when the userId is falsey', () => { + it('Should disable itself when the userId is falsey', async () => { let getActionStub: SinonStub<[HTMLElement, ClickedDocumentList], void>; const mock = Mock.advancedComponentSetup( ClickedDocumentList, @@ -258,13 +249,13 @@ describe('ClickedDocumentList', () => { return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + await waitForPromiseCompletion(); + + expect(getActionStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); - it('Should disable itself when the userId is empty string', () => { + it('Should disable itself when the userId is empty string', async () => { let getActionStub: SinonStub<[HTMLElement, ClickedDocumentList], void>; const mock = Mock.advancedComponentSetup( ClickedDocumentList, @@ -273,16 +264,16 @@ describe('ClickedDocumentList', () => { return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + await waitForPromiseCompletion(); + + expect(getActionStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); describe('template', () => { - it('should use the given template in options', () => { + it('should use the given template in options', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInsideResult'); - const instantiateToElementStub = sandbox.stub().returns(Promise.resolve(document.createElement('div'))); + const instantiateToElementStub = sandbox.stub().callsFake(() => Promise.resolve(document.createElement('div'))); Mock.advancedComponentSetup( ClickedDocumentList, @@ -297,19 +288,18 @@ describe('ClickedDocumentList', () => { }, }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_CLICKS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_CLICKS)); return env; } ) ); + await waitForPromiseCompletion(); const sortedClick = TEST_CLICKS.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()).reverse(); - return delay(() => { - expect(instantiateToElementStub.callCount).toBe(TEST_CLICKS.length); - sortedClick.forEach((userAction, i) => { - expect(instantiateToElementStub.args[i][0]).toBe(userAction.document); - }); + expect(instantiateToElementStub.callCount).toBe(TEST_CLICKS.length); + sortedClick.forEach((userAction, i) => { + expect(instantiateToElementStub.args[i][0]).toBe(userAction.document); }); }); }); diff --git a/tests/components/UserActions/ExpandableList.spec.ts b/tests/components/UserActions/ExpandableList.spec.ts index 487ae3ba..4d1e9e61 100644 --- a/tests/components/UserActions/ExpandableList.spec.ts +++ b/tests/components/UserActions/ExpandableList.spec.ts @@ -1,4 +1,4 @@ -import { ExpandableList } from '../../../src/components/UserActions/ExpandableList'; +import { ExpandableList, IExpandableListOptions } from '../../../src/components/UserActions/ExpandableList'; import { generate, delay } from '../../utils'; describe('ExpandableList', () => { @@ -10,83 +10,80 @@ describe('ExpandableList', () => { return el; }; - it('should render a no item message when there is no items', () => { + function getExpandableList(element: HTMLElement, items: T[], options: IExpandableListOptions) { + const list = new ExpandableList(element, items, options); + return delay>(() => list); + } + + it('should render a no item message when there is no items', async () => { const no_item_msg = 'no item'; - const list = new ExpandableList(document.createElement('div'), [], { transform: spanItemGenerator, messageWhenEmpty: no_item_msg }); + const list = await getExpandableList(document.createElement('div'), [], { transform: spanItemGenerator, messageWhenEmpty: no_item_msg }); - return delay(() => { - const emptyElement = list.element.querySelector('.coveo-empty'); - expect(emptyElement).not.toBeNull(); - expect(emptyElement.innerText).toBe(no_item_msg); - }); + const emptyElement = list.element.querySelector('.coveo-empty'); + expect(emptyElement).not.toBeNull(); + expect(emptyElement.innerText).toBe(no_item_msg); }); - it('should render an ordered list of items', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); + it('should render an ordered list of items', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); - return delay(() => { - const listElement = list.element.querySelector('.coveo-list'); + const listElement = list.element.querySelector('.coveo-list'); - expect(listElement).not.toBeNull(); - expect(listElement.childElementCount).toBe(list.options.minimumItemsShown); + expect(listElement).not.toBeNull(); + expect(listElement.childElementCount).toBe(list.options.minimumItemsShown); - listElement.childNodes.forEach((node, i) => { - expect((node as HTMLLIElement).innerHTML).toContain(TEST_ITEM_LIST[i]); - }); + listElement.childNodes.forEach((node, i) => { + expect((node as HTMLLIElement).innerHTML).toContain(TEST_ITEM_LIST[i]); }); }); - it('should render a button with "Show More" as text', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { + it('should render a button with "Show More" as text', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator, }); - return delay(() => { - const el = list.element.querySelector('.coveo-more-less'); + const el = list.element.querySelector('.coveo-more-less'); - expect(el).not.toBeNull(); - expect(el.innerText).toBe('Show More'); - }); + expect(el).not.toBeNull(); + expect(el.innerText).toBe('Show More'); }); - it('should set the min option to a default value of 4', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); + it('should set the min option to a default value of 4', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); expect(list.options.minimumItemsShown).toBe(4); }); - it('should set the max option to a default value of 8', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); + it('should set the max option to a default value of 8', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); expect(list.options.maximumItemsShown).toBe(8); }); - it('should set the title option to a default value', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); + it('should set the title option to a default value', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator }); expect(list.options.listLabel).not.toBeNull(); expect(typeof list.options.listLabel).toBe('string'); }); describe('show more/less button', () => { - it('should start with a "Show More" text and be of type button', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { + it('should start with a "Show More" text and be of type button', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator, maximumItemsShown: 10, minimumItemsShown: 5, }); - return delay(() => { - const el = list.element.querySelector('.coveo-more-less'); + const el = list.element.querySelector('.coveo-more-less'); - expect(el).not.toBeNull(); - expect(el.innerText).toBe('Show More'); - expect(el.getAttribute('type')).toBe('button'); - }); + expect(el).not.toBeNull(); + expect(el.innerText).toBe('Show More'); + expect(el.getAttribute('type')).toBe('button'); }); - it('should be hidden if the min option is the same as the max', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { + it('should be hidden if the min option is the same as the max', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator, maximumItemsShown: 5, minimumItemsShown: 5, @@ -94,13 +91,11 @@ describe('ExpandableList', () => { const el = list.element.querySelector('.coveo-more-less'); - return delay(() => { - expect(el).toBeNull(); - }); + expect(el).toBeNull(); }); - it('should show more items when the text of the button is "Show More" and change the button text to "Show Less"', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { + it('should show more items when the text of the button is "Show More" and change the button text to "Show Less"', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator, maximumItemsShown: 10, minimumItemsShown: 5, @@ -109,7 +104,7 @@ describe('ExpandableList', () => { const el = list.element.querySelector('.coveo-more-less'); el.click(); - return delay(() => { + delay(() => { const listElement = list.element.querySelector('.coveo-list'); expect(el.innerText).toBe('Show Less'); @@ -117,8 +112,8 @@ describe('ExpandableList', () => { }); }); - it('should show less items when the text of the button is "Show Less" and change the button text to "Show More"', () => { - const list = new ExpandableList(document.createElement('div'), TEST_ITEM_LIST, { + it('should show less items when the text of the button is "Show Less" and change the button text to "Show More"', async () => { + const list = await getExpandableList(document.createElement('div'), TEST_ITEM_LIST, { transform: spanItemGenerator, maximumItemsShown: TEST_ITEM_LIST.length, minimumItemsShown: 5, @@ -128,12 +123,10 @@ describe('ExpandableList', () => { el.click(); el.click(); - return delay(() => { - const listElement = list.element.querySelector('.coveo-list'); + const listElement = list.element.querySelector('.coveo-list'); - expect(el.innerText).toBe('Show More'); - expect(listElement.childElementCount).toBe(list.options.minimumItemsShown); - }); + expect(el.innerText).toBe('Show More'); + expect(listElement.childElementCount).toBe(list.options.minimumItemsShown); }); }); }); diff --git a/tests/components/UserActions/QueryList.spec.ts b/tests/components/UserActions/QueryList.spec.ts index 13db8048..bb487ced 100644 --- a/tests/components/UserActions/QueryList.spec.ts +++ b/tests/components/UserActions/QueryList.spec.ts @@ -2,7 +2,7 @@ import { createSandbox, SinonSandbox, SinonStub } from 'sinon'; import { Mock } from 'coveo-search-ui-tests'; import { QueryList } from '../../../src/components/UserActions/QueryList'; import { UserAction } from '../../../src/models/UserProfileModel'; -import { delay, generate, fakeUserProfileModel } from '../../utils'; +import { generate, fakeUserProfileModel, waitForPromiseCompletion } from '../../utils'; import { Logger, Omnibox } from 'coveo-search-ui'; import { UserActionType } from '../../../src/rest/UserProfilingEndpoint'; @@ -31,107 +31,105 @@ describe('QueryList', () => { Logger.enable(); }); - it('should show "No queries made by this user" when no query were made', () => { + it('should show "No queries made by this user" when no query were made', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve([])); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); - return delay(() => { - const emptyElement = mock.cmp.element.querySelector('.coveo-empty'); + await waitForPromiseCompletion(); + const emptyElement = mock.cmp.element.querySelector('.coveo-empty'); - expect(emptyElement).not.toBeNull(); - expect(emptyElement.innerText).toBe('No queries made by this user'); - }); + expect(emptyElement).not.toBeNull(); + expect(emptyElement.innerText).toBe('No queries made by this user'); }); - it('should show "Recent Queries" as title', () => { + it('should show "Recent Queries" as title', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-title').innerHTML).toMatch('Recent Queries'); - }); + await waitForPromiseCompletion(); + + expect(mock.cmp.element.querySelector('.coveo-title').innerHTML).toMatch('Recent Queries'); }); - it('should show 4 queries by default', () => { + it('should show 4 queries by default', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + await waitForPromiseCompletion(); - expect(list.childElementCount).toBe(4); - }); + const list = mock.env.element.querySelector('.coveo-list'); + + expect(list.childElementCount).toBe(4); }); - it('should show a number of queries equal to the "numberOfItems" option', () => { + it('should show a number of queries equal to the "numberOfItems" option', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + await waitForPromiseCompletion(); - expect(list.childElementCount).toBe(10); - }); + const list = mock.env.element.querySelector('.coveo-list'); + + expect(list.childElementCount).toBe(10); }); - it('should display a search icon on every list item', () => { + it('should display a search icon on every list item', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + await waitForPromiseCompletion(); - for (let i = 0; i < 4; i++) { - const icon = list.children.item(i).querySelector('svg'); - expect(icon).toBeDefined; - } - }); + const list = mock.env.element.querySelector('.coveo-list'); + + for (let i = 0; i < 4; i++) { + const icon = list.children.item(i).querySelector('svg'); + expect(icon).toBeDefined; + } }); - it('should show all queries when expanded', () => { + it('should show all queries when expanded', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); - return delay(() => { - mock.env.element.querySelector('.coveo-more-less').click(); + await waitForPromiseCompletion(); - return delay(() => { - expect(mock.env.element.querySelector('.coveo-list').childElementCount).toBe(TEST_QUERIES.length); - }); - }); + mock.env.element.querySelector('.coveo-more-less').click(); + await waitForPromiseCompletion(); + + expect(mock.env.element.querySelector('.coveo-list').childElementCount).toBe(TEST_QUERIES.length); }); - it('should not show the same query twice', () => { + it('should not show the same query twice', async () => { // Setup. const SEARCH_EVENTS = [ new UserAction(UserActionType.Search, new Date(0), { query_expression: 'someQuery', origin_level_1: 'foo' }, null, 'someQuery'), @@ -146,89 +144,88 @@ describe('QueryList', () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(SEARCH_EVENTS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(SEARCH_EVENTS)); return env; }) ); + await waitForPromiseCompletion(); // Validation. - return delay(() => { - // Expand the whole list of query. - const button = mock.cmp.element.querySelector('.coveo-more-less'); - if (button) { - button.click(); - } - - const list = mock.env.element.querySelector('.coveo-list'); - expect(list.childElementCount).toBe(SORTED_AND_TRIMMED_SEARCH_EVENT.length); - - // Check that the order is respected. - SORTED_AND_TRIMMED_SEARCH_EVENT.forEach((query, i) => { - const span = list.children.item(i).querySelector('.coveo-link'); - expect(span.innerText).toBe(query); - }); + // Expand the whole list of query. + const button = mock.cmp.element.querySelector('.coveo-more-less'); + if (button) { + button.click(); + await waitForPromiseCompletion(); + } + + const list = mock.env.element.querySelector('.coveo-list'); + expect(list.childElementCount).toBe(SORTED_AND_TRIMMED_SEARCH_EVENT.length); + + // Check that the order is respected. + SORTED_AND_TRIMMED_SEARCH_EVENT.forEach((query, i) => { + const span = list.children.item(i).querySelector('.coveo-link'); + expect(span.innerText).toBe(query); }); }); - it('should render a list of queries made by a user as a list and put the most recent queries on top', () => { + it('should render a list of queries made by a user as a list and put the most recent queries on top', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); + await waitForPromiseCompletion(); const queries = TEST_QUERIES.sort(sortUserActions).reverse(); - return delay(() => { - const list = mock.env.element.querySelector('.coveo-list'); + const list = mock.env.element.querySelector('.coveo-list'); - list.childNodes.forEach((node: HTMLElement, i) => { - expect(node.innerHTML).toMatch(queries[i].query); - }); + list.childNodes.forEach((node: HTMLElement, i) => { + expect(node.innerHTML).toMatch(queries[i].query); }); }); - it('should fetch the list of query made by a user from the model', () => { + it('should fetch the list of query made by a user from the model', async () => { let model; Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { model = fakeUserProfileModel(env.root, sandbox); - model.getActions.returns(Promise.reject()); + model.getActions.callsFake(() => Promise.reject()); return env; }) ); + await waitForPromiseCompletion(); // @ts-ignore expect(model.getActions.called).toBe(true); }); - it("should log an error message when the component can't fetch the a list of query made by a user from the model", () => { + it("should log an error message when the component can't fetch the a list of query made by a user from the model", async () => { const errorLoggerStub = sandbox.stub(Logger.prototype, 'error'); const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); + await waitForPromiseCompletion(); - return delay(() => { - expect(mock.cmp.element.childElementCount).toBe(0); - expect(errorLoggerStub.called).toBe(true); - }); + expect(mock.cmp.element.childElementCount).toBe(0); + expect(errorLoggerStub.called).toBe(true); }); describe('when a user click on a query', () => { - it('should do a query in the omnibox if the search interface has an omnibox', () => { + it('should do a query in the omnibox if the search interface has an omnibox', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); @@ -240,36 +237,36 @@ describe('QueryList', () => { const executeQueryStub = sandbox.stub(mock.env.queryController, 'executeQuery'); - return delay(() => { - const item = mock.env.element.querySelector('.coveo-list .coveo-link'); - item.click(); + await waitForPromiseCompletion(); + const item = mock.env.element.querySelector('.coveo-list .coveo-link'); + item.click(); + await waitForPromiseCompletion(); - expect(setTextStub.calledWith(item.innerText)).toBe(true); + expect(setTextStub.calledWith(item.innerText)).toBe(true); - expect(executeQueryStub.called).toBe(true); - }); + expect(executeQueryStub.called).toBe(true); }); - it('should not do a query if the search interface does not have an omnibox', () => { + it('should not do a query if the search interface does not have an omnibox', async () => { const mock = Mock.advancedComponentSetup( QueryList, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', numberOfItems: 10 }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(TEST_QUERIES)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(TEST_QUERIES)); return env; }) ); + await waitForPromiseCompletion(); const executeQueryStub = sandbox.stub(mock.env.queryController, 'executeQuery'); - return delay(() => { - const item = mock.env.element.querySelector('.coveo-list .coveo-link'); - item.click(); + const item = mock.env.element.querySelector('.coveo-list .coveo-link'); + item.click(); + await waitForPromiseCompletion(); - expect(executeQueryStub.called).toBe(false); - }); + expect(executeQueryStub.called).toBe(false); }); - it('Should disable itself when the userId is falsey', () => { + it('Should disable itself when the userId is falsey', async () => { let getActionStub: SinonStub<[HTMLElement, QueryList], void>; const mock = Mock.advancedComponentSetup( QueryList, @@ -278,13 +275,13 @@ describe('QueryList', () => { return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + await waitForPromiseCompletion(); + + expect(getActionStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); - it('Should disable itself when the userId is empty string', () => { + it('Should disable itself when the userId is empty string', async () => { let getActionStub: SinonStub<[HTMLElement, QueryList], void>; const mock = Mock.advancedComponentSetup( QueryList, @@ -293,10 +290,10 @@ describe('QueryList', () => { return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + await waitForPromiseCompletion(); + + expect(getActionStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); }); }); diff --git a/tests/components/UserActions/ResponsiveUserActions.spec.ts b/tests/components/UserActions/ResponsiveUserActions.spec.ts index 98253efd..8efa944d 100644 --- a/tests/components/UserActions/ResponsiveUserActions.spec.ts +++ b/tests/components/UserActions/ResponsiveUserActions.spec.ts @@ -36,7 +36,7 @@ describe('ResponsiveUserActions', () => { const userActions = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ).cmp; @@ -62,7 +62,7 @@ describe('ResponsiveUserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); @@ -88,7 +88,7 @@ describe('ResponsiveUserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); @@ -121,7 +121,7 @@ describe('ResponsiveUserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); @@ -150,7 +150,7 @@ describe('ResponsiveUserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'someId', buttonLabel: title }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); @@ -174,7 +174,7 @@ describe('ResponsiveUserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'someId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); diff --git a/tests/components/UserActions/UserActions.spec.ts b/tests/components/UserActions/UserActions.spec.ts index ca8dafa7..77169ea8 100644 --- a/tests/components/UserActions/UserActions.spec.ts +++ b/tests/components/UserActions/UserActions.spec.ts @@ -3,7 +3,7 @@ import { UserActions } from '../../../src/components/UserActions/UserActions'; import { Logger, Initialization, QueryEvents, ResultListEvents, IQueryResult, l } from 'coveo-search-ui'; import { createSandbox, SinonSandbox, SinonStub, SinonStubbedInstance } from 'sinon'; import { UserAction, UserProfileModel } from '../../../src/models/UserProfileModel'; -import { delay, fakeUserProfileModel } from '../../utils'; +import { fakeUserProfileModel } from '../../utils'; import { ClickedDocumentList, QueryList, UserActivity } from '../../../src/Index'; import { UserActionType } from '../../../src/rest/UserProfilingEndpoint'; import { ResponsiveUserActions } from '../../../src/components/UserActions/ResponsiveUserActions'; @@ -63,15 +63,14 @@ describe('UserActions', () => { UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: '' }, (env) => { getActionStub = fakeUserProfileModel(env.root, sandbox).getActions; + getActionStub.callsFake(() => Promise.resolve()); return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(responsiveComponentStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + expect(getActionStub.called).toBe(false); + expect(responsiveComponentStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); it('should not be displayed if hidden option is true', () => { @@ -81,15 +80,13 @@ describe('UserActions', () => { Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', hidden: true }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - return delay(() => { - expect(hideSpy.called).toBe(false); - expect(responsiveComponentStub.called).toBe(false); - }); + expect(hideSpy.called).toBe(false); + expect(responsiveComponentStub.called).toBe(false); }); it('should register to the ResponsiveComponentManager by default', () => { @@ -98,14 +95,12 @@ describe('UserActions', () => { Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - return delay(() => { - expect(responsiveComponentStub.called).toBe(true); - }); + expect(responsiveComponentStub.called).toBe(true); }); it('should not register to the ResponsiveComponentManager when useResponsiveManager is false', () => { @@ -114,14 +109,12 @@ describe('UserActions', () => { Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', useResponsiveManager: false }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - return delay(() => { - expect(responsiveComponentStub.called).toBe(false); - }); + expect(responsiveComponentStub.called).toBe(false); }); it('should be collapsed by defaut', () => { @@ -130,99 +123,89 @@ describe('UserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - return delay(() => { - expect(mock.cmp.element.classList).not.toContain('coveo-user-actions-opened'); - }); + expect(mock.cmp.element.classList).not.toContain('coveo-user-actions-opened'); }); - it('should show a panel that has as title "Session Summary"', () => { + it('should show a panel that has as title "Session Summary"', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-summary .coveo-accordion-header-title').innerText).toBe('Session Summary'); - }); + expect(mock.cmp.element.querySelector('.coveo-summary .coveo-accordion-header-title').innerText).toBe('Session Summary'); }); - it('should show a summary section that have a ClickedDocumentList and a Queries component', () => { + it('should show a summary section that have a ClickedDocumentList and a Queries component', async () => { const automaticallyCreateComponentsInsideStub = sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - const summarySection = mock.cmp.element.querySelector('.coveo-summary'); + const summarySection = mock.cmp.element.querySelector('.coveo-summary'); - expect(automaticallyCreateComponentsInsideStub.called).toBe(true); - expect(summarySection.querySelector(`.Coveo${ClickedDocumentList.ID}`)).not.toBeNull(); - expect(summarySection.querySelector(`.Coveo${QueryList.ID}`)).not.toBeNull(); - }); + expect(automaticallyCreateComponentsInsideStub.called).toBe(true); + expect(summarySection.querySelector(`.Coveo${ClickedDocumentList.ID}`)).not.toBeNull(); + expect(summarySection.querySelector(`.Coveo${QueryList.ID}`)).not.toBeNull(); }); - it('should show a user activity section that have a UserActivity component', () => { + it('should show a user activity section that have a UserActivity component', async () => { const automaticallyCreateComponentsInsideStub = sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - const detailSection = mock.cmp.element.querySelector('.coveo-details'); + const detailSection = mock.cmp.element.querySelector('.coveo-details'); - expect(automaticallyCreateComponentsInsideStub.called).toBe(true); - expect(detailSection.querySelector('.coveo-accordion-header-title').innerText).toBe("User's Recent Activity"); - expect(detailSection.querySelector('.CoveoUserActivity')).not.toBeNull(); - }); + expect(automaticallyCreateComponentsInsideStub.called).toBe(true); + expect(detailSection.querySelector('.coveo-accordion-header-title').innerText).toBe("User's Recent Activity"); + expect(detailSection.querySelector('.CoveoUserActivity')).not.toBeNull(); }); - it('should pass the user id option to each of it sub components', () => { + it('should pass the user id option to each of it sub components', async () => { const FAKE_USER_ID = 'someUserId' + Math.random(); const automaticallyCreateComponentsInsideStub = sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); - Mock.advancedComponentSetup( + await Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: FAKE_USER_ID }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ).cmp.show(); - return delay(() => { - expect(automaticallyCreateComponentsInsideStub.called).toBe(true); + expect(automaticallyCreateComponentsInsideStub.called).toBe(true); - [ClickedDocumentList.ID, QueryList.ID, UserActivity.ID].forEach((component) => { - expect(automaticallyCreateComponentsInsideStub.args[0][1].options[component]).toBeDefined(); - expect(automaticallyCreateComponentsInsideStub.args[0][1].options[component].userId).toBe(FAKE_USER_ID); - }); + [ClickedDocumentList.ID, QueryList.ID, UserActivity.ID].forEach((component) => { + expect(automaticallyCreateComponentsInsideStub.args[0][1].options[component]).toBeDefined(); + expect(automaticallyCreateComponentsInsideStub.args[0][1].options[component].userId).toBe(FAKE_USER_ID); }); }); - it('should pass custom init options to each of the sub components', () => { + it('should pass custom init options to each of the sub components', async () => { const FAKE_USER_ID = 'someUserId' + Math.random(); const initOptions = { QueryList: { @@ -245,191 +228,173 @@ describe('UserActions', () => { const component: UserActions = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: FAKE_USER_ID }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ).cmp; component.searchInterface.options.originalOptionsObject = initOptions; - component.show(); + await component.show(); - return delay(() => { - expect(automaticallyCreateComponentsInsideStub.called).toBe(true); + expect(automaticallyCreateComponentsInsideStub.called).toBe(true); - const actualInitOptions = automaticallyCreateComponentsInsideStub.args[0][1].options; + const actualInitOptions = automaticallyCreateComponentsInsideStub.args[0][1].options; - [QueryList.ID, ClickedDocumentList.ID, UserActivity.ID].forEach((component) => { - const actualComponentOptions = actualInitOptions[component]; - expect(actualComponentOptions).toBeDefined(); - expect(actualComponentOptions).toEqual(jasmine.objectContaining(initOptions[component])); - }); + [QueryList.ID, ClickedDocumentList.ID, UserActivity.ID].forEach((component) => { + const actualComponentOptions = actualInitOptions[component]; + expect(actualComponentOptions).toBeDefined(); + expect(actualComponentOptions).toEqual(jasmine.objectContaining(initOptions[component])); }); }); - it('should collapse itself whenever a query is made', () => { + it('should collapse itself whenever a query is made', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); - const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - mock.cmp.show(); - const hideSpy = sandbox.spy(mock.cmp, 'hide'); + await mock.cmp.show(); mock.env.root.dispatchEvent(new CustomEvent(QueryEvents.newQuery)); expect(hideSpy.called).toBe(true); }); - it('should show a message when user actions is not enabled', () => { + it('should show a message when user actions is not enabled', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject({ statusCode: 404 })); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject({ statusCode: 404 })); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-enable-prompt')).not.toBeNull(); - expect(mock.cmp.element.querySelector('.coveo-enable-prompt').innerText).toBe( - l(`${UserActions.ID}_enable_prompt`).replace('\n', '') - ); - }); + expect(mock.cmp.element.querySelector('.coveo-enable-prompt')).not.toBeNull(); + expect(mock.cmp.element.querySelector('.coveo-enable-prompt').innerText).toBe( + l(`${UserActions.ID}_enable_prompt`).replace('\n', '') + ); }); - it('should show a message when no actions are available', () => { + it('should show a message when no actions are available', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve([])); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-no-actions')).not.toBeNull(); - expect(mock.cmp.element.querySelector('.coveo-no-actions').innerText).toBe(l(`${UserActions.ID}_no_actions`)); - }); + expect(mock.cmp.element.querySelector('.coveo-no-actions')).not.toBeNull(); + expect(mock.cmp.element.querySelector('.coveo-no-actions').innerText).toBe(l(`${UserActions.ID}_no_actions`)); }); - it('should show a message when actions cannot be gathered', () => { + it('should show a message when actions cannot be gathered', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.reject()); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.reject()); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - expect(mock.cmp.element.querySelector('.coveo-no-actions').innerText).toBe(l(`${UserActions.ID}_no_actions`)); - }); + expect(mock.cmp.element.querySelector('.coveo-no-actions').innerText).toBe(l(`${UserActions.ID}_no_actions`)); }); describe('when the accordion header is clicked', () => { - it('should fold the accordion section when the accordion section is open', () => { + it('should fold the accordion section when the accordion section is open', async () => { const automaticallyCreateComponentsInsideStub = sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - const accordionSections = mock.cmp.element.querySelectorAll('.coveo-accordion'); - expect(automaticallyCreateComponentsInsideStub.called).toBe(true); + const accordionSections = mock.cmp.element.querySelectorAll('.coveo-accordion'); + expect(automaticallyCreateComponentsInsideStub.called).toBe(true); - accordionSections.forEach((el) => { - el.classList.remove('coveo-folded'); - el.querySelector('.coveo-accordion-header').click(); - expect(el.classList).toContain('coveo-folded'); - }); + accordionSections.forEach((el) => { + el.classList.remove('coveo-folded'); + el.querySelector('.coveo-accordion-header').click(); + expect(el.classList).toContain('coveo-folded'); }); }); - it('should unfold the accordion section when the accordion section is closed', () => { + it('should unfold the accordion section when the accordion section is closed', async () => { const automaticallyCreateComponentsInsideStub = sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS)); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve(ACTIONS)); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - const accordionSections = mock.cmp.element.querySelectorAll('.coveo-accordion'); + const accordionSections = mock.cmp.element.querySelectorAll('.coveo-accordion'); - expect(automaticallyCreateComponentsInsideStub.called).toBe(true); + expect(automaticallyCreateComponentsInsideStub.called).toBe(true); - accordionSections.forEach((el) => { - el.classList.add('coveo-folded'); - el.querySelector('.coveo-accordion-header').click(); - expect(el.classList).not.toContain('coveo-folded'); - }); + accordionSections.forEach((el) => { + el.classList.add('coveo-folded'); + el.querySelector('.coveo-accordion-header').click(); + expect(el.classList).not.toContain('coveo-folded'); }); }); }); describe('toggle', () => { - it('should open the panel if its not already opened', () => { + it('should open the panel if its not already opened', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); mock.cmp.hide(); - mock.cmp.toggle(); + await mock.cmp.toggle(); - return delay(() => { - expect(mock.cmp.root.className).toMatch('coveo-user-actions-opened'); - }); + expect(mock.cmp.root.className).toMatch('coveo-user-actions-opened'); }); - it('should collapse the panel if the panel is already opened', () => { + it('should collapse the panel if the panel is already opened', async () => { sandbox.stub(Initialization, 'automaticallyCreateComponentsInside'); const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); - mock.cmp.show(); + await mock.cmp.show(); - mock.cmp.toggle(); + await mock.cmp.toggle(); - return delay(() => { - expect(mock.cmp.root.className).not.toMatch('coveo-user-actions-opened'); - }); + expect(mock.cmp.root.className).not.toMatch('coveo-user-actions-opened'); }); }); @@ -445,7 +410,7 @@ describe('UserActions', () => { UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: someUserId }, (env) => { modelMock = fakeUserProfileModel(env.root, sandbox); - modelMock.getActions.returns(new Promise(() => {})); + modelMock.getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -453,45 +418,41 @@ describe('UserActions', () => { sandbox.resetHistory(); }); - it('should open the panel if it is not already opened', () => { + it('should open the panel if it is not already opened', async () => { mock.cmp.hide(); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - expect(mock.cmp.root.className).toMatch('coveo-user-actions-opened'); - }); + expect(mock.cmp.root.className).toMatch('coveo-user-actions-opened'); }); - it('should do nothing if the panel is already opened', () => { - mock.cmp.show(); + it('should do nothing if the panel is already opened', async () => { + await mock.cmp.show(); const domMutation = sandbox.stub(); const observer = new MutationObserver(domMutation); observer.observe(mock.cmp.element, { childList: true, subtree: true, attributes: true }); - mock.cmp.show(); + await mock.cmp.show(); - return delay(() => { - expect(domMutation.called).toBe(false); - expect(mock.cmp.root.className).toMatch('coveo-user-actions-opened'); - }).finally(() => { - observer.disconnect(); - }); + expect(domMutation.called).toBe(false); + expect(mock.cmp.root.className).toMatch('coveo-user-actions-opened'); + + observer.disconnect(); }); - it('should fetch all user actions', () => { - mock.cmp.show(); + it('should fetch all user actions', async function () { + await mock.cmp.show(); - return delay(() => { - expect(modelMock.getActions.calledWithExactly(someUserId)).toBe(true); - }); + expect(modelMock.getActions.calledWithExactly(someUserId)).toBe(true); }); - it('should trigger a userActionsShow event', () => { + it('should trigger a userActionsShow event', async () => { const spyDispatchEvent = sandbox.spy(mock.cmp.element, 'dispatchEvent'); - mock.cmp.show(); + await mock.cmp.show(); - expect(spyDispatchEvent.calledOnceWith(new CustomEvent('userActionsPanelHide'))); + expect(spyDispatchEvent.calledOnce); + expect(spyDispatchEvent.firstCall.args.length).toBe(1); + expect(spyDispatchEvent.firstCall.args[0].type).toBe('userActionsPanelShow'); }); }); @@ -507,7 +468,7 @@ describe('UserActions', () => { UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: someUserId }, (env) => { modelMock = fakeUserProfileModel(env.root, sandbox); - modelMock.getActions.returns(new Promise(() => {})); + modelMock.getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -515,13 +476,11 @@ describe('UserActions', () => { sandbox.resetHistory(); }); - it('should collapse the panel if the panel is opened', () => { - mock.cmp.show(); + it('should collapse the panel if the panel is opened', async () => { + await mock.cmp.show(); mock.cmp.hide(); - return delay(() => { - expect(mock.cmp.root.className).not.toMatch('coveo-user-actions-opened'); - }); + expect(mock.cmp.root.className).not.toMatch('coveo-user-actions-opened'); }); it('should do nothing if the panel is not opened', () => { @@ -535,30 +494,29 @@ describe('UserActions', () => { mock.cmp.hide(); // Tests. - return delay(() => { - expect(domMutation.called).toBe(false); - expect(mock.cmp.root.className).not.toMatch('coveo-user-actions-opened'); - }).finally(() => { - observer.disconnect(); - }); + + expect(domMutation.called).toBe(false); + expect(mock.cmp.root.className).not.toMatch('coveo-user-actions-opened'); + + observer.disconnect(); }); - it('should remove all user actions', () => { - mock.cmp.show(); + it('should remove all user actions', async () => { + await mock.cmp.show(); mock.cmp.hide(); - return delay(() => { - expect(modelMock.deleteActions.calledWithExactly(someUserId)).toBe(true); - }); + expect(modelMock.deleteActions.calledWithExactly(someUserId)).toBe(true); }); - it('should trigger a userActionsHide event', () => { - mock.cmp.show(); + it('should trigger a userActionsHide event', async () => { + await mock.cmp.show(); const spyDispatchEvent = sandbox.spy(mock.cmp.element, 'dispatchEvent'); mock.cmp.hide(); - expect(spyDispatchEvent.calledOnceWith(new CustomEvent('userActionsPanelHide'))); + expect(spyDispatchEvent.calledOnce); + expect(spyDispatchEvent.firstCall.args.length).toBe(1); + expect(spyDispatchEvent.firstCall.args[0].type).toBe('userActionsPanelHide'); }); }); @@ -567,7 +525,7 @@ describe('UserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -577,16 +535,14 @@ describe('UserActions', () => { const queryArgs = { e: 'error', args: queryData }; Coveo.$$(mock.env.root).trigger('buildingQuery', queryArgs); - return delay(() => { - expect(queryData.queryBuilder.userActions.tagViewsOfUser).toBe('testUserId'); - }); + expect(queryData.queryBuilder.userActions.tagViewsOfUser).toBe('testUserId'); }); it('should catch error', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', record: undefined }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -596,9 +552,7 @@ describe('UserActions', () => { const queryArgs = { e: 'error', args: queryData }; Coveo.$$(mock.env.root).trigger('buildingQuery', queryArgs); - return delay(() => { - expect(loggerSpy.called).toBe(true); - }); + expect(loggerSpy.called).toBe(true); }); }); @@ -647,7 +601,7 @@ describe('UserActions', () => { UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', viewedByCustomer: viewedByCustomerOption }, (env) => { setResultList(env.root, 'card'); - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -655,10 +609,8 @@ describe('UserActions', () => { const resultArgs = { result: result, item: resultElementFrame }; Coveo.$$(mock.env.root).trigger(ResultListEvents.newResultDisplayed, resultArgs); - return delay(() => { - expect(mock.cmp.options.viewedByCustomer).toBe(true); - expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); - }); + expect(mock.cmp.options.viewedByCustomer).toBe(true); + expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); }); it('should add a ViewedByCustomer Component when the result list layout is list', () => { @@ -666,7 +618,7 @@ describe('UserActions', () => { UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', viewedByCustomer: viewedByCustomerOption }, (env) => { setResultList(env.root, 'list'); - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -674,10 +626,8 @@ describe('UserActions', () => { const resultArgs = { result: result, item: resultElementFrame }; Coveo.$$(mock.env.root).trigger(ResultListEvents.newResultDisplayed, resultArgs); - return delay(() => { - expect(mock.cmp.options.viewedByCustomer).toBe(true); - expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); - }); + expect(mock.cmp.options.viewedByCustomer).toBe(true); + expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); }); it('should not add a ViewedByCustomer Component when the result list layout is table', () => { @@ -685,7 +635,7 @@ describe('UserActions', () => { UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', viewedByCustomer: viewedByCustomerOption }, (env) => { setResultList(env.root, 'table'); - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -693,17 +643,15 @@ describe('UserActions', () => { const resultArgs = { result: result, item: resultElementFrame }; Coveo.$$(mock.env.root).trigger(ResultListEvents.newResultDisplayed, resultArgs); - return delay(() => { - expect(mock.cmp.options.viewedByCustomer).toBe(true); - expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(0); - }); + expect(mock.cmp.options.viewedByCustomer).toBe(true); + expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(0); }); it('It should not add a viewedByCustomer if one is already there', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', viewedByCustomer: viewedByCustomerOption }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -713,9 +661,7 @@ describe('UserActions', () => { const resultArgs = { result: result, item: resultElementFrame }; Coveo.$$(mock.env.root).trigger(ResultListEvents.newResultDisplayed, resultArgs); - return delay(() => { - expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); - }); + expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); }); }); @@ -728,7 +674,7 @@ describe('UserActions', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', viewedByCustomer: viewedByCustomerOption }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -736,17 +682,15 @@ describe('UserActions', () => { const resultArgs = { result: result, item: resultElementFrame }; Coveo.$$(mock.env.root).trigger(ResultListEvents.newResultDisplayed, resultArgs); - return delay(() => { - expect(mock.cmp.options.viewedByCustomer).toBe(false); - expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(0); - }); + expect(mock.cmp.options.viewedByCustomer).toBe(false); + expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(0); }); it('It should not add a viewedByCustomer if one is already there', () => { const mock = Mock.advancedComponentSetup( UserActions, new Mock.AdvancedComponentSetupOptions(null, { userId: 'testUserId', viewedByCustomer: viewedByCustomerOption }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(new Promise(() => {})); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => Promise.resolve([])); return env; }) ); @@ -758,9 +702,7 @@ describe('UserActions', () => { const resultArgs = { result: result, item: resultElementFrame }; Coveo.$$(mock.env.root).trigger(ResultListEvents.newResultDisplayed, resultArgs); - return delay(() => { - expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); - }); + expect(resultElementFrame.getElementsByClassName('CoveoViewedByCustomer').length).toBe(1); }); }); }); diff --git a/tests/components/UserActions/UserActivity.spec.ts b/tests/components/UserActions/UserActivity.spec.ts index 947b5983..14672433 100644 --- a/tests/components/UserActions/UserActivity.spec.ts +++ b/tests/components/UserActions/UserActivity.spec.ts @@ -3,8 +3,9 @@ import { UserAction } from '../../../src/models/UserProfileModel'; import { Mock, Fake } from 'coveo-search-ui-tests'; import { UserActionType } from '../../../src/rest/UserProfilingEndpoint'; import { UserActivity } from '../../../src/Index'; -import { delay, fakeUserProfileModel } from '../../utils'; +import { fakeUserProfileModel } from '../../utils'; import { formatDate, formatTime, formatDateAndTime, formatDateAndTimeShort, formatTimeInterval } from '../../../src/utils/time'; + describe('UserActivity', () => { const TEST_DATE_STRING = 'December 17, 1995 1:00:00 AM'; const ACTIVITY_SELECTOR = '.coveo-activity'; @@ -89,17 +90,22 @@ describe('UserActivity', () => { }), ]; - const getMockComponent = (returnedActions: UserAction | UserAction[]) => { - return Mock.advancedComponentSetup( + const getMockComponent = async (returnedActions: UserAction | UserAction[], element = document.createElement('div')) => { + const mock = Mock.advancedComponentSetup( UserActivity, - new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, (env) => { - fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(returnedActions)); + new Mock.AdvancedComponentSetupOptions(element, { userId: 'testuserId' }, (env) => { + env.element = element; + getActionsPromise = Promise.resolve(returnedActions); + fakeUserProfileModel(env.root, sandbox).getActions.callsFake(() => getActionsPromise); return env; }) ); + await getActionsPromise; + return mock; }; let sandbox: SinonSandbox; + let getActionsPromise: Promise; beforeAll(() => { sandbox = createSandbox(); @@ -109,77 +115,65 @@ describe('UserActivity', () => { sandbox.restore(); }); - it('should show the starting date and time of the user action session', () => { - const mock = getMockComponent(FAKE_USER_ACTIONS); + it('should show the starting date and time of the user action session', async () => { + const mock = await getMockComponent(FAKE_USER_ACTIONS); const timestamps = FAKE_USER_ACTIONS.map((action) => action.timestamp).sort(); - return delay(() => { - const firstAction = timestamps[0]; + const firstAction = timestamps[0]; - expect(mock.cmp.element.innerHTML).toMatch(formatDate(firstAction)); - expect(mock.cmp.element.innerHTML).toMatch(formatTime(firstAction)); - }); + expect(mock.cmp.element.innerHTML).toMatch(formatDate(firstAction)); + expect(mock.cmp.element.innerHTML).toMatch(formatTime(firstAction)); }); - it('should duration of the user action session', () => { - const mock = getMockComponent(FAKE_USER_ACTIONS); + it('should duration of the user action session', async () => { + const mock = await getMockComponent(FAKE_USER_ACTIONS); const timestamps = FAKE_USER_ACTIONS.map((action) => action.timestamp).sort(); - return delay(() => { - expect(mock.cmp.element.innerHTML).toMatch(formatTimeInterval(timestamps[timestamps.length - 1].getTime() - timestamps[0].getTime())); - }); + expect(mock.cmp.element.innerHTML).toMatch(formatTimeInterval(timestamps[timestamps.length - 1].getTime() - timestamps[0].getTime())); }); - it('should fold each actions that are tagged as not meaningful', () => { - const mock = getMockComponent([...FAKE_USER_ACTIONS, ...IRRELEVANT_ACTIONS]); + it('should fold each actions that are tagged as not meaningful', async () => { + const mock = await getMockComponent([...FAKE_USER_ACTIONS, ...IRRELEVANT_ACTIONS]); - return delay(() => { - IRRELEVANT_ACTIONS.forEach((action) => { - expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).not.toMatch(action.raw.origin_level_1); - }); + IRRELEVANT_ACTIONS.forEach((action) => { + expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).not.toMatch(action.raw.origin_level_1); }); }); - it('should show each actions that are tagged as meaningful', () => { - const mock = getMockComponent([...FAKE_USER_ACTIONS, ...IRRELEVANT_ACTIONS]); + it('should show each actions that are tagged as meaningful', async () => { + const mock = await getMockComponent([...FAKE_USER_ACTIONS, ...IRRELEVANT_ACTIONS]); - return delay(() => { - FAKE_USER_ACTIONS.forEach((action) => { - expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).toMatch(action.raw.origin_level_1); - }); + FAKE_USER_ACTIONS.forEach((action) => { + expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).toMatch(action.raw.origin_level_1); }); }); - it('should show all actions when no action are tagged as meaningful', () => { - const mock = getMockComponent(IRRELEVANT_ACTIONS); + it('should show all actions when no action are tagged as meaningful', async () => { + const mock = await getMockComponent(IRRELEVANT_ACTIONS); - return delay(() => { - IRRELEVANT_ACTIONS.forEach((action) => { - expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).toMatch(action.raw.origin_level_1); - }); + IRRELEVANT_ACTIONS.forEach((action) => { + expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).toMatch(action.raw.origin_level_1); }); }); describe('folded events', () => { - it('should unfold on click', () => { - const mock = getMockComponent([...FAKE_USER_ACTIONS, ...IRRELEVANT_ACTIONS]); + it('should unfold on click', async () => { + const mock = await getMockComponent([...FAKE_USER_ACTIONS, ...IRRELEVANT_ACTIONS]); - return delay(() => { - const folded = mock.cmp.element.querySelector('.coveo-folded'); + const folded = mock.cmp.element.querySelector('.coveo-folded'); - expect(folded).not.toBeNull(); - folded.click(); - IRRELEVANT_ACTIONS.forEach((action) => { - expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).toMatch(action.raw.origin_level_1); - }); + expect(folded).not.toBeNull(); + folded.click(); + IRRELEVANT_ACTIONS.forEach((action) => { + expect(mock.cmp.element.querySelector(ACTIVITY_SELECTOR).innerHTML).toMatch(action.raw.origin_level_1); }); }); }); describe('search event', () => { ['omniboxAnalytics', 'userActionsSubmit', 'omniboxFromLink', 'searchboxAsYouType', 'searchboxSubmit', 'searchFromLink'].map((cause) => { - it(`should display the "User Query" as event title when there is a query expression and the cause is ${cause}`, () => { - const mock = getMockComponent([ + it(`should display the "User Query" as event title when there is a query expression and the cause is ${cause}`, async () => { + const mock = await getMockComponent([ new UserAction(UserActionType.Search, new Date(TEST_DATE_STRING), { origin_level_1: 'relevant' + Math.random(), query_expression: 'someSearch' + Math.random(), @@ -187,279 +181,259 @@ describe('UserActivity', () => { }), ]); - return delay(async () => { - const clickElement = mock.cmp.element.querySelector('.coveo-search'); + const clickElement = mock.cmp.element.querySelector('.coveo-search'); - const action = await mock.cmp['userProfileModel'].getActions(''); + const action = await mock.cmp['userProfileModel'].getActions(''); - expect(action[0].raw.cause).toBe(cause); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('User Query'); - }); + expect(action[0].raw.cause).toBe(cause); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('User Query'); }); }); - it('should display the "Query" as event title', () => { - const mock = getMockComponent([FAKE_SEARCH_EVENT]); + it('should display the "Query" as event title', async () => { + const mock = await getMockComponent([FAKE_SEARCH_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-search'); + const clickElement = mock.cmp.element.querySelector('.coveo-search'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Query'); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Query'); }); - it('should display the query made by the user as event data', () => { - const mock = getMockComponent([FAKE_USER_SEARCH_EVENT]); + it('should display the query made by the user as event data', async () => { + const mock = await getMockComponent([FAKE_USER_SEARCH_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-search'); + const clickElement = mock.cmp.element.querySelector('.coveo-search'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector('.coveo-data').innerText).toBe(FAKE_USER_SEARCH_EVENT.query); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector('.coveo-data').innerText).toBe(FAKE_USER_SEARCH_EVENT.query); }); - it('should display the time of the event', () => { - const mock = getMockComponent([FAKE_SEARCH_EVENT]); + it('should display the time of the event', async () => { + const mock = await getMockComponent([FAKE_SEARCH_EVENT]); - return delay(() => { - const searchElement = mock.cmp.element.querySelector('.coveo-search'); + const searchElement = mock.cmp.element.querySelector('.coveo-search'); - expect(searchElement).not.toBeNull(); - expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTimeShort(FAKE_SEARCH_EVENT.timestamp) - ); - }); + expect(searchElement).not.toBeNull(); + expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTimeShort(FAKE_SEARCH_EVENT.timestamp) + ); }); - it('should display the time of the event in long format if in a wider interface', () => { - const mock = getMockComponent([FAKE_SEARCH_EVENT]); - - Object.defineProperty(mock.cmp.element, 'offsetWidth', { value: 500 }); + it('should display the time of the event in long format if in a wider interface', async () => { + const element = document.createElement('div'); + Object.defineProperties(element, { + offsetWidth: { + get() { + return '500'; + }, + }, + }); - return delay(() => { - const searchElement = mock.cmp.element.querySelector('.coveo-search'); + const mock = await getMockComponent([FAKE_SEARCH_EVENT], element); - expect(searchElement).not.toBeNull(); - expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTime(FAKE_SEARCH_EVENT.timestamp) - ); - }); + const searchElement = mock.cmp.element.querySelector('.coveo-search'); + expect(searchElement).not.toBeNull(); + expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTime(FAKE_SEARCH_EVENT.timestamp) + ); }); - it('should display the originLevel1 as event footer', () => { - const mock = getMockComponent([FAKE_SEARCH_EVENT]); + it('should display the originLevel1 as event footer', async () => { + const mock = await getMockComponent([FAKE_SEARCH_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-search'); + const clickElement = mock.cmp.element.querySelector('.coveo-search'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_SEARCH_EVENT.raw.origin_level_1); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_SEARCH_EVENT.raw.origin_level_1); }); }); describe('click event', () => { - it('should display the "Clicked Document" as event title', () => { - const mock = getMockComponent([FAKE_CLICK_EVENT]); + it('should display the "Clicked Document" as event title', async () => { + const mock = await getMockComponent([FAKE_CLICK_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-click'); + const clickElement = mock.cmp.element.querySelector('.coveo-click'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Clicked Document'); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Clicked Document'); }); - it('should display a link to the clicked document as event data', () => { - const mock = getMockComponent([FAKE_CLICK_EVENT]); + it('should display a link to the clicked document as event data', async () => { + const mock = await getMockComponent([FAKE_CLICK_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-click'); + const clickElement = mock.cmp.element.querySelector('.coveo-click'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector('.coveo-data') instanceof HTMLAnchorElement).toBe(true); - expect(clickElement.querySelector('.coveo-data').innerText).toBe(FAKE_CLICK_EVENT.document.title); - expect(clickElement.querySelector('.coveo-data').href).toMatch(FAKE_CLICK_EVENT.document.clickUri); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector('.coveo-data') instanceof HTMLAnchorElement).toBe(true); + expect(clickElement.querySelector('.coveo-data').innerText).toBe(FAKE_CLICK_EVENT.document.title); + expect(clickElement.querySelector('.coveo-data').href).toMatch(FAKE_CLICK_EVENT.document.clickUri); }); - it('should display the time of the event', () => { - const mock = getMockComponent([FAKE_CLICK_EVENT]); + it('should display the time of the event', async () => { + const mock = await getMockComponent([FAKE_CLICK_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-click'); + const clickElement = mock.cmp.element.querySelector('.coveo-click'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTimeShort(FAKE_CLICK_EVENT.timestamp) - ); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTimeShort(FAKE_CLICK_EVENT.timestamp) + ); }); - it('should display the time of the event in long format if in a wider interface', () => { - const mock = getMockComponent([FAKE_CLICK_EVENT]); - - Object.defineProperty(mock.cmp.element, 'offsetWidth', { value: 500 }); + it('should display the time of the event in long format if in a wider interface', async () => { + const element = document.createElement('div'); + Object.defineProperties(element, { + offsetWidth: { + get() { + return '500'; + }, + }, + }); - return delay(() => { - const searchElement = mock.cmp.element.querySelector('.coveo-click'); + const mock = await getMockComponent([FAKE_CLICK_EVENT], element); - expect(searchElement).not.toBeNull(); - expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTime(FAKE_CLICK_EVENT.timestamp) - ); - }); + const searchElement = mock.cmp.element.querySelector('.coveo-click'); + expect(searchElement).not.toBeNull(); + expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTime(FAKE_CLICK_EVENT.timestamp) + ); }); - it('should display the originLevel1 as event footer', () => { - const mock = getMockComponent([FAKE_CLICK_EVENT]); + it('should display the originLevel1 as event footer', async () => { + const mock = await getMockComponent([FAKE_CLICK_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-click'); + const clickElement = mock.cmp.element.querySelector('.coveo-click'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_CLICK_EVENT.raw.origin_level_1); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_CLICK_EVENT.raw.origin_level_1); }); }); describe('page view event', () => { - it('should display the "Page View" as event title', () => { - const mock = getMockComponent([FAKE_VIEW_EVENT]); + it('should display the "Page View" as event title', async () => { + const mock = await getMockComponent([FAKE_VIEW_EVENT]); - return delay(() => { - const viewElement = mock.cmp.element.querySelector('.coveo-view'); + const viewElement = mock.cmp.element.querySelector('.coveo-view'); - expect(viewElement).not.toBeNull(); - expect(viewElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Page View'); - }); + expect(viewElement).not.toBeNull(); + expect(viewElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Page View'); }); - it('should display the content id key and value as event data', () => { - const mock = getMockComponent([FAKE_VIEW_EVENT]); + it('should display the content id key and value as event data', async () => { + const mock = await getMockComponent([FAKE_VIEW_EVENT]); - return delay(() => { - const viewElement = mock.cmp.element.querySelector('.coveo-view'); + const viewElement = mock.cmp.element.querySelector('.coveo-view'); - expect(viewElement).not.toBeNull(); - expect(viewElement.querySelector('.coveo-data').innerText).toMatch(FAKE_VIEW_EVENT.raw.content_id_key); - expect(viewElement.querySelector('.coveo-data').innerText).toMatch(FAKE_VIEW_EVENT.raw.content_id_value); - }); + expect(viewElement).not.toBeNull(); + expect(viewElement.querySelector('.coveo-data').innerText).toMatch(FAKE_VIEW_EVENT.raw.content_id_key); + expect(viewElement.querySelector('.coveo-data').innerText).toMatch(FAKE_VIEW_EVENT.raw.content_id_value); }); - it('should display the time of the event', () => { - const mock = getMockComponent([FAKE_VIEW_EVENT]); + it('should display the time of the event', async () => { + const mock = await getMockComponent([FAKE_VIEW_EVENT]); - return delay(() => { - const viewElement = mock.cmp.element.querySelector('.coveo-view'); + const viewElement = mock.cmp.element.querySelector('.coveo-view'); - expect(viewElement).not.toBeNull(); - expect(viewElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTimeShort(FAKE_VIEW_EVENT.timestamp) - ); - }); + expect(viewElement).not.toBeNull(); + expect(viewElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTimeShort(FAKE_VIEW_EVENT.timestamp) + ); }); - it('should display the time of the event in long format if in a wider interface', () => { - const mock = getMockComponent([FAKE_VIEW_EVENT]); - - Object.defineProperty(mock.cmp.element, 'offsetWidth', { value: 500 }); + it('should display the time of the event in long format if in a wider interface', async () => { + const element = document.createElement('div'); + Object.defineProperties(element, { + offsetWidth: { + get() { + return '500'; + }, + }, + }); - return delay(() => { - const searchElement = mock.cmp.element.querySelector('.coveo-view'); + const mock = await getMockComponent([FAKE_VIEW_EVENT], element); - expect(searchElement).not.toBeNull(); - expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTime(FAKE_VIEW_EVENT.timestamp) - ); - }); + const searchElement = mock.cmp.element.querySelector('.coveo-view'); + expect(searchElement).not.toBeNull(); + expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTime(FAKE_VIEW_EVENT.timestamp) + ); }); - it('should display the originLevel1 as event footer', () => { - const mock = getMockComponent([FAKE_VIEW_EVENT]); + it('should display the originLevel1 as event footer', async () => { + const mock = await getMockComponent([FAKE_VIEW_EVENT]); - return delay(() => { - const viewElement = mock.cmp.element.querySelector('.coveo-view'); + const viewElement = mock.cmp.element.querySelector('.coveo-view'); - expect(viewElement).not.toBeNull(); - expect(viewElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_VIEW_EVENT.raw.origin_level_1); - }); + expect(viewElement).not.toBeNull(); + expect(viewElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_VIEW_EVENT.raw.origin_level_1); }); }); describe('custom event', () => { - it('should display the event type as event title', () => { - const mock = getMockComponent([FAKE_CUSTOM_EVENT]); + it('should display the event type as event title', async () => { + const mock = await getMockComponent([FAKE_CUSTOM_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-custom'); + const clickElement = mock.cmp.element.querySelector('.coveo-custom'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe(FAKE_CUSTOM_EVENT.raw.event_type); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe(FAKE_CUSTOM_EVENT.raw.event_type); }); - it('should display "Custom Action" as event title when the event type is unavailable', () => { - const mock = getMockComponent([FAKE_CUSTOM_EVENT_WITHOUT_TYPE]); + it('should display "Custom Action" as event title when the event type is unavailable', async () => { + const mock = await getMockComponent([FAKE_CUSTOM_EVENT_WITHOUT_TYPE]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-custom'); + const clickElement = mock.cmp.element.querySelector('.coveo-custom'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Custom Action'); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVITY_TITLE_SELECTOR).innerText).toBe('Custom Action'); }); - it('should display the event value as event data', () => { - const mock = getMockComponent([FAKE_CUSTOM_EVENT]); + it('should display the event value as event data', async () => { + const mock = await getMockComponent([FAKE_CUSTOM_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-custom'); + const clickElement = mock.cmp.element.querySelector('.coveo-custom'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector('.coveo-data').innerText).toBe(FAKE_CUSTOM_EVENT.raw.event_value); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector('.coveo-data').innerText).toBe(FAKE_CUSTOM_EVENT.raw.event_value); }); - it('should display the time of the event', () => { - const mock = getMockComponent([FAKE_CUSTOM_EVENT]); + it('should display the time of the event', async () => { + const mock = await getMockComponent([FAKE_CUSTOM_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-custom'); + const clickElement = mock.cmp.element.querySelector('.coveo-custom'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTimeShort(FAKE_CUSTOM_EVENT.timestamp) - ); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTimeShort(FAKE_CUSTOM_EVENT.timestamp) + ); }); - it('should display the time of the event in long format if in a wider interface', () => { - const mock = getMockComponent([FAKE_CUSTOM_EVENT]); - - Object.defineProperty(mock.cmp.element, 'offsetWidth', { value: 500 }); + it('should display the time of the event in long format if in a wider interface', async () => { + const element = document.createElement('div'); + Object.defineProperties(element, { + offsetWidth: { + get() { + return '500'; + }, + }, + }); - return delay(() => { - const searchElement = mock.cmp.element.querySelector('.coveo-custom'); + const mock = await getMockComponent([FAKE_CUSTOM_EVENT], element); - expect(searchElement).not.toBeNull(); - expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( - formatDateAndTime(FAKE_CUSTOM_EVENT.timestamp) - ); - }); + const searchElement = mock.cmp.element.querySelector('.coveo-custom'); + expect(searchElement).not.toBeNull(); + expect(searchElement.querySelector(ACTIVIY_TIMESTAMP_SELECTOR).innerText).toMatch( + formatDateAndTime(FAKE_CUSTOM_EVENT.timestamp) + ); }); - it('should display the originLevel1 as event footer', () => { - const mock = getMockComponent([FAKE_CUSTOM_EVENT]); + it('should display the originLevel1 as event footer', async () => { + const mock = await getMockComponent([FAKE_CUSTOM_EVENT]); - return delay(() => { - const clickElement = mock.cmp.element.querySelector('.coveo-custom'); + const clickElement = mock.cmp.element.querySelector('.coveo-custom'); - expect(clickElement).not.toBeNull(); - expect(clickElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_CUSTOM_EVENT.raw.origin_level_1); - }); + expect(clickElement).not.toBeNull(); + expect(clickElement.querySelector('.coveo-footer').innerText).toMatch(FAKE_CUSTOM_EVENT.raw.origin_level_1); }); it('Should disable itself when the userId is falsey', () => { @@ -471,10 +445,9 @@ describe('UserActivity', () => { return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + + expect(getActionStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); it('Should disable itself when the userId is empty string', () => { @@ -486,10 +459,9 @@ describe('UserActivity', () => { return env; }) ); - return delay(() => { - expect(getActionStub.called).toBe(false); - expect(mock.cmp.disabled).toBe(true); - }); + + expect(getActionStub.called).toBe(false); + expect(mock.cmp.disabled).toBe(true); }); }); }); diff --git a/tests/components/ViewedByCustomer/ViewedByCustomer.spec.ts b/tests/components/ViewedByCustomer/ViewedByCustomer.spec.ts index 045e79f1..41d9cc75 100644 --- a/tests/components/ViewedByCustomer/ViewedByCustomer.spec.ts +++ b/tests/components/ViewedByCustomer/ViewedByCustomer.spec.ts @@ -72,7 +72,7 @@ describe('ViewedByCustomer', () => { // We don't care about the result, it's just to have some stuff at the very least. const fakeResult: IQueryResult = { ...Fake.createFakeResult(), isUserActionView: true }; const testEnvironment = Mock.advancedResultComponentSetup(ViewedByCustomer, fakeResult, option).env; - const resolveResultStub = sandbox.stub(ViewedByCustomer.prototype, 'resolveResult').returns(fakeResult); + const resolveResultStub = sandbox.stub(ViewedByCustomer.prototype, 'resolveResult').callsFake(() => fakeResult); new ViewedByCustomer(testEnvironment.element, null, testEnvironment); expect(resolveResultStub.called).toBe(true); }); @@ -88,7 +88,7 @@ describe('ViewedByCustomer', () => { it('should throw if no result is provided to the constructor and none can be resolved', () => { const fakeResult: IQueryResult = { ...Fake.createFakeResult(), isUserActionView: true }; const testEnvironment = Mock.advancedResultComponentSetup(ViewedByCustomer, fakeResult, option).env; - sandbox.stub(ViewedByCustomer.prototype, 'resolveResult').returns(undefined); + sandbox.stub(ViewedByCustomer.prototype, 'resolveResult').callsFake(() => undefined); return new Promise((resolve, reject) => { try { new ViewedByCustomer(testEnvironment.element, null, testEnvironment); diff --git a/tests/models/UserProfilingModel.spec.ts b/tests/models/UserProfilingModel.spec.ts index 2139bc54..39099f90 100644 --- a/tests/models/UserProfilingModel.spec.ts +++ b/tests/models/UserProfilingModel.spec.ts @@ -136,7 +136,7 @@ describe('UserProfilingModel', () => { documentResults.results[0].raw.urihash = TEST_URI_HASH; const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(documentResults)); + endpoint.search.callsFake(() => Promise.resolve(documentResults)); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -168,7 +168,7 @@ describe('UserProfilingModel', () => { it('should attach no documents on click actions when no document are available to the searching user', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(0))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(0))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -191,7 +191,7 @@ describe('UserProfilingModel', () => { it('should attach no documents on click actions when the search call for documents details fails', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.reject()); + endpoint.search.callsFake(() => Promise.reject()); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -214,7 +214,7 @@ describe('UserProfilingModel', () => { it('should not fetch documents when there is no event with an urihash', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(5))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(5))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -237,7 +237,7 @@ describe('UserProfilingModel', () => { it('should fetch all actions from a user', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -266,7 +266,7 @@ describe('UserProfilingModel', () => { describe('when no actions are present in the model', () => { it('should fetch all actions of a user from the backend', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -301,7 +301,7 @@ describe('UserProfilingModel', () => { it('should fetch all actions of a user from the backend only once', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -339,7 +339,7 @@ describe('UserProfilingModel', () => { it('should fetch all actions of a user from the backend even when the search call for document details fails', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.reject()); + endpoint.search.callsFake(() => Promise.reject()); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -376,7 +376,7 @@ describe('UserProfilingModel', () => { describe('when actions are present in the model', () => { it('should not fetch all actions of a user from the backend', async () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -416,7 +416,7 @@ describe('UserProfilingModel', () => { describe('when no actions are present in the model', () => { it('should have no impact', () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -432,7 +432,7 @@ describe('UserProfilingModel', () => { it('should remove pending fetch operation related to a user even when there is a pending fetch operation', () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -451,7 +451,7 @@ describe('UserProfilingModel', () => { describe('when actions are present in the model', () => { it('should remove actions related to a user', () => { const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, @@ -477,7 +477,7 @@ describe('UserProfilingModel', () => { it('should remove actions related to a user even when there is a pending fetch operation', async () => { const responseBody = JSON.stringify(buildActionHistoryResponse(FAKE_HISTORY_ACTIONS), null, 0); const endpoint = sandbox.createStubInstance(SearchEndpoint); - endpoint.search.returns(Promise.resolve(Fake.createFakeResults(10))); + endpoint.search.callsFake(() => Promise.resolve(Fake.createFakeResults(10))); const model = new UserProfileModel(document.createElement('div'), { organizationId: TEST_ORGANIZATION, diff --git a/tests/utils.ts b/tests/utils.ts index 0dc3ca39..9bc3c9a3 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -54,14 +54,16 @@ export function generate(time: number, generator: (i: number) => T): T[] { * @param callback The callback to call. * @param timemout The timeout to wait. */ -export function delay(callback: () => any, timemout = 0) { - return new Promise((resolve) => { +export function delay(callback: () => T, timemout = 0) { + return new Promise((resolve) => { setTimeout(() => { resolve(callback()); }, timemout); }); } +export const waitForPromiseCompletion = () => delay(() => {}); + /** * Create a fake user profile model instance. * @param root The root of the Search interface.