Bill
Bill

Reputation: 19328

React how to test out react compoennt with setTimeout

I am run into this test problem, which i am not sure how to test component with settimeout. anyone have suggestion on how to test out the following component with settimeout? Many thanks

import React, { PropTypes, Component } from 'react';
import styles from '../../../css/notification.css';

export default class Notification extends Component {
    static propTypes = {
        tagMetaUpdate: PropTypes.shape({
            submitUpdatedTagDataSuccessful: PropTypes.bool
        }),
        actions: PropTypes.shape({
            resetUpdatedTagDataSuccessfulFlag: PropTypes.func
        })
    };

    constructor(props) {
        super(props);
        this.state = {
            showMessage: true
        };
    }

    hideMessage(actions) {
        this.timer = setTimeout(() => {
            this.state.showMessage = false;
            actions.resetUpdatedTagDataSuccessfulFlag();
            this.forceUpdate();
        }, 3000);
    }

    render() {
        const { tagMetaUpdate, actions } = this.props;
        const output = (tagMetaUpdate.submitUpdatedTagDataSuccessful && this.state.showMessage) ?
            <div className={styles.notification}>Tag meta data successfully edited.</div> : null;

        if (this.props.tagMetaUpdate.submitUpdatedTagDataSuccessful) {
            this.hideMessage(actions); // HERE IS THE BIT BLOCKING ME
        }else {
            this.state.showMessage = true;
        }

        return <div>{output}</div>;
    }
}

Upvotes: 1

Views: 1230

Answers (2)

Bill
Bill

Reputation: 19328

use sinnon Faking time will solve the problem

http://sinonjs.org/

scroll to Faking time

Upvotes: 2

Shiva Nandan
Shiva Nandan

Reputation: 1845

It is generally ill-advised to mutate the state directly. Try to use this.setState({}), and when you call setState, this.forceUpdate is unnecessary. React would update your component by itself.

Also, try to use the render method to only perform rendering. No mutating state and all that.

If you directly do this.setState({ showMessage: true }) in the render method, react would complain about it - that it's not allowed.

React provides a lifecycle hook methods called componentWillRecieveProps and componentWillUpdate. You can use them to check if the prop has changed and then do setState accordingly.

componentWillReceiveProps(nextProps){
  if(!_.isEqual(nextProps, this.props) {
    if(nextProps.tagMetaUpdate.submitUpdatedTagDataSuccessful){
      this.setState({ showMessage: true })
      this.timer = setTimeout(() => {
        this.setState({ showMessage: false })
        actions.resetUpdatedTagDataSuccessfulFlag()
      }, 3000)
    }
  }
}

Note that:

  • by using setState in the setTimeout, I've eliminated the need to use forceUpdate()
  • i use lodash to do a check to see if the prop has changed from the previous render to the current one. React would re-render the component for one of these reasons:
    • if the prop changes
    • if the component's state updates
    • if one of its parents need to update for either of the two reasons. So we do a check to see that the update is only happening because the prop has changed, and if it has, then do a setState to show the message and a set timeout to not show the message after 3 seconds.

These are just usage advices. Can you tell me more about the framework you use for unit testing. I might be able to help a bit if it's jest.

Upvotes: 1

Related Questions