From 054eeaf765d491f8ecc4a06a22e82ab4e3f853f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Thu, 15 Feb 2024 14:03:50 +0100 Subject: [PATCH 1/7] refactor --- packages/uniforms/__suites__/BaseForm.tsx | 79 +++++++++++++++++++++-- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/packages/uniforms/__suites__/BaseForm.tsx b/packages/uniforms/__suites__/BaseForm.tsx index 1a2f49e9e..5b90eed5b 100644 --- a/packages/uniforms/__suites__/BaseForm.tsx +++ b/packages/uniforms/__suites__/BaseForm.tsx @@ -1,13 +1,80 @@ -import { render } from '@testing-library/react'; -import React, { ComponentType } from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import { BaseForm as UniformsBaseForm } from 'uniforms'; import { ZodBridge } from 'uniforms-bridge-zod'; import z from 'zod'; -export function testBaseForm(BaseForm: ComponentType) { +export function testBaseForm(BaseForm: typeof UniformsBaseForm) { + const model = { $: [1], _: 1 }; + const schema = new ZodBridge({ schema: z.object({}) }); + + const onSubmit = jest.fn(); + afterEach(() => { + onSubmit.mockClear(); + }); + test(' - renders', () => { - const schema = z.object({}); - const bridge = new ZodBridge({ schema }); - const screen = render(); + const screen = render(); expect(screen.getByTestId('form')).toBeInTheDocument(); }); + + test(' - when rendered, is
', () => { + const { container } = render(); + expect(container.getElementsByTagName('form')).toHaveLength(1); + }); + + test(' - when rendered, have correct children', () => { + const { container } = render( + +
+
+
+ , + ); + expect(container.getElementsByTagName('div')).toHaveLength(3); + }); + + test(' - when submitted, calls `onSubmit` once', () => { + render( + , + ); + + fireEvent.submit(screen.getByTestId('form')); + expect(onSubmit).toHaveBeenCalledTimes(1); + }); + + test(' - when submitted, calls `onSubmit` with correct model', () => { + render( + , + ); + + fireEvent.submit(screen.getByTestId('form')); + expect(onSubmit).toHaveBeenLastCalledWith(model); + }); + + test(' - when submitted, calls `onSubmit` with the correctly `modelTransform`ed model', () => { + render( + { + return mode === 'submit' ? { submit: 1 } : model; + }} + />, + ); + fireEvent.submit(screen.getByTestId('form')); + expect(onSubmit).toHaveBeenLastCalledWith({ submit: 1 }); + }); } From cee26bbe98ee8757fbb3c8e2f3fab8bd58109f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Thu, 15 Feb 2024 14:06:31 +0100 Subject: [PATCH 2/7] refactor --- packages/uniforms/__suites__/BaseForm.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/uniforms/__suites__/BaseForm.tsx b/packages/uniforms/__suites__/BaseForm.tsx index 5b90eed5b..1c5d36346 100644 --- a/packages/uniforms/__suites__/BaseForm.tsx +++ b/packages/uniforms/__suites__/BaseForm.tsx @@ -69,9 +69,9 @@ export function testBaseForm(BaseForm: typeof UniformsBaseForm) { schema={schema} onSubmit={onSubmit} data-testid="form" - modelTransform={(mode, model) => { - return mode === 'submit' ? { submit: 1 } : model; - }} + modelTransform={(mode, model) => + mode === 'submit' ? { submit: 1 } : model + } />, ); fireEvent.submit(screen.getByTestId('form')); From 2baa2d5087208e4d18b2b12a6883ebbb6f446353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Thu, 15 Feb 2024 14:10:09 +0100 Subject: [PATCH 3/7] removed enzyme BaseForm tests --- packages/uniforms/__tests__/BaseForm.tsx | 387 ----------------------- 1 file changed, 387 deletions(-) delete mode 100644 packages/uniforms/__tests__/BaseForm.tsx diff --git a/packages/uniforms/__tests__/BaseForm.tsx b/packages/uniforms/__tests__/BaseForm.tsx deleted file mode 100644 index be29a930f..000000000 --- a/packages/uniforms/__tests__/BaseForm.tsx +++ /dev/null @@ -1,387 +0,0 @@ -import { ReactWrapper } from 'enzyme'; -import React from 'react'; -import { BaseForm, Bridge, Context, useField } from 'uniforms'; - -import mount from './_mount'; - -jest.mock('meteor/aldeed:simple-schema'); -jest.mock('meteor/check'); - -describe('BaseForm', () => { - const error = new Error(); - const model = { $: [1], _: 1 }; - const schema: Bridge = { - getError() {}, - getErrorMessage: () => '', - getErrorMessages: () => [], - getField: () => ({}), - getInitialValue() {}, - getProps: () => ({}), - getSubfields: () => [], - getType() {}, - getValidator: () => () => {}, - }; - - const onChange = jest.fn(); - const onSubmit = jest.fn(); - - afterEach(() => { - onChange.mockClear(); - onSubmit.mockClear(); - }); - - it('have correct context', () => { - const wrapper = mount>( - , - ); - - const context = wrapper.instance().getContext(); - expect(context).toEqual>({ - changed: false, - changedMap: {}, - error, - model, - name: [], - onChange: expect.any(Function), - onSubmit: expect.any(Function), - randomId: expect.any(Function), - schema, - state: { - disabled: false, - readOnly: false, - showInlineError: false, - }, - submitted: false, - submitting: false, - validating: false, - formRef: expect.any(BaseForm), - }); - }); - - describe('when rendered', () => { - const wrapper = mount>( - -
-
-
- , - ); - - it('is ', () => { - expect(wrapper.find('form')).toHaveLength(1); - }); - - it('have correct props', () => { - expect(wrapper.props()).toHaveProperty('noValidate', true); - }); - - it('have correct children', () => { - expect(wrapper).toContainEqual(expect.anything()); - expect(wrapper.find('div')).toHaveLength(3); - }); - - it('have correct `resetCount`', () => { - expect(wrapper.state('resetCount')).toBe(0); - }); - - it('have correct `state`', () => { - const context = wrapper.instance().getContext(); - expect(context.state).toEqual['state']>({ - disabled: true, - readOnly: false, - showInlineError: true, - }); - }); - - it('updates schema bridge', () => { - const schema2 = { ...(schema as Omit), getType: () => {} }; - - wrapper.setProps({ schema: schema2 }); - - const context = wrapper.instance().getContext(); - - expect(context).toHaveProperty('schema', schema2); - }); - - it('ignores changes made on first render', () => { - function Field() { - const [props] = useField('name', {}); - props.onChange(123); - return null; - } - - const wrapper = mount>( - - - , - ); - - const context = wrapper.instance().getContext(); - expect(context).toHaveProperty('changed', false); - expect(context).toHaveProperty('changedMap', {}); - - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenCalledWith('name', 123); - }); - }); - - describe('when changed', () => { - type Form = BaseForm; - let wrapper: ReactWrapper; - - beforeEach(() => { - wrapper = mount( - , - ); - }); - - it('updates `changed` and `changedMap`', () => { - const context1 = wrapper.instance().getContext(); - expect(context1).toHaveProperty('changed', false); - expect(context1).toHaveProperty('changedMap', {}); - - wrapper.instance().getContext().onChange('$', [1, 2]); - - const context2 = wrapper.instance().getContext(); - expect(context2).toHaveProperty('changed', true); - expect(context2).toHaveProperty('changedMap.$'); - expect(context2.changedMap.$).toBeTruthy(); - expect(context2).toHaveProperty('changedMap.$.1'); - expect(context2.changedMap.$?.[1]).toBeTruthy(); - - wrapper.instance().getContext().onChange('$', [1]); - - const context3 = wrapper.instance().getContext(); - expect(context3).toHaveProperty('changed', true); - expect(context3).toHaveProperty('changedMap.$'); - expect(context3.changedMap.$).toBeTruthy(); - expect(context3).toHaveProperty('changedMap.$.1'); - expect(context3.changedMap.$?.[1]).toBeTruthy(); - }); - - it('autosaves correctly (`autosave` = true)', async () => { - wrapper.setProps({ autosave: true }); - wrapper.instance().getContext().onChange('a', 1); - await new Promise(resolve => setTimeout(resolve)); - const context = wrapper.instance().getContext(); - expect(onSubmit).toHaveBeenCalledTimes(1); - expect(context.submitted).toBe(true); - expect(onSubmit).toHaveBeenLastCalledWith(model); - }); - - it('autosaves are not delayed', async () => { - wrapper.setProps({ autosave: true }); - wrapper.instance().getContext().onChange('a', 1); - await new Promise(resolve => setTimeout(resolve)); - - expect(onSubmit).toHaveBeenCalledTimes(1); - expect(onSubmit).toHaveBeenLastCalledWith(model); - }); - - it('autosaves can be delayed', async () => { - wrapper.setProps({ autosave: true, autosaveDelay: 25 }); - wrapper.instance().getContext().onChange('a', 1); - wrapper.instance().getContext().onChange('a', 2); - wrapper.instance().getContext().onChange('a', 3); - await new Promise(resolve => setTimeout(resolve)); - - expect(onSubmit).not.toHaveBeenCalled(); - - await new Promise(resolve => setTimeout(resolve, 25)); - - expect(onSubmit).toHaveBeenCalledTimes(1); - expect(onSubmit).toHaveBeenLastCalledWith(model); - }); - - it('autosaves can be delayed (longer)', async () => { - wrapper.setProps({ autosave: true, autosaveDelay: 10 }); - wrapper.instance().getContext().onChange('a', 1); - wrapper.instance().getContext().onChange('a', 2); - wrapper.instance().getContext().onChange('a', 3); - - await new Promise(resolve => setTimeout(resolve, 25)); - - wrapper.instance().getContext().onChange('a', 1); - wrapper.instance().getContext().onChange('a', 2); - wrapper.instance().getContext().onChange('a', 3); - - await new Promise(resolve => setTimeout(resolve, 25)); - - expect(onSubmit).toHaveBeenCalledTimes(2); - expect(onSubmit).toHaveBeenLastCalledWith(model); - }); - - it('clears autosave correctly', () => { - wrapper.setProps({ autosave: true, autosaveDelay: 100 }); - wrapper.instance().getContext().onChange('a', 1); - wrapper.unmount(); - - expect(onSubmit).not.toBeCalled(); - }); - - it('autosaves correctly (`autosave` = false)', () => { - wrapper.setProps({ autosave: true }); - wrapper.setProps({ autosave: false }); - wrapper.instance().getContext().onChange('a', 1); - - expect(onSubmit).not.toBeCalled(); - }); - - it('calls `onChange` with correct name and value', () => { - wrapper.instance().getContext().onChange('a', 1); - - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenLastCalledWith('a', 1); - }); - - it('cancels `onChange` event', () => { - wrapper.find('form').simulate('change'); - - expect(onChange).not.toBeCalled(); - }); - - it('does nothing without `onChange`', () => { - wrapper.setProps({ onChange: undefined }); - wrapper.instance().getContext().onChange('a', 1); - - expect(onChange).not.toBeCalled(); - }); - }); - - describe('when reset', () => { - const createWrapper = () => - mount>( - , - ); - - it('increase `resetCount`', () => { - const wrapper = createWrapper(); - wrapper.instance().reset(); - - expect(wrapper.state('resetCount')).toBe(1); - }); - - it('sets submitted back to false', async () => { - const wrapper = createWrapper(); - const instance = wrapper.instance(); - expect(instance.getContext().submitted).toBe(false); - wrapper.find('form').simulate('submit'); - expect(instance.getContext().submitted).toBe(true); - instance.reset(); - expect(instance.getContext().submitted).toBe(false); - }); - }); - - describe('when submitted', () => { - const createWrapper = () => - mount>( - , - ); - - it('calls `onSubmit` once', () => { - const wrapper = createWrapper(); - wrapper.find('form').simulate('submit'); - - expect(onSubmit).toHaveBeenCalledTimes(1); - }); - - it('calls `onSubmit` with correct model', () => { - const wrapper = createWrapper(); - wrapper.find('form').simulate('submit'); - - expect(onSubmit).toHaveBeenLastCalledWith(model); - }); - - it('calls `onSubmit` with the correctly `modelTransform`ed model', () => { - const wrapper = createWrapper(); - wrapper.setProps({ - modelTransform(mode, model) { - return mode === 'submit' ? { submit: 1 } : model; - }, - }); - - wrapper.find('form').simulate('submit'); - - expect(onSubmit).toHaveBeenLastCalledWith({ submit: 1 }); - - wrapper.setProps({ modelTransform: undefined }); - }); - - it('sets `submitted` to true', async () => { - const wrapper = createWrapper(); - const instance = wrapper.instance(); - expect(instance.getContext().submitted).toBe(false); - wrapper.find('form').simulate('submit'); - expect(instance.getContext().submitted).toBe(true); - }); - - it('sets `submitting` state while submitting', async () => { - const wrapper = createWrapper(); - // FIXME: It should say `() => void`. - let resolveSubmit: (...args: any[]) => void = () => {}; - wrapper.setProps({ - onSubmit: () => new Promise(resolve => (resolveSubmit = resolve)), - }); - - const context1 = wrapper.instance().getContext(); - expect(context1).toHaveProperty('submitting', false); - - wrapper.find('form').simulate('submit'); - await new Promise(resolve => process.nextTick(resolve)); - - const context2 = wrapper.instance().getContext(); - expect(context2).toHaveProperty('submitting', true); - - resolveSubmit(); - await new Promise(resolve => process.nextTick(resolve)); - - const context3 = wrapper.instance().getContext(); - expect(context3).toHaveProperty('submitting', false); - }); - - it('ignores synchronous errors', async () => { - const wrapper = createWrapper(); - const error = new Error(); - wrapper.setProps({ - onSubmit() { - throw error; - }, - }); - - try { - wrapper.instance().submit(); - throw new Error('Unreachable.'); - } catch (catched) { - expect(catched).toBe(error); - } - }); - - it('returns asynchronous results', async () => { - const wrapper = createWrapper(); - const value = 42; - wrapper.setProps({ - async onSubmit() { - return value; - }, - }); - - await expect(wrapper.instance().submit()).resolves.toBe(value); - }); - - it('works when unmounted on submit', () => { - const spy = jest.spyOn(console, 'error'); - const wrapper = createWrapper(); - onSubmit.mockImplementationOnce(async () => wrapper.unmount()); - wrapper.find('form').simulate('submit'); - - expect(spy).not.toHaveBeenCalled(); - - spy.mockRestore(); - }); - }); -}); From 6839ddda14384878d2c36d6d29325a7d7f0828d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Thu, 15 Feb 2024 14:25:27 +0100 Subject: [PATCH 4/7] refactor --- packages/uniforms/__suites__/BaseForm.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/uniforms/__suites__/BaseForm.tsx b/packages/uniforms/__suites__/BaseForm.tsx index 1c5d36346..a060a50f2 100644 --- a/packages/uniforms/__suites__/BaseForm.tsx +++ b/packages/uniforms/__suites__/BaseForm.tsx @@ -31,6 +31,7 @@ export function testBaseForm(BaseForm: typeof UniformsBaseForm) {
, ); + expect(container.getElementsByTagName('div')).toHaveLength(3); }); @@ -74,6 +75,7 @@ export function testBaseForm(BaseForm: typeof UniformsBaseForm) { } />, ); + fireEvent.submit(screen.getByTestId('form')); expect(onSubmit).toHaveBeenLastCalledWith({ submit: 1 }); }); From 0e8276865788ed80c4637e87f79a8914731a7149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Thu, 15 Feb 2024 14:32:40 +0100 Subject: [PATCH 5/7] refactor --- packages/uniforms/__suites__/BaseForm.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/uniforms/__suites__/BaseForm.tsx b/packages/uniforms/__suites__/BaseForm.tsx index a060a50f2..b6baee8bf 100644 --- a/packages/uniforms/__suites__/BaseForm.tsx +++ b/packages/uniforms/__suites__/BaseForm.tsx @@ -25,7 +25,7 @@ export function testBaseForm(BaseForm: typeof UniformsBaseForm) { test(' - when rendered, have correct children', () => { const { container } = render( - +
@@ -36,14 +36,7 @@ export function testBaseForm(BaseForm: typeof UniformsBaseForm) { }); test(' - when submitted, calls `onSubmit` once', () => { - render( - , - ); + render(); fireEvent.submit(screen.getByTestId('form')); expect(onSubmit).toHaveBeenCalledTimes(1); From 3babc0b47856fabf6ff16a140ff0af2ecb388731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Fri, 16 Feb 2024 13:49:55 +0100 Subject: [PATCH 6/7] moved test from suites to tests --- packages/uniforms/__suites__/BaseForm.tsx | 68 +------------------- packages/uniforms/__tests__/BaseForm.tsx | 76 +++++++++++++++++++++++ 2 files changed, 79 insertions(+), 65 deletions(-) create mode 100644 packages/uniforms/__tests__/BaseForm.tsx diff --git a/packages/uniforms/__suites__/BaseForm.tsx b/packages/uniforms/__suites__/BaseForm.tsx index b6baee8bf..89c887748 100644 --- a/packages/uniforms/__suites__/BaseForm.tsx +++ b/packages/uniforms/__suites__/BaseForm.tsx @@ -1,75 +1,13 @@ -import { fireEvent, render, screen } from '@testing-library/react'; -import React from 'react'; -import { BaseForm as UniformsBaseForm } from 'uniforms'; +import { render } from '@testing-library/react'; +import React, { ComponentType } from 'react'; import { ZodBridge } from 'uniforms-bridge-zod'; import z from 'zod'; -export function testBaseForm(BaseForm: typeof UniformsBaseForm) { - const model = { $: [1], _: 1 }; +export function testBaseForm(BaseForm: ComponentType) { const schema = new ZodBridge({ schema: z.object({}) }); - const onSubmit = jest.fn(); - afterEach(() => { - onSubmit.mockClear(); - }); - test(' - renders', () => { - const screen = render(); - expect(screen.getByTestId('form')).toBeInTheDocument(); - }); - - test(' - when rendered, is ', () => { const { container } = render(); expect(container.getElementsByTagName('form')).toHaveLength(1); }); - - test(' - when rendered, have correct children', () => { - const { container } = render( - -
-
-
- , - ); - - expect(container.getElementsByTagName('div')).toHaveLength(3); - }); - - test(' - when submitted, calls `onSubmit` once', () => { - render(); - - fireEvent.submit(screen.getByTestId('form')); - expect(onSubmit).toHaveBeenCalledTimes(1); - }); - - test(' - when submitted, calls `onSubmit` with correct model', () => { - render( - , - ); - - fireEvent.submit(screen.getByTestId('form')); - expect(onSubmit).toHaveBeenLastCalledWith(model); - }); - - test(' - when submitted, calls `onSubmit` with the correctly `modelTransform`ed model', () => { - render( - - mode === 'submit' ? { submit: 1 } : model - } - />, - ); - - fireEvent.submit(screen.getByTestId('form')); - expect(onSubmit).toHaveBeenLastCalledWith({ submit: 1 }); - }); } diff --git a/packages/uniforms/__tests__/BaseForm.tsx b/packages/uniforms/__tests__/BaseForm.tsx new file mode 100644 index 000000000..9e2212e87 --- /dev/null +++ b/packages/uniforms/__tests__/BaseForm.tsx @@ -0,0 +1,76 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import { BaseForm } from 'uniforms'; +import { ZodBridge } from 'uniforms-bridge-zod'; +import z from 'zod'; + +describe('BaseForm', () => { + const model = { $: [1], _: 1 }; + const schema = new ZodBridge({ schema: z.object({}) }); + + const onSubmit = jest.fn(); + afterEach(() => { + onSubmit.mockClear(); + }); + + describe('when rendered', () => { + it('is ', () => { + const { container } = render(); + expect(container.getElementsByTagName('form')).toHaveLength(1); + }); + + it('have correct children', () => { + const { container } = render( + +
+
+
+ , + ); + + expect(container.getElementsByTagName('div')).toHaveLength(3); + }); + }); + + describe('when submitted', () => { + it('calls `onSubmit` once', () => { + render( + , + ); + + fireEvent.submit(screen.getByTestId('form')); + expect(onSubmit).toHaveBeenCalledTimes(1); + }); + + it('calls `onSubmit` with correct model', () => { + render( + , + ); + + fireEvent.submit(screen.getByTestId('form')); + expect(onSubmit).toHaveBeenLastCalledWith(model); + }); + + it('calls `onSubmit` with the correctly `modelTransform`ed model', () => { + render( + + mode === 'submit' ? { submit: 1 } : model + } + />, + ); + + fireEvent.submit(screen.getByTestId('form')); + expect(onSubmit).toHaveBeenLastCalledWith({ submit: 1 }); + }); + }); +}); From 2588b6162e4fe530678175572f70fd5f0ec05bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= Date: Thu, 22 Feb 2024 14:34:21 +0100 Subject: [PATCH 7/7] updated base form tests --- packages/uniforms/__tests__/BaseForm.tsx | 193 ++++++++++++++++++++++- 1 file changed, 190 insertions(+), 3 deletions(-) diff --git a/packages/uniforms/__tests__/BaseForm.tsx b/packages/uniforms/__tests__/BaseForm.tsx index 9e2212e87..4ab9cdb62 100644 --- a/packages/uniforms/__tests__/BaseForm.tsx +++ b/packages/uniforms/__tests__/BaseForm.tsx @@ -1,15 +1,20 @@ import { fireEvent, render, screen } from '@testing-library/react'; -import React from 'react'; -import { BaseForm } from 'uniforms'; +import React, { useContext } from 'react'; +import { BaseForm, context } from 'uniforms'; import { ZodBridge } from 'uniforms-bridge-zod'; +import { AutoField } from 'uniforms-unstyled'; import z from 'zod'; describe('BaseForm', () => { const model = { $: [1], _: 1 }; - const schema = new ZodBridge({ schema: z.object({}) }); + const schema = new ZodBridge({ + schema: z.object({ a: z.string().optional() }), + }); + const onChange = jest.fn(); const onSubmit = jest.fn(); afterEach(() => { + onChange.mockClear(); onSubmit.mockClear(); }); @@ -32,6 +37,137 @@ describe('BaseForm', () => { }); }); + describe('when changed', () => { + it('autosaves correctly (`autosave` = false)', async () => { + render( + + + , + ); + + const input = screen.getByLabelText('A'); + fireEvent.change(input, { target: { value: 'test' } }); + + await new Promise(resolve => setTimeout(resolve)); + + expect(onSubmit).not.toBeCalled(); + }); + + it('autosaves correctly (`autosave` = true)', async () => { + render( + + + , + ); + + const input = screen.getByLabelText('A'); + fireEvent.change(input, { target: { value: 'test' } }); + + await new Promise(resolve => setTimeout(resolve)); + + expect(onSubmit).toHaveBeenCalledTimes(1); + expect(onSubmit).toHaveBeenLastCalledWith(model); + }); + + it('autosaves can be delayed', async () => { + render( + + + , + ); + + const input = screen.getByLabelText('A'); + fireEvent.change(input, { target: { value: 'test 1' } }); + fireEvent.change(input, { target: { value: 'test 2' } }); + fireEvent.change(input, { target: { value: 'test 3' } }); + + await new Promise(resolve => setTimeout(resolve)); + + expect(onSubmit).not.toHaveBeenCalled(); + + await new Promise(resolve => setTimeout(resolve, 25)); + + expect(onSubmit).toHaveBeenCalledTimes(1); + expect(onSubmit).toHaveBeenLastCalledWith(model); + }); + + it('autosaves can be delayed (longer)', async () => { + render( + + + , + ); + + const input = screen.getByLabelText('A'); + fireEvent.change(input, { target: { value: 'test 1' } }); + fireEvent.change(input, { target: { value: 'test 2' } }); + fireEvent.change(input, { target: { value: 'test 3' } }); + + await new Promise(resolve => setTimeout(resolve, 25)); + + fireEvent.change(input, { target: { value: 'test 1' } }); + fireEvent.change(input, { target: { value: 'test 2' } }); + fireEvent.change(input, { target: { value: 'test 3' } }); + + await new Promise(resolve => setTimeout(resolve, 25)); + + expect(onSubmit).toHaveBeenCalledTimes(2); + expect(onSubmit).toHaveBeenLastCalledWith(model); + }); + + it('clears autosave correctly', () => { + const { unmount } = render( + + + , + ); + + const input = screen.getByLabelText('A'); + fireEvent.change(input, { target: { value: 'test 1' } }); + + unmount(); + + expect(onSubmit).not.toBeCalled(); + }); + + it('calls `onChange` with correct name and value', () => { + render( + + + , + ); + + const input = screen.getByLabelText('A'); + fireEvent.change(input, { target: { value: 'test 1' } }); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenLastCalledWith('a', 'test 1'); + }); + }); + describe('when submitted', () => { it('calls `onSubmit` once', () => { render( @@ -72,5 +208,56 @@ describe('BaseForm', () => { fireEvent.submit(screen.getByTestId('form')); expect(onSubmit).toHaveBeenLastCalledWith({ submit: 1 }); }); + + it('sets `submitted` to true', async () => { + let submitted: boolean | undefined; + + function Field() { + const test = useContext(context); + submitted = test?.submitted; + return null; + } + + render( + + + , + ); + + expect(submitted).toBe(false); + fireEvent.submit(screen.getByTestId('form')); + expect(submitted).toBe(true); + }); + + it('sets `submitting` state while submitting', async () => { + let submitting: boolean | undefined; + + function Field() { + const test = useContext(context); + submitting = test?.submitting; + return null; + } + + let resolveSubmit: (...args: any[]) => void = () => {}; + const test = () => new Promise(resolve => (resolveSubmit = resolve)); + + render( + + + , + ); + + expect(submitting).toBe(false); + + const form = screen.getByTestId('form'); + fireEvent.submit(form); + + expect(submitting).toBe(true); + + resolveSubmit(); + await new Promise(resolve => process.nextTick(resolve)); + + expect(submitting).toBe(false); + }); }); });