Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stub document method with sinon - React

import React, { PropTypes, Component } from 'react';
import classNames from 'classnames/bind';
import { get, includes } from 'lodash';
import { Link } from 'react-router';
import * as styles from '../CAMNavPanel.css';

const cx = classNames.bind(styles);

class CAMNavPanelListItem extends Component {
    static propTypes = {
        navData: PropTypes.shape({
            title: PropTypes.string,
            isRedirect: PropTypes.bool,
            url: PropTypes.string,
        }).isRequired,
        location: PropTypes.shape({ pathname: PropTypes.string.isRequired,
            query: PropTypes.objectOf(PropTypes.object).isRequired,
            search: PropTypes.string.isRequired,
        }).isRequired,
    };
    constructor() {
        super();
        this.state = { currentView: '' };
        this.getClasses.bind(this);
    }

    // in case of url being manually set, figure out correct tab to highlight
    componentWillMount() {
        this.changeLocation();
    }

    // give correct tab the 'active' class
    getClasses(navData) {
        const { location } = this.props;
        const activeClass = 'active';
        let isContainedInOtherUrls = false;

        if (get(navData, 'otherUrls') && includes(navData.otherUrls, location.pathname)) {
            isContainedInOtherUrls = true;
        }
        if ((this.state.currentView === navData.url) || isContainedInOtherUrls) {
            return activeClass;
        }
        return '';
    }

    getActiveClass(e, navData) {
        const elements = document.getElementsByClassName('CAMNavPanel-rewardsMenu')[0].getElementsByTagName('li');

        for (let i = 0; i < elements.length; i += 1) {
            elements[i].className = '';
        }

        this.setState({ currentView: navData.url }, () => {
            if (get(navData, 'scrollIntoView')) {
                document.getElementsByClassName(navData.scrollIntoView)[0].scrollIntoView();
            }
        });
    }
    // update state based on the URL
    changeLocation() {
        const { location } = this.props;
        const currentView = location.pathname;
        this.setState({ currentView });
    }

    render() {
        const { navData } = this.props;
        let target = '';
        if (navData.isExternalLink) {
            target = '_blank';
        }
        return (
            <li className={cx(this.getClasses(navData))} key={navData.title}>
                { navData.isRedirect ? <a href={navData.url} target={target}>
                    {navData.title}</a> :
                <Link to={navData.url} onClick={e => this.getActiveClass(e, navData)}>{navData.title}</Link> }
            </li>
        );
    }
}


export default CAMNavPanelListItem;

Test case:

describe('CAMNavPanelListItem with isRedirect false plus highlight li', () => {
let wrapper;

const navData = {
    title: 'My Orders',
    isRedirect: false,
    isExternalLink: false,
    url: '/orders',
};

const location = {
    pathname: '/orders',
};
beforeEach(() => {
    documentObj = sinon.stub(document, 'getElementsByClassName');
    const li = {
        getElementsByTagName: sinon.stub(),
    };

    documentObj.withArgs('CAMNavPanel-rewardsMenu').returns([li]);
    wrapper = shallow(
        <CAMNavPanelListItem
            navData={navData}
            location={location}
            />,
    );
    wrapper.setState({ currentView: navData.url });
});

it('should render CAMNavPanelListItem with Link as well', () => {
    expect(wrapper.find('li')).to.have.length(1);
    expect(wrapper.find('li').hasClass('active')).to.equal(true);
    expect(wrapper.find('Link')).to.have.length(1);
});

it('should click and activate activeClass', () => {
    wrapper.find('Link').simulate('click', { button: 0 });
});

afterEach(() => {
    wrapper.unmount();
    documentObj.restore();
});

});

Errors I am getting:

 const elements = document.getElementsByClassName('CAMNavPanel-rewardsMenu')[0].getElementsByTagName('li');

    console.log('Elements of getElementsByTagName', elements);

The elements I am getting as undefined.

Please help. How do I stub after the click of the Link element.

like image 721
vini Avatar asked Dec 14 '22 18:12

vini


1 Answers

You might want to look into something like jsdom to mock out an entire DOM instead of manually mocking a couple of the DOM functions. Then, you wouldn't have to implement the document.getElementsByClassName() function and it would make the test suite a bit more robust to changes in the component's implementation. You would just test for certain elements using functions on the jsdom itself.

You could also try mocha-jsdom to automatically setup and teardown the test DOM for each describe() block.

like image 90
wgoodall01 Avatar answered Dec 17 '22 23:12

wgoodall01