From 44563fd244db1aabd64dc1bc9539642362963b04 Mon Sep 17 00:00:00 2001 From: mmitiche <86681870+mmitiche@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:04:51 -0400 Subject: [PATCH] feat(quantic): added support to the custom sort property in the quantic facet component (#4600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [SFINT-5316](https://coveord.atlassian.net/browse/SFINT-5316) - Exposed the property `customSort` in the Quantic Facet, this property allows the end user to specify a custom order of the facet values. #### Example: with `customSort` set to `[]`: Screenshot 2024-10-28 at 9 12 24 AM #### Example: with `customSort` set to `['HTML', 'incident']`: Screenshot 2024-10-28 at 9 11 37 AM - This new logic is being unit tested. the unit tests of remaining logic of the component will be added in a later PR after doing the migration to the E2E Playwright tests. [SFINT-5316]: https://coveord.atlassian.net/browse/SFINT-5316?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --------- Co-authored-by: Simon Milord Co-authored-by: Etienne Rocheleau --- .../__tests__/quanticFacet.test.js | 102 ++++++++++++++++++ .../default/lwc/quanticFacet/quanticFacet.js | 14 +++ .../templates/disabledDynamicNavigation.html | 1 + .../templates/dynamicNavigation.html | 1 + packages/quantic/jest.config.js | 2 + 5 files changed, 120 insertions(+) create mode 100644 packages/quantic/force-app/main/default/lwc/quanticFacet/__tests__/quanticFacet.test.js diff --git a/packages/quantic/force-app/main/default/lwc/quanticFacet/__tests__/quanticFacet.test.js b/packages/quantic/force-app/main/default/lwc/quanticFacet/__tests__/quanticFacet.test.js new file mode 100644 index 00000000000..04ed94b5425 --- /dev/null +++ b/packages/quantic/force-app/main/default/lwc/quanticFacet/__tests__/quanticFacet.test.js @@ -0,0 +1,102 @@ +/* eslint-disable no-import-assign */ +// @ts-ignore +import {createElement} from 'lwc'; +import QuanticFacet from 'c/quanticFacet'; +import * as mockHeadlessLoader from 'c/quanticHeadlessLoader'; + +jest.mock('c/quanticHeadlessLoader'); + +function createTestComponent(options = {}) { + prepareHeadlessState(); + + const element = createElement('c-quantic-facet', { + is: QuanticFacet, + }); + for (const [key, value] of Object.entries(options)) { + element[key] = value; + } + + document.body.appendChild(element); + return element; +} + +const functionsMocks = { + buildFacet: jest.fn(() => ({ + subscribe: jest.fn((callback) => callback()), + state: { + values: [], + }, + })), + buildSearchStatus: jest.fn(() => ({ + subscribe: jest.fn((callback) => callback()), + state: {}, + })), +}; + +function prepareHeadlessState() { + // @ts-ignore + mockHeadlessLoader.getHeadlessBundle = () => { + return { + buildFacet: functionsMocks.buildFacet, + buildSearchStatus: functionsMocks.buildSearchStatus, + }; + }; +} + +// Helper function to wait until the microtask queue is empty. +function flushPromises() { + // eslint-disable-next-line @lwc/lwc/no-async-operation + return new Promise((resolve) => setTimeout(resolve, 0)); +} + +const exampleEngine = { + id: 'dummy engine', +}; +let isInitialized = false; + +function mockSuccessfulHeadlessInitialization() { + // @ts-ignore + mockHeadlessLoader.initializeWithHeadless = (element, _, initialize) => { + if (element instanceof QuanticFacet && !isInitialized) { + isInitialized = true; + initialize(exampleEngine); + } + }; +} + +function cleanup() { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + isInitialized = false; +} + +describe('c-quantic-facet', () => { + beforeAll(() => { + mockSuccessfulHeadlessInitialization(); + }); + + afterEach(() => { + cleanup(); + }); + + describe('controller initialization', () => { + it('should initialize the controller with the correct customSort value', async () => { + const exampleCustomSortValues = ['test']; + createTestComponent({customSort: exampleCustomSortValues}); + await flushPromises(); + + expect(functionsMocks.buildFacet).toHaveBeenCalledTimes(1); + expect(functionsMocks.buildFacet).toHaveBeenCalledWith( + exampleEngine, + expect.objectContaining({ + options: expect.objectContaining({ + customSort: exampleCustomSortValues, + }), + }) + ); + }); + }); +}); diff --git a/packages/quantic/force-app/main/default/lwc/quanticFacet/quanticFacet.js b/packages/quantic/force-app/main/default/lwc/quanticFacet/quanticFacet.js index 7994301b74d..2443cb6dbca 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticFacet/quanticFacet.js +++ b/packages/quantic/force-app/main/default/lwc/quanticFacet/quanticFacet.js @@ -129,6 +129,16 @@ export default class QuanticFacet extends LightningElement { * @defaultValue `1000` */ @api injectionDepth = 1000; + /** + * Identifies the facet values that must appear at the top, in order. + * This parameter can be used in conjunction with the `sortCriteria` parameter. + * Facet values not part of the `customSort` list will be sorted according to the `sortCriteria`. + * The maximum amount of custom sort values is 25. + * The default value is `undefined`, and the facet values will be sorted using only the `sortCriteria`. + * @api + * @type {String[]} + */ + @api customSort; /** * Whether the facet is collapsed. * @api @@ -154,6 +164,7 @@ export default class QuanticFacet extends LightningElement { 'displayValuesAs', 'noFilterFacetCount', 'injectionDepth', + 'customSort', ]; /** @type {FacetState} */ @@ -249,6 +260,9 @@ export default class QuanticFacet extends LightningElement { facetId: this.facetId ?? this.field, filterFacetCount: !this.noFilterFacetCount, injectionDepth: Number(this.injectionDepth), + customSort: Array.isArray(this.customSort) + ? [...this.customSort] + : undefined, }; this.facet = this.headless.buildFacet(engine, {options}); this.unsubscribe = this.facet.subscribe(() => this.updateState()); diff --git a/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/disabledDynamicNavigation.html b/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/disabledDynamicNavigation.html index af19c4c8f75..944ad407846 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/disabledDynamicNavigation.html +++ b/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/disabledDynamicNavigation.html @@ -120,6 +120,7 @@ no-filter-facet-count={facet.noFilterFacetCount} injection-depth={facet.injectionDepth} key={facet.field} + custom-sort={facet.customSort} is-collapsed > diff --git a/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/dynamicNavigation.html b/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/dynamicNavigation.html index 058def95d12..0e0f37c4601 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/dynamicNavigation.html +++ b/packages/quantic/force-app/main/default/lwc/quanticRefineModalContent/templates/dynamicNavigation.html @@ -121,6 +121,7 @@ no-filter-facet-count={facet.noFilterFacetCount} injection-depth={facet.injectionDepth} key={facet.field} + custom-sort={facet.customSort} is-collapsed > diff --git a/packages/quantic/jest.config.js b/packages/quantic/jest.config.js index d41019db77f..79116280322 100644 --- a/packages/quantic/jest.config.js +++ b/packages/quantic/jest.config.js @@ -29,6 +29,8 @@ module.exports = { '/force-app/main/default/lwc/quanticResultActionStyles/quanticResultActionStyles', '^c/searchBoxStyle$': '/force-app/main/default/lwc/searchBoxStyle/searchBoxStyle', + '^c/quanticFacetStyles$': + '/force-app/main/default/lwc/quanticFacetStyles/quanticFacetStyles', }, modulePathIgnorePatterns: ['.cache'], // add any custom configurations here