Skip to content

Commit 0d57657

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

File tree

4 files changed

+280
-6
lines changed

4 files changed

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

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)