Skip to content
This repository was archived by the owner on Apr 6, 2022. It is now read-only.

2021 01 12 Insights of testing

Endre Bock edited this page Jan 27, 2021 · 3 revisions

Mock a react component

By mocking of React Components, we have multiply options to do so.

So first is, to just simple do a global mock:

jest.mock('path/to/component', function () {
    return function (props: any) {
        return <div>Hello Replacement. (Debug: {JSON.stringify(props)})</div>;
    };
});

But at moment you will add some specials, for example some attachment to external connectors it getting a bit complicated:

export default class SomeComponent extends Component<Properties, State> {
    public set somethingFromOutsideOfReactWhatRerenderTheComponent(value: SomeData) {
        this.setState({someData: value});
    }

    componentDidMount(): void {
        Container.someExternal.attachToReact(this);
    }

    render(): JSX.Element {
        return <SomeSubComponent data={this.state.someData}/>;
    }
}

Now I want to mock SomeSubComponent and see, that new someData so I arrive somethings like:

    it('test somethings', function() {   
        let componentInstance: SomeComponent|undefined; 
// snipp
        (Container.someExternal.attachToReact as jest.Mock).mockImplementation(
            function (component: SomeComponent {
                componentInstance = component;
                component.somethingFromOutsideOfReactWhatRerenderTheComponent = 'first data';
            }
        );
// snipp

That seem "easy". But now I want to add new data:

        componentInstance.somethingFromOutsideOfReactWhatRerenderTheComponent = 'second data';

That the state and all React stuff full work, I need a working React-Class now as replacement.
Also I need it inside the testing code context.
I came to follow result (maybe not correct restored example code;) :

    beforeEach(function() {
// snipp
        (SomeSubComponent as jest.Mock).mockImplementation(
            (props:any) => new class SomeSubComponentMock extends Component<any, any> {
                render(): JSX.Element {
                    return return <div>Hello Replacement. (Debug: {JSON.stringify(this.props)})</div>;
                }
            }(props)
        );

To simplify it, wo create an helper.
JestHelper.ts:

import {Component} from 'react';

export type RenderImplementation = (props?: any, state?: any) => JSX.Element;

export default class JestHelper {
    public static createReactMockImplementation<T>(renderImplementation: RenderImplementation): (...args: any) => T {
        return function (props: any): T {
            class ReactMock<T> extends Component<any, any> {
                render(): JSX.Element {
                    return renderImplementation(this.props, this.state);
                }
            }

            return new ReactMock<T>(props) as unknown as T;
        };
    }
}

Now is it more easy to rember, how to create an mock implementation:

    beforeEach(function() {
// snipp
        (SomeSubComponent as jest.Mock).mockImplementation(
            JestHelper.createReactMockImplementation<SomeSubComponent>(function (props: any) {
                return return <div>Hello Replacement. (Debug: {JSON.stringify(props)})</div>;
            })
        );
//snipp

Maybe it seems complecated, but now I can to inside the render-Implementation, what ever needed, inclusive interact with testing code, while building the testing output.

Appendix

Where I need somethings like this?

The case is happend for component, which a manage by any kind of react router, or for the first Component of the application.