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.tsximport 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
delayfunction used to delay the backend query and display the loading indicator has been removed inprojectAPI.ts. The delay call causes themswlibrary 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.tsximport 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 Workerto mock the HTTP requests.$ npm install msw --save-dev# or$ yarn add msw --devExport the url used in the component from the
projectAPI.tsfile.src\projects\projectAPI.tsimport { 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.tsximport 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