From 19c1d10a668b06805b1f9cdd854be22559b6744f Mon Sep 17 00:00:00 2001 From: Nicholas-David Labarre Date: Mon, 15 Apr 2024 15:02:26 -0400 Subject: [PATCH 1/2] add pagination and sort sub-controllers --- .../headless-sub-controller.test.ts | 76 +++++++++++++++++++ .../sub-controller/headless-sub-controller.ts | 29 ++++++- .../headless-product-listing.ts | 1 + .../commerce/search/headless-search.ts | 1 + 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts diff --git a/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts b/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts new file mode 100644 index 00000000000..210cfd750ed --- /dev/null +++ b/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts @@ -0,0 +1,76 @@ +import {buildMockCommerceState} from '../../../../test/mock-commerce-state'; +import { + MockedCommerceEngine, + buildMockCommerceEngine, +} from '../../../../test/mock-engine-v2'; +import {buildCorePagination} from '../pagination/headless-core-commerce-pagination'; +import {buildCoreInteractiveResult} from '../result-list/headless-core-interactive-result'; +import {buildCoreSort} from '../sort/headless-core-commerce-sort'; +import { + buildSolutionTypeSubControllers, + SolutionTypeSubControllers, +} from './headless-sub-controller'; + +jest.mock('../result-list/headless-core-interactive-result'); +jest.mock('../pagination/headless-core-commerce-pagination'); +jest.mock('../sort/headless-core-commerce-sort'); + +describe('sub controllers', () => { + let engine: MockedCommerceEngine; + let subControllers: SolutionTypeSubControllers; + const mockResponseIdSelector = jest.fn(); + const mockFetchResultsActionCreator = jest.fn(); + + function initSubControllers() { + engine = buildMockCommerceEngine(buildMockCommerceState()); + + subControllers = buildSolutionTypeSubControllers(engine, { + responseIdSelector: mockResponseIdSelector, + fetchResultsActionCreator: mockFetchResultsActionCreator, + }); + } + + beforeEach(() => { + initSubControllers(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('#interactiveResult builds interactive result controller', () => { + const props = { + options: { + product: { + productId: '1', + name: 'Product name', + price: 17.99, + }, + position: 1, + }, + }; + + subControllers.interactiveResult({ + ...props, + }); + + expect(buildCoreInteractiveResult).toHaveBeenCalledWith(engine, { + ...props, + responseIdSelector: mockResponseIdSelector, + }); + }); + + it('#pagination builds pagination controller', () => { + subControllers.pagination(); + expect(buildCorePagination).toHaveBeenCalledWith(engine, { + fetchResultsActionCreator: mockFetchResultsActionCreator, + }); + }); + + it('#sort builds sort controller', () => { + subControllers.sort(); + expect(buildCoreSort).toHaveBeenCalledWith(engine, { + fetchResultsActionCreator: mockFetchResultsActionCreator, + }); + }); +}); diff --git a/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.ts b/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.ts index 46c33200711..4fbf72d6bd4 100644 --- a/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.ts +++ b/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.ts @@ -2,29 +2,56 @@ import { CommerceEngine, CommerceEngineState, } from '../../../../app/commerce-engine/commerce-engine'; +import {FetchResultsActionCreator} from '../common'; +import { + buildCorePagination, + Pagination, + PaginationProps, +} from '../pagination/headless-core-commerce-pagination'; import { buildCoreInteractiveResult, InteractiveResult, InteractiveResultProps, } from '../result-list/headless-core-interactive-result'; +import { + buildCoreSort, + Sort, + SortProps, +} from '../sort/headless-core-commerce-sort'; export interface SolutionTypeSubControllers { interactiveResult: (props: InteractiveResultProps) => InteractiveResult; + pagination: (props?: PaginationProps) => Pagination; + sort: (props?: SortProps) => Sort; } interface SubControllerProps { responseIdSelector: (state: CommerceEngineState) => string; + fetchResultsActionCreator: FetchResultsActionCreator; } export function buildSolutionTypeSubControllers( engine: CommerceEngine, subControllerProps: SubControllerProps ): SolutionTypeSubControllers { + const {responseIdSelector, fetchResultsActionCreator} = subControllerProps; return { interactiveResult(props: InteractiveResultProps) { return buildCoreInteractiveResult(engine, { ...props, - responseIdSelector: subControllerProps.responseIdSelector, + responseIdSelector, + }); + }, + pagination(props?: PaginationProps) { + return buildCorePagination(engine, { + ...props, + fetchResultsActionCreator, + }); + }, + sort(props?: SortProps) { + return buildCoreSort(engine, { + ...props, + fetchResultsActionCreator, }); }, }; diff --git a/packages/headless/src/controllers/commerce/product-listing/headless-product-listing.ts b/packages/headless/src/controllers/commerce/product-listing/headless-product-listing.ts index d25b0e6adf9..0dcb1502f58 100644 --- a/packages/headless/src/controllers/commerce/product-listing/headless-product-listing.ts +++ b/packages/headless/src/controllers/commerce/product-listing/headless-product-listing.ts @@ -54,6 +54,7 @@ export function buildProductListing(engine: CommerceEngine): ProductListing { const getState = () => engine.state; const subControllers = buildSolutionTypeSubControllers(engine, { responseIdSelector, + fetchResultsActionCreator: fetchProductListing, }); return { diff --git a/packages/headless/src/controllers/commerce/search/headless-search.ts b/packages/headless/src/controllers/commerce/search/headless-search.ts index e27e5d41c12..628f08825da 100644 --- a/packages/headless/src/controllers/commerce/search/headless-search.ts +++ b/packages/headless/src/controllers/commerce/search/headless-search.ts @@ -47,6 +47,7 @@ export function buildSearch(engine: CommerceEngine): Search { const getState = () => engine.state; const subControllers = buildSolutionTypeSubControllers(engine, { responseIdSelector, + fetchResultsActionCreator: executeSearch, }); return { From 86f3881890a7b7e1ca40b7b28938a7f871a0794d Mon Sep 17 00:00:00 2001 From: Nicholas-David Labarre Date: Tue, 16 Apr 2024 16:05:37 -0400 Subject: [PATCH 2/2] make builder tests more thorough --- .../headless-sub-controller.test.ts | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts b/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts index 210cfd750ed..56d24629a9b 100644 --- a/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts +++ b/packages/headless/src/controllers/commerce/core/sub-controller/headless-sub-controller.test.ts @@ -3,18 +3,14 @@ import { MockedCommerceEngine, buildMockCommerceEngine, } from '../../../../test/mock-engine-v2'; -import {buildCorePagination} from '../pagination/headless-core-commerce-pagination'; -import {buildCoreInteractiveResult} from '../result-list/headless-core-interactive-result'; -import {buildCoreSort} from '../sort/headless-core-commerce-sort'; +import * as CorePagination from '../pagination/headless-core-commerce-pagination'; +import * as CoreInteractiveResult from '../result-list/headless-core-interactive-result'; +import * as CoreSort from '../sort/headless-core-commerce-sort'; import { buildSolutionTypeSubControllers, SolutionTypeSubControllers, } from './headless-sub-controller'; -jest.mock('../result-list/headless-core-interactive-result'); -jest.mock('../pagination/headless-core-commerce-pagination'); -jest.mock('../sort/headless-core-commerce-sort'); - describe('sub controllers', () => { let engine: MockedCommerceEngine; let subControllers: SolutionTypeSubControllers; @@ -39,6 +35,11 @@ describe('sub controllers', () => { }); it('#interactiveResult builds interactive result controller', () => { + const buildCoreInteractiveResultMock = jest.spyOn( + CoreInteractiveResult, + 'buildCoreInteractiveResult' + ); + const props = { options: { product: { @@ -50,27 +51,31 @@ describe('sub controllers', () => { }, }; - subControllers.interactiveResult({ + const interactiveResult = subControllers.interactiveResult({ ...props, }); - expect(buildCoreInteractiveResult).toHaveBeenCalledWith(engine, { - ...props, - responseIdSelector: mockResponseIdSelector, - }); + expect(interactiveResult).toEqual( + buildCoreInteractiveResultMock.mock.results[0].value + ); }); it('#pagination builds pagination controller', () => { - subControllers.pagination(); - expect(buildCorePagination).toHaveBeenCalledWith(engine, { - fetchResultsActionCreator: mockFetchResultsActionCreator, - }); + const buildCorePaginationMock = jest.spyOn( + CorePagination, + 'buildCorePagination' + ); + + const pagination = subControllers.pagination(); + + expect(pagination).toEqual(buildCorePaginationMock.mock.results[0].value); }); it('#sort builds sort controller', () => { - subControllers.sort(); - expect(buildCoreSort).toHaveBeenCalledWith(engine, { - fetchResultsActionCreator: mockFetchResultsActionCreator, - }); + const buildCoreSortMock = jest.spyOn(CoreSort, 'buildCoreSort'); + + const sort = subControllers.sort(); + + expect(sort).toEqual(buildCoreSortMock.mock.results[0].value); }); });