diff --git a/packages/atomic/scripts/dev.mjs b/packages/atomic/scripts/dev.mjs index de164f968e8..8ed1a8b60ae 100644 --- a/packages/atomic/scripts/dev.mjs +++ b/packages/atomic/scripts/dev.mjs @@ -121,6 +121,16 @@ startServers(); // Watch the src folder for changes watch('src', {recursive: true}, async (_, filename) => { + // Ignore irrelevant files + if ( + filename.endsWith('.mdx') || + filename.endsWith('.new.stories.tsx') || + filename.endsWith('.spec.ts') || + filename.includes('e2e') + ) { + return; + } + // Stop all processes if a file changes to prevent multiple builds at once await stopAllProcesses(); console.log(chalk.cyanBright(`📂 File changed: ${filename}`)); diff --git a/packages/atomic/scripts/generate-component.mjs b/packages/atomic/scripts/generate-component.mjs index d0e7110f222..d6fdcf86d5b 100644 --- a/packages/atomic/scripts/generate-component.mjs +++ b/packages/atomic/scripts/generate-component.mjs @@ -23,7 +23,9 @@ async function generateFiles(name, outputDir) { ); const resolvedOutputDir = path.resolve(outputDir); const namePascalCase = kebabToPascal(name); - const shorterName = name.replace(/^atomic-/, '').toLowerCase(); + const shorterName = namePascalCase + .replace(/^Atomic/, '') + .replace(/^./, (c) => c.toLowerCase()); const files = [ {template: 'component.ts.hbs', output: `${name}.ts`}, diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.spec.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.spec.ts new file mode 100644 index 00000000000..be5bbc5314a --- /dev/null +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.spec.ts @@ -0,0 +1,17 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +//https://coveord.atlassian.net/browse/KIT-3955 +describe('AtomicCommerceSearchBox', () => { + describe('with instant products & suggestions', () => { + describe('when using keyboard navigation', () => { + test('should be able to navigate from the suggestions to the instant results and vice-versa', async () => {}); + test('should execute the search after pressing "Enter" on a suggestion', async () => {}); + test('should redirect to the result page after pressing "Enter" on an instant result', async () => {}); + }); + + describe('when typing and then hovering a suggestion', () => { + test('should execute the search reflected in the search box', () => {}); + }); + }); +}); diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx b/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx index cd4d262fb1f..c63ca085ed5 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx @@ -429,12 +429,7 @@ export class AtomicCommerceSearchBox private onSubmit() { this.isExpanded = false; - if ( - this.suggestionManager.isRightPanelInFocus() || - this.suggestionManager.activeDescendantElement?.part.contains( - 'recent-query-title-item' - ) - ) { + if (this.suggestionManager.keyboardActiveDescendant) { this.suggestionManager.onSubmit(); return; } diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index 5e0eaa18596..d394c2ae5f5 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -304,6 +304,16 @@ test.describe('with instant results & query suggestions', () => { }); }); }); + + test.describe('when hovering a instant result and pressing Enter', () => { + test('should execute the query in the search box', async ({searchBox}) => { + await searchBox.searchInput.click(); + await searchBox.searchInput.fill('a'); + await searchBox.instantResult({listSide: 'Right'}).first().hover(); + await searchBox.searchInput.press('Enter'); + await expect(searchBox.searchInput).toHaveValue('a'); + }); + }); }); test.describe('with disable-search=true and minimum-query-length=1', () => { diff --git a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.spec.ts b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.spec.ts new file mode 100644 index 00000000000..e3553aad14c --- /dev/null +++ b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.spec.ts @@ -0,0 +1,19 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +//https://coveord.atlassian.net/browse/KIT-3957 +describe('AtomicCommerceSearchBoxInstantProducts', () => { + describe('when clicking', () => { + test('on a instant product, it should redirect to the product page', async () => {}); + test('on the "See all products" button, it should execute the proper search', async () => {}); + }); + + describe('when using keyboard navigation', () => { + test('on instant products, it should redirect to the product page', async () => {}); + test('on the "See all products" button, it should execute the proper search', async () => {}); + }); + + describe('when using keyboard navigation and then switching to mouse and hovering a new product', () => { + test('it should execute the search reflected in the search box', () => {}); + }); +}); diff --git a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.spec.ts b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.spec.ts new file mode 100644 index 00000000000..877986f5d17 --- /dev/null +++ b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.spec.ts @@ -0,0 +1,18 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +//https://coveord.atlassian.net/browse/KIT-3956 +describe('AtomicCommerceSearchBoxQuerySuggestions', () => { + describe('when clicking', () => { + test('it should execute the proper search', async () => {}); + }); + + describe('when using keyboard navigation', () => { + test('it should reflect the proper suggestion in the search box', async () => {}); + test('it should execute the proper search after pressing "Enter"', async () => {}); + }); + + describe('when using keyboard navigation and then switching to mouse and hovering a new suggestion', () => { + test('it should execute the search reflected in the search box', () => {}); + }); +}); diff --git a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.spec.ts b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.spec.ts new file mode 100644 index 00000000000..7a5a906463e --- /dev/null +++ b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.spec.ts @@ -0,0 +1,20 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +//https://coveord.atlassian.net/browse/KIT-3958 +describe('AtomicCommerceSearchBoxRecentQueries', () => { + describe('when clicking', () => { + test('on a recent query, it should execute the proper search', async () => {}); + test('on the "Clear" button, it should clear the recent queries', async () => {}); + }); + + describe('when using keyboard navigation', () => { + test('on recent queries, it should reflect the proper query in the search box', async () => {}); + test('on recent queries, it should execute the proper search', async () => {}); + test('on the "Clear" button, it should clear the recent queries ', async () => {}); + }); + + describe('when using keyboard navigation and then switching to mouse and hovering a new recent query', () => { + test('it should execute the search reflected in the search box', () => {}); + }); +}); diff --git a/packages/atomic/src/components/common/suggestions/suggestion-manager.ts b/packages/atomic/src/components/common/suggestions/suggestion-manager.ts index 992dd44158a..1f55242aeac 100644 --- a/packages/atomic/src/components/common/suggestions/suggestion-manager.ts +++ b/packages/atomic/src/components/common/suggestions/suggestion-manager.ts @@ -59,6 +59,7 @@ export class SuggestionManager { public triggerSuggestions: () => Promise; public activeDescendant = ''; public suggestedQuery = ''; + public keyboardActiveDescendant = ''; private queryDataAttribute = 'data-query'; private suggestionEvents: SearchBoxSuggestionsEvent[] = @@ -114,6 +115,10 @@ export class SuggestionManager { forceUpdate(this.ownerSearchBoxProps.getHost()); } + public updateKeyboardActiveDescendant(id = '') { + this.keyboardActiveDescendant = id; + } + public clickOnActiveElement() { this.activeDescendantElement?.click(); this.updateActiveDescendant(); @@ -187,6 +192,7 @@ export class SuggestionManager { } public focusValue(value: HTMLElement) { + this.updateKeyboardActiveDescendant(value.id); this.updateActiveDescendant(value.id); this.scrollActiveDescendantIntoView(); this.updateQueryFromSuggestion(); @@ -198,6 +204,8 @@ export class SuggestionManager { id: string ) { const thisPanel = side === 'left' ? this.leftPanel : this.rightPanel; + // When hovering, always reset the keyboard active descendant + this.updateKeyboardActiveDescendant(); if (this.panelInFocus === thisPanel) { this.updateActiveDescendant(id); } else { @@ -226,6 +234,7 @@ export class SuggestionManager { public focusPreviousValue() { if (this.firstValue === this.activeDescendantElement) { + this.updateKeyboardActiveDescendant(); this.updateActiveDescendant(); return; } diff --git a/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.spec.ts b/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.spec.ts new file mode 100644 index 00000000000..27f06ae1188 --- /dev/null +++ b/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.spec.ts @@ -0,0 +1,16 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +describe('AtomicSearchBox', () => { + describe('with instant results & suggestions', () => { + describe('when using keyboard navigation', () => { + test('should be able to navigate from the suggestions to the instant results and vice-versa', async () => {}); + test('should execute the search after pressing "Enter" on a suggestion', async () => {}); + test('should redirect to the result page after pressing "Enter" on an instant result', async () => {}); + }); + + describe('when typing and then hovering a suggestion', () => { + test('should execute the search reflected in the search box', () => {}); + }); + }); +}); diff --git a/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx b/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx index 5759bf6ad81..4b45f83ba73 100644 --- a/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx +++ b/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx @@ -427,12 +427,7 @@ export class AtomicSearchBox implements InitializableComponent { private onSubmit() { this.isExpanded = false; - if ( - this.suggestionManager.isRightPanelInFocus() || - this.suggestionManager.activeDescendantElement?.part.contains( - 'recent-query-title-item' - ) - ) { + if (this.suggestionManager.keyboardActiveDescendant) { this.suggestionManager.onSubmit(); return; } diff --git a/packages/atomic/src/components/search/atomic-search-box/e2e/atomic-search-box.e2e.ts b/packages/atomic/src/components/search/atomic-search-box/e2e/atomic-search-box.e2e.ts index dc8d09792d9..8c4d1304b90 100644 --- a/packages/atomic/src/components/search/atomic-search-box/e2e/atomic-search-box.e2e.ts +++ b/packages/atomic/src/components/search/atomic-search-box/e2e/atomic-search-box.e2e.ts @@ -154,6 +154,16 @@ test.describe('with instant results & query suggestions', () => { }); }); }); + + test.describe('when hovering a instant result and pressing Enter', () => { + test('should execute the query in the search box', async ({searchBox}) => { + await searchBox.searchInput.click(); + await searchBox.searchInput.fill('a'); + await searchBox.instantResult({listSide: 'Right'}).first().hover(); + await searchBox.searchInput.press('Enter'); + await expect(searchBox.searchInput).toHaveValue('a'); + }); + }); }); test.describe('with disable-search=true and minimum-query-length=1', () => { diff --git a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.spec.ts b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.spec.ts new file mode 100644 index 00000000000..be47d40ffef --- /dev/null +++ b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.spec.ts @@ -0,0 +1,18 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +describe('AtomicSearchBoxInstantResults', () => { + describe('when clicking', () => { + test('on a instant result, it should redirect to the result page', async () => {}); + test('on the "See all results" button, it should execute the proper search', async () => {}); + }); + + describe('when using keyboard navigation', () => { + test('on instant results, it should redirect to the result page', async () => {}); + test('on the "See all results" button, it should execute the proper search', async () => {}); + }); + + describe('when using keyboard navigation and then switching to mouse and hovering a new result', () => { + test('it should execute the search reflected in the search box', () => {}); + }); +}); diff --git a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.spec.ts b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.spec.ts new file mode 100644 index 00000000000..7115ada9b4e --- /dev/null +++ b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.spec.ts @@ -0,0 +1,17 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +describe('AtomicSearchBoxQuerySuggestions', () => { + describe('when clicking', () => { + test('it should execute the proper search', async () => {}); + }); + + describe('when using keyboard navigation', () => { + test('it should reflect the proper suggestion in the search box', async () => {}); + test('it should execute the proper search after pressing "Enter"', async () => {}); + }); + + describe('when using keyboard navigation and then switching to mouse and hovering a new suggestion', () => { + test('it should execute the search reflected in the search box', () => {}); + }); +}); diff --git a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.spec.ts b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.spec.ts new file mode 100644 index 00000000000..4dbfd1f6aa1 --- /dev/null +++ b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.spec.ts @@ -0,0 +1,19 @@ +import {describe, test} from 'vitest'; + +//TODO: Write those tests during the lit migration +describe('AtomicSearchBoxRecentQueries', () => { + describe('when clicking', () => { + test('on a recent query, it should execute the proper search', async () => {}); + test('on the "Clear" button, it should clear the recent queries', async () => {}); + }); + + describe('when using keyboard navigation', () => { + test('on recent queries, it should reflect the proper query in the search box', async () => {}); + test('on recent queries, it should execute the proper search', async () => {}); + test('on the "Clear" button, it should clear the recent queries ', async () => {}); + }); + + describe('when using keyboard navigation and then switching to mouse and hovering a new recent query', () => { + test('it should execute the search reflected in the search box', () => {}); + }); +});