Skip to content

Commit

Permalink
fix(headless): ensure each folded result keep a reference of its 'sou…
Browse files Browse the repository at this point in the history
  • Loading branch information
y-lakhdar authored Nov 6, 2024
1 parent b65b5c7 commit 97bd35c
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 15 deletions.
2 changes: 2 additions & 0 deletions packages/headless/src/features/folding/folding-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface LoadCollectionFulfilledReturn {
results: Result[];
collectionId: CollectionId;
rootResult: ResultWithFolding;
searchUid: string;
}

export const foldingOptionsSchemaDefinition: SchemaDefinition<
Expand Down Expand Up @@ -105,6 +106,7 @@ export const loadCollection = createAsyncThunk<
return {
collectionId,
results: response.success.results,
searchUid: response.success.searchUid,
rootResult: state.folding.collections[collectionId]!
.result as ResultWithFolding,
};
Expand Down
27 changes: 26 additions & 1 deletion packages/headless/src/features/folding/folding-slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ describe('folding slice', () => {
collectionId: results[0].raw.collection!,
results,
rootResult,
searchUid: 'some-search-uid',
});
}

Expand Down Expand Up @@ -205,6 +206,30 @@ describe('folding slice', () => {
);
};

it('when a fetchPage fulfilled is received, new results should contain the latest search #searchUid', () => {
const indexedResults = buildMockResultsFromHierarchy(
'thread',
testThreadHierarchy
);
const rootResult = emulateAPIFolding(indexedResults);
const response = {
...buildMockSearchResponse({results: [rootResult]}),
searchUid: 'a_new_id',
};
const search = buildMockSearch({
response,
});

const finalState = foldingReducer(
state,
fetchMoreResults.fulfilled(search, '')
);

expect(finalState.collections.thread.children[0].result.searchUid).toBe(
'a_new_id'
);
});

it('uses #cq with correct expression to obtain the full collection', async () => {
await doLoadCollection();
expect(apiClient.search).toHaveBeenCalledWith(
Expand Down Expand Up @@ -257,7 +282,7 @@ describe('folding slice', () => {
);
});

it('does not uses facets to get the full collection', async () => {
it('does not use facets to get the full collection', async () => {
await doLoadCollection();
expect(apiClient.search).toHaveBeenCalledWith(
expect.not.objectContaining({
Expand Down
38 changes: 25 additions & 13 deletions packages/headless/src/features/folding/folding-slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,16 @@ function resolveChildrenFromFields(
getParentField(result, fields) === sourceChildValue;
return isChildOfSource && !isSameResultAsSource;
})
.map((result) => ({
result,
children: resolveChildrenFromFields(result, results, fields, [
...resolvedAncestors,
sourceChildValue,
]),
}));
.map((result) => {
const extendedResult = {...result, searchUid: parent.searchUid};
return {
result: extendedResult,
children: resolveChildrenFromFields(extendedResult, results, fields, [
...resolvedAncestors,
sourceChildValue,
]),
};
});
}

function resolveRootFromFields(
Expand Down Expand Up @@ -101,6 +104,7 @@ function resolveRootFromParentResult(
function createCollectionFromResult(
relevantResult: ResultWithFolding,
fields: FoldingFields,
searchUid: string,
rootResult?: ResultWithFolding
): FoldedCollection {
const resultsInCollection = getAllIncludedResultsFrom(relevantResult);
Expand All @@ -110,10 +114,12 @@ function createCollectionFromResult(
resolveRootFromFields(resultsInCollection, fields) ??
resolveRootFromParentResult(relevantResult);

const extendedResultToUseAsRoot = {...resultToUseAsRoot, searchUid};

return {
result: resultToUseAsRoot,
result: extendedResultToUseAsRoot,
children: resolveChildrenFromFields(
resultToUseAsRoot,
extendedResultToUseAsRoot,
resultsInCollection,
fields
),
Expand All @@ -125,6 +131,7 @@ function createCollectionFromResult(
function createCollections(
results: ResultWithFolding[],
fields: FoldingFields,
searchUid: string,
rootResult?: ResultWithFolding
) {
const collections: Record<CollectionId, FoldedCollection> = {};
Expand All @@ -139,6 +146,7 @@ function createCollections(
collections[collectionId] = createCollectionFromResult(
result,
fields,
searchUid,
rootResult
);
});
Expand Down Expand Up @@ -168,15 +176,17 @@ export const foldingReducer = createReducer(
state.collections = state.enabled
? createCollections(
payload.response.results as ResultWithFolding[],
state.fields
state.fields,
payload.response.searchUid
)
: {};
})
.addCase(fetchPage.fulfilled, (state, {payload}) => {
state.collections = state.enabled
? createCollections(
payload.response.results as ResultWithFolding[],
state.fields
state.fields,
payload.response.searchUid
)
: {};
})
Expand All @@ -186,7 +196,8 @@ export const foldingReducer = createReducer(
...state.collections,
...createCollections(
payload.response.results as ResultWithFolding[],
state.fields
state.fields,
payload.response.searchUid
),
}
: {};
Expand Down Expand Up @@ -222,10 +233,11 @@ export const foldingReducer = createReducer(
})
.addCase(
loadCollection.fulfilled,
(state, {payload: {collectionId, results, rootResult}}) => {
(state, {payload: {collectionId, results, rootResult, searchUid}}) => {
const newCollections = createCollections(
results as ResultWithFolding[],
state.fields,
searchUid,
rootResult
);
if (!newCollections || !newCollections[collectionId]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const loadCollection = createAsyncThunk<
return {
collectionId,
results: response.success.results,
searchUid: response.success.searchUid,
rootResult: state.folding.collections[collectionId]!
.result as ResultWithFolding,
};
Expand Down
19 changes: 19 additions & 0 deletions packages/headless/src/features/search/search-slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,25 @@ describe('search-slice', () => {
expect(finalState.results[1].searchUid).toBe('a_new_id');
});

it('when a fetchPage fulfilled is received, new results should contain the latest search #searchUid', () => {
state.results = state.results.map((result) => ({
...result,
searchUid: 'an_initial_id',
}));
const response = buildMockSearchResponse({results: [newResult]});
response.searchUid = 'a_new_id';
const search = buildMockSearch({
response,
});

const finalState = searchReducer(
state,
fetchPage.fulfilled(search, '', {legacy: logPageNext()})
);

expect(finalState.results[0].searchUid).toBe('a_new_id');
});

it('when a fetchMoreResults fulfilled is received, keeps the previous #questionAnswer', () => {
const originalQuestionAnswers = buildMockQuestionsAnswers({
question: 'Why?',
Expand Down
7 changes: 6 additions & 1 deletion packages/headless/src/features/search/search-slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ export const searchReducer = createReducer(
});
builder.addCase(fetchPage.fulfilled, (state, action) => {
handleFulfilledSearch(state, action);
state.results = action.payload.response.results;
state.results = [
...action.payload.response.results.map((result) => ({
...result,
searchUid: action.payload.response.searchUid,
})),
];
});
builder.addCase(fetchFacetValues.fulfilled, (state, action) => {
state.response.facets = action.payload.response.facets;
Expand Down

0 comments on commit 97bd35c

Please sign in to comment.