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.js.
- Add the setup code below to test the component. - src\projects\__tests__\ProjectsPage-test.jsimport 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.js- ! Check to make sure the - delayfunction used to delay the backend query and display the loading indicator has been removed in- projectAPI.js. The delay call causes the- mswlibrary 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.jsimport 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.js
Test the Projects Display
- Open a - command prompt(Windows) or- terminal(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 --dev
- Export the url used in the component from the - projectAPI.jsfile.- src\projects\projectAPI.jsimport { 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.jsimport 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.js...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.js
Test the More Button Displays
- Test that the More button displays after the projects have loaded. - src\projects\__tests__\ProjectsPage-test.js...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.js
Test the Error Displays
- Test that a custom error displays when a server error is returned. - src\projects\__tests__\ProjectsPage-test.js...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.js