Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test react components with mobx observable state

Here is a simplified version of my component:

import React from 'react';
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';
import { fromPromise } from 'mobx-utils';

@observer
export class MyComponent extends React.Component {
  @action componentDidMount() {
    const { store, params } = this.props;
    this.warehouse = store.findById(params.id);
  }

  @observable warehouse = fromPromise(Promise.resolve());

  render() {
    return this.warehouse.case({
      fulfilled: (value) => (
        <div>
          fulfilled
        </div>
      ),
      rejected: (error) => (
        <div>
          rejected
        </div>
      ),
      pending: () => (
        <div>
          pending
        </div>
      )
    });
  }
}

And here is my test (using jest and enzyme):

import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { observable, when } from 'mobx';
import { fromPromise } from 'mobx-utils';

import { MyComponent } from './MyComponent';

describe('<MyComponent>', () => {
  it('should render correctly for state "fulfilled"', (done) => {
    const mockStore = observable({
      findById: jest.fn(() => fromPromise(Promise.resolve({ id: 'id' })))
    });

    const wrapper = mount(<MyComponent store={mockStore} params={{ id: '1' }} />);
    const wh = wrapper.instance().warehouse;

    when(
      () => wh.state === 'fulfilled',
      () => {
        expect(wrapper.text()).toBe('fulfilled');

        done();
      }
    );
  });
});

The problem is that the handler for when in test runs before render method, so I don't have access to rendered markup there. My question is how to run my except codes after rendering the fulfilled state. Also I don't want to hack my component. Here I am using wrapper.instance().warehouse which I don't like very much.

Generally, the question would be how to test components with observable states in them?

like image 602
alisabzevari Avatar asked Jan 31 '17 13:01

alisabzevari


1 Answers

I ended up with this solution:

import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { observable, when } from 'mobx';
import { fromPromise } from 'mobx-utils';

import { MyComponent } from './MyComponent';

describe('<MyComponent>', () => {
  it('should render correctly for state "fulfilled"', (done) => {
    const mockStore = observable({
      findById: jest.fn(() => fromPromise(Promise.resolve({ id: 'id' })))
    });

    const wrapper = mount(<MyComponent store={mockStore} params={{ id: '1' }} />);
    const wh = wrapper.instance().warehouse;

    when(
      () => wh.state === 'fulfilled',
      () => {
        process.nextTick(() => {
          expect(wrapper.text()).toBe('fulfilled');
          done();
        });
      }
    );
  });
});

Also there is a related question in mobx-react project issues.

like image 89
alisabzevari Avatar answered Oct 13 '22 05:10

alisabzevari