Testing Lab 5: Container Components
Objectives
- Test Setup
- Test the Loading Indicator Displays
- Test the Projects Display
- Test the More Button Displays
- Test the Error Displays
Steps
Test Setup
Create the file
src\projects\__tests__\ProjectsPage-test.tsx
.Add the setup code below to test the component.
src\projects\__tests__\ProjectsPage-test.tsx
import React from "react";import { MemoryRouter } from "react-router-dom";import { Provider } from "react-redux";import { store } from "../../state";import ProjectsPage from "../ProjectsPage";import {render,screen,waitForElementToBeRemoved,} from "@testing-library/react";describe("<ProjectsPage />", () => {function renderComponent() {render(<Provider store={store}><MemoryRouter><ProjectsPage /></MemoryRouter></Provider>);}test("should render without crashing", () => {renderComponent();expect(screen).toBeDefined();});});Verify the initial test passed.
PASS src/projects/__tests__/ProjectsPage-test.tsx! Check to make sure the
delay
function used to delay the backend query and display the loading indicator has been removed inprojectAPI.ts
. The delay call causes themsw
library to throw an error.
Test the Loading Indicator Displays
Test that the loading indicator displays when the component initially renders.
src\projects\__tests__\ProjectsPage-test.tsx
import React from 'react';import { MemoryRouter } from 'react-router-dom';import { Provider } from 'react-redux';import { store } from '../../state';import ProjectsPage from '../ProjectsPage';import {render,screen,waitForElementToBeRemoved,} from '@testing-library/react';describe('<ProjectsPage />', () => {function renderComponent() {render(<Provider store={store}><MemoryRouter><ProjectsPage /></MemoryRouter></Provider>);}...+ test('should display loading', () => {+ renderComponent();+ expect(screen.getByText(/loading/i)).toBeInTheDocument();+ });});Verify the test passed.
PASS src/projects/__tests__/ProjectsPage-test.tsx
Test the Projects Display
Open a
command prompt
(Windows) orterminal
(Mac).Change the current directory to
code\keeptrack
.Run one of the following sets of commands to install
Mock Service Worker
to mock the HTTP requests.$ npm install msw --save-dev# or$ yarn add msw --devExport the url used in the component from the
projectAPI.ts
file.src\projects\projectAPI.ts
import { Project } from './Project';const baseUrl = 'http://localhost:4000';- const url = `${baseUrl}/projects`;+ export const url = `${baseUrl}/projects`;...Add the setup code to mock the requests.
src\projects\__tests__\ProjectsPage-test.tsx
import React from 'react';import { MemoryRouter } from 'react-router-dom';import { MOCK_PROJECTS } from '../MockProjects';import { Provider } from 'react-redux';import { store } from '../../state';import ProjectsPage from '../ProjectsPage';import {render,screen,waitForElementToBeRemoved,} from '@testing-library/react';+ import { rest } from 'msw';+ import { setupServer } from 'msw/node';+ import { url as projectsUrl } from '../projectAPI';+ import { MOCK_PROJECTS } from '../MockProjects';+ // declare which API requests to mock+ const server = setupServer(+ // capture "GET http://localhost:3000/projects" requests+ rest.get(projectsUrl, (req, res, ctx) => {+ // respond using a mocked JSON body+ return res(ctx.json(MOCK_PROJECTS));+ })+ );describe('<ProjectsPage />', () => {function renderComponent() {render(<Provider store={store}><MemoryRouter><ProjectsPage /></MemoryRouter></Provider>);}+ beforeAll(() => server.listen());+ afterEach(() => server.resetHandlers());+ afterAll(() => server.close());test('should render without crashing', () => {renderComponent();expect(screen).toBeDefined();});test('should display loading', () => {renderComponent();expect(screen.getByText(/loading/i)).toBeInTheDocument();});});Test that the projects display after the mocked data is returned.
src\projects\__tests__\ProjectsPage-test.tsx
...describe('<ProjectsPage />', () => {function renderComponent() {render(<Provider store={store}><MemoryRouter><ProjectsPage /></MemoryRouter></Provider>);}beforeAll(() => server.listen());afterEach(() => server.resetHandlers());afterAll(() => server.close());...+ test('should display projects', async () => {+ renderComponent();+ expect(await screen.findAllByRole('img')).toHaveLength(+ MOCK_PROJECTS.length+ );+ });});Verify the test passed.
PASS src/projects/__tests__/ProjectsPage-test.tsx
Test the More Button Displays
Test that the More button displays after the projects have loaded.
src\projects\__tests__\ProjectsPage-test.tsx
...import {render,screen,waitForElementToBeRemoved,} from '@testing-library/react';...describe('<ProjectsPage />', () => {...+ test('should display more button', async () => {+ renderComponent();+ expect(+ await screen.findByRole('button', { name: /more/i })+ ).toBeInTheDocument();+ });++ // this tests the same as the last test but demonstrates+ // what find* methods are doing+ test('should display more button with get', async () => {+ renderComponent();+ await waitForElementToBeRemoved(() => screen.queryByText(/loading/i));+ expect(screen.getByRole('button', { name: /more/i })).toBeInTheDocument();+ });});Verify the test passed.
PASS src/projects/__tests__/ProjectsPage-test.tsx
Test the Error Displays
Test that a custom error displays when a server error is returned.
src\projects\__tests__\ProjectsPage-test.tsx
...import {render,screen,waitForElementToBeRemoved,} from '@testing-library/react';...describe('<ProjectsPage />', () => {...+ test('should display custom error on server error', async () => {+ server.use(+ rest.get(projectsUrl, (req, res, ctx) => {+ return res(ctx.status(500, 'Server error'));+ })+ );+ renderComponent();++ expect(+ await screen.findByText(/There was an error retrieving the project(s)./i)+ ).toBeInTheDocument();+ });});Verify the test passed.
PASS src/projects/__tests__/ProjectsPage-test.tsx