Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storybook JS Interaction Testing with Enzyme - State Changes being Overidden

I am using storybook to visualize changes to React components after simulating user interaction with enzyme. As a small example, I want a story displaying a component after one of its button has been clicked.

The issue I'm having is the component's constructor gets called twice: once when the component is mounted by enzyme and then after when storybook displays the component. This puts the component back to its default state so any changes following the simulated user interactions are lost.

Here's some code showing the issue. After the story loads, the button component is in the "unclicked" state, even though a click was simulated with enzyme:

import React from 'react';

class SampleComponent extends React.Component {

    constructor(props){
        super(props);
        console.log('constructor');

        this.state = {isClicked: false};
        this.onClick = this.onClick.bind(this);
    }

    onClick(){
        console.log('onClick');
        this.setState({isClicked: true});
    }

    render(){
        const text = (this.state.isClicked)? 'Clicked!' : 'Not Clicked';
        return (
            <div>
                <input type='button' value='Click' onClick={this.onClick} />
                <p>{text}</p>
            </div>
        );
    }
}

export default SampleComponent;

The story file:

import React from 'react';
import { storiesOf } from '@storybook/react';
import { mount } from 'enzyme';
import { specs, describe, it } from 'storybook-addon-specifications';
import SampleComponent from '../src/SampleComponent';

storiesOf('SampleComponent', module)
    .add('clicked', () => {

        const comp = <SampleComponent/>;
        specs(() => describe('clicked', function () {
            it('Should display clicked state message', function () {
                const output = mount(comp);
                output.find('input').simulate('click');
            });
        }));

        return comp;
    });

The output to console would be:

constructor
onClick
constructor
like image 849
Steven Avatar asked Jun 02 '18 17:06

Steven


1 Answers

You need to get back the underlying component instance. This will do what you want:

storiesOf('SampleComponent', module)
  .add('clicked', () => {
    let output;

    specs(() => describe('clicked', function () {
      it('Should display clicked state message', function () {
        output = mount(<SampleComponent />);
        output.find('input').simulate('click');
      });
    }));

    const Inst = () => output.instance();
    return <Inst />
  });
like image 121
Colin Ricardo Avatar answered Oct 20 '22 14:10

Colin Ricardo