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 all 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
81 changes: 45 additions & 36 deletions packages/uniforms/__suites__/render.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,56 @@
import { render as renderOnScreen } from '@testing-library/react';
import React, { ReactElement } from 'react';
import { render as renderOnScreen, RenderResult } from '@testing-library/react';
import React, { ReactElement, cloneElement } from 'react';
import SimpleSchema, { SimpleSchemaDefinition } from 'simpl-schema';
import { BaseForm, Context, UnknownObject, context, randomIds } from 'uniforms';
import { SimpleSchema2Bridge } from 'uniforms-bridge-simple-schema-2';

const randomId = randomIds();

export function render<Model extends UnknownObject>(
element: ReactElement,
schema: SimpleSchemaDefinition,
export function render<P, Model extends UnknownObject>(
element: ReactElement<P>,
schema?: SimpleSchemaDefinition,
contextValueExtension?: Partial<Context<Model>>,
model = {} as Model,
) {
const contextValue = {
changed: false,
changedMap: {},
error: null,
model,
name: [],
onChange() {},
onSubmit() {},
randomId,
submitted: false,
submitting: false,
validating: false,
...contextValueExtension,
schema: new SimpleSchema2Bridge(new SimpleSchema(schema)),
state: {
disabled: false,
label: false,
placeholder: false,
readOnly: false,
showInlineError: false,
...contextValueExtension?.state,
},
formRef: {} as BaseForm<UnknownObject>,
};

return renderOnScreen(element, {
): RenderResult & { rerenderWithProps: (props: P) => void } {
const renderResult = renderOnScreen(element, {
wrapper({ children }) {
return (
<context.Provider value={contextValue}>{children}</context.Provider>
);
if (schema) {
const contextValue = {
changed: false,
changedMap: {},
error: null,
model,
name: [],
onChange() {},
onSubmit() {},
randomId,
submitted: false,
submitting: false,
validating: false,
...contextValueExtension,
schema: new SimpleSchema2Bridge(new SimpleSchema(schema)),
state: {
disabled: false,
label: false,
placeholder: false,
readOnly: false,
showInlineError: false,
...contextValueExtension?.state,
},
formRef: {} as BaseForm<UnknownObject>,
};
return (
<context.Provider value={contextValue}>{children}</context.Provider>
);
}
return <>{children}</>;
radekmie marked this conversation as resolved.
Show resolved Hide resolved
},
});

const { rerender } = renderResult;

const rerenderWithProps = (props: P) => {
rerender(cloneElement(element, props));
};

return { rerenderWithProps, ...renderResult };
}
212 changes: 121 additions & 91 deletions packages/uniforms/__tests__/AutoForm.tsx
Original file line number Diff line number Diff line change
@@ -1,92 +1,103 @@
import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import React, { ReactNode } from 'react';
import SimpleSchema from 'simpl-schema';
import { AutoForm, connectField } from 'uniforms';
import { AutoForm, connectField, Context, 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();
describe('<AutoForm />', () => {
const onChange = jest.fn();
const onChangeModel = jest.fn();
const onSubmit = jest.fn();
const validator = jest.fn();
const contextSpy = jest.fn<ReactNode, [Context<any> | null]>();
const model = { a: '1' };
const schema = new SimpleSchema2Bridge(
new SimpleSchema({
a: { type: String, defaultValue: '' },
b: { type: String, defaultValue: '' },
c: { type: String, defaultValue: '' },
}),
);
const schemaDefinition = {
a: { type: String, defaultValue: '' },
b: { type: String, defaultValue: '' },
c: { type: String, defaultValue: '' },
};
const schema = new SimpleSchema2Bridge(new SimpleSchema(schemaDefinition));

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

beforeEach(() => {
onChange.mockClear();
onChangeModel.mockClear();
onSubmit.mockClear();
validator.mockClear();
});
beforeEach(() => jest.clearAllMocks());

describe('when changed', () => {
it('updates', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm onChange={onChange} schema={schema} />,
render(
<AutoForm onChange={onChange} schema={schema}>
<AutoFields />
</AutoForm>,
schemaDefinition,
{ onChange },
);

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

expect(onChange).toHaveBeenCalledTimes(1);
const input = screen.getByLabelText('A');
fireEvent.change(input, { target: { value: '2' } });
expect(onChange).toHaveBeenCalledTimes(4);
expect(onChange).toHaveBeenLastCalledWith('a', '2');
});

it('validates', () => {
// FIXME: AutoForm is not a valid Component.
const wrapper = mount<AutoForm | any>(
<AutoForm onChange={onChange} schema={schema} />,
render(
<AutoForm
// @ts-expect-error https://github.com/vazco/uniforms/issues/1165
name="form"
onChange={onChange}
schema={schema}
>
<AutoFields />
</AutoForm>,
);

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
// @ts-expect-error https://github.com/vazco/uniforms/issues/1165
name="form"
onChangeModel={onChangeModel}
schema={schema}
/>,
);

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 children={contextSpy} />
<AutoFields />
</AutoForm>,
schemaDefinition,
);

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

describe('when rendered', () => {
describe('when render', () => {
it('calls `onChange` before render', () => {
const field = () => null;
const Field = connectField(field);
Expand All @@ -98,86 +109,105 @@ 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}
/>,
);

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>,
);

expect(onSubmit).not.toBeCalled();
wrapper.instance().getContext().onChange('a', 1);
const input = screen.getByLabelText('A');
fireEvent.change(input, { target: { value: '1' } });

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

expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenLastCalledWith({ a: 1 });
expect(onSubmit).toHaveBeenLastCalledWith({ a: '1', b: '', c: '' });
expect(validator).toHaveBeenCalledTimes(1);
expect(validator).toHaveBeenLastCalledWith({ a: 1 });
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 Component = () => (
<AutoForm autosave model={model} schema={schema}>
<context.Consumer children={contextSpy} />
</AutoForm>
);
const { rerender } = render(<Component />, schemaDefinition);

rerender(<Component />);

wrapper.instance().reset();
expect(wrapper.instance().getContext().model).toEqual(model);
expect(contextSpy).toHaveBeenLastCalledWith(
expect.objectContaining({ 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 Component = () => (
<AutoForm autosave model={model} schema={schema}>
<context.Consumer children={contextSpy} />
</AutoForm>
);

wrapper.instance().reset();
expect(wrapper.instance().getContext().changedMap).toEqual({});
const { rerender } = render(<Component />, schemaDefinition);

rerender(<Component />);

expect(contextSpy).toHaveBeenLastCalledWith(
expect.objectContaining({ changedMap: {} }),
);
});

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 Component = () => (
<AutoForm autosave model={model} schema={schema}>
<context.Consumer children={contextSpy} />
</AutoForm>
);
const { rerender } = render(<Component />, schemaDefinition);

rerender(<Component />);

wrapper.instance().reset();
expect(wrapper.instance().getContext().changed).toEqual(false);
expect(contextSpy).toHaveBeenLastCalledWith(
expect.objectContaining({ changed: false }),
);
});
});
describe('when update', () => {
it('<AutoForm />, updates', () => {
const { rerenderWithProps } = render(
<AutoForm schema={schema}>
<context.Consumer children={contextSpy} />
</AutoForm>,
schemaDefinition,
);

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

wrapper.setProps({ model: {} });
expect(wrapper.instance().props.model).toEqual({});
rerenderWithProps({ model: {} });
expect(contextSpy).toHaveBeenLastCalledWith(
expect.objectContaining({ model: {} }),
);
});

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

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