Table of contents
  1. Jest
    1. config in package.json
    2. Modify existing object in test
    3. fire button example
    4. use mount to fully render,
    5. Use the object property selector to find nodes
  2. REACT TESTING LIB
    1. MUTATION OBSERVER
    2. use test-id in material-ui text-field
      1. And then passing data - testid as an input prop on text field like this
    3. Use queryBy to test if something should be null
    4. Firing events
    5. Getting component
      1. Testing component
    6. Get by TagName / Element Type / NodeName
    7. Check TagName / Element Type / NodeName
    8. React-Hook-Forms
      1. FormProvider Wrapper
    9. Workarounds
      1. tooltip calling document.createRange
  3. Enzyme




Jest

config in package.json

this is transformIgnorePatterns for jest, defaultPhrases used for dateRangePicker needed to be ignored for jest and adding a workaround for using a
webworker

{
  "jest": {
    "transformIgnorePatterns": [
      "<rootDir>/node_modules/defaultPhrases.js"
    ],
    "transform": {
      "^.+\\.worker.[t|j]sx?$": "workerloader-jest-transformer"
    }
  }
}

Modify existing object in test

const modifiedProps = JSON.parse(JSON.stringify(defaultProps));

fire button example

import React from "react";

import {render, fireEvent} from "react-testing-library";

import Counter from "../lessons/02-testing-hooks";

test("counter increments the count", () => {
    const {container} = render(<Counter/>);

    const button = container.firstChild;

    expect(button.textContent).toBe("0");

    fireEvent.click(button);

    expect(button.textContent).toBe("1");
});

use mount to fully render,

can only set props on root, use dive to access child components

To test a component (with Jest) that containsand withRouter you need to import Router in you test

import {BrowserRouter as Router} from "react-router-dom";

it("containts stuff", () => {
    const wrapper = mount(<Router>
        {" "}
        <Footer/>
        {" "}
    </Router>,);
    console.log(wrapper.find("FooterContainer").html());

    expect(wrapper
        .find('a[href="https://talentmine.talentplus.com/s/contactsupport"]')
        .text(),).toBe("Contact    Support    ");
});

Use the object property selector to find nodes

by passing in an object that matches the property of a node as a selectoin

expect(wrapper.find({alt: "logo"}).text()).toBe("Welcome to React");
it("test with enzyme", () => {
    const container = shallow(<GoalCreationForm
        {...defaultProps}
        currentStep={GOAL_CREATION_WIZARD.LANDING}
    />,);

    container.setProps({
        owner: {
            id: 123, accountInfo: {clientSetupId: 1}, userInfo: {
                firstName: "John", lastName: "Wayne", preferredName: "TheDuke",
            },
        },
    });

    console.log(container
        .find({
            "data-qa": "goals-creation-title-name",
        })
        .at(0)
        .html(),);
    console.log(container
        .find({
            "data-qa": "goals-creation-title-name",
        })
        .html(),);
    console.log(container
        .find({
            "data-qa": "goals-creation-title-name",
        })
        .text(),);
    console.log(container.debug());
    console.log(container.find("[variant='h5']").html());
    expect(container
        .find({
            "data-qa": "goals-creation-title-name",
        })
        .exists(),).toBe(true);
    expect(container
        .find({
            "data-qa": "goals-creation-title-name",
        })
        .text(),).toBe("Creating Goal for    TheDuke    Wayne    ");
});

REACT TESTING LIB

MUTATION OBSERVER

global.MutationObserver = class {
    constructor(callback) {}

    disconnect() {}

    observe(element, initObject) {}
}

or

global.MutationObserver = MutationObserver;

HTMLCanvasElement;

HTMLCanvasElement.prototype.getContext = jest.fn();

use test-id in material-ui text-field

import "@testing-library/jest-dom";
import React from "react";
import {createMount} from "@material-ui/core/test-utils";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import EditProfileForm from "./editForm";
import {
    render as testRender, fireEvent, screen, getByText,
} from "@testing-library/react";

const props = {
    handleChange:   jest.fn(),
    onSubmit:       jest.fn(),
    bio:            "test",
    gravatar:       "https://i.pravatar.cc/150?img=3",
    handleBio:      jest.fn(),
    handleGravatar: jest.fn(),
};
describe("<EditProfileForm/>", () => {
    let wrapper;
    let mount;
    beforeEach(() => {
        mount = createMount();
        wrapper = mount(<EditProfileForm {...props} />);
    });
    // must be called first
    it("calls handleBio on bio TextField change", () => {
        const input = screen.getByTestId("bio");

        fireEvent.change(input, {target: {value: "new value"}});

        expect(props.handleBio).toHaveBeenCalledTimes(1);
    });

    it("should render <EditProfileForm/>", () => {
        expect(wrapper).toHaveLength(1);
    });

    it("should check header title ", () => {
        expect(wrapper.find(Typography).at(0)).toHaveLength(1);
        expect(wrapper.find(Typography).at(0).text()).toContain("Edit Profile");
    });

    it("should test bio prop", () => {
        expect(wrapper.props().bio).toContain("test");
    });

    it("should test gravtar prop", () => {
        const link = "https://i.pravatar.cc/150?img=3";
        expect(wrapper.props().gravatar).toContain(link);
    });

    it("should test handleChange props", () => {
        const title = "Test";
        expect(wrapper.props().handleChange({
            target: {
                value: title,
            },
        }),);
        expect(props.handleChange).toHaveBeenCalled();
    });

    it("should test onSubmit prop", () => {
        // console.log(wrapper.find(TextField).debug());
        const submit = jest.fn();
        wrapper.simulate("submit", {submit});
        expect(props.onSubmit).toBeCalled();
    });

    it("should test button click", () => {
        const button = wrapper.find(Button);
        button.simulate("click");
        expect(props.onSubmit).toBeCalled();
    });
});
  • And then passing data - testid as an input prop on text field like this

      <TextField
          id="outlined-name"
          className="bio-test"
          style=
          name="bio"
          inputProps=data-testid
          multiline={true}
          rows="3"
          defaultValue={props.bio}
          onChange={props.handleBio}
          margin="normal"
          variant="outlined"
      />
    

Use queryBy to test if something should be null

it("ellipsis should not appear for shared result viewer role", async () => {
    render(<LanguageProvider>
        {" "}
        <CurrentUserContext.Provider value=>
            {" "}
            <Members data={members}/>{" "}
        </CurrentUserContext.Provider>{" "}
    </LanguageProvider>,);

    const ellipsisColumn = await waitFor(() => screen.queryByTestId("ellipses-action-buttons-members-table"),);
    expect(ellipsisColumn).toBeNull();
});

Firing events

import userEvent from "@testing-library/user-event";

fireEvent.change(input, {
    target: {
        value: "GroupA",
    },
});

userEvent.type(input, "GroupA");

Getting component

const {getByTestId, queryByTestId} = render(<CreateGroupForm groups={groupNames}/>,);
  • Testing component

      expect(input).toHaveValue("GROUP");
    

Get by TagName / Element Type / NodeName

screen.getByText((_content, element) => element?.tagName.toLowerCase() === 'svg');

Check TagName / Element Type / NodeName

it('should render as div when the "as" attribute is passed with a value of "div"', () => {
    render(<Button label={testText} as='div' data-testid='test-button'/>)

    expect(screen.getByTestId('test-button').nodeName.toLowerCase()).toBe('div')
})

React-Hook-Forms

FormProvider Wrapper

import {render, renderHook} from '@testing-library/react';
import {ReactElement, ReactNode} from 'react';
import {FormProvider, useForm} from 'react-hook-form';


interface IWrapperProps {
    children?: ReactNode;
    props?: object;
}

const renderReactHookForm = (ui: ReactElement, {defaultValues = {}} = {}) => {
    const {result} = renderHook(() => {
        return useForm(defaultValues);
    });

    const Wrapper = ({children}: IWrapperProps) => {

        return (<FormProvider {...result.current}>{children}</FormProvider>);
    };

    return {
        ...render(ui, {wrapper: Wrapper})
    };
};

export default renderReactHookForm;

Workarounds

tooltip calling document.createRange

  • otherwise will get error: Uncaught [TypeError: document.createRange is not a function]

global.document.createRange = () => ({
    setStart: () => {}, setEnd: () => {}, commonAncestorContainer: {
        nodeName: "BODY", ownerDocument: document,
    },
});

Enzyme

expect(wrapper.find(".App-intro").exists()).toBe(true);

expect(wrapper.find("ul").children().length).toBe(3);

expect(wrapper.find("ul").hasClass("tyler")).toBe(true);

expect(wrapper.find("h1").text()).toBe("Welcome to React");

expect(wrapper.find('[href="tyler"]').text()).toBe("WelcometoReact");

expect(wrapper.find('[href="tyler ~.clark"]').text()).toBe("Welcome to React");
expect(wrapper.find('[text="Sometitle"]').text()).toBe("Welcome to React");