Unit Testing for EveryOne

Gabrelsoft
3 min readJul 2, 2023
unit testing with storybook
unit testing with storybook

It’s never a must to test it’s even faster to push to the production server without testing, testing slows down development time. But, why must we always test? below outlines the benefits of unit testing;

  • Improves your application architecture and maintainability.
  • Improves developer experience(DX)
  • Improves confidence level when adding features

When writing tests it’s vital to achieve some of the benefits listed above, it takes extra discipline, patience, and, practice. Lots of developers delay before writing tests, and when you don’t write tests you fail to follow the development process.

TDD and unit testing helps in writing reusable simple reusable components, which are simple to maintain. A recent innovation in my testing development is the use of Storybook, which helps in writing maintainable tests.

No matter what framework you use, the following tips will help you write better, more testable, more readable, and more composable UI components:

  • Separate business Logic
  • Separate Side Effect
  • Wrap Pure Components (UI code) — wrap pure components in a container component that manages state and side effects.

Wrap Pure Components

Pure components will always render the same UI passed as props with no side effects.

import React from 'react';

const Detail = ({ name }) => (
<div className="greeting">Hello, {name}</div>
);
export default Detail;

Components of this kind are easy to test. You just need to select the component and you’ll need to know the expected result.

To get started, install Storybook.

npm i -D @storybook/react

Internally, Storybook uses react-dom, and babel, and wraps the output in a canvas.

import { ComponentProps } from 'react'; 
import { Story } from '@storybook/react'
import Button, { ButtonSize, ButtonVariant } from './index';
import { Box } from '@mui/system';
import LinkButton from './LinkButton';

// eslint-disable-next-line import/no-anonymous-default-export
export default {
title: 'core/Button',
argTypes: {
size: {
control: { type: 'select', options: ButtonSize },
},
variant: {
control: {
type: 'select',
options: ButtonVariant,
},
},
},
};



export const AllButtons = () => {
return (
<>
<Box sx={{ m: 1 }}>
<Button text="Primary" />
</Box>
<Box sx={{ m: 1 }}>
<Button text="Outlined" variant={ButtonVariant.OUTLINED} />
</Box>
<Box sx={{ m: 1 }}>
<Button text="Outlined Warning" variant={ButtonVariant.OUTLINED_WARNING} />
</Box>
<Box sx={{ m: 1 }}>
<Button text="Transparent" variant={ButtonVariant.TRANSPARENT} />
</Box>
<Box sx={{ m: 1 }}>
<Button text="Large" size={ButtonSize.LARGE} />
</Box>
<Box sx={{ m: 1 }}>
<Button text="Small" size={ButtonSize.SMALL} />
</Box>
<Box sx={{ m: 1 }}>
<Button text="Full width" takeFull />
</Box>
<Box sx={{ m: 1 }}>
<Button isLoading />
</Box>
<Box sx={{ m: 1 }}>
<LinkButton>Link Button</LinkButton>
</Box>
</>
);
}


export const ButtonArgs: Story<ComponentProps<typeof Button>> = (args) => {
return <Button {...args} />
}

ButtonArgs.args = {
text: "primary",
size: ButtonSize.LARGE,
variant: ButtonVariant.PRIMARY,
isLoading: false
}

What if you need to test a stateful component, or probably a component with some side effects? That’s where Test-Driven(TDD) gets really interesting for React components. Some questions that crop up most times are; “How do I make my React Components maintainable?”

Answer

Separating your state and side effects from presentation components. This can be achieved by encapsulating your state and side-effect in a container component and then passing the state into a pure component using props. It’s always a good idea to keep your component flat according to the following;

  • Display
  • Business Logic and,
  • Side effect

Let’s demonstrate stateful components by building a Numberpill

Let’s demonstrate stateful components by building a Numberpill. First, we need to build the UI component. it should display something like, “Clicks: 1” to tell the user the number of times it has been clicked.

In this case, we’ll create a component called <NumberPill/>, and that component will have a prop for the number clicked.

import NumberPill from '../index';
import { shallow, ShallowWrapper } from 'enzyme';
import { aRandomNumber } from '../../../../utils/testData';

describe('NumberPill', () => {
let wrapper: ShallowWrapper;
const number = aRandomNumber();

it('renders pill component with provided number', () => {
wrapper = shallow(<NumberPill number={number} />);
expect(wrapper.text()).toEqual(String(number));
});
});

Gabrielsoft is a Javascript developer keen on building software solutions that solve problems.

He enjoys his computer science lectures while in school.

--

--