From ba819c6339f4bef7172e902171f74000ec46830e Mon Sep 17 00:00:00 2001 From: Misha Moroshko Date: Sun, 4 Oct 2020 13:37:44 +1100 Subject: [PATCH] Add onChange prop to Select and Dropdown --- src/components/Dropdown.js | 42 ++++++++++++++++----------------- src/components/Dropdown.test.js | 21 +++++++++++++++++ src/components/Select.js | 35 +++++++++++++++++++-------- src/components/Select.test.js | 20 +++++++++++++++- 4 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js index f325c4f4..cfb80fb5 100644 --- a/src/components/Dropdown.js +++ b/src/components/Dropdown.js @@ -49,6 +49,7 @@ function Dropdown(props) { helpText: (helpText) => typeof helpText === "string", disabled: (disabled) => typeof disabled === "boolean", options: (options) => areDropdownOptionsValid(options), + onChange: (onChange) => typeof onChange === "function", } ); const { @@ -63,6 +64,7 @@ function Dropdown(props) { disabled, validate, validateData, + onChange: propsOnChange, testId, __internal__focus, __internal__open, @@ -87,16 +89,20 @@ function Dropdown(props) { }), [isEmpty, validateData] ); - const { value, errors, hasErrors, onFocus, onBlur, onChange } = useField( - "Dropdown", - { - name, - disabled, - optional: false, - validate, - data, - } - ); + const { + value, + errors, + hasErrors, + onFocus, + onBlur, + onChange: fieldOnChange, + } = useField("Dropdown", { + name, + disabled, + optional: false, + validate, + data, + }); const windowFromContext = useWindow(); const buttonRef = useRef(); const itemToString = useCallback( @@ -118,10 +124,12 @@ function Dropdown(props) { itemToString, initialSelectedItem, onSelectedItemChange: ({ selectedItem: selectedOption }) => { - onChange({ + fieldOnChange({ target: buttonRef.current, value: selectedOption.value, }); + + propsOnChange && propsOnChange({ selectedOption }); }, environment: windowFromContext, }); @@ -132,21 +140,12 @@ function Dropdown(props) { getToggleButtonProps({ onFocus, onBlur, - onChange, disabled, "aria-invalid": isValid ? null : "true", "aria-describedby": describedBy, ref: buttonRef, }), - [ - getToggleButtonProps, - onFocus, - onBlur, - onChange, - disabled, - isValid, - describedBy, - ] + [getToggleButtonProps, onFocus, onBlur, disabled, isValid, describedBy] ); const maxHeightProps = useAllResponsiveProps(props, "maxHeight"); @@ -203,6 +202,7 @@ Dropdown.propTypes = { ...responsiveMaxHeightType, validate: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), validateData: PropTypes.any, + onChange: PropTypes.func, testId: PropTypes.string, __internal__focus: PropTypes.bool, __internal__open: PropTypes.bool, diff --git a/src/components/Dropdown.test.js b/src/components/Dropdown.test.js index 771c1f73..7b7b67a7 100644 --- a/src/components/Dropdown.test.js +++ b/src/components/Dropdown.test.js @@ -140,6 +140,27 @@ describe("Dropdown", () => { }); }); + it("with onChange", () => { + const onChange = jest.fn(); + + render(); + + const button = screen.getByRole("button", { name: /Please select/ }); + + userEvent.click(button); + userEvent.click(screen.getByText("Movie 2")); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toBeCalledWith({ + selectedOption: { + data: { + name: "Movie 2", + }, + value: "movie-2", + }, + }); + }); + it("with testId", () => { const { container } = render(); diff --git a/src/components/Select.js b/src/components/Select.js index 99ccf302..af7303fe 100644 --- a/src/components/Select.js +++ b/src/components/Select.js @@ -43,6 +43,7 @@ function Select(props) { disabled: (disabled) => typeof disabled === "boolean", optional: (optional) => typeof optional === "boolean", options: (options) => areOptionsValid(options), + onChange: (onChange) => typeof onChange === "function", } ); const { @@ -56,6 +57,7 @@ function Select(props) { optional, validate, validateData, + onChange: propsOnChange, testId, __internal__focus, } = mergedProps; @@ -79,16 +81,28 @@ function Select(props) { }), [isEmpty, validateData] ); - const { value, errors, hasErrors, onFocus, onBlur, onChange } = useField( - "Select", - { - name, - disabled, - optional, - validate, - data, - } - ); + const { + value, + errors, + hasErrors, + onFocus, + onBlur, + onChange: fieldOnChange, + } = useField("Select", { + name, + disabled, + optional, + validate, + data, + }); + const onChange = (event) => { + fieldOnChange(event); + + const selectedValue = event.target.value; + const selectedOption = options.find(({ value }) => value === selectedValue); + + propsOnChange && propsOnChange({ selectedOption }); + }; return ( { }); }); + it("with onChange", () => { + const onChange = jest.fn(); + + render(); + + const select = screen.getByDisplayValue("Please select"); + + userEvent.selectOptions(select, "married"); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toBeCalledWith({ + selectedOption: { + label: "Married", + value: "married", + }, + }); + }); + it("with testId", () => { const { container } = render(