Skip to content

Commit

Permalink
fix(quantic): fixed issue with breadcrumb component when facet ids ar…
Browse files Browse the repository at this point in the history
…e used (#4791)

## [SFINT-5847](https://coveord.atlassian.net/browse/SFINT-5847)


### The issue

passing a facetId to a Quantic Facet component like the following:

```html
     <c-quantic-facet
        facet-id="obj"
        field="objecttype"
        label="Type"
        engine-id={engineId}
        data-cy="type"
      ></c-quantic-facet>
      <c-quantic-facet
        facet-id="file"
        display-values-as="link"
        field="filetype"
        label="File Type"
        engine-id={engineId}
      ></c-quantic-facet>
```

is causing an issue with the Quantic Breadcrumb component:
 
<img width="1455" alt="Screenshot 2024-11-28 at 11 27 45 AM"
src="https://github.com/user-attachments/assets/5a541704-c6e6-475a-9e8f-c32ebfd4746b"
/>


The issue is that the Quantic Breadcrumb component was reading the
facets from the store only using the facet `field` however the facet
`field` is used by the facets as `facetId` only when no facetId value is
passed to the facet components.


### After:
Updated the Quantic Breadcrumb component to read the facets info from
the store using the facet id instead of the facet field.

https://github.com/user-attachments/assets/56c3f3fa-b65b-4662-b3d1-4272e3879a8c



[SFINT-5847]:
https://coveord.atlassian.net/browse/SFINT-5847?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

---------

Co-authored-by: Etienne Rocheleau <erocheleau@coveo.com>
  • Loading branch information
mmitiche and erocheleau authored Dec 18, 2024
1 parent 5411883 commit 87491c6
Show file tree
Hide file tree
Showing 3 changed files with 357 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,341 @@
/* eslint-disable no-import-assign */
// @ts-ignore
import QuanticBreadcrumbManager from 'c/quanticBreadcrumbManager';
// @ts-ignore
import {createElement} from 'lwc';
import * as mockHeadlessLoader from 'c/quanticHeadlessLoader';

const initialBreadcrumbManagerState = {
hasBreadcrumbs: false,
numericFacetBreadcrumbs: [],
categoryFacetBreadcrumbs: [],
dateFacetBreadcrumbs: [],
facetBreadcrumbs: [],
};
let breadcrumbManagerState = initialBreadcrumbManagerState;

const initialStoreState = {};
let storeState = initialStoreState;

const functionsMocks = {
buildBreadcrumbManager: jest.fn(() => ({
state: breadcrumbManagerState,
subscribe: functionsMocks.subscribe,
})),
subscribe: jest.fn((cb) => {
cb();
return functionsMocks.unsubscribe;
}),
unsubscribe: jest.fn(() => {}),
};

const selectors = {
facetBreadcrumb: '[data-test="facet-breadcrumb"]',
facetBreadcrumbValue: '[data-test="facet-breadcrumb-value"]',
categoryFacetBreadcrumb: '[data-test="category-facet-breadcrumb"]',
categoryFacetBreadcrumbValue: '[data-test="category-facet-breadcrumb-value"]',
numericFacetBreadcrumb: '[data-test="numeric-facet-breadcrumb"]',
numericFacetBreadcrumbValue: '[data-test="numeric-facet-breadcrumb-value"]',
dateFacetBreadcrumb: '[data-test="date-facet-breadcrumb"]',
dateFacetBreadcrumbValue: '[data-test="date-facet-breadcrumb-value"]',
};

const exampleEngine = {
id: 'dummy engine',
};
const exampleFacetId = 'idOne';

let isInitialized = false;

function createTestComponent(options = {}) {
const element = createElement('c-quantic-breadcrumb-manager', {
is: QuanticBreadcrumbManager,
});
for (const [key, value] of Object.entries(options)) {
element[key] = value;
}

document.body.appendChild(element);
return element;
}

function prepareHeadlessState() {
// @ts-ignore
mockHeadlessLoader.getHeadlessBundle = () => {
return {
buildBreadcrumbManager: functionsMocks.buildBreadcrumbManager,
};
};
}

function mockStoreState() {
// @ts-ignore
mockHeadlessLoader.getFromStore = () => {
return storeState;
};
}

// 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));
}

function mockSuccessfulHeadlessInitialization() {
// @ts-ignore
mockHeadlessLoader.initializeWithHeadless = (element, _, initialize) => {
if (element instanceof QuanticBreadcrumbManager && !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-breadcrumb-manager', () => {
beforeEach(() => {
mockSuccessfulHeadlessInitialization();
prepareHeadlessState();
mockStoreState();
});

afterEach(() => {
breadcrumbManagerState = initialBreadcrumbManagerState;
storeState = initialStoreState;
cleanup();
});

describe('facet breadcrumbs', () => {
const exampleFacetBreadcrumbs = [
{
field: 'fieldOne',
facetId: exampleFacetId,
values: [{value: 'one'}, {value: 'two'}],
},
];

beforeAll(() => {
breadcrumbManagerState = {
...breadcrumbManagerState,
facetBreadcrumbs: exampleFacetBreadcrumbs,
hasBreadcrumbs: true,
};

storeState = {
[exampleFacetId]: {
facetId: exampleFacetId,
format: (value) => value,
},
};
});

it('should properly display the breadcrumb values', async () => {
const element = createTestComponent();
await flushPromises();

const facetBreadcrumbs = element.shadowRoot.querySelectorAll(
selectors.facetBreadcrumb
);

expect(facetBreadcrumbs.length).toBe(exampleFacetBreadcrumbs.length);
facetBreadcrumbs.forEach((facetBreadcrumb, index) => {
const exampleFacetBreadcrumb = exampleFacetBreadcrumbs[index];
const facetBreadcrumbValues = Array.from(
facetBreadcrumb.querySelectorAll(selectors.facetBreadcrumbValue)
);

expect(facetBreadcrumbValues.length).toBe(
exampleFacetBreadcrumb.values.length
);

const labels = facetBreadcrumbValues.map(
(facetBreadcrumbValue) => facetBreadcrumbValue.label
);
const values = exampleFacetBreadcrumb.values.map((item) => item.value);
expect(labels).toEqual(values);
});
});
});

describe('category facet breadcrumbs', () => {
const exampleCategoryFacetBreadcrumbs = [
{
field: exampleFacetId,
facetId: exampleFacetId,
path: [{value: 'one'}, {value: 'two'}],
},
];

beforeAll(() => {
breadcrumbManagerState = {
...breadcrumbManagerState,
categoryFacetBreadcrumbs: exampleCategoryFacetBreadcrumbs,
hasBreadcrumbs: true,
};

storeState = {
[exampleFacetId]: {
facetId: exampleFacetId,
format: (item) => item.value,
},
};
});

it('should properly display the breadcrumb values', async () => {
const element = createTestComponent();
await flushPromises();

const categoryFacetBreadcrumbs = element.shadowRoot.querySelectorAll(
selectors.categoryFacetBreadcrumb
);

expect(categoryFacetBreadcrumbs.length).toBe(
exampleCategoryFacetBreadcrumbs.length
);
categoryFacetBreadcrumbs.forEach((categoryFacetBreadcrumb, index) => {
const exampleFacetBreadcrumb = exampleCategoryFacetBreadcrumbs[index];
const categoryFacetBreadcrumbValues = Array.from(
categoryFacetBreadcrumb.querySelectorAll(
selectors.categoryFacetBreadcrumbValue
)
);

expect(categoryFacetBreadcrumbValues.length).toBe(1);

const labels = categoryFacetBreadcrumbValues.map(
(facetBreadcrumbValue) => facetBreadcrumbValue.label
);
const values = exampleFacetBreadcrumb.path.map((item) => item.value);
expect(labels).toEqual([values.join(' / ')]);
});
});
});

describe('numeric facet breadcrumbs', () => {
const exampleNumericFacetBreadcrumbs = [
{
field: 'fieldOne',
facetId: exampleFacetId,
values: [{value: {start: 0, end: 1}}, {value: {start: 1, end: 2}}],
},
];

beforeAll(() => {
breadcrumbManagerState = {
...breadcrumbManagerState,
numericFacetBreadcrumbs: exampleNumericFacetBreadcrumbs,
hasBreadcrumbs: true,
};

storeState = {
[exampleFacetId]: {
facetId: exampleFacetId,
format: (item) => `${item.start} - ${item.end}`,
},
};
});

it('should properly display the breadcrumb values', async () => {
const element = createTestComponent();
await flushPromises();

const numericFacetBreadcrumbs = element.shadowRoot.querySelectorAll(
selectors.numericFacetBreadcrumb
);

expect(numericFacetBreadcrumbs.length).toBe(
exampleNumericFacetBreadcrumbs.length
);
numericFacetBreadcrumbs.forEach((numericFacetBreadcrumb, index) => {
const exampleFacetBreadcrumb = exampleNumericFacetBreadcrumbs[index];
const facetBreadcrumbValues = Array.from(
numericFacetBreadcrumb.querySelectorAll(
selectors.numericFacetBreadcrumbValue
)
);

expect(facetBreadcrumbValues.length).toBe(
exampleFacetBreadcrumb.values.length
);

const labels = facetBreadcrumbValues.map(
(facetBreadcrumbValue) => facetBreadcrumbValue.label
);
const values = exampleFacetBreadcrumb.values.map(
(item) => `${item.value.start} - ${item.value.end}`
);
expect(labels).toEqual(values);
});
});
});

describe('date facet breadcrumbs', () => {
const exampleDateFacetBreadcrumbs = [
{
field: 'fieldOne',
facetId: exampleFacetId,
values: [
{value: {start: 'yesterday', end: 'today'}},
{value: {start: 'today', end: 'tomorrow'}},
],
},
];

beforeAll(() => {
breadcrumbManagerState = {
...breadcrumbManagerState,
dateFacetBreadcrumbs: exampleDateFacetBreadcrumbs,
hasBreadcrumbs: true,
};

storeState = {
[exampleFacetId]: {
facetId: exampleFacetId,
format: (item) => `${item.start} - ${item.end}`,
},
};
});

it('should properly display the breadcrumb values', async () => {
const element = createTestComponent();
await flushPromises();

const dateFacetBreadcrumbs = element.shadowRoot.querySelectorAll(
selectors.dateFacetBreadcrumb
);

expect(dateFacetBreadcrumbs.length).toBe(
exampleDateFacetBreadcrumbs.length
);

dateFacetBreadcrumbs.forEach((dateFacetBreadcrumb, index) => {
const exampleFacetBreadcrumb = exampleDateFacetBreadcrumbs[index];
const facetBreadcrumbValues = Array.from(
dateFacetBreadcrumb.querySelectorAll(
selectors.dateFacetBreadcrumbValue
)
);

expect(facetBreadcrumbValues.length).toBe(
exampleFacetBreadcrumb.values.length
);

const labels = facetBreadcrumbValues.map(
(facetBreadcrumbValue) => facetBreadcrumbValue.label
);
const values = exampleFacetBreadcrumb.values.map(
(item) => `${item.value.start} - ${item.value.end}`
);
expect(labels).toEqual(values);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
<div class="slds-col slds-truncate slds-col_bump-right breadcrumb-manager__column">
<ul>
<template for:each={facetBreadcrumbValues} for:item="breadcrumb">
<li key={breadcrumb.facetId} class="slds-list_horizontal breadcrumb-manager__facet-list breadcrumb-manager__line">
<li data-test="facet-breadcrumb" key={breadcrumb.facetId} class="slds-list_horizontal breadcrumb-manager__facet-list breadcrumb-manager__line">
<span class="slds-col breadcrumb-manager__field-name">{breadcrumb.label}{labels.colon} </span>
<ul class="slds-col slds-truncate slds-list_horizontal slds-grid slds-wrap">
<template for:each={breadcrumb.values} for:item="breadcrumbValue">
<li key={breadcrumbValue.value.value} class="breadcrumb__container">
<c-quantic-pill label={breadcrumbValue.formattedValue} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumb.label} action-name={labels.clearFilter}></c-quantic-pill>
<c-quantic-pill data-test="facet-breadcrumb-value" label={breadcrumbValue.formattedValue} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumb.label} action-name={labels.clearFilter}></c-quantic-pill>
</li>
</template>
<template if:true={breadcrumb.showMoreButton}>
Expand All @@ -26,12 +26,12 @@
</li>
</template>
<template for:each={numericFacetBreadcrumbsValues} for:item="breadcrumb">
<li key={breadcrumb.facetId} class="slds-list_horizontal breadcrumb-manager__numeric-facet-list breadcrumb-manager__line">
<li data-test="numeric-facet-breadcrumb" key={breadcrumb.facetId} class="slds-list_horizontal breadcrumb-manager__numeric-facet-list breadcrumb-manager__line">
<span class="slds-col breadcrumb-manager__field-name">{breadcrumb.label}{labels.colon} </span>
<ul class="slds-col slds-truncate slds-list_horizontal slds-grid slds-wrap">
<template for:each={breadcrumb.values} for:item="breadcrumbValue">
<li key={breadcrumbValue.value} class="breadcrumb__container">
<c-quantic-pill label={breadcrumbValue.formattedValue} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumb.label} action-name={labels.clearFilter}></c-quantic-pill>
<c-quantic-pill data-test="numeric-facet-breadcrumb-value" label={breadcrumbValue.formattedValue} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumb.label} action-name={labels.clearFilter}></c-quantic-pill>
</li>
</template>
<template if:true={breadcrumb.showMoreButton}>
Expand All @@ -43,22 +43,22 @@
</li>
</template>
<template for:each={categoryFacetBreadcrumbsValues} for:item="breadcrumbValue">
<li key={breadcrumbValue.facetId} class="slds-list_horizontal breadcrumb-manager__category-facet-list breadcrumb-manager__line">
<li data-test="category-facet-breadcrumb" key={breadcrumbValue.facetId} class="slds-list_horizontal breadcrumb-manager__category-facet-list breadcrumb-manager__line">
<span class="slds-col breadcrumb-manager__field-name">{breadcrumbValue.label}{labels.colon} </span>
<ul class="slds-col slds-truncate slds-list_horizontal slds-grid slds-wrap">
<li class="breadcrumb__container">
<c-quantic-pill label={breadcrumbValue.value} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumbValue.label} action-name={labels.clearFilter}></c-quantic-pill>
<c-quantic-pill data-test="category-facet-breadcrumb-value" label={breadcrumbValue.value} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumbValue.label} action-name={labels.clearFilter}></c-quantic-pill>
</li>
</ul>
</li>
</template>
<template for:each={dateFacetBreadcrumbsValues} for:item="breadcrumb">
<li key={breadcrumb.facetId} class="slds-list_horizontal breadcrumb-manager__date-facet-list breadcrumb-manager__line">
<li data-test="date-facet-breadcrumb" key={breadcrumb.facetId} class="slds-list_horizontal breadcrumb-manager__date-facet-list breadcrumb-manager__line">
<span class="slds-col breadcrumb-manager__field-name">{breadcrumb.label}{labels.colon} </span>
<ul class="slds-col slds-truncate slds-list_horizontal slds-grid slds-wrap">
<template for:each={breadcrumb.values} for:item="breadcrumbValue">
<li key={breadcrumbValue.value} class="breadcrumb__container">
<c-quantic-pill label={breadcrumbValue.value} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumb.label} action-name={labels.clearFilter}></c-quantic-pill>
<c-quantic-pill data-test="date-facet-breadcrumb-value" label={breadcrumbValue.value} onquantic__deselect={breadcrumbValue.deselect} group-name={breadcrumb.label} action-name={labels.clearFilter}></c-quantic-pill>
</li>
</template>
<template if:true={breadcrumb.showMoreButton}>
Expand Down
Loading

0 comments on commit 87491c6

Please sign in to comment.