测试 React Select 组件

新手上路,请多包涵

https://github.com/JedWatson/react-select

我想使用 React-Select 反应组件,但我需要添加测试。

我已经尝试了几个在谷歌上找到的选项,但似乎没有任何效果。我有下面的代码,但它不会导致更改事件。我已经能够添加一个焦点事件,它添加了 ‘is-focussed’ 类,但仍然缺少 ‘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'

});
});

被测组件

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;

命令行 要运行测试,我会:

 >> npm run test

在 package.js 我有这个脚本:

 "test": "mocha --compilers js:babel-core/register -w test/browser.js ./new",

测试设置

和 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'
};

我也尝试过使用此处概述的测试方法: https ://github.com/StephenGrider/ReduxSimpleStarter

任何帮助将不胜感激

原文由 Llewellyn 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 475
1 个回答

这是一个反复出现的问题。我正在与 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>;
}

我在我的 Selectdata-testid="my-select-component" 上添加包装的原因是渲染的选项元素将可用,否则我无法检查文本选项是否存在(你’当你看到我的测试时会更好地理解)。

这是一个 实时运行的示例,在渲染时它会显示一个带有 10 个选项的选择组件。

在此处输入图像描述

测试 1:应无错误地呈现

  • 我渲染组件。

  • 我搜索要存在的占位符。

测试 2:选择第一个选项时应调用 onChange

  • 我渲染组件。

  • 我检查我的 mockedOnChange 是否还没有被调用。

  • 模拟 ArrowDown 事件。

  • 点击第一个选项。

  • 我检查 mockedOnChange 是否使用第一个选项标签和值调用了 1 次。

测试 3:应该在选择第一个选项然后选择第二个选项然后选择第 9 个选项时调用 onChange

  • 我渲染组件。

  • 我模拟了第一个选项的选择。

  • 我模拟了第二个选项的选择。

  • 我模拟了第 9 个选项的选择。

  • 我检查 mockedOnChange 是否使用第 9 个选项包和值被调用 3 次。

测试 4:按输入值过滤时应调用 onChange

  • 我渲染组件。

  • 我通过键入“选项 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'});
    });

});

我希望这会有所帮助。

原文由 Ala Eddine JEBALI 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进