React Testing Components

From bibbleWiki
Jump to navigation Jump to search

Introduction

Guiding principle for testing is

Testing Exactly what you are trying to test and nothing more

DOM Overview

Definition

The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects. That way, programming languages can connect to the page.

A Web page is a document. This document can be either displayed in the browser window or as the HTML source. But it is the same document in both cases. The Document Object Model (DOM) represents that same document so it can be manipulated. The DOM is an object-oriented representation of the web page, which can be modified with a scripting language such as JavaScript.

Document Element

This is one element in a DOM e.g. a div.

innerHTML vs outterHTML

InnerHTML is used for getting or setting a content of the selected whilst the outerHTML is used for getting or setting content with the selected tag. This is a referred to a lot by Web developers so here is a picture to remind people of the difference.

Testing Rendering

React Testing Library

React Testing Library is one of the most well known. They say,

  • The more your tests resemble the way the software is used, the more confidence they can give you.
  • Encourages rendering components to DOM nodes,
  • Making asserts against DOM nodes


It's API tries to encourage tests to represent how the software is used by the user. For example these tests focus on how the user might access the screen, by label, by text

const r = render(<Message content="Some Stuff" isImportant={true} />);
r.getByLabelText('First Name')
r.getByText('2017-5-13')
r.getByTitle('introduction')
// Frown upon because as a user id are not visible but...
r.getByTestId('target')

Example Test

Here is a full example for testing the Date slider

The tests use the getByTestId and render API.

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect'
import DateSlider from './DateSlider';
import {solToDate, dateToSol} from '../services/sols';

describe('DateSlider', () => {

    describe('render', () => {
        it("should return a container", () => {
            const { container } = render(
              <DateSlider earth_date="2017-5-13" onDateChanged={()=>{}} />
            );
            expect(container).toBeDefined();
            expect(container.outerHTML).toBe("<div><div class=\"Dateslider\"><div class=\"row\"><div class=\"col-12\" style=\"text-align: center;\"><label for=\"date\">Earth Day</label><p class=\"Dateslider-date\" data-testid=\"date-label\">2017-5-13</p></div></div><div class=\"row\"><div class=\"col-3\" style=\"text-align: right;\"><small>2004-01-05</small></div><div class=\"col-6 form-group\"><input data-testid=\"date-slider\" type=\"range\" id=\"date\" class=\"form-control\" min=\"1\" max=\"5746\" value=\"4878\"></div><div class=\"col-3\"><small>2019-09-28</small></div></div></div></div>");
          });

        it('should display the correct date', () => {
            const { getByTestId } = render(<DateSlider earth_date="2017-5-13" onDateChanged={()=>{}} />);
            const date = getByTestId("date-label");
            expect(date).toHaveTextContent("2017-5-13");
        });
        it('should have the correct slider position', () => {
            const { getByTestId } = render(<DateSlider earth_date="2017-5-13" onDateChanged={()=>{}} />);
            const input = getByTestId("date-slider");
            expect(input).toHaveValue(dateToSol("2017-5-13").toString());
        });
    });

    describe('click', () => {
        it('should publish the selected date', () => {
            const fn = jest.fn();
            const { getByTestId } = render(<DateSlider earth_date="2017-5-13" onDateChanged={fn} />);
            
            const input = getByTestId("date-slider");
            fireEvent.change(input, { target: { value: '3877' } });
            
            expect(fn.mock.calls.length).toBe(1);
            expect(fn.mock.calls[0][0]).toBe(solToDate(3877));
        });
    });
});

React Test Utilities

This library provides the function act() which provides a more realistic environment for rendering and updating componenemts.

Example Test Camera

This example is testing a combobox
To use the act API it was noted

  • create a container and make sure you add it to the document
  • jest provides beforeEach and AferEach to prepare and tear down
  • act is the API to render and update components
  • remember the ReactDOM.render requires the container as an argument
  • in the after each we remove the container and reset to null


The tests will consist of testing

  • should render a select element (something selected)
  • the selector renders each of the options
  • it selects the one we ask it to select
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-dom/test-utils';
import CameraSelection from './CameraSelection';

describe('CameraSelection', () => {

    describe('rendering', () => {
        let container,select;
        const cameras = {
            BC: "Big camera",
            LC: "Little camera"
        };
        beforeEach(() => {
            container = document.createElement('div');
            document.body.appendChild(container);
            ReactTestUtils.act(()=>{
                ReactDOM.render(<CameraSelection camera="LC" cameras={cameras} onCameraSelected={()=>{}} />, container);
            });
            select = container.querySelector('select');
          });
          
          afterEach(() => {
            document.body.removeChild(container);
            container = null;
          });

        it("should render a select element", () => {
            expect(select).toBeDefined();
        });
        it("should have 2 options", ()=>{
            expect(select.length).toBe(2);
        });
        it("should have LC (Little Camera) selected", ()=>{
            expect(select.value).toBe("LC");
            expect(select.selectedOptions[0].text).toBe('Little camera');
        });
    });
});

Testing Component Events

Testing States and Effects