Lle*_*lyn 14 testing mocha.js reactjs reactjs-testutils react-select
https://github.com/JedWatson/react-select
我想使用React-Select react组件,但我需要添加测试.
我已经尝试了谷歌发现的几个选项,但似乎没有任何效果.我有下面的代码,但它不会导致更改事件.我已经能够添加一个焦点事件,它增加了'is-focusedsed'类,但'is-open'类仍然缺失.
我用过:https://github.com/JedWatson/react-select/blob/master/test/Select-test.js作为参考
我曾尝试仅在输入字段上使用更改事件,但这也没有帮助.我注意到有一个onInputChange={this.change}选择.
测试
import Home from '../../src/components/home';
import { mount } from 'enzyme'
describe('Home', () => {
it("renders home", () => {
const component = mount(<Home/>);
// default class on .Select div
// "Select foobar Select--single is-searchable"
const select = component.find('.Select');
// After focus event
// "Select foobar Select--single is-searchable is-focussed"
// missing is-open
TestUtils.Simulate.focus(select.find('input'));
//this is not working
TestUtils.Simulate.keyDown(select.find('.Select-control'), { keyCode: 40, key: 'ArrowDown' });
TestUtils.Simulate.keyDown(select.find('.Select-control'), { keyCode: 13, key: 'Enter' });
// as per code below I expect the h2 to have the select value in it eg 'feaure'
});
});
Run Code Online (Sandbox Code Playgroud)
被测组件
import React, { Component } from 'react';
import Select from 'react-select';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
message: "Please select option"};
this.change = this.change.bind(this);
}
change(event) {
if(event.value) {
this.setState({message: event.label});
}
}
render () {
const options = [ {label: 'bug', value: 1} , {label: 'feature', value: 2 }, {label: 'documents', value: 3}, {label: 'discussion', value: 4}];
return (
<div className='content xs-full-height'>
<div>
<h2>{this.state.message}</h2>
<Select
name="select"
value={this.state.message}
options={options}
onInputChange={this.change}
onChange={this.change}
/>
</div>
</div>
);
}
}
export default Home;
Run Code Online (Sandbox Code Playgroud)
命令行 要运行测试我做:
>> npm run test
Run Code Online (Sandbox Code Playgroud)
并在package.js我有这个脚本:
"test": "mocha --compilers js:babel-core/register -w test/browser.js ./new",
Run Code Online (Sandbox Code Playgroud)
测试设置
和browser.js是:
import 'babel-register';
import jsdom from 'jsdom';
const exposedProperties = ['window', 'navigator', 'document'];
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
Run Code Online (Sandbox Code Playgroud)
我也试过使用这里概述的测试方法:https://github.com/StephenGrider/ReduxSimpleStarter
任何帮助将不胜感激
Kei*_*ith 17
来自https://github.com/JedWatson/react-select/issues/1357
我发现的唯一解决方案是通过按键事件来模拟选择:
wrapper.find('.Select-control').simulate('keyDown', { keyCode: 40 });
// you can use 'input' instead of '.Select-control'
wrapper.find('.Select-control').simulate('keyDown', { keyCode: 13 });
expect(size).to.eql('your first value in the list')
Run Code Online (Sandbox Code Playgroud)
San*_*nda 15
我已经尝试过上面列出的两个答案,但仍然没有运气.
对我有用的是:
添加classNamePrefixprop - ie list(如其他答案中所述):
<Select
classNamePrefix='list'
options={[
{ label: 'one', value: 'one' },
{ label: 'two', value: 'two' }
]}/>
Run Code Online (Sandbox Code Playgroud)选择下拉指示器并模拟mouseDown =>已打开的下拉列表:
wrapper
.find('.list__dropdown-indicator')
.simulate('mouseDown', {
button: 0
});
Run Code Online (Sandbox Code Playgroud)期待事情发生,即在我的情况下,我正在检查下拉选项的数量
expect(wrapper.find('.list__option').length).toEqual(2);
Run Code Online (Sandbox Code Playgroud)
如果您可以控制正在发送的道具,您可以添加menuIsOpen道具以始终打开菜单(也就是列表中的第2步).
要在打开下拉列表后从下拉列表中选择值:
wrapper.find('.list__option').last().simulate('click', null);
Run Code Online (Sandbox Code Playgroud)
然后你可以测试:
expect(wrapper.find('.list__value-container').text()).toEqual('two');
Run Code Online (Sandbox Code Playgroud)
要么
expect(wrapper.find('.list__single-value').text()).toEqual('two');
Run Code Online (Sandbox Code Playgroud)
Ala*_*ALI 13
这是一个反复出现的问题。我正在与 100% 通过的测试共享我自己的代码,这些测试覆盖了我 100% 的源代码。
我的组件看起来像这样
MySelectComponent({ options, onChange }) {
return <div data-testid="my-select-component">
<Select
className="basic-single"
classNamePrefix="select"
name="myOptions"
placeholder="Select an option"
options={options}
onChange={e => onChange(e)}
/>
</div>;
}
Run Code Online (Sandbox Code Playgroud)
我在Selectwith添加一个包装器的原因data-testid="my-select-component"是渲染的选项元素将可用,否则我无法检查文本选项是否存在(当你看到我的测试时你会更好地理解)。
这是一个实时运行的示例,渲染时它将显示一个带有 10 个选项的选择组件。
我渲染组件。
我搜索存在的占位符。
我渲染组件。
我检查我的mockedOnChange是否还没有被调用。
模拟一个ArrowDown事件。
单击第一个选项。
我检查是否mockedOnChange使用第一个选项标签和值调用了 1 次。
我渲染组件。
我模拟了第一个选项的选择。
我模拟了第二个选项的选择。
我模拟了第 9 个选项的选择。
我检查是否mockedOnChange使用第 9 个选项包和值调用了 3 次。
我渲染组件。
我通过键入“选项 1”来模拟输入字段的更改。
我知道,基于我mockedOptions的过滤结果将是“模拟选项 1”和“模拟选项 10”。
我模拟了 2 个ArrowDown事件。
我检查mockedOnChange是否使用带有正确标签和值的第二个过滤选项调用了 。
import React from 'react';
import { render, fireEvent, cleanup, waitForElement } from '@testing-library/react';
import MySelectComponent from './MySelectComponent';
afterEach(cleanup);
describe ('Test react-select component', () => {
const mockedOptions = [
{label: 'Mocked option 1', value: 'mocked-option-1'},
{label: 'Mocked option 2', value: 'mocked-option-2'},
{label: 'Mocked option 3', value: 'mocked-option-3'},
{label: 'Mocked option 4', value: 'mocked-option-4'},
{label: 'Mocked option 5', value: 'mocked-option-5'},
{label: 'Mocked option 6', value: 'mocked-option-6'},
{label: 'Mocked option 7', value: 'mocked-option-7'},
{label: 'Mocked option 8', value: 'mocked-option-8'},
{label: 'Mocked option 9', value: 'mocked-option-9'},
{label: 'Mocked option 10', value: 'mocked-option-10'},
];
it('should render without errors', async () => {
const mockedOnChange = jest.fn();
const { getByText } = render(<MySelectComponent
options={mockedOptions}
onChange={mockedOnChange} />);
const placeholder = getByText('Select an option');
expect(placeholder).toBeTruthy();
});
it('should call onChange when the first option is selected', async () => {
const mockedOnChange = jest.fn();
const { getByText, queryByTestId } = render(<MySelectComponent
options={mockedOptions}
onChange={mockedOnChange} />);
const mySelectComponent = queryByTestId('my-select-component');
expect(mySelectComponent).toBeDefined();
expect(mySelectComponent).not.toBeNull();
expect(mockedOnChange).toHaveBeenCalledTimes(0);
fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' });
await waitForElement(() => getByText('Mocked option 1'));
fireEvent.click(getByText('Mocked option 1'));
expect(mockedOnChange).toHaveBeenCalledTimes(1);
expect(mockedOnChange).toHaveBeenCalledWith({label: 'Mocked option 1', value: 'mocked-option-1'});
});
it('should call onChange when the first option is selected then second option then the 9th one', async () => {
const mockedOnChange = jest.fn();
const { getByText, queryByTestId } = render(<MySelectComponent
options={mockedOptions}
onChange={mockedOnChange} />);
const mySelectComponent = queryByTestId('my-select-component');
expect(mySelectComponent).toBeDefined();
expect(mySelectComponent).not.toBeNull();
expect(mockedOnChange).toHaveBeenCalledTimes(0);
fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' });
await waitForElement(() => getByText('Mocked option 1'));
fireEvent.click(getByText('Mocked option 1'));
fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' });
await waitForElement(() => getByText('Mocked option 2'));
fireEvent.click(getByText('Mocked option 2'));
fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' });
await waitForElement(() => getByText('Mocked option 9'));
fireEvent.click(getByText('Mocked option 9'));
expect(mockedOnChange).toHaveBeenCalledTimes(3);
expect(mockedOnChange).toHaveBeenCalledWith({label: 'Mocked option 9', value: 'mocked-option-9'});
});
it('should call onChange when filtering by input value', async () => {
const mockedOnChange = jest.fn();
const { getByText, queryByTestId, container } = render(<MySelectComponent
options={mockedOptions}
onChange={mockedOnChange} />);
const mySelectComponent = queryByTestId('my-select-component');
fireEvent.change(container.querySelector('input'), {
target: { value: 'option 1' },
});
// select Mocked option 1
fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' });
// select Mocked option 10
fireEvent.keyDown(mySelectComponent.firstChild, { key: 'ArrowDown' });
await waitForElement(() => getByText('Mocked option 10'));
fireEvent.click(getByText('Mocked option 10'));
expect(mockedOnChange).toHaveBeenCalledTimes(1);
expect(mockedOnChange).toHaveBeenCalledWith({label: 'Mocked option 10', value: 'mocked-option-10'});
});
});
Run Code Online (Sandbox Code Playgroud)
我希望这有帮助。
使用测试库和 v2.0
试图classNamePrefix通过寻找 onChange 道具或其他任何东西来避免使用任何非常具体的东西,例如或侵入组件的运行方式。
const callback = jest.fn();
const { container, getByText} = render(<Select ... onChange={callback} />);
Run Code Online (Sandbox Code Playgroud)
现在我们基本上假装是屏幕阅读器和焦点,然后按向下箭头。
fireEvent.focus(container.querySelector('input'));
fireEvent.keyDown(container.querySelector('input'), { key: 'ArrowDown', code: 40 });
Run Code Online (Sandbox Code Playgroud)
现在点击你想要的值
fireEvent.click(getByText('Option Two'));
Run Code Online (Sandbox Code Playgroud)
并断言。
expect(callback).toHaveBeenCalledWith({ value: 'two', label: 'Option Two'});
Run Code Online (Sandbox Code Playgroud)
补充一下 Keith 所说的,使用模拟方法似乎确实是行使该功能的唯一方法。然而,当我在我的解决方案中尝试这个时,它不起作用 - 我正在使用 Typescript,所以不确定这是否有影响,但我发现在模拟事件时也有必要传递key属性:
wrapper.find('.Select-control').simulate('keyDown', { key: 'ArrowDown', keyCode: 40 });
wrapper.find('.Select-control').simulate('keyDown', { key: 'Enter', keyCode: 13 });
Run Code Online (Sandbox Code Playgroud)
我还发现,设置classNamePrefix属性可以更轻松地进行简单测试,让我确信组件能够正确响应模拟事件。设置此前缀时,组件的有用部分会用类名进行装饰,以便轻松访问它们(您可以通过检查 google 开发工具中的元素来识别这些有用的类名)。一个简单的 Jest 测试:
it('react-select will respond to events correctly', () => {
const sut = Enzyme.mount(
<Select
classNamePrefix="list"
options={[{ label: 'item 1', value: 1 }]}
/>);
// The intereactive element uses the suffix __control **note there are two underscores**
sut.find('.list__control').first().simulate('keyDown', { key: 'ArrowDown', keyCode: 40 });
sut.find('.list__control').first().simulate('keyDown', { key: 'Enter', keyCode: 13 });
// the selected value uses the suffix __single-value **note there are two underscores**
expect(sut.find('.list__single-value').first().text()).toEqual('item 1');
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10355 次 |
| 最近记录: |