Skip to content

Commit

Permalink
feat(commerce): add pagination and sort sub-controllers (#3800)
Browse files Browse the repository at this point in the history
In follow-up PRs, I will:
- Add pagination to the recs controller
- Make sub-controller state handled separated, to allow multiple
solution types to coexist
- Add the facet generator as sub-controller
- Remove the `build[SolutionType]pagination`, `build[SolutionType]sort`,
`build[SolutionType]facetGenerator` and similar top-level builders that
become sub-controllers

[CAPI-719]

[CAPI-719]:
https://coveord.atlassian.net/browse/CAPI-719?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
Spuffynism authored Apr 17, 2024
1 parent 313164d commit 5f2d2a2
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {buildMockCommerceState} from '../../../../test/mock-commerce-state';
import {
MockedCommerceEngine,
buildMockCommerceEngine,
} from '../../../../test/mock-engine-v2';
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';

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 buildCoreInteractiveResultMock = jest.spyOn(
CoreInteractiveResult,
'buildCoreInteractiveResult'
);

const props = {
options: {
product: {
productId: '1',
name: 'Product name',
price: 17.99,
},
position: 1,
},
};

const interactiveResult = subControllers.interactiveResult({
...props,
});

expect(interactiveResult).toEqual(
buildCoreInteractiveResultMock.mock.results[0].value
);
});

it('#pagination builds pagination controller', () => {
const buildCorePaginationMock = jest.spyOn(
CorePagination,
'buildCorePagination'
);

const pagination = subControllers.pagination();

expect(pagination).toEqual(buildCorePaginationMock.mock.results[0].value);
});

it('#sort builds sort controller', () => {
const buildCoreSortMock = jest.spyOn(CoreSort, 'buildCoreSort');

const sort = subControllers.sort();

expect(sort).toEqual(buildCoreSortMock.mock.results[0].value);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export function buildProductListing(engine: CommerceEngine): ProductListing {
const getState = () => engine.state;
const subControllers = buildSolutionTypeSubControllers(engine, {
responseIdSelector,
fetchResultsActionCreator: fetchProductListing,
});

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export function buildSearch(engine: CommerceEngine): Search {
const getState = () => engine.state;
const subControllers = buildSolutionTypeSubControllers(engine, {
responseIdSelector,
fetchResultsActionCreator: executeSearch,
});

return {
Expand Down

0 comments on commit 5f2d2a2

Please sign in to comment.