Repository: medly/medly-components (ts)

Issue:
bug: SearchBox - onSearch event is getting triggered on option selection using enter key
### Describe the bug
onSearch event is getting triggered when we select the option using the up-down arrow keys and press enter.

### To Reproduce
Provide step-by-step instructions to reproduce the bug:

1. Go to SearchBox, search for something and press enter
2. Select an option using the up-down arrow and press enter
3. This will trigger the onSearch event again.

### Expected behavior
When we select an option using an up-down arrow it should not trigger the onSearch event.

### Package versions
 - @medly-components/core : 6.26.2



Pull request description:
feat(core): fixed SearchBox search trigger issue on option selection using enter
affects: @medly-components/core

ISSUES CLOSED: #725

# PR Checklist

## Description
 fixed the SearchBox search trigger issue on option selection using the up-down arrow keys and enter key press.


### Type of change
<!-- Please check the one that applies to this PR using "x". -->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes and API changes)
- [ ] Build changes
- [ ] CI changes
- [ ] Document content changes
- [ ] Performance improvement
- [ ] Add missing tests
- [ ] Others (please describe)


## How has this been tested?
(Replace This Text: Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.)

[ ] Test A

[ ] Test B


## Fixes #725 


## What is the current behaviour?
when we select an option using the up-down arrow keys and press enter, it triggers the search event again.


## What is the new behaviour?
when we select an option using the up-down arrow keys and press enter, it will not trigger the search event.


## Does this PR introduce a breaking change?

- [ ] Yes
- [x] No

**Note:** (Replace This Text: If this PR contains a breaking change please describe the impact and migration path for existing application.)


## Checklist
<!-- Please check the one that applies to this PR using "x". -->

- [x] My code follows the style guidelines of this project

- [x] I have performed a self-review of my own code

- [ ] I have commented my code, particularly in hard-to-understand areas

- [ ] I have made corresponding changes to the documentation

- [ ] My changes generate no new warnings

- [x] I have added tests that prove my fix is effective or that my feature works

- [x] New and existing unit tests pass locally with my changes

- [ ] Any dependent changes have been merged and published in downstream modules


Patch:
diff --git a/packages/core/src/components/DateRangePicker/DateRangePicker.tsx b/packages/core/src/components/DateRangePicker/DateRangePicker.tsx
index 08da724b..64c9ca7f 100644
--- a/packages/core/src/components/DateRangePicker/DateRangePicker.tsx
+++ b/packages/core/src/components/DateRangePicker/DateRangePicker.tsx
@@ -33,6 +33,7 @@ export const DateRangePicker: FC<DateRangeProps> = memo(props => {
         showTooltipForHelperAndErrorText,
         customDateRangeOptions,
         onPopupClose,
+        autoComplete,
         ...restProps
     } = props;
     const startDateRef = useRef<HTMLInputElement>(null),
@@ -131,6 +132,7 @@ export const DateRangePicker: FC<DateRangeProps> = memo(props => {
                 onCustomRangeIconClick={onCustomRangeIconClick}
                 showChevronIcon={customDateRangeOptions!.length > 0}
                 outerClickValidator={outerClickValidator}
+                autoComplete={autoComplete}
             />
             {isActive &&
                 (activePopover === PopoverTypes.CALENDAR ? (
diff --git a/packages/core/src/components/DateRangePicker/DateRangeTextFields/DateRangeTextFields.tsx b/packages/core/src/components/DateRangePicker/DateRangeTextFields/DateRangeTextFields.tsx
index bdd0c611..0b501d08 100644
--- a/packages/core/src/components/DateRangePicker/DateRangeTextFields/DateRangeTextFields.tsx
+++ b/packages/core/src/components/DateRangePicker/DateRangeTextFields/DateRangeTextFields.tsx
@@ -1,4 +1,5 @@
 import { ChevronDownIcon, DateRangeIcon } from '@medly-components/icons';
+import type { FC } from 'react';
 import { memo, useEffect } from 'react';
 import { DateIconWrapper as IconWrapper } from '../../DatePicker/DatePicker.styled';
 import datePickerPattern from '../../DatePicker/datePickerPattern';
@@ -10,7 +11,6 @@ import { Wrapper } from './DateRangeTextFields.styled';
 import InputSeparator from './InputSeparator';
 import { Props } from './types';
 import { useDateRangeTextFieldsHandlers } from './useDateRangeTextFieldsHandlers';
-import type { FC } from 'react';
 
 export const DateRangeTextFields: FC<Props> = memo(props => {
     const {
@@ -32,7 +32,8 @@ export const DateRangeTextFields: FC<Props> = memo(props => {
             showChevronIcon,
             activePopover,
             onCustomRangeIconClick,
-            outerClickValidator
+            outerClickValidator,
+            autoComplete
         } = props,
         {
             mask,
@@ -61,7 +62,8 @@ export const DateRangeTextFields: FC<Props> = memo(props => {
             placeholder: mask,
             onChange: handleTextChange,
             errorText: errorText || builtInErrorMessage,
-            pattern: datePickerPattern[displayFormat]
+            pattern: datePickerPattern[displayFormat],
+            autoComplete
         },
         iconProps = {
             variant,
diff --git a/packages/core/src/components/DateRangePicker/DateRangeTextFields/types.ts b/packages/core/src/components/DateRangePicker/DateRangeTextFields/types.ts
index 89ab18e6..b1f8cbe1 100644
--- a/packages/core/src/components/DateRangePicker/DateRangeTextFields/types.ts
+++ b/packages/core/src/components/DateRangePicker/DateRangeTextFields/types.ts
@@ -26,4 +26,5 @@ export type Props = {
     showTooltipForHelperAndErrorText?: boolean;
     onCustomRangeIconClick: () => void;
     outerClickValidator: RefObject<(e: MouseEvent) => void>;
+    autoComplete?: string;
 };
diff --git a/packages/core/src/components/SearchBox/SearchBox.tsx b/packages/core/src/components/SearchBox/SearchBox.tsx
index 48b4d2af..838b9fb0 100644
--- a/packages/core/src/components/SearchBox/SearchBox.tsx
+++ b/packages/core/src/components/SearchBox/SearchBox.tsx
@@ -1,6 +1,6 @@
 import { CloseIcon, ExpandIcon, SearchIcon } from '@medly-components/icons';
 import { CircleLoader } from '@medly-components/loaders';
-import { useCombinedRefs, useKeyPress, useOuterClickNotifier, WithStyle } from '@medly-components/utils';
+import { WithStyle, useCombinedRefs, useKeyPress, useOuterClickNotifier } from '@medly-components/utils';
 import type { FC } from 'react';
 import { forwardRef, memo, useCallback, useEffect, useRef, useState } from 'react';
 import Options from '../SingleSelect/Options';
@@ -68,13 +68,13 @@ const Component: FC<SearchBoxProps> = memo(
                 setOptionsVisibilityState(false);
                 setShowCloseIcon(false);
                 updateIsTyping(false);
-                onClear && onClear();
+                onClear?.();
             }, []),
             handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
                 const { value } = event.target;
                 updateIsTyping(value.length !== 0);
                 setShowCloseIcon(value.length !== 0);
-                onInputChange && onInputChange(value);
+                onInputChange?.(value);
             }, []),
             handleOptionClick = useCallback(
                 (option: Option) => {
@@ -83,7 +83,7 @@ const Component: FC<SearchBoxProps> = memo(
                         inputRef.current.focus();
                     }
                     setOptionsVisibilityState(false);
-                    onOptionSelected && onOptionSelected(option);
+                    onOptionSelected?.(option);
                 },
                 [onOptionSelected]
             ),
@@ -98,7 +98,7 @@ const Component: FC<SearchBoxProps> = memo(
             handleBlur = useCallback(() => {
                 isFocused.current = false;
             }, []),
-            handleSearchIconClick = useCallback(() => onSearch && onSearch(inputRef.current?.value || ''), [onSearch]);
+            handleSearchIconClick = useCallback(() => onSearch?.(inputRef.current?.value || ''), [onSearch]);
 
         useKeyboardNavigation({
             isFocused,
@@ -119,10 +119,10 @@ const Component: FC<SearchBoxProps> = memo(
                 const currentSelectedOption = options.find(option => option.hovered === true);
                 if (inputRef.current && currentSelectedOption) {
                     inputRef.current.value = currentSelectedOption.label;
-                    onOptionSelected && onOptionSelected(currentSelectedOption);
+                    onOptionSelected?.(currentSelectedOption);
                     inputRef.current.blur();
                 }
-                onSearch && onSearch(inputRef.current?.value || '');
+                !currentSelectedOption && onSearch?.(inputRef.current?.value || '');
                 setOptionsVisibilityState(false);
                 setShowCloseIcon(inputRef.current?.value.length !== 0);
                 updateIsTyping(false);


Test patch:
diff --git a/packages/core/src/components/DateRangePicker/DateRangePicker.test.tsx b/packages/core/src/components/DateRangePicker/DateRangePicker.test.tsx
index 96b6f5f6..e2f3c085 100644
--- a/packages/core/src/components/DateRangePicker/DateRangePicker.test.tsx
+++ b/packages/core/src/components/DateRangePicker/DateRangePicker.test.tsx
@@ -566,4 +566,18 @@ describe('DateRangePicker', () => {
             await waitFor(() => expect(container.querySelector(customDateRangeOptionsPopoverSelector)).toHaveStyle(`top: ${position}`));
         });
     });
+
+    describe('input element', () => {
+        afterEach(cleanup);
+
+        it('should render properly with default input attributes being passed to input elements', () => {
+            renderComponent({
+                autoComplete: 'off'
+            });
+            const inputs = screen.getAllByPlaceholderText('MM / DD / YYYY');
+            inputs.forEach(input => {
+                expect(input).toHaveAttribute('autoComplete', 'off');
+            });
+        });
+    });
 });
diff --git a/packages/core/src/components/SearchBox/SearchBox.test.tsx b/packages/core/src/components/SearchBox/SearchBox.test.tsx
index 6d030011..56a69599 100644
--- a/packages/core/src/components/SearchBox/SearchBox.test.tsx
+++ b/packages/core/src/components/SearchBox/SearchBox.test.tsx
@@ -216,8 +216,9 @@ describe('SearchBox', () => {
         });
 
         describe('with option selected', () => {
-            const onOptionSelectedMock = jest.fn();
-            const withOptionCB = { ...props, onOptionSelected: onOptionSelectedMock };
+            const onOptionSelectedMock = jest.fn(),
+                onSearch = jest.fn(),
+                withOptionCB = { ...props, onOptionSelected: onOptionSelectedMock, onSearch };
 
             it('should call on OptionSelected when option is clicked', () => {
                 const { inputEl } = renderComponent(withOptionCB);
@@ -233,6 +234,15 @@ describe('SearchBox', () => {
                 fireEvent.keyDown(container, { key: 'Enter', code: 13 });
                 expect(inputEl).toHaveValue('Dummy 1');
             });
+
+            it('should not call onSearch on option selection using enter', () => {
+                const { container, inputEl } = renderComponent(withOptionCB);
+                fireEvent.focus(inputEl);
+                fireEvent.keyDown(container, { key: 'ArrowDown', code: 40 });
+                fireEvent.keyDown(container, { key: 'Enter', code: 13 });
+                expect(onSearch).not.toBeCalled();
+                expect(inputEl).toHaveValue('Dummy 1');
+            });
         });
     });
 });