Search code examples
reactjsreact-bootstrapsnapshot-testing

How to mock react-bootstrap components while doing snapshot testing in React?


I am working on a react project which is built using react-bootstrap UI. While there are a lot of options for writing test cases, I opted for Snapshot testing using Jest.


I have a component which is wrapped inside a bootstrap Modal and is always rendered with a null value in the generated snapshot. If remove the Modal wrapper and directly return the form then it generates the output just fine.

I want to mock the bootstrap Modal so as to return a simple implementation (while keeping rest of the library un-touched) and reduce the complexities of passing all the various props required by the react-boostrap library.

Component:
function MyComponent(){
  return (
    <div>
      <Modal
        show={props.showReviewModal}
        onHide={handleClose}
        className="well-connection-review"
      >
        <Modal.Header closeButton>
          <Modal.Title className="m-auto p-auto">
            Modal Title
          </Modal.Title>
        </Modal.Header>
        <Form
          noValidate
          validated={validated}
          onSubmit={(e) => handleValidation(e)}
        >
          <Modal.Body>
            <Form.Row className="m-2 d-flex align-items-center">
              <Form.Group as={Col} controlId="formPowerCompany" className="m-1">
                <Form.Label className="label">Power Company</Form.Label>
                <Select
                  isClearable={true}
                  name="PowerCompany"
                  options={ELECTRIC_PROVIDERS}
                  className="basic-multi-select well-connection-report-filters"
                  onChange={PowerCompanyChange}
                  value={powerCompany}
                  isSearchable={false}
                  placeholder="Power Company"
                />
              </Form.Group>
            </Form.Row>
            <Form.Row className="m-2 d-flex align-items-center">
              <Form.Group as={Col} controlId="formMeterID" className="m-1">
                <Form.Label className="label">Meter ID</Form.Label>
                <Form.Control
                  type="text"
                  value={meterId}
                  name="meterId"
                  onChange={handleChange}
                  autoComplete="off"
                />
                <Form.Control.Feedback type="invalid">
                  Please enter an ID
                </Form.Control.Feedback>
              </Form.Group>
            </Form.Row>
          </Modal.Body>

          <Modal.Footer className="mr-3">
            <Button
              variant="primary"
              onClick={() => handleClose()}
              type="submit"
            >
              Close
            </Button>
          </Modal.Footer>
        </Form>
      </Modal>
    </div>
  );
}

export default MyComponent;
Test Case for the component:
import React from "react"; 
import MyComponent from "../MyComponent"; 
import renderer from "react-test-renderer"; 

describe("Snapshot testing of MyComponent", () => { 
    it("MyComponent snapshot", () => { 
        const MyComponent = renderer.
        create(<MyComponent message={"message"} />).toJSON(); 
        expect(MyComponent).toMatchSnapshot(); 
    }); 
});
Snapshot output for the component:
// Jest Snapshot v1, [link to jest docs]

exports[`Snapshot testing of MyComponent`] = `null`;

Solution

  • Posting a solution here so that it helps anyone who stumbles upon it in future. The easiest way to do away with the complexities of passing the required props and mocking the various methods of the react-boostrap library components is to mock the individual components of the library and return a custom implementation for it.

    The idea here is to NOT test the structure of components of the external library but to just test the structure of your own components.

    Solution:
    // MyComponents.test.js
    
    import React from "react"; 
    import MyComponent from "../MyComponent"; 
    import renderer from "react-test-renderer"; 
    
    // this code will be auto hoisted by Jest
    jest.mock("react-bootstrap", () => { 
        // get the original boostrap library
        const orgBootstrap = jest.requireActual("react-bootstrap"); 
        // mock the Modal component
        const mockModal = ({ children }) => { return <div>{children}</div>; }; 
    
        // mock the sub-components of the Modal
        mockModal.Header = (props) => <div>{props.children}</div>; 
        mockModal.Body = (props) => <div>{props.children}</div>; 
        mockModal.Footer = (props) => <div>{props.children}</div>; 
        
        // return your modified boostrap library instance with mocked Modal
        const mockBoostrap = { __esModule: true, ...orgBootstrap, Modal: mockModal }; 
        return mockBoostrap; 
    });
    
    describe("Snapshot testing of MyComponent", () => { 
        it("MyComponent snapshot", () => { 
            const MyComponent = renderer.
            create(<MyComponent />).toJSON(); 
            expect(MyComponent).toMatchSnapshot(); 
        }); 
    });