Skip to content

Commit

Permalink
fix(commerce): fix commerce search facet selectors and facet order (#…
Browse files Browse the repository at this point in the history
…3496)

* set facet order on commerce search query response

* use solution type-specific selector

* test selector usage

* test selectors in specific controllers
  • Loading branch information
Spuffynism authored Dec 19, 2023
1 parent 61dc3cd commit 0166932
Show file tree
Hide file tree
Showing 22 changed files with 277 additions and 116 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {CommerceFacetRequest} from '../../../../../features/commerce/facets/facet-set/interfaces/request';
import {FacetType} from '../../../../../features/commerce/facets/facet-set/interfaces/response';
import {fetchProductListing} from '../../../../../features/commerce/product-listing/product-listing-actions';
import {
toggleExcludeDateFacetValue,
toggleSelectDateFacetValue,
Expand All @@ -12,6 +11,7 @@ import {buildMockCommerceDateFacetResponse} from '../../../../../test/mock-comme
import {buildMockCommerceFacetSlice} from '../../../../../test/mock-commerce-facet-slice';
import {buildMockCommerceDateFacetValue} from '../../../../../test/mock-commerce-facet-value';
import {buildMockCommerceState} from '../../../../../test/mock-commerce-state';
import {commonOptions} from '../../../product-listing/facets/headless-product-listing-facet-options';
import {
CommerceDateFacet,
CommerceDateFacetOptions,
Expand Down Expand Up @@ -45,7 +45,7 @@ describe('CommerceDateFacet', () => {
beforeEach(() => {
options = {
facetId,
fetchResultsActionCreator: fetchProductListing,
...commonOptions,
};

state = buildMockCommerceState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {buildMockCommerceFacetSlice} from '../../../../test/mock-commerce-facet-
import {buildMockCommerceRegularFacetValue} from '../../../../test/mock-commerce-facet-value';
import {buildMockCommerceState} from '../../../../test/mock-commerce-state';
import {FacetValueState} from '../../../core/facets/facet/headless-core-facet';
import {commonOptions} from '../../product-listing/facets/headless-product-listing-facet-options';
import {
buildCoreCommerceFacet,
CoreCommerceFacet,
Expand Down Expand Up @@ -52,23 +53,22 @@ describe('CoreCommerceFacet', () => {
}

function setFacetResponse(config: Partial<RegularFacetResponse> = {}) {
state.productListing.facets = [
options.facetResponseSelector = () =>
buildMockCommerceRegularFacetResponse({
facetId,
field,
type,
displayName,
...config,
}),
];
});
}

beforeEach(() => {
options = {
facetId,
fetchResultsActionCreator,
toggleExcludeActionCreator,
toggleSelectActionCreator,
...commonOptions,
};

state = buildMockCommerceState();
Expand Down Expand Up @@ -381,34 +381,47 @@ describe('CoreCommerceFacet', () => {
expect(facet.state.displayName).toBe(displayName);
});

it('#state.values contains the same values as from the response', () => {
it('#state.values uses #facetResponseSelector', () => {
const values = [buildMockCommerceRegularFacetValue()];
const facetResponse = buildMockCommerceRegularFacetResponse({
facetId,
values,
});
options = {
...options,
facetResponseSelector: () =>
buildMockCommerceRegularFacetResponse({
facetId,
values,
}),
};
initFacet();

state.productListing.facets = [facetResponse];
expect(facet.state.values).toBe(values);
});

it('#state.isLoading uses #isFacetLoadingResponseSelector', () => {
options = {
...options,
isFacetLoadingResponseSelector: () => true,
};
initFacet();
expect(facet.state.isLoading).toBe(true);
});

describe('#state.hasActiveValues', () => {
it('when #state.values has a value with a non-idle state, returns "true"', () => {
const facetResponse = buildMockCommerceRegularFacetResponse({facetId});
facetResponse.values = [
buildMockCommerceRegularFacetValue({state: 'selected'}),
];
state.productListing.facets = [facetResponse];
setFacetResponse({
...buildMockCommerceRegularFacetResponse({facetId}),
values: [buildMockCommerceRegularFacetValue({state: 'selected'})],
});
initFacet();

expect(facet.state.hasActiveValues).toBe(true);
});

it('when #state.values only has idle values, returns "false"', () => {
const facetResponse = buildMockCommerceRegularFacetResponse({facetId});
facetResponse.values = [
buildMockCommerceRegularFacetValue({state: 'idle'}),
];
state.productListing.facets = [facetResponse];
setFacetResponse({
...buildMockCommerceRegularFacetResponse({facetId}),
values: [buildMockCommerceRegularFacetValue({state: 'idle'})],
});
initFacet();

expect(facet.state.hasActiveValues).toBe(false);
});
Expand All @@ -420,22 +433,26 @@ describe('CoreCommerceFacet', () => {
});

it('when #moreValuesAvailable in the response is "true", returns "true"', () => {
const facetResponse = buildMockCommerceRegularFacetResponse({
facetId,
moreValuesAvailable: true,
});
setFacetResponse(
buildMockCommerceRegularFacetResponse({
facetId,
moreValuesAvailable: true,
})
);
initFacet();

state.productListing.facets = [facetResponse];
expect(facet.state.canShowMoreValues).toBe(true);
});

it('when #moreValuesAvailable in the response is "false", returns "false"', () => {
const facetResponse = buildMockCommerceRegularFacetResponse({
facetId,
moreValuesAvailable: false,
});
setFacetResponse(
buildMockCommerceRegularFacetResponse({
facetId,
moreValuesAvailable: false,
})
);
initFacet();

state.productListing.facets = [facetResponse];
expect(facet.state.canShowMoreValues).toBe(false);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ import {
AsyncThunkAction,
} from '@reduxjs/toolkit';
import {CommerceEngine} from '../../../../app/commerce-engine/commerce-engine';
import {
commerceFacetResponseSelector,
isCommerceFacetLoadingResponseSelector,
} from '../../../../features/commerce/facets/facet-set/facet-set-selector';
import {commerceFacetSetReducer as commerceFacetSet} from '../../../../features/commerce/facets/facet-set/facet-set-slice';
import {
AnyFacetResponse,
AnyFacetValueResponse,
DateFacetValue,
FacetType,
Expand Down Expand Up @@ -74,13 +71,20 @@ export interface CoreCommerceFacetOptions {
>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fetchResultsActionCreator: () => AsyncThunkAction<unknown, void, any>;
facetResponseSelector: (
state: CommerceEngine['state'],
facetId: string
) => AnyFacetResponse | undefined;
isFacetLoadingResponseSelector: (state: CommerceEngine['state']) => boolean;
}

export type CommerceFacetOptions = Omit<
CoreCommerceFacetOptions,
| 'fetchResultsActionCreator'
| 'toggleSelectActionCreator'
| 'toggleExcludeActionCreator'
| 'facetResponseSelector'
| 'isFacetLoadingResponseSelector'
>;

export type CoreCommerceFacet<
Expand Down Expand Up @@ -176,9 +180,9 @@ export function buildCoreCommerceFacet<

const getRequest = () => engine.state.commerceFacetSet[facetId].request;
const getResponse = () =>
commerceFacetResponseSelector(engine.state, facetId)!;
props.options.facetResponseSelector(engine.state, facetId)!;
const getIsLoading = () =>
isCommerceFacetLoadingResponseSelector(engine.state);
props.options.isFacetLoadingResponseSelector(engine.state);

const getNumberOfActiveValues = () => {
return getRequest().values.filter((v) => v.state !== 'idle').length;
Expand Down Expand Up @@ -279,7 +283,7 @@ export function buildCoreCommerceFacet<
field: response.field,
displayName: response.displayName,
values,
isLoading: getIsLoading() ?? false,
isLoading: getIsLoading(),
hasActiveValues,
canShowMoreValues,
canShowLessValues: computeCanShowLessValues(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {CommerceFacetRequest} from '../../../../../features/commerce/facets/facet-set/interfaces/request';
import {FacetType} from '../../../../../features/commerce/facets/facet-set/interfaces/response';
import {fetchProductListing} from '../../../../../features/commerce/product-listing/product-listing-actions';
import {
toggleExcludeNumericFacetValue,
toggleSelectNumericFacetValue,
Expand All @@ -12,6 +11,7 @@ import {buildMockCommerceNumericFacetResponse} from '../../../../../test/mock-co
import {buildMockCommerceFacetSlice} from '../../../../../test/mock-commerce-facet-slice';
import {buildMockCommerceNumericFacetValue} from '../../../../../test/mock-commerce-facet-value';
import {buildMockCommerceState} from '../../../../../test/mock-commerce-state';
import {commonOptions} from '../../../product-listing/facets/headless-product-listing-facet-options';
import {
CommerceNumericFacet,
CommerceNumericFacetOptions,
Expand Down Expand Up @@ -45,7 +45,7 @@ describe('CommerceNumericFacet', () => {
beforeEach(() => {
options = {
facetId,
fetchResultsActionCreator: fetchProductListing,
...commonOptions,
};

state = buildMockCommerceState();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {CommerceFacetRequest} from '../../../../../features/commerce/facets/facet-set/interfaces/request';
import {fetchProductListing} from '../../../../../features/commerce/product-listing/product-listing-actions';
import {
toggleExcludeFacetValue,
toggleSelectFacetValue,
Expand All @@ -11,6 +10,7 @@ import {buildMockCommerceRegularFacetResponse} from '../../../../../test/mock-co
import {buildMockCommerceFacetSlice} from '../../../../../test/mock-commerce-facet-slice';
import {buildMockCommerceRegularFacetValue} from '../../../../../test/mock-commerce-facet-value';
import {buildMockCommerceState} from '../../../../../test/mock-commerce-state';
import {commonOptions} from '../../../product-listing/facets/headless-product-listing-facet-options';
import {
CommerceRegularFacet,
CommerceRegularFacetOptions,
Expand Down Expand Up @@ -41,7 +41,7 @@ describe('CommerceRegularFacet', () => {
beforeEach(() => {
options = {
facetId,
fetchResultsActionCreator: fetchProductListing,
...commonOptions,
};

state = buildMockCommerceState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,17 @@ describe('ProductListingDateFacet', () => {
expectContainAction(fetchProductListing.pending);
});
});

describe('#state', () => {
it('#state.values uses #facetResponseSelector', () => {
expect(facet.state.facetId).toEqual(
state.productListing.facets[0].facetId
);
});

it('#state.isLoading uses #isFacetLoadingResponseSelector', () => {
state.productListing.isLoading = true;
expect(facet.state.isLoading).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {CommerceEngine} from '../../../../app/commerce-engine/commerce-engine';
import {fetchProductListing} from '../../../../features/commerce/product-listing/product-listing-actions';
import {loadReducerError} from '../../../../utils/errors';
import {
CommerceDateFacet,
buildCommerceDateFacet,
} from '../../facets/core/date/headless-commerce-date-facet';
import {CommerceFacetOptions} from '../../facets/core/headless-core-commerce-facet';
import {loadProductListingReducer} from '../utils/load-product-listing-reducers';
import {commonOptions} from './headless-product-listing-facet-options';

export function buildProductListingDateFacet(
engine: CommerceEngine,
Expand All @@ -18,6 +18,6 @@ export function buildProductListingDateFacet(

return buildCommerceDateFacet(engine, {
...options,
fetchResultsActionCreator: fetchProductListing,
...commonOptions,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {isFacetResponse} from '../../../../features/commerce/facets/facet-set/facet-set-selector';
import {fetchProductListing} from '../../../../features/commerce/product-listing/product-listing-actions';
import {
CommerceFacetSetSection,
ProductListingV2Section,
} from '../../../../state/state-sections';
import {CoreCommerceFacetOptions} from '../../facets/core/headless-core-commerce-facet';

const facetResponseSelector = (
state: ProductListingV2Section & CommerceFacetSetSection,
facetId: string
) => {
const response = state.productListing.facets.find(
(response) => response.facetId === facetId
);
if (isFacetResponse(state, response)) {
return response;
}

return undefined;
};

const isFacetLoadingResponseSelector = (state: ProductListingV2Section) =>
state.productListing.isLoading;

export const commonOptions: Pick<
CoreCommerceFacetOptions,
| 'fetchResultsActionCreator'
| 'facetResponseSelector'
| 'isFacetLoadingResponseSelector'
> = {
fetchResultsActionCreator: fetchProductListing,
facetResponseSelector,
isFacetLoadingResponseSelector,
};
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,17 @@ describe('ProductListingNumericFacet', () => {
expectContainAction(fetchProductListing.pending);
});
});

describe('#state', () => {
it('#state.values uses #facetResponseSelector', () => {
expect(facet.state.facetId).toEqual(
state.productListing.facets[0].facetId
);
});

it('#state.isLoading uses #isFacetLoadingResponseSelector', () => {
state.productListing.isLoading = true;
expect(facet.state.isLoading).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {CommerceEngine} from '../../../../app/commerce-engine/commerce-engine';
import {fetchProductListing} from '../../../../features/commerce/product-listing/product-listing-actions';
import {loadReducerError} from '../../../../utils/errors';
import {CommerceFacetOptions} from '../../facets/core/headless-core-commerce-facet';
import {
CommerceNumericFacet,
buildCommerceNumericFacet,
} from '../../facets/core/numeric/headless-commerce-numeric-facet';
import {loadProductListingReducer} from '../utils/load-product-listing-reducers';
import {commonOptions} from './headless-product-listing-facet-options';

export function buildProductListingNumericFacet(
engine: CommerceEngine,
Expand All @@ -18,6 +18,6 @@ export function buildProductListingNumericFacet(

return buildCommerceNumericFacet(engine, {
...options,
fetchResultsActionCreator: fetchProductListing,
...commonOptions,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,17 @@ describe('ProductListingRegularFacet', () => {
expectContainAction(fetchProductListing.pending);
});
});

describe('#state', () => {
it('#state.values uses #facetResponseSelector', () => {
expect(facet.state.facetId).toEqual(
state.productListing.facets[0].facetId
);
});

it('#state.isLoading uses #isFacetLoadingResponseSelector', () => {
state.productListing.isLoading = true;
expect(facet.state.isLoading).toBe(true);
});
});
});
Loading

0 comments on commit 0166932

Please sign in to comment.