Skip to content

Commit

Permalink
fix(headless+atomic): make recent queries case insensitive + display …
Browse files Browse the repository at this point in the history
…recent query even if it fully matches current query (#4854)

https://coveord.atlassian.net/browse/JSUI-3546

---------

Co-authored-by: GitHub Actions Bot <>
  • Loading branch information
fbeaudoincoveo authored Jan 29, 2025
1 parent fc6ff33 commit 6ceebaa
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const setInstantResults = (count: number) => (fixture: TestFixture) => {
const setRecentQueries = (count: number) => () => {
new SafeStorage().setJSON(
StorageItems.RECENT_QUERIES,
Array.from({length: count}, (_, i) => `Recent query ${i}`)
Array.from({length: count}, (_, i) => `recent query ${i}`)
);
};

Expand Down Expand Up @@ -165,7 +165,7 @@ describe('Instant Results Test Suites', () => {
);

SearchBoxAssertions.assertSuggestionIsSelectedWithoutIt(0);
SearchBoxAssertions.assertHasTextWithoutIt('Recent query 0');
SearchBoxAssertions.assertHasTextWithoutIt('recent query 0');

cy.log('when navigating to first suggestion and back with up arrow');
SearchBoxSelectors.textArea().type(`${downKeys(3)}{upArrow}`, delay());
Expand Down Expand Up @@ -202,7 +202,7 @@ describe('Instant Results Test Suites', () => {

SearchBoxAssertions.assertNoSuggestionIsSelected();

SearchBoxAssertions.assertHasTextWithoutIt('Recent query ');
SearchBoxAssertions.assertHasTextWithoutIt('recent query ');

cy.wait(1000);
SearchBoxSelectors.textArea().type(
Expand Down
14 changes: 7 additions & 7 deletions packages/atomic/cypress/e2e/search-box/search-box.cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const setSuggestions = (count: number) => () => {
const setRecentQueries = (count: number) => () => {
new SafeStorage().setJSON(
StorageItems.RECENT_QUERIES,
Array.from({length: count}, (_, i) => `Recent query ${i}`)
Array.from({length: count}, (_, i) => `recent query ${i}`)
);
};

Expand Down Expand Up @@ -349,11 +349,11 @@ describe('Search Box Test Suites', () => {
beforeEach(() => {
setupWithRecentQueries();
SearchBoxSelectors.textArea().focus();
SearchBoxSelectors.querySuggestion('Recent query 1').click();
SearchBoxSelectors.querySuggestion('recent query 1').click();
});

SearchBoxAssertions.assertFocusSearchBox();
SearchBoxAssertions.assertHasText('Recent query 1');
SearchBoxAssertions.assertHasText('recent query 1');
});

describe('after focusing a suggestion with the keyboard', () => {
Expand All @@ -368,11 +368,11 @@ describe('Search Box Test Suites', () => {
});

it('has recent query', () => {
SearchBoxAssertions.assertHasText('Recent query 1');
SearchBoxAssertions.assertHasText('recent query 1');
});

it('should always have one active suggestion at a time', () => {
SearchBoxSelectors.querySuggestion('Recent query 2').trigger(
SearchBoxSelectors.querySuggestion('recent query 2').trigger(
'mouseover'
);

Expand All @@ -383,7 +383,7 @@ describe('Search Box Test Suites', () => {

it('still has recent query after pressing the search button', () => {
SearchBoxSelectors.submitButton().click();
SearchBoxAssertions.assertHasText('Recent query 1');
SearchBoxAssertions.assertHasText('recent query 1');
});
});

Expand All @@ -395,7 +395,7 @@ describe('Search Box Test Suites', () => {
});

it('should submit what is in the search box regardless of the mouse position', () => {
SearchBoxSelectors.querySuggestion('Recent query 1').trigger(
SearchBoxSelectors.querySuggestion('recent query 1').trigger(
'mouseover'
);
SearchBoxSelectors.submitButton().click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const setSuggestions = (count: number) => () => {
const setRecentQueries = (count: number) => () => {
new SafeStorage().setJSON(
StorageItems.RECENT_QUERIES,
Array.from({length: count}, (_, i) => `Recent query ${i}`)
Array.from({length: count}, (_, i) => `recent query ${i}`)
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function setRecentQueries(page: Page, count: number) {
await page.evaluate((count: number) => {
const recentQueries = Array.from(
{length: count},
(_, i) => `Recent query ${i}`
(_, i) => `recent query ${i}`
);
const stringified = JSON.stringify(recentQueries);
localStorage.setItem('coveo-recent-queries', stringified);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,8 @@ export class AtomicCommerceSearchBoxRecentQueries {
const hasQuery = query !== '';
const max = hasQuery ? this.maxWithQuery : this.maxWithoutQuery;
const filteredQueries = this.recentQueriesList.state.queries
.filter(
(recentQuery) =>
recentQuery !== query &&
recentQuery.toLowerCase().startsWith(query.toLowerCase())
.filter((recentQuery) =>
recentQuery.toLowerCase().startsWith(query.toLowerCase())
)
.slice(0, max);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,8 @@ export class AtomicSearchBoxRecentQueries {
const hasQuery = query !== '';
const max = hasQuery ? this.maxWithQuery : this.maxWithoutQuery;
const filteredQueries = this.recentQueriesList.state.queries
.filter(
(recentQuery) =>
recentQuery !== query &&
recentQuery.toLowerCase().startsWith(query.toLowerCase())
.filter((recentQuery) =>
recentQuery.toLowerCase().startsWith(query.toLowerCase())
)
.slice(0, max);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,52 @@ describe('commerce/recent-queries-slice', () => {
});
});

it('#registerRecentQueries should set queries and maxLength params in state', () => {
it('#registerRecentQueries should trim and lowercase queries, and eliminate duplicates in state', () => {
state = recentQueriesReducer(
state,
registerRecentQueries({
queries: [
'what is LOVE',
'Oh baby',
"don't hurt me",
" DON'T HURT ME ",
'no more!',
],
maxLength: testMaxLength,
})
);

expect(state.queries).toEqual([
'what is love',
'oh baby',
"don't hurt me",
'no more!',
]);
});

it('#registerRecentQueries should set maxLength params in state', () => {
state = recentQueriesReducer(
state,
registerRecentQueries({queries: testQueries, maxLength: testMaxLength})
);

expect(state.queries).toEqual(testQueries);
expect(state.maxLength).toEqual(testMaxLength);
});

it('#registerRecentQueries should shorten queries if it exceeds maxLength param', () => {
const queries = ['q1', 'q2', 'q3', 'q4'];
it('#registerRecentQueries should only keep queries up to the specified maxLength (after eliminating duplicates) in state', () => {
const queries = [
'what is LOVE',
'Oh baby',
"don't hurt me",
" DON'T HURT ME ",
'no more!',
];
state = recentQueriesReducer(
state,
registerRecentQueries({queries: queries, maxLength: 3})
);

expect(state.queries).toEqual(['q1', 'q2', 'q3']);
expect(state.queries).toEqual(['what is love', 'oh baby', "don't hurt me"]);
});

it('#clearRecentQueries should remove all queries from the queue in state', () => {
Expand All @@ -57,7 +85,7 @@ describe('commerce/recent-queries-slice', () => {
expect(state.queries).toEqual([]);
});

it('should add new recent query on search fulfilled if queue is empty', () => {
it('should add trimmed and lowercased new recent query on search fulfilled if queue is empty', () => {
const searchAction = executeSearch.fulfilled(
buildSearchResponse(
{products: [buildMockProduct()]},
Expand All @@ -73,7 +101,7 @@ describe('commerce/recent-queries-slice', () => {
});

it('should add new recent query on search fulfilled if queue is non-empty', () => {
const otherTestQuery = 'bar';
const otherTestQuery = ' BAR ';
state.queries = testQueries;
state.maxLength = 10;
const searchAction = executeSearch.fulfilled(
Expand All @@ -86,29 +114,29 @@ describe('commerce/recent-queries-slice', () => {
);

expect(recentQueriesReducer(state, searchAction).queries).toEqual([
otherTestQuery,
'bar',
...testQueries,
]);
});

it('should add new recent query on search fulfilled and kick out oldest query if queue is full', () => {
state.queries = ['5', '4', '3', '2', '1'];
state.queries = ['five', 'four', 'three', 'two', 'one'];
state.maxLength = 5;
const searchAction = executeSearch.fulfilled(
buildSearchResponse({products: [buildMockProduct()]}, '6', '6'),
buildSearchResponse({products: [buildMockProduct()]}, 'SiX', 'SiX'),
''
);

expect(recentQueriesReducer(state, searchAction).queries).toEqual([
'6',
'5',
'4',
'3',
'2',
'six',
'five',
'four',
'three',
'two',
]);
});

it('should not add new recent query on search fulfilled if queue already contains the query', () => {
it('should not add new recent query on search fulfilled if first query in queue is already the query', () => {
const duplicates = [testQuery, ` ${testQuery} `];
for (const i in duplicates) {
state.queries = testQueries;
Expand Down Expand Up @@ -156,25 +184,25 @@ describe('commerce/recent-queries-slice', () => {
});

it('should place the query at the start of the list if it already exists', () => {
state.queries = ['5', '4', '3', '2', '1'];
state.queries = ['five', 'four', 'three', 'two', 'one'];
state.maxLength = 5;
const searchAction = executeSearch.fulfilled(
buildSearchResponse(
{
products: [buildMockProduct()],
},
'3',
'3'
'THREE',
'THREE'
),
''
);

expect(recentQueriesReducer(state, searchAction).queries).toEqual([
'3',
'5',
'4',
'2',
'1',
'three',
'five',
'four',
'two',
'one',
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const recentQueriesReducer = createReducer(
.addCase(registerRecentQueries, handleRegisterQueries)
.addCase(clearRecentQueries, handleClearRecentQueries)
.addCase(commerceExecuteSearch.fulfilled, (state, action) => {
const query = action.payload.queryExecuted?.trim() || '';
const query = action.payload.queryExecuted;
const products = action.payload.response.products;
if (!query.length || !products.length) {
return;
Expand Down
Loading

0 comments on commit 6ceebaa

Please sign in to comment.