Chafroud Tarek
Posted on June 26, 2023
In our latest blog post on creating components with Storybook, we will leverage the existing stories of our button components to create comprehensive test cases using Testing Library.
You can refer to the official documentation for setting up Testing Library
https://testing-library.com/docs/react-testing-library/setup/
The first step is to create our testing file, in my case "button.test.tsx", and add the necessary imports.
and this is the full example:
// Describe block for the Button Component
describe('Button Component', () => {
// Test case for rendering primary button
test('should render primary button', () => {
render(<Primary {...Primary.args} />);
expect(screen.getByRole('button')).toHaveTextContent('Button');
});
// Test case for rendering secondary button
test('should render secondary button', () => {
render(<Secondary {...Secondary.args} />);
expect(screen.getByRole('button')).toHaveTextContent('Button');
});
// Test case for rendering danger button
test('should render danger button', () => {
render(<Danger {...Danger.args} />);
expect(screen.getByRole('button')).toHaveTextContent('Button');
});
// Test case for rendering disabled button
test('should render disabled button', () => {
render(<Disabled {...Disabled.args} disabled />);
const buttonElement = screen.getByRole('button');
expect(buttonElement).toBeDisabled();
});
// Test case for rendering button instead of spinner when not loading
test('should render button instead of spinner when not loading', () => {
render(<Loading {...Loading.args} loading={false} />);
expect(screen.getByRole('button')).toHaveTextContent('Button');
});
// Test case for rendering Spinner instead of button when loading
test('should render Spinner instead of button when loading', () => {
render(<Loading {...Loading.args} />);
const spinnerElement = screen.getByTestId('spinner');
expect(spinnerElement).toBeInTheDocument();
});
});
Let's explore a couple more test cases, focusing on the Select component and the Login/Signup form:
▪️ Select component:
// Import necessary libraries and components
import React from 'react';
import { render, screen } from '@testing-library/react';
import InputSelect, { Option } from '.';
// Describe block for the InputSelect component
describe('InputSelect', () => {
// Define options array for testing
const options: Option[] = [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
{ value: 'option3', label: 'Option 3' },
];
// Create a mock onChange function
const mockOnChange = jest.fn();
// Test case for rendering label and options correctly
test('should label and options correctly', () => {
render(<InputSelect label='Select' options={options} value={null} onChangeAction={mockOnChange} />);
// Get elements from the rendered component
const labelElement = screen.getByText('Select');
const selectElement = screen.getByRole('combobox');
const optionElements = screen.queryAllByRole('option');
// Assert label and select elements are in the document
expect(labelElement).toBeInTheDocument();
expect(selectElement).toBeInTheDocument();
// Assert select element has correct aria-label attribute
expect(selectElement).toHaveAttribute('aria-label', 'Select');
// Assert each option element has correct text content
optionElements.forEach((option, index) => {
expect(option).toHaveTextContent(options[index].label);
});
});
// Test case for rendering error message when error prop is provided
test('should render error message when error prop is provided', () => {
// Define an error object
const error = { message: 'This field is required' };
render(<InputSelect label='Select Option' options={options} value={null} error={error} onChangeAction={mockOnChange} />);
// Get the error message element
const errorMessage = screen.getByText('This field is required');
// Assert error message is in the document
expect(errorMessage).toBeInTheDocument();
});
});
▪️ Login form:
// Import necessary functions and components from testing libraries
import { render, screen, fireEvent, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import LoginForm from '.';
// Describe block for the LoginForm Component
describe('LoginForm Component', () => {
// Test case for rendering the login form correctly
test('should render the login form correctly', () => {
render(<LoginForm onhandleSubmit={() => {}} loading={false} />);
// Get form elements
const emailInput = screen.getByTestId('email');
const passwordInput = screen.getByTestId('password');
const rememberMeCheckbox = screen.getByLabelText('Remember me');
const signInButton = screen.getByRole('button', { name: 'Sign in' });
const signupLink = screen.getByRole('link', { name: 'Signup' });
// Assert form elements are in the document
expect(emailInput).toBeInTheDocument();
expect(passwordInput).toBeInTheDocument();
expect(rememberMeCheckbox).toBeInTheDocument();
expect(signInButton).toBeInTheDocument();
expect(signupLink).toBeInTheDocument();
});
// Test case for displaying error messages when form validation fails
test('should display error messages when form validation fails', async () => {
render(<LoginForm onhandleSubmit={() => {}} loading={false} />);
// Get form elements
const emailInput = screen.getByTestId('email');
const passwordInput = screen.getByTestId('password');
const signInButton = screen.getByRole('button', { name: 'Sign in' });
// Simulate form submission
await act(async () => {
userEvent.click(emailInput);
userEvent.click(passwordInput);
fireEvent.click(signInButton);
});
// Get error messages
const emailErrorMessage = screen.getByTestId('email-error');
const passwordErrorMessage = screen.getByTestId('password-error');
// Assert error messages are in the document
expect(emailErrorMessage).toBeInTheDocument();
expect(passwordErrorMessage).toBeInTheDocument();
});
// Test case for calling onhandleSubmit when form is submitted
test('should call onhandleSubmit when form is submitted', async () => {
// Mock the handleSubmit function
const mockHandleSubmit = jest.fn();
render(<LoginForm onhandleSubmit={mockHandleSubmit} loading={false} />);
const emailInput = screen.getByTestId('email');
const passwordInput = screen.getByTestId('password');
const signInButton = screen.getByRole('button', { name: 'Sign in' });
// Simulate form submission
await act(async () => {
userEvent.type(emailInput, 'test@test.com');
userEvent.type(passwordInput, 'test123');
fireEvent.submit(signInButton);
});
// Assert that handleSubmit function was called
expect(mockHandleSubmit).toHaveBeenCalled();
});
});
▪️ Signup form:
import { render, screen, fireEvent, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import RegisterForm from '.';
// Describe the RegisterForm component test suite
describe('RegisterForm Component', () => {
// Define options for the select input
let options = [{ label: 'lessor', value: 'lessor' }];
// Test case for rendering the RegisterForm correctly
test('should render the login form correctly', () => {
render(<RegisterForm onhandleSubmit={() => {}} loading={false} roles={options} />);
// Get form inputs and buttons
const usernameInput = screen.getByTestId('username');
const emailInput = screen.getByTestId('email');
const passwordInput = screen.getByTestId('password');
const selectInput = screen.getByTestId('selectrole');
const signInButton = screen.getByRole('button', { name: 'Sign up' });
const signupLink = screen.getByRole('link', { name: 'Login' });
// Assert form elements are in the document
expect(usernameInput).toBeInTheDocument();
expect(emailInput).toBeInTheDocument();
expect(passwordInput).toBeInTheDocument();
expect(selectInput).toBeInTheDocument();
expect(signInButton).toBeInTheDocument();
expect(signupLink).toBeInTheDocument();
});
// Test case for displaying error messages when form validation fails
test('should display error messages when form validation fails', async () => {
render(<RegisterForm onhandleSubmit={() => {}} loading={false} roles={options} />);
// Get form inputs and submit button
const emailInput = screen.getByTestId('email');
const passwordInput = screen.getByTestId('password');
const signInButton = screen.getByRole('button', { name: 'Sign up' });
// Simulate form submission
await act(async () => {
userEvent.click(emailInput);
userEvent.click(passwordInput);
fireEvent.click(signInButton);
});
// Get error messages
const emailErrorMessage = screen.getByTestId('email-error');
const passwordErrorMessage = screen.getByTestId('password-error');
// Assert error messages are in the document
expect(emailErrorMessage).toBeInTheDocument();
expect(passwordErrorMessage).toBeInTheDocument();
});
// Test case for submitting the form with valid data
test('should submit the form with valid data', async () => {
const handleSubmit = jest.fn();
render(<RegisterForm onhandleSubmit={handleSubmit} loading={false} roles={options} />);
// Simulate form submission with valid data
await act(async () => {
fireEvent.change(screen.getByTestId('username'), { target: { value: 'testname' } });
fireEvent.change(screen.getByTestId('email'), { target: { value: 'email@provider.com' } });
fireEvent.change(screen.getByTestId('password'), { target: { value: 'test123' } });
fireEvent.click(screen.getByTestId('selectrole'));
const optionElements = screen.queryAllByRole('option');
optionElements.forEach((option, index) => {
fireEvent.click(screen.getByRole('button', { name: 'Sign up' }));
// Assert option text content and form submission
expect(option).toHaveTextContent(options[index].label);
expect(handleSubmit).toHaveBeenCalled();
});
});
});
});
We have reached the end of the process. If you have any further questions or need more tips, feel free to contact me. 👋
Posted on June 26, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.