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;
测试用例:
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();
});
});
我遇到的错误:
const elements = document.getElementsByClassName('CAMNavPanel-rewardsMenu')[0].getElementsByTagName('li');
console.log('Elements of getElementsByTagName', elements);
我得到的元素未定义。
请帮忙。单击 Link
元素后如何 stub 。
最佳答案
您可能想查看类似 jsdom
的内容模拟整个 DOM,而不是手动模拟几个 DOM 函数。然后,您不必实现 document.getElementsByClassName() 函数,这将使测试套件对组件实现中的更改更加稳健。您只需使用 jsdom 本身的函数来测试某些元素。
您也可以尝试mocha-jsdom
自动设置和拆卸每个 describe()
block 的测试 DOM。
关于reactjs - 如何使用 sinon stub 文档方法 - React,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48641300/