Unverified Commit 5fb91328 authored by Ridwan Amode's avatar Ridwan Amode Committed by GitHub
Browse files

React testing refactor (#484)

* ENSWBSITES-1045: update test scripts to use react-testing library
parent 9b48d325
Pipeline #143244 passed with stages
in 7 minutes and 6 seconds
......@@ -15,9 +15,9 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { render } from '@testing-library/react';
import faker from 'faker';
import BadgedButton from './BadgedButton';
import BadgedButton, { Props as BadgedButtonProps } from './BadgedButton';
import Button from '../button/Button';
const onClick = jest.fn();
......@@ -26,66 +26,48 @@ const defaultProps = {
badgeContent: faker.lorem.words()
};
const renderButton = (
ButtonComponent: React.FunctionComponent<any>,
props: any = defaultProps
) => mount(<ButtonComponent {...props} />);
const renderButton = (props: Partial<BadgedButtonProps> = {}) =>
render(
<BadgedButton {...defaultProps} {...props}>
<Button onClick={onClick}>{faker.lorem.words()}</Button>
</BadgedButton>
);
describe('BadgedButton', () => {
let wrapper: any;
beforeEach(() => {
wrapper = renderButton(BadgedButton, {
...defaultProps,
children: <Button onClick={onClick}>{faker.lorem.words()}</Button>
});
});
afterEach(() => {
jest.resetAllMocks();
});
it('renders the passed in button', () => {
expect(wrapper.find('button').length).toEqual(1);
const { container } = renderButton();
expect(container.querySelectorAll('.button')).toHaveLength(1);
});
it('assigns the "badgeDefault" class to the badge by default', () => {
const renderedBadge = wrapper.find('.badgeDefault');
expect(renderedBadge).toHaveLength(1);
const { container } = renderButton();
expect(container.querySelectorAll('.badgeDefault')).toHaveLength(1);
});
it('extends the badge class', () => {
const fakeClassName = faker.lorem.word();
const wrapper = renderButton(BadgedButton, {
...defaultProps,
children: <Button onClick={onClick}>{faker.lorem.words()}</Button>,
className: fakeClassName
});
const renderedBadge = wrapper.find('.badgeDefault');
expect(renderedBadge.hasClass(fakeClassName)).toBe(true);
const { container } = renderButton({ className: fakeClassName });
expect(
container
.querySelector('.badgeDefault')
?.classList.contains(fakeClassName)
).toBeTruthy;
});
it('trims the longer strings to three characters', () => {
const wrapper = renderButton(BadgedButton, {
badgeContent: 'abcd',
children: <Button onClick={onClick}>{faker.lorem.words()}</Button>
});
const renderedBadge = wrapper.find('.badgeDefault');
expect(renderedBadge.text()).toBe('abc');
const { container } = renderButton({ badgeContent: 'abcd' });
expect(container.querySelector('.badgeDefault')?.textContent).toEqual(
'abc'
);
});
it('formats number greater than 99 to "99+"', () => {
const wrapper = renderButton(BadgedButton, {
badgeContent: 100,
children: <Button onClick={onClick}>{faker.lorem.words()}</Button>
});
const renderedBadge = wrapper.find('.badgeDefault');
expect(renderedBadge.text()).toBe('99+');
const { container } = renderButton({ badgeContent: 100 });
expect(container.querySelector('.badgeDefault')?.textContent).toEqual(
'99+'
);
});
});
......@@ -18,7 +18,7 @@ import React from 'react';
import defaultStyles from './BadgedButton.scss';
import classNames from 'classnames';
type Props = {
export type Props = {
children: React.ReactChild;
badgeContent?: string | number | undefined;
className?: string;
......
......@@ -15,7 +15,9 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import faker from 'faker';
import ExpandableSection, { ExpandableSectionProps } from './ExpandableSection';
......@@ -39,64 +41,64 @@ const defaultProps: ExpandableSectionProps = {
describe('<ExpandableSection />', () => {
const renderExpandableSection = (
props: Partial<ExpandableSectionProps> = {}
) => mount(<ExpandableSection {...defaultProps} {...props} />);
) => render(<ExpandableSection {...defaultProps} {...props} />);
let wrapper: any;
let container: any;
beforeEach(() => {
jest.resetAllMocks();
wrapper = renderExpandableSection();
container = renderExpandableSection().container;
});
it('renders without error', () => {
expect(() => wrapper).not.toThrow();
expect(() => container).not.toThrow();
});
it('hides the expanded content when isExpanded is false', () => {
wrapper = renderExpandableSection({
container = renderExpandableSection({
isExpanded: false
});
expect(wrapper.find('.expandedContent')).toHaveLength(0);
expect(wrapper.find('.collapsedContent')).toHaveLength(1);
}).container;
expect(container.querySelectorAll('.expandedContent')).toHaveLength(0);
expect(container.querySelectorAll('.collapsedContent')).toHaveLength(1);
});
it('shows the expanded content when isExpanded is true', () => {
expect(wrapper.find('.expandedContent')).toHaveLength(1);
expect(wrapper.find('.collapsedContent')).toHaveLength(0);
expect(container.querySelectorAll('.expandedContent')).toHaveLength(1);
expect(container.querySelectorAll('.collapsedContent')).toHaveLength(0);
});
it('calls onToggle prop when collapsing or expanding', () => {
wrapper.find('.toggle').simulate('click');
userEvent.click(container.querySelector('.toggle'));
expect(mockOnToggle).toBeCalledWith(false);
wrapper = renderExpandableSection({
container = renderExpandableSection({
isExpanded: false
});
}).container;
wrapper.find('.toggle').simulate('click');
userEvent.click(container.querySelector('.toggle'));
expect(mockOnToggle).toBeCalledWith(true);
});
it('applies the passed in classNames', () => {
expect(
wrapper
.find('.expandableSection')
.hasClass(defaultProps.classNames?.wrapper)
container
.querySelector('.expandableSection')
.classList.contains(defaultProps.classNames?.wrapper)
).toBeTruthy();
expect(
wrapper
.find('.expandedContent')
.hasClass(defaultProps.classNames?.expanded)
container
.querySelector('.expandedContent')
.classList.contains(defaultProps.classNames?.expanded)
).toBeTruthy();
wrapper = renderExpandableSection({
container = renderExpandableSection({
isExpanded: false
});
}).container;
expect(
wrapper
.find('.collapsedContent')
.hasClass(defaultProps.classNames?.collapsed)
container
.querySelector('.collapsedContent')
.classList.contains(defaultProps.classNames?.collapsed)
).toBeTruthy();
});
});
......@@ -15,7 +15,8 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { render } from '@testing-library/react';
import faker from 'faker';
import ExternalLink, { ExternalLinkProps } from './ExternalLink';
......@@ -24,32 +25,27 @@ const defaultProps: ExternalLinkProps = {
linkText: faker.random.words(),
to: faker.internet.url(),
classNames: {
icon: faker.random.words(),
link: faker.random.words()
icon: faker.random.word(),
link: faker.random.word()
}
};
describe('<ExternalLink />', () => {
const renderExternalLink = (props: Partial<ExternalLinkProps> = {}) =>
mount(<ExternalLink {...defaultProps} {...props} />);
let wrapper: any;
beforeEach(() => {
jest.resetAllMocks();
wrapper = renderExternalLink();
});
render(<ExternalLink {...defaultProps} {...props} />);
it('renders without error', () => {
expect(() => wrapper).not.toThrow();
const { container } = renderExternalLink();
expect(() => container).not.toThrow();
});
it('applies the passed in classNames', () => {
const { container } = renderExternalLink();
expect(container.getElementsByClassName('.icon')).toBeTruthy();
expect(
wrapper.find('.icon').hasClass(defaultProps.classNames?.icon)
).toBeTruthy();
expect(
wrapper.find('.link').hasClass(defaultProps.classNames?.link)
container
.querySelector('.link')
?.classList.contains(defaultProps.classNames?.link as string)
).toBeTruthy();
});
});
......@@ -36,7 +36,7 @@ const ExternalLink = (props: ExternalLinkProps) => {
const linkClass = classNames(styles.link, props.classNames?.link);
return (
<span className={styles.container}>
<span className={styles.container} data-test-id="external link container">
<LinkIcon className={iconClass} />
<a
className={linkClass}
......
......@@ -15,55 +15,67 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { render, screen } from '@testing-library/react';
import faker from 'faker';
import ExternalReference, { ExternalReferenceProps } from './ExternalReference';
import ExternalLink from '../external-link/ExternalLink';
const defaultProps: ExternalReferenceProps = {
label: faker.random.words(),
linkText: faker.random.words(),
label: faker.random.word(),
linkText: faker.random.word(),
to: faker.internet.url(),
classNames: {
container: faker.random.words(),
label: faker.random.words(),
icon: faker.random.words(),
link: faker.random.words()
container: faker.random.word(),
label: faker.random.word(),
icon: faker.random.word(),
link: faker.random.word()
}
};
describe('<ExternalReference />', () => {
const renderExternalReference = (
props: Partial<ExternalReferenceProps> = {}
) => mount(<ExternalReference {...defaultProps} {...props} />);
) => render(<ExternalReference {...defaultProps} {...props} />);
let wrapper: any;
let container: any;
beforeEach(() => {
jest.resetAllMocks();
wrapper = renderExternalReference();
container = renderExternalReference().container;
});
it('renders without error', () => {
expect(() => wrapper).not.toThrow();
expect(() => container).not.toThrow();
});
it('hides label container div when there is no label', () => {
wrapper = renderExternalReference({ label: undefined });
expect(wrapper.find('.label')).toHaveLength(0);
container = renderExternalReference({ label: undefined }).container;
expect(container.querySelectorAll('.label')).toHaveLength(0);
});
it('applies the passed in classNames', () => {
expect(
wrapper.render().hasClass(defaultProps.classNames?.container)
screen
.getByTestId('external reference container')
.classList.contains(defaultProps.classNames?.container as string)
).toBeTruthy();
expect(
container
.querySelector('.label')
.classList.contains(defaultProps.classNames?.label)
).toBeTruthy();
const externalLink = screen.getByTestId('external link container');
expect(
externalLink
.getElementsByTagName('icon-mock')[0]
.getAttribute('classname')
).toMatch(defaultProps.classNames?.icon as string);
expect(
wrapper.find('.label').hasClass(defaultProps.classNames?.label)
externalLink
.getElementsByTagName('a')[0]
.classList.contains(defaultProps.classNames?.link as string)
).toBeTruthy();
expect(wrapper.find(ExternalLink).prop('classNames')).toEqual({
icon: defaultProps.classNames?.icon,
link: defaultProps.classNames?.link
});
});
});
......@@ -44,7 +44,7 @@ const ExternalReference = (props: ExternalReferenceProps) => {
const labelClass = classNames(styles.label, props.classNames?.label);
return (
<div {...containerProps}>
<div {...containerProps} data-test-id="external reference container">
{!!props.label && <span className={labelClass}>{props.label}</span>}
{props.to ? (
<ExternalLink
......
......@@ -15,14 +15,12 @@
*/
import React from 'react';
import { act } from 'react-dom/test-utils';
import { mount } from 'enzyme';
import { render, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import faker from 'faker';
import { ImageButton, Props as ImageButtonProps } from './ImageButton';
import Tooltip from 'src/shared/components/tooltip/Tooltip';
import { Status } from 'src/shared/types/status';
jest.mock(
......@@ -38,68 +36,70 @@ const defaultProps = {
describe('<ImageButton />', () => {
const renderImageButton = (props: Partial<ImageButtonProps> = {}) =>
mount(<ImageButton {...defaultProps} {...props} />);
render(<ImageButton {...defaultProps} {...props} />);
it('renders without error', () => {
expect(() => renderImageButton()).not.toThrow();
expect(() => renderImageButton().container).not.toThrow();
});
describe('prop status', () => {
it('has a status set by default', () => {
const wrapper = renderImageButton();
expect(wrapper.prop('status')).toEqual(Status.DEFAULT);
const container = renderImageButton().container;
expect(
container
.querySelectorAll('.imageButton')[0]
.classList.contains(Status.DEFAULT)
).toBeTruthy();
});
});
describe('prop description', () => {
it('has a description set by default', () => {
const wrapper = renderImageButton();
expect(wrapper.prop('description')).toEqual('');
const container = renderImageButton().container;
expect(container.querySelector('img')?.alt).toEqual('');
});
it('respects the description prop', () => {
const wrapper = renderImageButton({ description: 'foo' });
expect(wrapper.prop('description')).toEqual('foo');
const container = renderImageButton({ description: 'foo' }).container;
expect(container.querySelector('img')?.alt).toEqual('foo');
});
});
describe('prop image', () => {
it('has an image set by default', () => {
const wrapper = renderImageButton();
expect(wrapper.prop('image')).toEqual('');
const container = renderImageButton().container;
expect(container.querySelector('img')?.getAttribute('src')).toEqual('');
});
it('renders an img tag if a path to an image file is passed', () => {
const wrapper = renderImageButton({ image: 'foo.png' });
expect(wrapper.find('button').find('img[src="foo.png"]')).toHaveLength(1);
const container = renderImageButton({ image: 'foo.png' }).container;
expect(
container.querySelector('button img')?.getAttribute('src')
).toEqual('foo.png');
});
it('renders the svg file passed in', () => {
const mockSVG = () => {
return <svg />;
return <svg className="test_svg" />;
};
const wrapper = renderImageButton({ image: mockSVG });
expect(wrapper.find('button').find(mockSVG)).toHaveLength(1);
const container = renderImageButton({ image: mockSVG }).container;
expect(container.querySelector('button .test_svg')).toBeTruthy();
});
});
describe('prop classNames', () => {
it('applies the default className when no status is provided', () => {
const wrapper = renderImageButton();
const container = renderImageButton().container;
expect(wrapper.find('.default')).toHaveLength(1);
expect(container.querySelectorAll('.default')).toHaveLength(1);
});
it('applies the respective className depending on the button status', () => {
const wrapper = renderImageButton({ status: Status.SELECTED });
const container = renderImageButton({ status: Status.SELECTED })
.container;
expect(wrapper.find('.selected')).toHaveLength(1);
expect(container.querySelectorAll('.selected')).toHaveLength(1);
});
});
......@@ -110,20 +110,19 @@ describe('<ImageButton />', () => {
});
it('calls the onClick prop when clicked', () => {
const wrapper = renderImageButton({ onClick });
wrapper.simulate('click');
const container = renderImageButton({ onClick }).container;
userEvent.click(container.querySelectorAll('button')[0]);
expect(onClick).toBeCalled();
});
it('does not call the onClick prop when clicked if the status is disabled', () => {
const wrapper = renderImageButton({
const container = renderImageButton({
onClick,
status: Status.DISABLED
});
}).container;
wrapper.simulate('click');
userEvent.click(container.querySelectorAll('button')[0]);
expect(onClick).not.toBeCalled();
});
......@@ -131,52 +130,40 @@ describe('<ImageButton />', () => {
describe('tooltip on hover', () => {
const mockSVG = () => {
return <svg />;
return <svg className="test-svg" />;
};
const description = faker.lorem.words();
const props = {
image: mockSVG,
description
};
const mouseEnterEvent = new Event('mouseenter');
const clickEvent = new Event('click');
it('shows tooltip when moused over', () => {
const wrapper = renderImageButton(props);
expect(wrapper.find(Tooltip).length).toBe(0);
const container = renderImageButton(props).container;
expect(container.querySelectorAll('.tooltip').length).toBe(0);
act(() => {
wrapper.getDOMNode().dispatchEvent(mouseEnterEvent);
});
wrapper.update();
fireEvent.mouseEnter(container.querySelectorAll('.imageButton')[0]);
const tooltip = wrapper.find(Tooltip);
expect(tooltip.length).toBe(1);
expect(tooltip.text()).toBe(description);
const tooltip = container.querySelectorAll('.tooltip');
expect(tooltip).toHaveLength(1);
expect(tooltip[0].textContent).toBe(description);
});
it('does not show tooltip if clicked', () => {
const wrapper = renderImageButton(props);
const container = renderImageButton(props).container;
act(() => {
const rootNode = wrapper.getDOMNode();
rootNode.dispatchEvent(mouseEnterEvent);
rootNode.dispatchEvent(clickEvent);
});
wrapper.update();
fireEvent.mouseEnter(container.querySelectorAll('.imageButton')[0]);
userEvent.click(container.querySelectorAll('.imageButton')[0]);