Skip to content
This repository has been archived by the owner on Aug 20, 2024. It is now read-only.

Rewrite unit tests in the manner of RTL #54

Merged
merged 5 commits into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 11 additions & 5 deletions __test__/src/components/atoms/button/PrimaryButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { shallow } from 'enzyme';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
import { PrimaryButton } from '../../../../../src/components/atoms/button/PrimaryButton';

describe('PrimaryButton', () => {
it('renders a child', () => {
const mockCallback = jest.fn();
const button = shallow(<PrimaryButton onClick={mockCallback}>Hello</PrimaryButton>);
button.simulate('click');
expect(button.text()).toEqual('Hello');
expect(mockCallback.mock.calls.length).toBe(1);
render(<PrimaryButton onClick={mockCallback}>Hello</PrimaryButton>);
expect(screen.getByText('Hello')).toBeInTheDocument();
});

it('calls onClick handler when it is clicked', async () => {
const mockCallback = jest.fn();
render(<PrimaryButton onClick={mockCallback}>Hello</PrimaryButton>);
await userEvent.click(screen.getByRole('button'));
expect(mockCallback).toBeCalledTimes(1);
});
});
103 changes: 67 additions & 36 deletions __test__/src/components/molecules/forms/EditableProperty.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { mount, shallow } from 'enzyme';
import { EditableProperty } from '../../../../../src/components/molecules/forms/EditableProperty';
import { isVisible } from '../../../../util';
import userEvent from '@testing-library/user-event';
import { render, screen, waitFor } from '@testing-library/react';

Expand All @@ -12,18 +10,16 @@ import { render, screen, waitFor } from '@testing-library/react';
disabled?: boolean;
loading?: boolean;
*/
describe('PrimaryButton', () => {
it('render non-editable value', () => {
describe('EditableProperty', () => {
it('renders non-editable value', () => {
const mockCallback = jest.fn();
const prop = shallow(
<EditableProperty label='myLabel' property='myprop' defaultValue='default' onUpdateProp={mockCallback} />,
);
expect(prop.find('Heading').text()).toEqual('myLabel');
expect(prop.find('Text.value').text()).toEqual('default');
render(<EditableProperty label='myLabel' property='myprop' defaultValue='default' onUpdateProp={mockCallback} />);
expect(screen.getByRole('heading')).toHaveTextContent('myLabel');
expect(screen.getByText('default', { selector: '.value' })).toBeInTheDocument();
});
it('click to edit for editable value', () => {
it('shows a textbox to edit, after an edit button is clicked', async () => {
const mockCallback = jest.fn();
const prop = mount(
render(
<EditableProperty
label='myLabel'
property='myprop'
Expand All @@ -32,13 +28,17 @@ describe('PrimaryButton', () => {
editable={true}
/>,
);
expect(isVisible(prop.find('input').getDOMNode())).toEqual(false);
prop.find('button').simulate('click');
expect(isVisible(prop.find('input').getDOMNode())).toEqual(true);
// A textbox should not be in DOM before staring edit
expect(screen.queryByRole('textbox')).not.toBeInTheDocument();

// The aria-label of an edit button should be `${property}-edit`
await userEvent.click(screen.getByLabelText('myprop-edit'));
expect(screen.getByRole('textbox')).toBeVisible();
});
it('the data should be editable', async () => {
it('changes the value, after an user edits and saves it', async () => {
const user = userEvent.setup();
const mockCallback = jest.fn().mockResolvedValue(true);
const prop = mount(
render(
<EditableProperty
label='myLabel'
property='myprop'
Expand All @@ -47,18 +47,35 @@ describe('PrimaryButton', () => {
editable={true}
/>,
);
prop.find('button').simulate('click'); // edit
expect(prop.find('EditablePreview').text()).toEqual('default');
prop.find('input').simulate('change', { target: { value: 'New Text' } }); // enter text
expect(prop.find('input').props()['value']).toEqual('New Text'); // text should be changed
prop.find('button.commit').simulate('click'); // click commit
expect(mockCallback.call.length).toBe(1); // the mock function should be called
expect(mockCallback).toHaveBeenCalledWith('myprop', 'New Text'); // with correct parameters
expect(prop.find('EditablePreview').text()).toEqual('New Text'); // the displaying text should be chaned
// 'default' should be shown as preview text
expect(screen.getByText('default')).toBeInTheDocument();

// User begins to edit
await user.click(screen.getByLabelText('myprop-edit'));

// User deletes existing text and enters new one
const input = screen.getByRole('textbox');
await user.click(input);
await user.clear(input);
await user.keyboard('New Text');
expect(input).toHaveValue('New Text');

// User saves the change
// The aria-label of a save button should be `${property}-commit`
await userEvent.click(screen.getByLabelText('myprop-commit'));

// The onUpdateProp handler should be called once
// with the changed prop name and its new vaue.
expect(mockCallback).toHaveBeenCalledTimes(1);
expect(mockCallback).toHaveBeenCalledWith('myprop', 'New Text');

// 'New Text' should be shown as new preview text
expect(screen.getByText('New Text')).toBeInTheDocument();
});
it('the data should be cancellable', () => {
it('restores the value, after the change is discarded', async () => {
const user = userEvent.setup();
const mockCallback = jest.fn();
const prop = mount(
render(
<EditableProperty
label='myLabel'
property='myprop'
Expand All @@ -68,14 +85,28 @@ describe('PrimaryButton', () => {
/>,
);

prop.find('button').simulate('click'); // edit
prop.find('input').simulate('change', { target: { value: 'New Text' } });
expect(prop.find('input').props()['value']).toEqual('New Text');
prop.find('button.cancel').simulate('click');
expect(prop.find('input').props()['value']).toEqual('default');
// User begins to edit
await user.click(screen.getByLabelText('myprop-edit'));

// User deletes existing text and enters new one
const input = screen.getByRole('textbox');
await user.click(input);
await user.clear(input);
await user.keyboard('New Text');
expect(input).toHaveValue('New Text');

// User discards the change
// The aria-label of a discard button should be `${property}-cancel`
await userEvent.click(screen.getByLabelText('myprop-cancel'));

// 'default' should be left as preview text
expect(screen.getByText('default')).toBeInTheDocument();
// 'New text' should not be shown because it was discarded
expect(screen.queryByText('New Text')).not.toBeInTheDocument();
});

test('show error message when update is failed', async () => {
it('shows error message when fails to update the value', async () => {
const user = userEvent.setup();
const mockCallback = jest.fn().mockRejectedValue(new Error('error text'));
render(
<EditableProperty
Expand All @@ -86,11 +117,11 @@ describe('PrimaryButton', () => {
editable={true}
/>,
);
userEvent.click(screen.getByLabelText('myprop-edit'));
userEvent.type(screen.getByRole('textbox'), 'new bad text');
userEvent.click(screen.getByLabelText('myprop-commit'));
await user.click(screen.getByLabelText('myprop-edit'));
await user.type(screen.getByRole('textbox'), 'new bad text');
await user.click(screen.getByLabelText('myprop-commit'));
await waitFor(() => {
expect(screen.getByLabelText('error-message').textContent).toEqual('error text');
expect(screen.getByLabelText('error-message')).toHaveTextContent('error text');
});
});
});
3 changes: 0 additions & 3 deletions __test__/util.ts

This file was deleted.

7 changes: 0 additions & 7 deletions jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,3 @@
// Used for __tests__/testing-library.js
// Learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';
// setup enzyme
import { configure } from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

configure({
adapter: new Adapter(),
});
9 changes: 1 addition & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,15 @@
"react-dom": "17.0.2"
},
"devDependencies": {
"@testing-library/dom": "^8.11.3",
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"@types/enzyme": "^3.10.11",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@testing-library/user-event": "^14.0.0-beta",
"@types/node": "^17.0.17",
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0",
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.6",
"cypress": "^9.4.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"eslint": "^8.9.0",
"eslint-config-next": "12.0.10",
"eslint-config-prettier": "^8.3.0",
Expand All @@ -59,7 +53,6 @@
"mrm": "2",
"openapi-typescript": "^5.2.0",
"prettier": "^2.5.1",
"react-addons-test-utils": "^15.6.2",
"typescript": "4.5.5"
},
"lint-staged": {
Expand Down
Loading