反应/酶成分功能未更新状态

时间:2020-04-28 18:57:55

标签: javascript reactjs tdd enzyme

我有一个可以在localhost上运行的组件。如果输入冠军的字母,则onInputHandler(input)会将组件的状态更改为有效的冠军的名称。不幸的是,当我用酶进行测试时,组件的状态永远不会改变(保持默认状态)。我很乐意提供任何建议。当我使用数组设置this.statechampionsList时,结果是相同的。通常,数组会在componentDidMount()之后填充getChampionsList()。

        export class ChooseChampion extends React.Component {
    constructor() {
        super();
        this.state = {
            championSelected: "Choose champion",
            championsList: []
        };

        this.onInputHandler = this.onInputHandler.bind(this);
        this.getFilteredChampion = this.getFilteredChampion.bind(this);
    }

    componentDidMount() {
        this.getChampionsList();
    }

    getChampionsList = () => {
        fetch('/champions-list')
            .then(res => res.json())
            .then(champions => this.setState({ championsList: champions }))
    }

    onInputHandler(event) {
        if (event.target.value === "") {
            this.setState({
                championSelected: "Choose champion"
            });
        } else {
            const input = event.currentTarget.value;
            const filteredChampion = this.getFilteredChampion(input)
            this.setState({
                championSelected: filteredChampion
            });
        }
    }

    getFilteredChampion(input) {
        let oneFilteredChampion = this.state.championsList.find(champion => champion.toLowerCase().includes(input.toLowerCase()))
        if (oneFilteredChampion) {
            return oneFilteredChampion;
        } else {
            return "Wrong name!"
        }
    }

    render() {
        return (
            <div className="choose-champion-container">

                <div className="role-and-caption inactive">
                    <img className="role-icon" src={require(`../assets/images/${this.props.lane}_icon.png`)} alt={this.props.lane} />
                    <span className="role-caption">{this.props.lane}</span>
                </div>

                <div className="champion-avatar-and-caption">
                    <ChampionAvatar currentChampion={this.state.championSelected} championsList={this.state.championsList} />
                    <ChampionCaption currentChampion={this.state.championSelected} championsList={this.state.championsList} />
                </div>

                <div className="search-container">
                    <button type="submit" className="search-button"><img src={SearchIcon} className="search-icon" alt="Search" /></button>
                    <input type="text" placeholder="Find champion..." name="search" onInput={this.onInputHandler} />
                </div>
            </div>
        )
    };
}

这是我的测试语句:

const lanes = ["Top", "Jungle", "Middle", "Bottom", "Support"]
const app = <ChooseChampion lane={lanes[Math.floor(Math.random() * (5))]} />;

it('Should change the state after change the input value', () => {
  const newValue = 'Ahri';
  const wrapper = mount(app);
  const input = wrapper.find('input');

  input.value = newValue;

  wrapper.update();
  expect(input.value).toEqual(newValue);
  expect(wrapper.state('championSelected')).toEqual(newValue);
});

1 个答案:

答案 0 :(得分:1)

尝试更换

input.value = newValue;

使用

input.simulate('change', {target: {value: newValue}});

input.simulate('input', {target: {value: newValue}});

要实际触发事件(onChangeonInput),您需要模拟DOM事件。仅更改输入中的值不会触发React监听器。

另一件事是您在componentDidMount中进行访存。那是一个异步调用。在mount之后,将不会填充冠军名单。有两种方法可以等待直到发生。您可以使用wait-for-expect或自己编写类似的函数。因此,最终测试应类似于:

it('Should change the state after change the input value', () => {
  const newValue = 'Ahri';
  const wrapper = mount(app);

  await waitForExpect(() => {
    expect(wrapper.state('championsList')).to.be.not.empty;
  });

  const input = wrapper.find('input');

  input.simulate('change', {target: {value: newValue}});

  wrapper.update();
  expect(input.value).toEqual(newValue);
  expect(wrapper.state('championSelected')).toEqual(newValue);
});

注意:您可能更喜欢使用nock之类的工具来模拟后端,而不是在测试中调用实际的端点。