Skip to main content

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

  1. Create the file src\projects\__tests__\ProjectsPage-test.js.

  2. Add the setup code below to test the component.

    src\projects\__tests__\ProjectsPage-test.js

    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();
    });
    });
  3. Verify the initial test passed.

    PASS  src/projects/__tests__/ProjectsPage-test.js

    ! Check to make sure the delay function used to delay the backend query and display the loading indicator has been removed in projectAPI.js. The delay call causes the msw library to throw an error.

Test the Loading Indicator Displays

  1. Test that the loading indicator displays when the component initially renders.

    src\projects\__tests__\ProjectsPage-test.js

    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();
    + });
    });
  2. Verify the test passed.

    PASS  src/projects/__tests__/ProjectsPage-test.js

Test the Projects Display

  1. Open a command prompt (Windows) or terminal (Mac).

  2. Change the current directory to code\keeptrack.

  3. 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 --dev
  4. Export the url used in the component from the projectAPI.js file.

    src\projects\projectAPI.js

    import { Project } from './Project';

    const baseUrl = 'http://localhost:4000';
    - const url = `${baseUrl}/projects`;
    + export const url = `${baseUrl}/projects`;
    ...
  5. Add the setup code to mock the requests.

    src\projects\__tests__\ProjectsPage-test.js

    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();
    });
    });
  6. 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
    + );
    + });
    });

  7. Verify the test passed.

    PASS  src/projects/__tests__/ProjectsPage-test.js

Test the More Button Displays

  1. 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();
    + });
    });

  2. Verify the test passed.

    PASS  src/projects/__tests__/ProjectsPage-test.js

Test the Error Displays

  1. 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();
    + });

    });

  2. Verify the test passed.

    PASS  src/projects/__tests__/ProjectsPage-test.js

You have completed Testing Lab 5