Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(quantic): document suggestion jest tests #5146

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

mikegron
Copy link
Contributor

@mikegron mikegron commented Apr 8, 2025

SFINT-5793

Created Jest tests for Document suggestion component. Had some troubles testing some things but should be good now lol

Some things maybe different as I was trying to follow jest docs:

  • Package mocks before imports so you have a clean mock using jest.mocked, instead of the prepareHeadlessState and mockSuccessfulHeadlessInitialization
  • Tested all parameters, actions dispatched, rendering etc.

I didn't really like the formatting but I hope you have suggestions! For instance, the global.CoveoHeadlessCaseAssist mock could probably be a utility.
image

@mikegron mikegron self-assigned this Apr 8, 2025
@mikegron mikegron requested a review from a team as a code owner April 8, 2025 18:36
Copy link

github-actions bot commented Apr 8, 2025

Pull Request Report

PR Title

✅ Title follows the conventional commit spec.

Live demo links

Bundle Size

File Old (kb) New (kb) Change (%)
case-assist 248.6 248.6 0
commerce 361 361 0
search 419.6 419.6 0
insight 410.8 410.8 0
recommendation 259.5 259.5 0
ssr 413.4 413.4 0
ssr-commerce 377.5 377.5 0

updateSuggestions();
await flushPromises();

expect(engineMock.dispatch).not.toHaveBeenCalled();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which action is the one we are checking that it is not dispatched here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchSuggestion especially!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in that case wouldn't be better to have expect(fetchSuggestion).not.toHaveBeenCalled();?

Copy link
Contributor

@mmitiche mmitiche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice tests!
looks good to me after addressing the issue of the polluting logs!

Comment on lines +17 to +19
headlessLoaderMock.getHeadlessEnginePromise.mockImplementation(() =>
Promise.reject({message: 'Skip initialization'})
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is causing the following which is polluting the logs: https://github.com/coveo/ui-kit/actions/runs/14365598472/job/40277925597?pr=5146
Screenshot 2025-04-11 at 7 59 28 AM

We need to address this, a suggestion could be to handle initialization like we do for other components.

Comment on lines +42 to +46
loadCaseAssistAnalyticsActions: jest.fn().mockReturnValue({}),
loadDocumentSuggestionActions: jest.fn().mockReturnValue({
fetchDocumentSuggestions: functionsMocks.fetchDocumentSuggestions,
logDocumentSuggestionClick: functionsMocks.logDocumentSuggestionClick,
logDocumentSuggestionRating: functionsMocks.logDocumentSuggestionRating,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To stay lawful to the Headless implementation, logDocumentSuggestionClick and logDocumentSuggestionRating should come from loadCaseAssistAnalyticsActions and not loadDocumentSuggestionActions :

export function loadCaseAssistAnalyticsActions(
engine: CaseAssistEngine
): CaseAssistAnalyticsActionCreators {
engine.addReducers({});
return {
logCaseStart,
logCaseNextStage,
logCreateCase,
logSolveCase,
logAbandonCase,
logUpdateCaseField,
logClassificationClick,
logDocumentSuggestionClick,
logDocumentSuggestionRating,
logQuickviewDocumentSuggestionClick,

const sections = element.shadowRoot.querySelectorAll(
selectors.accordionSection
);
expect(sections.length).toBe(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an improvements could be to store the suggestions in a variable exampleSuggestions.
And then here instead of comparing to 2, we compare to exampleSuggestions.length

This case our test become a bit more scalalble, if in the future we need to add a new test case where we need three document suggestions for example, we would only care about changing exampleSuggestions, the rest will follow smoothly.

Comment on lines +197 to +202
expect(section.label).toBe(
documentSuggestionListMock.state.documents[index].title
);
const uniqueId =
documentSuggestionListMock.state.documents[index].uniqueId;
expect(section.getAttribute('data-id')).toBe(uniqueId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(section.label).toBe(
documentSuggestionListMock.state.documents[index].title
);
const uniqueId =
documentSuggestionListMock.state.documents[index].uniqueId;
expect(section.getAttribute('data-id')).toBe(uniqueId);
sections.forEach((section, index) => {
const {title, uniqueId} = documentSuggestionListMock.state.documents[index];
expect(section.label).toBe(title);
expect(section.getAttribute('data-id')).toBe(uniqueId);

expect(element.shadowRoot.querySelector(selectors.quickview)).toBeFalsy();
});

it('should log a suggestion click if not opened', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should log a suggestion click if not opened', async () => {
it('should log a suggestion click if the suggestion is not opened', async () => {

});
});

describe('when two document suggestions have a similar title', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the cypress test do this with a component that has numberOfAutoOpenedDocuments set to 0:

describe('when two document suggestions have a similar title', () => {
it('should open the right document suggestion when clicked', () => {
const exampleResponseId = crypto.randomUUID();
visitDocumentSuggestion({
numberOfAutoOpenedDocuments: 0,
});

I think we should do the same here, as this cypress test was added after a bug that we fixed, so we need to replicate exactly the stup that was causing the issue previously.

Copy link
Contributor

@SimonMilord SimonMilord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

);
}

function checkElement(element, selector, shouldExist) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this could be in a utils?

Copy link
Contributor

@mmitiche mmitiche Apr 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't prefer the usage of such functions, cause they lead to the absence of assertions in the tests which for more is not very ideal.

I prefer that when I read the test, I instantly understand what's going on and what's being tested without having to check for function definitions that are defined in the same file or even less ideal when defined in separate files.

I know the benefit of such functions is to reduce code duplication and follow the DRY mindset (Don't repeat yourself ).
But for me DRY is less applicable and less beneficial when it comes to test writing, for tests and for me, it's more about clarity and simplicity, even if it includes some code duplication like here a duplication of the expect assertion that checks that an element is present.

Thoughts? @mikegron @SimonMilord @erocheleau

});
});

it('should not render quick view button when withoutQuickview is set to true', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should not render quick view button when withoutQuickview is set to true', async () => {
it('should not render quickview button when withoutQuickview is set to true', async () => {

);
});

it('should handle document rating event', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should handle document rating event', async () => {
it('should log analytics when rating a document', async () => {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants