diff --git a/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/__tests__/quanticCategoryFacet.test.js b/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/__tests__/quanticCategoryFacet.test.js index 52cfa59a7e..7f22ca11d4 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/__tests__/quanticCategoryFacet.test.js +++ b/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/__tests__/quanticCategoryFacet.test.js @@ -50,7 +50,10 @@ function createTestComponent(options = defaultOptions) { const functionsMocks = { buildCategoryFacet: jest.fn(() => categoryFacetControllerMock), - buildFacetConditionsManager: jest.fn(), + stopWatching: jest.fn(), + buildFacetConditionsManager: jest.fn(() => ({ + stopWatching: functionsMocks.stopWatching, + })), buildSearchStatus: jest.fn(() => ({ subscribe: jest.fn((callback) => callback()), state: {}, @@ -194,4 +197,24 @@ describe('c-quantic-category-facet', () => { ); }); }); + + describe('when the component is disconnected', () => { + it('should make the condition manager stop watching the facet', async () => { + const exampleFacetDependency = { + parentFacetId: 'filetype', + expectedValue: 'txt', + }; + const element = createTestComponent({ + ...defaultOptions, + dependsOn: exampleFacetDependency, + }); + await flushPromises(); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( + 1 + ); + + document.body.removeChild(element); + expect(functionsMocks.stopWatching).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/quanticCategoryFacet.js b/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/quanticCategoryFacet.js index d3628485fc..1a152f4647 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/quanticCategoryFacet.js +++ b/packages/quantic/force-app/main/default/lwc/quanticCategoryFacet/quanticCategoryFacet.js @@ -28,6 +28,7 @@ import {api, LightningElement, track} from 'lwc'; /** @typedef {import("coveo").CategoryFacetValue} CategoryFacetValue */ /** @typedef {import("coveo").SearchStatus} SearchStatus */ /** @typedef {import("coveo").SearchEngine} SearchEngine */ +/** @typedef {import("coveo").FacetConditionsManager} FacetConditionsManager */ /** @typedef {import('../quanticUtils/facetDependenciesUtils').DependsOn} DependsOn */ /** * @typedef FocusTarget @@ -219,6 +220,8 @@ export default class QuanticCategoryFacet extends LightningElement { focusShouldBeInFacet = false; /** @type {boolean} */ hasInitializationError = false; + /** @type {FacetConditionsManager} */ + categoryfacetConditionsManager; labels = { clear, @@ -256,6 +259,7 @@ export default class QuanticCategoryFacet extends LightningElement { disconnectedCallback() { this.unsubscribe?.(); this.unsubscribeSearchStatus?.(); + this.categoryfacetConditionsManager?.stopWatching(); } /** @@ -327,15 +331,13 @@ export default class QuanticCategoryFacet extends LightningElement { } initFacetConditionManager(engine) { - this.facetConditionsManager = this.headless.buildFacetConditionsManager( - engine, - { + this.categoryfacetConditionsManager = + this.headless.buildFacetConditionsManager(engine, { facetId: this.facet.state.facetId, conditions: generateFacetDependencyConditions({ [this.dependsOn.parentFacetId]: this.dependsOn.expectedValue, }), - } - ); + }); } get values() { diff --git a/packages/quantic/force-app/main/default/lwc/quanticDateFacet/__tests__/quanticDateFacet.test.js b/packages/quantic/force-app/main/default/lwc/quanticDateFacet/__tests__/quanticDateFacet.test.js index 09d8c7e8db..f50f1d8885 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticDateFacet/__tests__/quanticDateFacet.test.js +++ b/packages/quantic/force-app/main/default/lwc/quanticDateFacet/__tests__/quanticDateFacet.test.js @@ -47,7 +47,10 @@ function createTestComponent(options = defaultOptions) { const functionsMocks = { buildDateFacet: jest.fn(() => dateFacetControllerMock), - buildFacetConditionsManager: jest.fn(), + stopWatching: jest.fn(), + buildFacetConditionsManager: jest.fn(() => ({ + stopWatching: functionsMocks.stopWatching, + })), buildSearchStatus: jest.fn(() => ({ subscribe: jest.fn((callback) => callback()), state: {}, @@ -189,4 +192,24 @@ describe('c-quantic-date-facet', () => { functionsMocks.buildDateFacet.mockReturnValue(dateFacetControllerMock); }); }); + + describe('when the component is disconnected', () => { + it('should make the condition manager stop watching the facet', async () => { + const exampleFacetDependency = { + parentFacetId: 'filetype', + expectedValue: 'txt', + }; + const element = createTestComponent({ + ...defaultOptions, + dependsOn: exampleFacetDependency, + }); + await flushPromises(); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( + 1 + ); + + document.body.removeChild(element); + expect(functionsMocks.stopWatching).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/packages/quantic/force-app/main/default/lwc/quanticDateFacet/quanticDateFacet.js b/packages/quantic/force-app/main/default/lwc/quanticDateFacet/quanticDateFacet.js index 0d88c771d4..43df3eaa95 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticDateFacet/quanticDateFacet.js +++ b/packages/quantic/force-app/main/default/lwc/quanticDateFacet/quanticDateFacet.js @@ -23,6 +23,7 @@ import {LightningElement, track, api} from 'lwc'; /** @typedef {import("coveo").DateFacetValue} DateFacetValue */ /** @typedef {import("coveo").SearchStatus} SearchStatus */ /** @typedef {import("coveo").SearchEngine} SearchEngine */ +/** @typedef {import("coveo").FacetConditionsManager} FacetConditionsManager */ /** @typedef {import('../quanticUtils/facetDependenciesUtils').DependsOn} DependsOn */ /** * @typedef FocusTarget @@ -160,6 +161,8 @@ export default class QuanticDateFacet extends LightningElement { focusShouldBeInFacet = false; /** @type {boolean} */ hasInitializationError = false; + /** @type {FacetConditionsManager} */ + dateFacetConditionsManager; labels = { clearFilter, @@ -214,6 +217,7 @@ export default class QuanticDateFacet extends LightningElement { disconnectedCallback() { this.unsubscribe?.(); this.unsubscribeSearchStatus?.(); + this.dateFacetConditionsManager?.stopWatching(); } updateState() { @@ -235,7 +239,7 @@ export default class QuanticDateFacet extends LightningElement { } initFacetConditionManager(engine) { - this.facetConditionsManager = this.headless.buildFacetConditionsManager( + this.dateFacetConditionsManager = this.headless.buildFacetConditionsManager( engine, { facetId: this.facet.state.facetId, 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 index 839e8feaf0..de20c1fc18 100644 --- 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 @@ -47,7 +47,10 @@ function createTestComponent(options = defaultOptions) { const functionsMocks = { buildFacet: jest.fn(() => facetControllerMock), - buildFacetConditionsManager: jest.fn(), + stopWatching: jest.fn(), + buildFacetConditionsManager: jest.fn(() => ({ + stopWatching: functionsMocks.stopWatching, + })), buildSearchStatus: jest.fn(() => ({ subscribe: jest.fn((callback) => callback()), state: {}, @@ -210,4 +213,24 @@ describe('c-quantic-facet', () => { functionsMocks.buildFacet.mockReturnValue(facetControllerMock); }); }); + + describe('when the component is disconnected', () => { + it('should make the condition manager stop watching the facet', async () => { + const exampleFacetDependency = { + parentFacetId: 'filetype', + expectedValue: 'txt', + }; + const element = createTestComponent({ + ...defaultOptions, + dependsOn: exampleFacetDependency, + }); + await flushPromises(); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( + 1 + ); + + document.body.removeChild(element); + expect(functionsMocks.stopWatching).toHaveBeenCalledTimes(1); + }); + }); }); 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 e80f9fb39a..8311d80214 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticFacet/quanticFacet.js +++ b/packages/quantic/force-app/main/default/lwc/quanticFacet/quanticFacet.js @@ -29,6 +29,7 @@ import {LightningElement, track, api} from 'lwc'; /** @typedef {import("coveo").FacetValue} FacetValue */ /** @typedef {import("coveo").SearchStatus} SearchStatus */ /** @typedef {import("coveo").SearchEngine} SearchEngine */ +/** @typedef {import("coveo").FacetConditionsManager} FacetConditionsManager */ /** @typedef {import('../quanticUtils/facetDependenciesUtils').DependsOn} DependsOn */ /** * @typedef FocusTarget @@ -229,6 +230,8 @@ export default class QuanticFacet extends LightningElement { focusShouldBeInFacet = false; /** @type {boolean} */ hasInitializationError = false; + /** @type {FacetConditionsManager} */ + facetConditionsManager; labels = { showMore, @@ -319,6 +322,7 @@ export default class QuanticFacet extends LightningElement { disconnectedCallback() { this.unsubscribe?.(); this.unsubscribeSearchStatus?.(); + this.facetConditionsManager?.stopWatching(); } updateState() { diff --git a/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/__tests__/quanticNumericFacet.test.js b/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/__tests__/quanticNumericFacet.test.js index 17382a5db8..e9b20d8a8c 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/__tests__/quanticNumericFacet.test.js +++ b/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/__tests__/quanticNumericFacet.test.js @@ -20,6 +20,7 @@ const selectors = { }; const exampleFacetId = 'example facet id'; +const exampleFilterId = `${exampleFacetId}_input`; const defaultOptions = { field: 'example field', }; @@ -47,7 +48,16 @@ function createTestComponent(options = defaultOptions) { const functionsMocks = { buildNumericFacet: jest.fn(() => numericFacetControllerMock), - buildFacetConditionsManager: jest.fn(), + buildNumericFilter: jest.fn(() => ({ + subscribe: jest.fn((callback) => callback()), + state: { + facetId: exampleFilterId, + }, + })), + stopWatching: jest.fn(), + buildFacetConditionsManager: jest.fn(() => ({ + stopWatching: functionsMocks.stopWatching, + })), buildSearchStatus: jest.fn(() => ({ subscribe: jest.fn((callback) => callback()), state: {}, @@ -59,6 +69,7 @@ function prepareHeadlessState() { mockHeadlessLoader.getHeadlessBundle = () => { return { buildNumericFacet: functionsMocks.buildNumericFacet, + buildNumericFilter: functionsMocks.buildNumericFilter, buildSearchStatus: functionsMocks.buildSearchStatus, buildFacetConditionsManager: functionsMocks.buildFacetConditionsManager, }; @@ -113,12 +124,14 @@ describe('c-quantic-numeric-facet', () => { createTestComponent({ ...defaultOptions, dependsOn: exampleFacetDependency, + withInput: true, }); await flushPromises(); expect(functionsMocks.buildNumericFacet).toHaveBeenCalledTimes(1); + expect(functionsMocks.buildNumericFilter).toHaveBeenCalledTimes(1); expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( - 1 + 2 ); expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledWith( exampleEngine, @@ -126,8 +139,14 @@ describe('c-quantic-numeric-facet', () => { facetId: exampleFacetId, } ); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledWith( + exampleEngine, + { + facetId: exampleFilterId, + } + ); - expect(generateFacetDependencyConditions).toHaveBeenCalledTimes(1); + expect(generateFacetDependencyConditions).toHaveBeenCalledTimes(2); expect(generateFacetDependencyConditions).toHaveBeenCalledWith({ [exampleFacetDependency.parentFacetId]: exampleFacetDependency.expectedValue, @@ -135,7 +154,10 @@ describe('c-quantic-numeric-facet', () => { }); it('should not build the controller when the dependsOn property is not set', async () => { - createTestComponent(); + createTestComponent({ + ...defaultOptions, + withInput: true, + }); await flushPromises(); expect(functionsMocks.buildNumericFacet).toHaveBeenCalledTimes(1); @@ -191,4 +213,25 @@ describe('c-quantic-numeric-facet', () => { ); }); }); + + describe('when the component is disconnected', () => { + it('should make the condition manager stop watching the facet', async () => { + const exampleFacetDependency = { + parentFacetId: 'filetype', + expectedValue: 'txt', + }; + const element = createTestComponent({ + ...defaultOptions, + dependsOn: exampleFacetDependency, + withInput: true, + }); + await flushPromises(); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( + 2 + ); + + document.body.removeChild(element); + expect(functionsMocks.stopWatching).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/quanticNumericFacet.js b/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/quanticNumericFacet.js index 32f7a950f8..aa577a666d 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/quanticNumericFacet.js +++ b/packages/quantic/force-app/main/default/lwc/quanticNumericFacet/quanticNumericFacet.js @@ -33,6 +33,7 @@ import {LightningElement, track, api} from 'lwc'; /** @typedef {import("coveo").NumericFacetValue} NumericFacetValue */ /** @typedef {import("coveo").SearchStatus} SearchStatus */ /** @typedef {import("coveo").SearchEngine} SearchEngine */ +/** @typedef {import("coveo").FacetConditionsManager} FacetConditionsManager */ /** @typedef {import('../quanticUtils/facetDependenciesUtils').DependsOn} DependsOn */ /** * @typedef FocusTarget @@ -217,6 +218,10 @@ export default class QuanticNumericFacet extends LightningElement { focusShouldBeInFacet = false; /** @type {boolean} */ hasInitializationError = false; + /** @type {FacetConditionsManager} */ + numericFacetConditionsManager; + /** @type {FacetConditionsManager} */ + numericFilterConditionsManager; /** @type {string} */ start; @@ -281,9 +286,6 @@ export default class QuanticNumericFacet extends LightningElement { format: this.formattingFunction, element: this.template.host, }); - if (this.dependsOn) { - this.initFacetConditionManager(engine); - } }; /** @@ -301,18 +303,12 @@ export default class QuanticNumericFacet extends LightningElement { }, }); this.unsubscribe = this.facet.subscribe(() => this.updateState()); - } - - initFacetConditionManager(engine) { - this.facetConditionsManager = this.headless.buildFacetConditionsManager( - engine, - { - facetId: this.facet.state.facetId, - conditions: generateFacetDependencyConditions({ - [this.dependsOn.parentFacetId]: this.dependsOn.expectedValue, - }), - } - ); + if (this.dependsOn) { + this.numericFacetConditionsManager = this.initFacetConditionManager( + engine, + this.facet.state?.facetId + ); + } } /** @@ -330,12 +326,29 @@ export default class QuanticNumericFacet extends LightningElement { this.unsubscribeFilter = this.numericFilter.subscribe(() => this.updateFilterState() ); + if (this.dependsOn) { + this.numericFilterConditionsManager = this.initFacetConditionManager( + engine, + this.numericFilter.state?.facetId + ); + } + } + + initFacetConditionManager(engine, facetId) { + return this.headless.buildFacetConditionsManager(engine, { + facetId, + conditions: generateFacetDependencyConditions({ + [this.dependsOn.parentFacetId]: this.dependsOn.expectedValue, + }), + }); } disconnectedCallback() { this.unsubscribe?.(); this.unsubscribeFilter?.(); this.unsubscribeSearchStatus?.(); + this.numericFacetConditionsManager?.stopWatching(); + this.numericFilterConditionsManager?.stopWatching(); } updateState() { diff --git a/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/__tests__/quanticTimeframeFacet.test.js b/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/__tests__/quanticTimeframeFacet.test.js index fcdbd2d325..7c6a29be37 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/__tests__/quanticTimeframeFacet.test.js +++ b/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/__tests__/quanticTimeframeFacet.test.js @@ -20,6 +20,7 @@ const selectors = { }; const exampleFacetId = 'example facet id'; +const exampleFilterId = `${exampleFacetId}_input`; const defaultOptions = { field: 'example field', }; @@ -49,9 +50,14 @@ const functionsMocks = { buildDateFacet: jest.fn(() => timeframeFacetControllerMock), buildDateFilter: jest.fn(() => ({ subscribe: jest.fn((callback) => callback()), - state: {}, + state: { + facetId: exampleFilterId, + }, + })), + stopWatching: jest.fn(), + buildFacetConditionsManager: jest.fn(() => ({ + stopWatching: functionsMocks.stopWatching, })), - buildFacetConditionsManager: jest.fn(), buildSearchStatus: jest.fn(() => ({ subscribe: jest.fn((callback) => callback()), state: {}, @@ -122,8 +128,9 @@ describe('c-quantic-timeframe-facet', () => { await flushPromises(); expect(functionsMocks.buildDateFacet).toHaveBeenCalledTimes(1); + expect(functionsMocks.buildDateFilter).toHaveBeenCalledTimes(1); expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( - 1 + 2 ); expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledWith( exampleEngine, @@ -131,8 +138,14 @@ describe('c-quantic-timeframe-facet', () => { facetId: exampleFacetId, } ); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledWith( + exampleEngine, + { + facetId: exampleFilterId, + } + ); - expect(generateFacetDependencyConditions).toHaveBeenCalledTimes(1); + expect(generateFacetDependencyConditions).toHaveBeenCalledTimes(2); expect(generateFacetDependencyConditions).toHaveBeenCalledWith({ [exampleFacetDependency.parentFacetId]: exampleFacetDependency.expectedValue, @@ -144,6 +157,7 @@ describe('c-quantic-timeframe-facet', () => { await flushPromises(); expect(functionsMocks.buildDateFacet).toHaveBeenCalledTimes(1); + expect(functionsMocks.buildDateFilter).toHaveBeenCalledTimes(1); expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( 0 ); @@ -196,4 +210,24 @@ describe('c-quantic-timeframe-facet', () => { ); }); }); + + describe('when the component is disconnected', () => { + it('should make the condition manager stop watching the facet', async () => { + const exampleFacetDependency = { + parentFacetId: 'filetype', + expectedValue: 'txt', + }; + const element = createTestComponent({ + ...defaultOptions, + dependsOn: exampleFacetDependency, + }); + await flushPromises(); + expect(functionsMocks.buildFacetConditionsManager).toHaveBeenCalledTimes( + 2 + ); + + document.body.removeChild(element); + expect(functionsMocks.stopWatching).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.js b/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.js index 0f47f445a0..ddd543084f 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.js +++ b/packages/quantic/force-app/main/default/lwc/quanticTimeframeFacet/quanticTimeframeFacet.js @@ -33,6 +33,7 @@ import {api, LightningElement, track} from 'lwc'; /** @typedef {import("coveo").DateFacetValue} DateFacetValue */ /** @typedef {import("coveo").RelativeDatePeriod} RelativeDatePeriod */ /** @typedef {import("coveo").RelativeDateUnit} RelativeDateUnit */ +/** @typedef {import("coveo").FacetConditionsManager} FacetConditionsManager */ /** @typedef {import('../quanticUtils/facetDependenciesUtils').DependsOn} DependsOn */ /** * @typedef {Object} DatepickerElement @@ -208,6 +209,10 @@ export default class QuanticTimeframeFacet extends LightningElement { focusShouldBeInFacet = false; /** @type {boolean} */ hasInitializationError = false; + /** @type {FacetConditionsManager} */ + dateFacetConditionsManager; + /** @type {FacetConditionsManager} */ + dateFilterConditionsManager; _isCollapsed = false; _showValues = true; @@ -239,6 +244,8 @@ export default class QuanticTimeframeFacet extends LightningElement { this.unsubscribeFacet?.(); this.unsubscribeSearchStatus?.(); this.unsubscribeDateFilter?.(); + this.dateFacetConditionsManager?.stopWatching(); + this.dateFilterConditionsManager?.stopWatching(); } get isFacetEnabled() { @@ -418,23 +425,8 @@ export default class QuanticTimeframeFacet extends LightningElement { element: this.template.host, metadata: {timeframes: this.timeframes}, }); - if (this.dependsOn) { - this.initFacetConditionManager(engine); - } }; - initFacetConditionManager(engine) { - this.facetConditionsManager = this.headless.buildFacetConditionsManager( - engine, - { - facetId: this.facet.state.facetId, - conditions: generateFacetDependencyConditions({ - [this.dependsOn.parentFacetId]: this.dependsOn.expectedValue, - }), - } - ); - } - /** * @param {SearchEngine} engine */ @@ -461,6 +453,12 @@ export default class QuanticTimeframeFacet extends LightningElement { }, }); this.unsubscribeFacet = this.facet.subscribe(() => this.updateFacetState()); + if (this.dependsOn) { + this.dateFacetConditionsManager = this.initFacetConditionManager( + engine, + this.facet.state?.facetId + ); + } } /** @@ -480,6 +478,21 @@ export default class QuanticTimeframeFacet extends LightningElement { this.unsubscribeDateFilter = this.dateFilter.subscribe(() => this.updateDateFilterState() ); + if (this.dependsOn) { + this.dateFilterConditionsManager = this.initFacetConditionManager( + engine, + this.dateFilter.state?.facetId + ); + } + } + + initFacetConditionManager(engine, facetId) { + return this.headless.buildFacetConditionsManager(engine, { + facetId, + conditions: generateFacetDependencyConditions({ + [this.dependsOn.parentFacetId]: this.dependsOn.expectedValue, + }), + }); } updateSearchStatusState() {