diff --git a/.axioma/quality.md b/.axioma/quality.md index fe59e1f..f7da919 100644 --- a/.axioma/quality.md +++ b/.axioma/quality.md @@ -93,3 +93,7 @@ ## 2024-07-01 - [Achieving 100% Branch Coverage for Optional Callbacks] **Learning:** To achieve 100% branch coverage in components that utilize optional callbacks (e.g., `Input`'s `onChangeValue`, `onChangeDebounce`), unit tests must trigger relevant events (like `fireEvent.change`) while intentionally omitting these optional props to exercise the 'falsy' branches of conditional logic. **Action:** Always include a test case that omits optional callback props when testing components with event handlers to ensure all logical paths are verified. + +## 2024-07-05 - [Ensuring Internal Event Handlers Precedence] +**Learning:** When creating wrapper components that spread `restProps` onto a native element, placing internal event handlers (like `onSubmit` or `onChange`) *after* the spread ensures they are not accidentally overwritten by user-provided props. Additionally, destructuring the specific handler from props allows it to be manually invoked within the internal handler, preserving both functionalities. +**Action:** Always spread `restProps` before specifying internal event handlers in wrapper components to maintain control over the component's core logic while still supporting custom callbacks. diff --git a/lib/components/Form/index.test.tsx b/lib/components/Form/index.test.tsx index c70f9ca..930c409 100644 --- a/lib/components/Form/index.test.tsx +++ b/lib/components/Form/index.test.tsx @@ -212,4 +212,28 @@ describe('Form Component', () => { expect(ref.current).not.toBeNull() expect(ref.current?.tagName).toBe('FORM') }) + + it('should call both onSubmitValues and onSubmit when both are provided', () => { + const onSubmitValues = vi.fn() + const onSubmit = vi.fn() + const testId = 'test-both-submits' + + render( + + onSubmitValues={onSubmitValues} + onSubmit={onSubmit} + data-testid={testId} + > + + + , + ) + + fireEvent.submit(screen.getByTestId(testId)) + + expect(onSubmitValues).toHaveBeenCalledWith({ + name: 'John', + }) + expect(onSubmit).toHaveBeenCalled() + }) }) diff --git a/lib/components/Form/index.tsx b/lib/components/Form/index.tsx index 68ad873..879c7ee 100644 --- a/lib/components/Form/index.tsx +++ b/lib/components/Form/index.tsx @@ -5,7 +5,12 @@ const FormInner = ( props: FormProps, ref: ForwardedRef, ): JSX.Element => { - const { onSubmitValues, filterEmptyValues, ...restProps } = props + const { + onSubmitValues, + filterEmptyValues, + onSubmit: onSubmitProp, + ...restProps + } = props /** * Handles the form submission event. @@ -31,9 +36,9 @@ const FormInner = ( onSubmitValues(values) } - props.onSubmit && props.onSubmit(event) + onSubmitProp && onSubmitProp(event) } - return
+ return } /** @@ -69,9 +74,12 @@ const FormInner = ( * * ``` */ -export const Form = forwardRef(FormInner) as ( - props: FormProps & React.RefAttributes, -) => JSX.Element +export const Form = forwardRef(FormInner) as { + (props: FormProps & React.RefAttributes): JSX.Element + displayName?: string +} + +Form.displayName = 'Form' /** * The properties for the Form component. @@ -99,8 +107,6 @@ export interface FormProps onSubmitValues?: (values: T) => void /** * A flag to determine if empty values should be included in the form values. - * - * @param {boolean} filterEmptyValues - A flag to determine if empty values should be included in the form values. */ filterEmptyValues?: boolean }