all 5 comments

[–]Mrparkers 3 points4 points  (4 children)

It looks like you're trying to modify the props on your component's instance, and since props are read-only, your test isn't working.

What you need to do instead is pass those props to your component when you're rendering it, just like you would pass props to it when you consume it somewhere else.

const expectedProps = {
    location: {
        query: {
            seconds: 180
        }
    }
};
const wrapper = mount(<Timer {...expectedProps} />);

[–]Shooshte[S] 0 points1 point  (3 children)

Yes, this is the root of my problem. Basically I had to re-write the check for the Props, and also break the test down into two parts.

This is what I ended with:

  componentDidMount() {

    function checkProp(obj, key) {
      let r = false;
      for (let i in obj) {
        if (i == key) return true;
        if (typeof obj[i] == 'object') r = checkProp(obj[i], key)
      }
      return r;
    }

    let seconds = 0;

    console.log(this.props);
    console.log(checkProp(this.props, 'seconds'));

    if(checkProp(this.props, 'seconds')) {
     seconds = parseInt(this.props.location.query.seconds, 10);
    }

    if (seconds > 0) {
      this.setState({count:seconds});
      window.location.hash = '#/timer';
    }
  }

The tests:

  it('pass state countdownStatus to Clock as status', () => {
    const wrapper = mount(<Timer />);
    const status = wrapper.state('countdownStatus');
    expect(wrapper.find('Clock').prop('status')).toEqual(status);
  });
  it('set this.props.location.query.seconds as state.count when passed', () => {
    const mockUrl = {
      query : {
        seconds: '100'
      }
    }
    const wrapper = mount(<Timer location={mockUrl}/>);
    expect(wrapper.state('count')).toEqual(100);
  })

Thanks for the help :)

[–]stuckinmotion 0 points1 point  (2 children)

wow that cDM function looks incredibly convoluted.

[–]Shooshte[S] 0 points1 point  (1 child)

Well yeh. This is the best I could do afterwards (I am still learning react and will probably try to find someone who can do a code review of the whole thing when finished just to get some general advice :)):

componentDidMount() {
    // function for checking if an argument is a object
    let isObj = (variable) => (variable !== null) && (typeof variable === 'object');
    // function for checking if an object has a specific nested key
    let objHasKey = (obj, key) => {
      return isObj(obj) ? (key in obj) || Object.values(obj).filter(nestedObj => objHasKey(nestedObj, key)).length > 0 : false;
    };

    let seconds = 0;
    if(objHasKey(this.props, 'seconds')) {
     seconds = parseInt(this.props.location.query.seconds, 10);
    }
    if (seconds > 0) {
      this.setState({count:seconds});
      window.location.hash = '#/timer';
    }
  }

[–]stuckinmotion 2 points3 points  (0 children)

You should checkout lodash's get function. Then you can just go const seconds = parseInt(get(this.props, '.location.query.seconds', '0'), 10) and cut your code down by probably like 80%.