schiehll / react-alert

alerts for React
MIT License
608 stars 98 forks source link

Document how to test a component wrapped in withAlert #87

Closed DrOFay closed 6 years ago

DrOFay commented 6 years ago

I have a component:

import {withAlert} from 'react-alert';
// other imports

class MyComponent extends React.PureComponent {
   ...

   // functions that change the state

   ...
}

export default withAlert(MyComponent);

I want to test my component to make sure the business logic functions are setting state correctly. This is what I had to do to get my test to assert the state properly.

import React from 'react';
import {configure, mount, shallow} from 'enzyme';
import {Provider as AlertProvider} from 'react-alert';
import MyAlertTemplate from '.../MyAlertTemplate'; // located in some other directory
import Adapter from 'enzyme-adapter-react-16';
import MyComponent from '.../MyComponent'; // located in some other directory

configure({ adapter: new Adapter() });

let wrapper = mount( // notice I'm `mount`ing this wrapper here
    <AlertProvider template={MyAlertTemplate} >
        <MyComponent/>
    </AlertProvider>
);

describe('my component tests', () => {
    test('assert my state changes as expected', () => {
        // this is bonkers!! is there an easier/better way??
        const sut = shallow(
            React.createElement(alertWrapper
                .childAt(0) // <Broadcast/>
                .childAt(0) // <AlertProvider/>
                .childAt(0) // <withAlert/>
                .get(0) // MyComponent as a function
                .type) // An Enzyme ShallowWrapper containing our SUT
        );

        // given
        expect(sut.state('myStateProperty')).toEqual('initialValue');

        // when
        // handleAction should change the component's state
        sut.instance().handleAction('some-action', {});

        // then 
        expect(sut.state('myStateProperty')).toEqual('finalValue);
    });
});

The test passes, but it seems a bit extreme to have to delve that deeply to get my component to test. My application is a mix of SPA and non-SPA (not my decision), so I have a lot of components that get wrapped with withAlert.

I mean, if this is really how one has to go about testing components, it's not terrible. But, it did take me hours to figure out. So, unless there is a better way, I'm submitting this issue as a documentation issue to save other developers the time it took me to piece this together.

schiehll commented 6 years ago

Hey @DrOFay!

I think that either one of the following ways would be easier:

1 - You can export the component without the alert, like so:

import {withAlert} from 'react-alert';

export class MyComponent extends React.PureComponent {...}
export default withAlert(MyComponent);

And then import it like import { MyComponent } from '.../MyComponent'; in the tests. If you need the alert prop you can pass it in manually.

2 - Since you are using enzyme you may just use find, like:

const wrapper = shallow(<TheWrapperWithAlertProvider />);
const sut = wrapper.find(MyComponent);
expect(sut.state('myStateProperty')).toEqual('initialValue');
...

Both ways should work.

But you are right, maybe we should add some docs covering tests.

Well, I hope it helps! Feel free to ask me to reopen it or even open a new issue if this doesn't help you at all.