Unittests - lumen-org/LumenReact GitHub Wiki

Run test with yarn test

General Structure

  • Tests are always called by Componentname.test.js
  • the global file setupTests.js is run at the beginning of the a testrun
  • beforEach() and afterEach() are run before or after each individual test

Template for Component Testing

import React from "react";
import { unmountComponentAtNode } from "react-dom";
import TestRenderer from "react-test-renderer";
import Field from "./Field";

/// mock children components for shallow rendering
jest.mock("../../components/Titles/TitleH2", () => (props) => (
  <h2>{props.value}</h2>
));

jest.mock("../../components/FieldList/FieldList", () => (props) => (
<div>FieldList</div>
));

/// executed before every describe
let container = null;
let spy = null;
beforeEach(() => {
  // setup a DOM element as a render target
  container = document.createElement("div");
  document.body.appendChild(container);
  spy = jest.spyOn(console, 'error').mockImplementation(); /// prevents console from showing the errors while simultaniously being able to catch errors
});

/// executed after every describe
afterEach(() => {
  // cleanup on exiting
  unmountComponentAtNode(container);
  container.remove();
  container = null;
  console.clear();
  spy.mockRestore(); // important so errors are displayed again
});

/// Test missing Values
describe("Field.js Missing Values Test", () => {

  it("missing value data", () => {
    let title = "TestTitle";
    TestRenderer.create(<Field title={title} />);
    expect(console.error).toHaveBeenCalledTimes(1);
  });

  it("missing value title", () => {
    let data = ["TestTitle"];
    TestRenderer.create(<Field data={data} />);
    expect(console.error).toHaveBeenCalledTimes(1);
  }); 
});

/// test normal rendering and additional functionality
describe("Field.js Functionality Test", () => {
  it("render normally", () => {
    let title = "TestTitle";
    let data = ["Test", "Test", "Test"];
    const component = TestRenderer.create(<Field title={title} data={data} />);
    let tree = component.toJSON();
    expect(console.error).not.toBeCalled();
    expect(tree).toMatchSnapshot();
  });
});

Components

Structure of test file

  • imports
  • mock all child components
  • before and after setup
  • encapsulate tests with describe

Workflow

  • test the functionality (if it does what it is supposed to, what happens for border cases...)
    • create snapshots for that purpose
    • test if the internal state of the component changes as expected (always from the outside. Dont test the state directly!)
    • only test the specific component. If possible mock as many relying components as possible without changing the functionality of the tested component or use shallow
    • mock api calls
  • test if there exists some kind of typecheck for the input parameter (e.g. propTypes)

Render vs Shallow

  • only renders a component one level deep -> no worrying about the behaviour of child components
const component = TestRenderer.create(
    <Component property1={argument1} property2={argument2} />
)
  • renders everything which is depended on the rendered

Mocking

components are mocked by calling

jest.mock("path/to/component", () => (props) => {
    <div>
        {props.argument}
    </div>
} 

Snapshots

  • to create a snapshot run expect(componentAsJson).toMatchSnapshot()
  • a snapshot is automatically created when a snapshot test is run the first time. The snapshot is placed under the folder snapshot in the same directory
  • update snapshots with yarn test --updateSnapshot or interactively in watch mode by pressing u or i -its also possible to compare to inlinesnapshots expect(componentAsJson).toMatchInlineSnapshot();
  • the next time you run yarn test the component tree will be evaluated and written as argument to toMatchInlineSnapshot(componentTree)

React Component Testing

see: https://reactjs.org/docs/testing.html

Redux

see: https://redux.js.org/recipes/writing-tests

todo:: redux todo:: id testing >.>

⚠️ **GitHub.com Fallback** ⚠️