From 44b557214af57b6332fe0a87e105abeba2dc23c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Wed, 26 Aug 2020 16:28:40 +0200 Subject: [PATCH] Add test coverage to FormDataProvider to subscribe to updated form value --- .../components/form_data_provider.test.tsx | 62 ++++++++++++++++++- .../components/form_data_provider.ts | 10 ++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.test.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.test.tsx index 3e4ce4a412b3..25448dff18e8 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.test.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.test.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; +import React, { useState } from 'react'; import { act } from 'react-dom/test-utils'; import { registerTestBed, TestBed } from '../shared_imports'; @@ -36,13 +36,14 @@ describe('', () => { return (
- {(formData) => { onFormData(formData); return null; }} + {/* Putting one field below to make sure the order in the DOM does not affect behaviour */} + ); }; @@ -95,6 +96,63 @@ describe('', () => { }); }); + test('should subscribe to the latest updated form data when mounting late', async () => { + const onFormData = jest.fn(); + + const TestComp = () => { + const { form } = useForm(); + const [isOn, setIsOn] = useState(false); + + return ( +
+ + + {isOn && ( + + {(formData) => { + onFormData(formData); + return null; + }} + + )} + + ); + }; + + const setup = registerTestBed(TestComp, { + memoryRouter: { wrapComponent: false }, + }); + + const { + form: { setInputValue }, + find, + } = setup() as TestBed; + + expect(onFormData.mock.calls.length).toBe(0); // Not present in the DOM yet + + // Make some changes to the form fields + await act(async () => { + setInputValue('nameField', 'updated value'); + }); + + // Update state to trigger the mounting of the FormDataProvider + await act(async () => { + find('btn').simulate('click').update(); + }); + + expect(onFormData.mock.calls.length).toBe(1); + + const [formDataUpdated] = onFormData.mock.calls[onFormData.mock.calls.length - 1] as Parameters< + OnUpdateHandler + >; + + expect(formDataUpdated).toEqual({ + name: 'updated value', + }); + }); + test('props.pathsToWatch (string): should not re-render the children when the field that changed is not the one provided', async () => { const onFormData = jest.fn(); diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.ts index a212012f3f8b..3630b902f056 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/form_data_provider.ts @@ -31,6 +31,7 @@ export const FormDataProvider = React.memo(({ children, pathsToWatch }: Props) = const form = useFormContext(); const { subscribe } = form; const previousRawData = useRef(form.__getFormData$().value); + const isMounted = useRef(false); const [formData, setFormData] = useState(previousRawData.current); const onFormData = useCallback( @@ -59,7 +60,14 @@ export const FormDataProvider = React.memo(({ children, pathsToWatch }: Props) = return subscription.unsubscribe; }, [subscribe, onFormData]); - if (Object.keys(formData).length === 0) { + useEffect(() => { + isMounted.current = true; + return () => { + isMounted.current = false; + }; + }, []); + + if (!isMounted.current && Object.keys(formData).length === 0) { // No field has mounted yet, don't render anything return null; }