Skip to content

Commit d04c4f9

Browse files
committed
test(quantic): document suggestion jest tests
SFINT-5793
1 parent 6a3e2f5 commit d04c4f9

File tree

4 files changed

+312
-6
lines changed

4 files changed

+312
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
jest.mock('c/quanticHeadlessLoader');
2+
3+
import QuanticDocumentSuggestion from 'c/quanticDocumentSuggestion';
4+
import {buildCreateTestComponent, cleanup, flushPromises} from 'c/testUtils';
5+
import * as quanticHeadlessLoader from 'c/quanticHeadlessLoader';
6+
const headlessLoaderMock = jest.mocked(quanticHeadlessLoader);
7+
8+
const engineMock = {
9+
id: 'exampleEngineIdMock',
10+
dispatch: jest.fn(),
11+
};
12+
headlessLoaderMock.initializeWithHeadless.mockImplementation(
13+
async (element, _, initialize) => {
14+
initialize(engineMock);
15+
}
16+
);
17+
headlessLoaderMock.getHeadlessEnginePromise.mockImplementation(() =>
18+
Promise.reject({message: 'Skip initialization'})
19+
);
20+
21+
let updateSuggestions;
22+
const documentSuggestionListMock = {
23+
subscribe: jest.fn((callback) => {
24+
updateSuggestions = callback;
25+
return () => {}; // Fake unsubscribe function
26+
}),
27+
};
28+
29+
// @ts-ignore
30+
global.CoveoHeadlessCaseAssist = {
31+
buildDocumentSuggestionList: jest
32+
.fn()
33+
.mockReturnValue(documentSuggestionListMock),
34+
loadCaseAssistAnalyticsActions: jest.fn().mockReturnValue({}),
35+
loadDocumentSuggestionActions: jest.fn().mockReturnValue({
36+
fetchDocumentSuggestions: jest
37+
.fn()
38+
.mockReturnValue('mockedFetchDocumentSuggestions'),
39+
logDocumentSuggestionClick: jest.fn((id) => [
40+
'mockedLogDocumentSuggestionClick',
41+
id,
42+
]),
43+
logDocumentSuggestionRating: jest.fn((id, score) => [
44+
'mockedLogDocumentSuggestionRating',
45+
id,
46+
score,
47+
]),
48+
}),
49+
};
50+
51+
const createTestComponent = buildCreateTestComponent(
52+
QuanticDocumentSuggestion,
53+
'c-quantic-document-suggestion',
54+
{
55+
engineId: engineMock.id,
56+
}
57+
);
58+
59+
const selectors = {
60+
container: '.slds-card',
61+
accordion: 'lightning-accordion',
62+
accordionSection: 'lightning-accordion-section',
63+
noSuggestions: 'slot[name="no-suggestions"]',
64+
spinner: '.loading-holder lightning-spinner',
65+
quickview: 'c-quantic-result-quickview',
66+
componentError: 'c-quantic-component-error',
67+
};
68+
69+
describe('c-quantic-document-suggestion', () => {
70+
beforeEach(() => {
71+
documentSuggestionListMock.state = {
72+
documents: [],
73+
loading: false,
74+
};
75+
});
76+
77+
afterEach(() => {
78+
cleanup();
79+
});
80+
81+
describe('when using default options', () => {
82+
describe('when loading suggestions', () => {
83+
it('should render the loading holder only', async () => {
84+
const element = createTestComponent();
85+
documentSuggestionListMock.state.loading = true;
86+
updateSuggestions();
87+
await flushPromises();
88+
89+
expect(
90+
element.shadowRoot.querySelector(selectors.spinner)
91+
).toBeTruthy();
92+
expect(
93+
element.shadowRoot.querySelector(selectors.container)
94+
).toBeFalsy();
95+
expect(
96+
element.shadowRoot.querySelector(selectors.noSuggestions)
97+
).toBeFalsy();
98+
});
99+
});
100+
101+
describe('when there are no suggestions', () => {
102+
it('should render the no-suggestions message', async () => {
103+
const element = createTestComponent();
104+
updateSuggestions();
105+
await flushPromises();
106+
107+
expect(engineMock.dispatch).not.toHaveBeenCalled();
108+
expect(headlessLoaderMock.registerComponentForInit).toHaveBeenCalled();
109+
110+
expect(
111+
element.shadowRoot.querySelector(selectors.accordion)
112+
).toBeNull();
113+
expect(
114+
element.shadowRoot.querySelector(selectors.noSuggestions)
115+
).not.toBeNull();
116+
});
117+
});
118+
119+
describe('when suggestions are fetched', () => {
120+
it('should render the component and all parts', async () => {
121+
const element = createTestComponent();
122+
await flushPromises();
123+
124+
documentSuggestionListMock.state.documents = [
125+
{
126+
uniqueId: 'ego',
127+
fields: {
128+
uri: 'weed eater',
129+
},
130+
},
131+
{
132+
uniqueId: 'stihl',
133+
fields: {
134+
uri: 'chainsaw',
135+
},
136+
},
137+
];
138+
updateSuggestions();
139+
await flushPromises();
140+
141+
expect(engineMock.dispatch).not.toHaveBeenCalled();
142+
expect(headlessLoaderMock.registerComponentForInit).toHaveBeenCalled();
143+
144+
expect(
145+
element.shadowRoot.querySelector(selectors.noSuggestions)
146+
).toBeFalsy();
147+
expect(
148+
element.shadowRoot.querySelector(selectors.container)
149+
).toBeTruthy();
150+
expect(
151+
element.shadowRoot.querySelector(selectors.accordion)
152+
).toBeTruthy();
153+
expect(
154+
element.shadowRoot.querySelectorAll(selectors.accordionSection).length
155+
).toBe(2);
156+
const firstSection = element.shadowRoot.querySelector(
157+
selectors.accordionSection
158+
);
159+
expect(firstSection.getAttribute('data-id')).toBe('ego');
160+
expect(
161+
element.shadowRoot.querySelector(selectors.quickview)
162+
).toBeTruthy();
163+
});
164+
});
165+
});
166+
167+
describe('when fetchOnInit is true', () => {
168+
beforeEach(() => {
169+
documentSuggestionListMock.state.documents = [
170+
{
171+
uniqueId: 'ego',
172+
fields: {
173+
uri: 'weed eater',
174+
},
175+
},
176+
{
177+
uniqueId: 'stihl',
178+
fields: {
179+
uri: 'chainsaw',
180+
},
181+
},
182+
];
183+
});
184+
185+
it('should fetch suggestions automatically', async () => {
186+
createTestComponent({
187+
fetchOnInit: true,
188+
});
189+
await flushPromises();
190+
191+
expect(engineMock.dispatch).toHaveBeenCalledWith(
192+
'mockedFetchDocumentSuggestions'
193+
);
194+
});
195+
196+
it('should hide the quickview with withoutQuickview true', async () => {
197+
const element = createTestComponent({
198+
withoutQuickview: true,
199+
fetchOnInit: true,
200+
});
201+
await flushPromises();
202+
203+
expect(element.shadowRoot.querySelector(selectors.quickview)).toBeFalsy();
204+
});
205+
206+
it('should log a suggestion click if not opened', async () => {
207+
const element = createTestComponent({
208+
fetchOnInit: true,
209+
});
210+
updateSuggestions();
211+
await flushPromises();
212+
213+
const accordion = element.shadowRoot.querySelector(selectors.accordion);
214+
const sections = element.shadowRoot.querySelectorAll(
215+
selectors.accordionSection
216+
);
217+
218+
// Should not log click when opening first
219+
sections[0].click();
220+
expect(engineMock.dispatch).not.toHaveBeenCalledWith(
221+
'mockedLogDocumentSuggestionClick'
222+
);
223+
224+
accordion.activeSectionName = sections[1].name;
225+
sections[1].click();
226+
expect(engineMock.dispatch).toHaveBeenCalledWith([
227+
'mockedLogDocumentSuggestionClick',
228+
sections[1].name,
229+
]);
230+
});
231+
232+
it('handle rating event', async () => {
233+
const element = createTestComponent({
234+
fetchOnInit: true,
235+
});
236+
updateSuggestions();
237+
await flushPromises();
238+
239+
const customEvent = new CustomEvent('quantic__rating', {
240+
detail: {id: 'mastercraft', score: 2},
241+
});
242+
element.shadowRoot.dispatchEvent(customEvent);
243+
expect(engineMock.dispatch).toHaveBeenCalledWith([
244+
'mockedLogDocumentSuggestionRating',
245+
'mastercraft',
246+
2,
247+
]);
248+
});
249+
250+
it('should truncate documents to maxDocuments', async () => {
251+
const element = createTestComponent({
252+
fetchOnInit: true,
253+
maxDocuments: 1,
254+
});
255+
updateSuggestions();
256+
await flushPromises();
257+
258+
const sections = element.shadowRoot.querySelectorAll(
259+
selectors.accordionSection
260+
);
261+
expect(sections.length).toBe(1);
262+
});
263+
264+
it('should open the documents depending on numberOfAutoOpenedDocuments', async () => {
265+
const element = createTestComponent({
266+
fetchOnInit: true,
267+
numberOfAutoOpenedDocuments: 2,
268+
});
269+
updateSuggestions();
270+
await flushPromises();
271+
272+
const accordion = element.shadowRoot.querySelector(selectors.accordion);
273+
const sections = element.shadowRoot.querySelectorAll(
274+
selectors.accordionSection
275+
);
276+
expect(sections.length).toBe(2);
277+
expect(accordion.activeSectionName).toEqual([
278+
sections[0].name,
279+
sections[1].name,
280+
]);
281+
});
282+
});
283+
284+
describe('with invalid options', () => {
285+
it('should set an error message if maxDocuments is invalid', async () => {
286+
const element = createTestComponent({
287+
maxDocuments: 0,
288+
});
289+
await flushPromises();
290+
291+
expect(
292+
element.shadowRoot.querySelector(selectors.componentError)
293+
).toBeTruthy();
294+
});
295+
it('should set an error message if numberOfAutoOpenedDocuments is invalid', async () => {
296+
const element = createTestComponent({
297+
numberOfAutoOpenedDocuments: -1,
298+
});
299+
await flushPromises();
300+
301+
expect(
302+
element.shadowRoot.querySelector(selectors.componentError)
303+
).toBeTruthy();
304+
});
305+
});
306+
});

packages/quantic/force-app/main/default/lwc/quanticResultQuickview/__tests__/quanticResultQuickview.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {createElement} from 'lwc';
55
import QuanticResultQuickview from '../quanticResultQuickview';
66

77
const selectors = {
8-
quickviewButton: '[data-cy="quick-view-button"]',
9-
closeQuickviewButton: '[data-cy="quickview-modal__close-button"]',
8+
quickviewButton: '[data-testid="quick-view-button"]',
9+
closeQuickviewButton: '[data-testid="quickview-modal__close-button"]',
1010
quickviewContent: 'c-quantic-quickview-content',
1111
icon: 'lightning-icon',
1212
tooltip: 'c-quantic-tooltip',

packages/quantic/force-app/main/default/lwc/quanticResultQuickview/e2e/pageObject.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export class ResultQuickviewObject {
77
}
88

99
get quickviewButton(): Locator {
10-
return this.page.locator('c-quantic-result-quickview button');
10+
return this.page.getByRole('button', {name: 'Open'});
1111
}
1212

1313
get quickviewContent(): Locator {

packages/quantic/force-app/main/default/lwc/quanticResultQuickview/quanticResultQuickview.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
2-
<div data-cy="quick-view-button__container" class={buttonContainerClass} onmouseenter={showTooltip}
2+
<div data-cy="quick-view-button__container" data-testid="quick-view-button__container" class={buttonContainerClass} onmouseenter={showTooltip}
33
onmouseleave={hideTooltip}>
4-
<button data-cy="quick-view-button" aria-hidden={isQuickviewOpen} class={buttonClass} onclick={openQuickview}
4+
<button data-cy="quick-view-button" data-testid="quick-view-button" aria-hidden={isQuickviewOpen} class={buttonClass} onclick={openQuickview}
55
title={buttonTitle} disabled={hasNoPreview} aria-label={buttonAriaLabelValue}>
66
<template if:true={hasButtonLabel}> {previewButtonLabel} </template>
77
<template if:true={hasIcon}>
@@ -21,7 +21,7 @@
2121
aria-modal="true" aria-describedby="quickview__content-container"
2222
class="slds-modal slds-modal_medium slds-fade-in-open">
2323
<div class="slds-modal__container">
24-
<button data-cy="quickview-modal__close-button" class="slds-button slds-button_icon slds-modal__close" onclick={closeQuickview}
24+
<button data-cy="quickview-modal__close-button" data-testid="quickview-modal__close-button" class="slds-button slds-button_icon slds-modal__close" onclick={closeQuickview}
2525
onkeydown={onCloseKeyDown}>
2626
<lightning-icon class="slds-current-color" icon-name="utility:close" size="small"
2727
alternative-text={labels.close}></lightning-icon>

0 commit comments

Comments
 (0)