Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate core tests from Enzyme to React Testing Library #1193

Merged
merged 29 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
32080ea
rewrite AutoForm
ErnestTeluk Jul 22, 2022
f161089
change it to test in ts files for consistency
ErnestTeluk Jul 22, 2022
ef6139e
delete dry in AutoForm tests
ErnestTeluk Jul 22, 2022
89564a7
rewrite useField
ErnestTeluk Jul 22, 2022
0e9390d
rewrite test from enzyme to rts for the useField component
ErnestTeluk Aug 5, 2022
5e8ea22
wip
ErnestTeluk Oct 18, 2022
7734125
rewrite almost all validateForm to rts
ErnestTeluk Nov 27, 2022
30508fa
delete test scripts
ErnestTeluk Nov 27, 2022
ae05068
write conflict
ErnestTeluk Nov 27, 2022
b73c2c0
fix ts error related with ref in ValidateForm
ErnestTeluk Nov 27, 2022
b6251e8
fix skipped test in autoform
ErnestTeluk Nov 27, 2022
6c0f33c
add mockContext and replace test to it
ErnestTeluk Nov 28, 2022
cb32cd0
add rerenderWithProps to render fn
ErnestTeluk Nov 28, 2022
e8838c5
fix naming test to it
ErnestTeluk Nov 28, 2022
b781eef
fix test to it name in material tests
ErnestTeluk Nov 28, 2022
615d7d0
rewrite last describe in ValidateForm to rtl
ErnestTeluk Dec 2, 2022
3fcd882
rename testFn to test
ErnestTeluk Dec 2, 2022
3661997
transfer const and mocks from global scope to describe
ErnestTeluk Dec 2, 2022
af0ef23
fix typing for render fn and fix context mocking in validateForm and …
ErnestTeluk Feb 15, 2023
ceae676
add expect in first AutoForm test
ErnestTeluk Feb 15, 2023
91bcd67
add proper typing to useField <TestComponent>
ErnestTeluk Feb 17, 2023
442b18d
change schema passing to render function
ErnestTeluk Feb 17, 2023
27ef2a5
fix naming convention in useFields
ErnestTeluk Feb 17, 2023
33f7bb0
fix conflicts
ErnestTeluk Feb 17, 2023
24e9af2
fix ListField and TextField tests
ErnestTeluk Feb 17, 2023
076de80
fixes
ErnestTeluk Feb 23, 2023
4942fe5
fix onChangeModel test
ErnestTeluk Feb 24, 2023
188b5e6
revert prettier unnecessary changes
ErnestTeluk Feb 24, 2023
81f69df
add lacking expects to autoForm test
ErnestTeluk Feb 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions packages/uniforms/__suites__/render.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render as renderOnScreen } from '@testing-library/react';
import React, { ReactElement } from 'react';
import { render as renderOnScreen, RenderResult } from '@testing-library/react';
import React, { cloneElement, ReactElement } from 'react';
import SimpleSchema, { SimpleSchemaDefinition } from 'simpl-schema';
import { BaseForm, context, Context, randomIds } from 'uniforms';
import { SimpleSchema2Bridge } from 'uniforms-bridge-simple-schema-2';
Expand All @@ -11,7 +11,9 @@ export function render(
schema: SimpleSchemaDefinition,
contextValueExtension?: Partial<Context<unknown>>,
initialModel?: object,
) {
): RenderResult & {
rerenderWithProps: (props: Record<any, any>) => void;
} {
radekmie marked this conversation as resolved.
Show resolved Hide resolved
const contextValue = {
changed: false,
changedMap: {},
Expand All @@ -37,11 +39,19 @@ export function render(
formRef: {} as BaseForm<unknown>,
};

return renderOnScreen(element, {
const originalRender = renderOnScreen(element, {
radekmie marked this conversation as resolved.
Show resolved Hide resolved
wrapper({ children }) {
return (
<context.Provider value={contextValue}>{children}</context.Provider>
);
},
});

const { rerender } = originalRender;

const rerenderWithProps = (props: Record<any, any>) => {
rerender(cloneElement(element, props));
};
radekmie marked this conversation as resolved.
Show resolved Hide resolved

return { rerenderWithProps, ...originalRender };
radekmie marked this conversation as resolved.
Show resolved Hide resolved
}
213 changes: 139 additions & 74 deletions packages/uniforms/__tests__/AutoForm.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { fireEvent, screen } from '@testing-library/react';
import React from 'react';
import SimpleSchema from 'simpl-schema';
import { AutoForm, connectField } from 'uniforms';
import { AutoForm, connectField, context } from 'uniforms';
import { SimpleSchema2Bridge } from 'uniforms-bridge-simple-schema-2';
import { AutoFields } from 'uniforms-unstyled';

import mount from './_mount';
import { render } from '../__suites__';

describe('AutoForm', () => {
const onChangeModel = jest.fn();
const validator = jest.fn();
const onChange = jest.fn();
const onSubmit = jest.fn();
const model = { a: '1' };
describe('<AutoForm />', () => {
const schema = new SimpleSchema2Bridge(
new SimpleSchema({
a: { type: String, defaultValue: '' },
b: { type: String, defaultValue: '' },
c: { type: String, defaultValue: '' },
}),
);
const model = { a: '1' };
radekmie marked this conversation as resolved.
Show resolved Hide resolved
const onChange = jest.fn();
const onChangeModel = jest.fn();
const onSubmit = jest.fn();
const validator = jest.fn();
const mockContext = jest.fn();

jest.spyOn(schema.schema, 'validator').mockImplementation(() => validator);

beforeEach(() => {
Expand All @@ -27,66 +31,84 @@ describe('AutoForm', () => {
validator.mockClear();
});

describe('when changed', () => {
describe('when changes', () => {
radekmie marked this conversation as resolved.
Show resolved Hide resolved
it('updates', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
render(
<AutoForm onChange={onChange} schema={schema} />,
{ schema: { type: SimpleSchema2Bridge } },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this argument? It should be used as the schema for the context, but we don't actually need seeding context here - we're rendering forms in these tests. (Also, this is not a valid schema. At least for any value.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the render function types and now the schema field is not required, If we don't pass it our component will not have a <Context.Provider>. I have also added the correct schema where we use context.

{ onChange },
);

wrapper.instance().getContext().onChange('a', '2');

expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenLastCalledWith('a', '2');
radekmie marked this conversation as resolved.
Show resolved Hide resolved
});

it('validates', () => {
// FIXME: AutoForm is not a valid Component.
radekmie marked this conversation as resolved.
Show resolved Hide resolved
const wrapper = mount<AutoForm | any>(
<AutoForm onChange={onChange} schema={schema} />,
render(
<AutoForm
// TODO: delete ts-expect-error if this issue is resolved https://github.com/vazco/uniforms/issues/1165
// @ts-expect-error
radekmie marked this conversation as resolved.
Show resolved Hide resolved
name="form"
schema={schema}
>
<AutoFields />
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

wrapper.instance().submit();
const form = screen.getByRole('form');
const input = screen.getByLabelText('A');
fireEvent.submit(form);

expect(validator).toHaveBeenCalledTimes(1);
expect(validator).toHaveBeenLastCalledWith({});
expect(validator).toHaveBeenLastCalledWith({ a: '', b: '', c: '' });
radekmie marked this conversation as resolved.
Show resolved Hide resolved

wrapper.instance().getContext().onChange('a', '1');
fireEvent.change(input, { target: { value: '2' } });

expect(validator).toHaveBeenCalledTimes(2);
expect(validator).toHaveBeenLastCalledWith({ a: '1' });
expect(validator).toHaveBeenLastCalledWith({ a: '2', b: '', c: '' });
});

it('calls `onChangeModel`', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm onChangeModel={onChangeModel} schema={schema} />,
render(
<AutoForm
// TODO: delete ts-expect-error if this issue is resolved https://github.com/vazco/uniforms/issues/1165
// @ts-expect-error
name="form"
onChange={onChangeModel}
schema={schema}
/>,
{ schema: { type: SimpleSchema2Bridge } },
);

wrapper.instance().getContext().onChange('a', '2');
const form = screen.getByRole('form');
fireEvent.change(form, onChangeModel({ a: '2' }));

expect(onChangeModel).toHaveBeenCalledTimes(1);
expect(onChangeModel).toHaveBeenLastCalledWith({ a: '2' });
});

it('updates `changed` and `changedMap`', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(<AutoForm schema={schema} />);

const context1 = wrapper.instance().getContext();
expect(context1).toHaveProperty('changed', false);
expect(context1).toHaveProperty('changedMap', {});

wrapper.instance().getContext().onChange('a', '2');
render(
<AutoForm schema={schema}>
<context.Consumer>
{context => mockContext(context?.changed, context?.changedMap)}
</context.Consumer>
radekmie marked this conversation as resolved.
Show resolved Hide resolved
<AutoFields />
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

const context2 = wrapper.instance().getContext();
expect(context2).toHaveProperty('changed', true);
expect(context2).toHaveProperty('changedMap.a');
expect(context2.changedMap.a).toBeTruthy();
expect(mockContext).toHaveBeenLastCalledWith(true, {
a: {},
b: {},
c: {},
});
});
});

describe('when rendered', () => {
describe('when render', () => {
it('calls `onChange` before render', () => {
const field = () => null;
const Field = connectField(field);
Expand All @@ -99,85 +121,128 @@ describe('AutoForm', () => {
}

// FIXME: AutoForm is not a valid Component.
mount<CustomAutoForm | any>(
render(
// @ts-expect-error Convoluted AutoForm types
<CustomAutoForm
autoField={Field}
model={model}
onChange={onChange}
schema={schema}
autoField={Field}
model={model}
/>,
{ schema: { type: SimpleSchema2Bridge } },
);

expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange.mock.calls[0]).toEqual(expect.arrayContaining(['b', '']));
expect(onChange.mock.calls[1]).toEqual(expect.arrayContaining(['c', '']));
});

it('skips `onSubmit` until rendered (`autosave` = true)', async () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm autosave onSubmit={onSubmit} schema={schema} />,
render(
<AutoForm autosave onSubmit={onSubmit} schema={schema}>
<AutoFields />
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

expect(onSubmit).not.toBeCalled();
wrapper.instance().getContext().onChange('a', 1);

await new Promise(resolve => setTimeout(resolve));

const input = screen.getByLabelText('A');

expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenLastCalledWith({ a: 1 });
expect(validator).toHaveBeenCalledTimes(1);
expect(validator).toHaveBeenLastCalledWith({ a: 1 });
expect(onSubmit).toHaveBeenLastCalledWith({ a: '', b: '', c: '' });

await new Promise(resolve => setTimeout(resolve));
fireEvent.change(input, { target: { value: '1' } });

expect(validator).toHaveBeenCalledTimes(2);
expect(validator).toHaveBeenLastCalledWith({ a: '1', b: '', c: '' });
});
});

describe('when reset', () => {
it('reset `model`', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm autosave model={model} schema={schema} />,
const { rerenderWithProps } = render(
// FIXME: AutoForm is not a valid Component.
<AutoForm autosave model={model} schema={schema}>
<context.Consumer>
{context => mockContext(context?.model)}
</context.Consumer>
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

wrapper.instance().reset();
expect(wrapper.instance().getContext().model).toEqual(model);
rerenderWithProps({});
radekmie marked this conversation as resolved.
Show resolved Hide resolved

expect(mockContext).toHaveBeenLastCalledWith(model);
});

it('resets state `changedMap`', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm autosave model={model} onSubmit={onSubmit} schema={schema} />,
const { rerenderWithProps } = render(
// FIXME: AutoForm is not a valid Component.
<AutoForm autosave model={model} schema={schema}>
<context.Consumer>
{context => mockContext(context?.changedMap)}
</context.Consumer>
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

wrapper.instance().reset();
expect(wrapper.instance().getContext().changedMap).toEqual({});
rerenderWithProps({});

expect(mockContext).toHaveBeenLastCalledWith({});
});

it('resets state `changed`', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm autosave model={model} onSubmit={onSubmit} schema={schema} />,
const { rerenderWithProps } = render(
// FIXME: AutoForm is not a valid Component.
<AutoForm autosave model={model} schema={schema}>
<context.Consumer>
{context => mockContext(context?.changed)}
</context.Consumer>
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

wrapper.instance().reset();
expect(wrapper.instance().getContext().changed).toEqual(false);
rerenderWithProps({});

expect(mockContext).toHaveBeenLastCalledWith(false);
});
});

describe('when updated', () => {
it('updates', () => {
describe('when update', () => {
it('<AutoForm />, updates', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(<AutoForm schema={schema} />);
render(
<AutoForm schema={schema}>
<context.Consumer>
{context => mockContext(context?.model)}
</context.Consumer>
</AutoForm>,
{
schema: { type: SimpleSchema2Bridge },
},
);

wrapper.setProps({ model: {} });
expect(wrapper.instance().props.model).toEqual({});
expect(mockContext).toHaveBeenLastCalledWith({});
});

it('validates', () => {
it('<AutoForm />, validates', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(<AutoForm schema={schema} />);
const { rerenderWithProps } = render(<AutoForm schema={schema} />, {
schema: { type: SimpleSchema2Bridge },
});

wrapper.setProps({ model, validate: 'onChange' });
rerenderWithProps({ model, validate: 'onChange' });
expect(validator).toHaveBeenCalledTimes(1);
});
});
Expand Down
Loading