模拟("更改")状态未更新后



我有一个搜索过滤器组件,里面有一个输入,它连接到redux。

class SearchFilter extends PureComponent {
   constructor (props) {
       super(props);
       this.handleInputChange = this.handleInputChange.bind(this);
       this.state = {
           keyword: props.searchKeyword
       };
   }
   handleInputChange (e) {
       this.setState({keyword: e.target.value});
       this.props.dispatch(SetFiltersValue(...);
   }
   render () {
       const {keyword} = this.state;
       return (
           <div className="search-w bp3-input-group">
               <span className="bp3-icon bp3-icon-search"/>
               <input className="bp3-input" value={keyword} type="text" placeholder="Search input" dir="auto" onChange={this.handleInputChange} />
           </div>
       );
   }
}
const mapStateToProps = (_, ownParams) => {...};
export default connect(mapStateToProps)(SearchFilter);

我用开玩笑和酶写了一个测试,以在用户输入新值时测试状态更新

import React from "react";
import SearchFilter from "../../dev/components/shared/searchFilter";
import {shallow, mount} from "enzyme";
import configureStore from "redux-mock-store";
describe("Testing Search filter", () => {
    const mockStore = configureStore(),
        initialStoreState = {
            filtersParams: {}
        };
    let store;
    beforeEach(() => {
        store = mockStore(initialStoreState);
    });
    it("Update search field value when user enters a value", () => {
        const wrapper = shallow(<SearchFilter store={store}/>).dive(),
            searchInput = wrapper.find("input.bp3-input").first();
        expect(searchInput).toBeDefined();
        const mockedEvent = {
            preventDefault () {},
            target: { value: "foo" }
        };
        expect(wrapper.state("keyword")).toEqual("");
        searchInput.simulate("change", mockedEvent);
        wrapper.update();
        expect(wrapper.state("keyword")).toEqual("foo");
    });
});

问题是状态在模拟更改后不会更新,并且测试总是失败。

如何解决此问题,或者有其他方法可以测试状态更新?

一个完整的测试示例:

index.tsx

import React, { PureComponent } from 'react';
import { connect, DispatchProp } from 'react-redux';
import { SetFiltersValue } from './actionCreators';
interface ISearchFilterStateProps {
  searchKeyword: string;
}
interface ISearchFilterState {
  keyword: string;
}
type Props = ISearchFilterStateProps & DispatchProp;
class SearchFilter extends PureComponent<Props, ISearchFilterState> {
  constructor(props: Props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.state = {
      keyword: props.searchKeyword
    };
  }
  public handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
    this.setState({ keyword: e.target.value });
    this.props.dispatch(SetFiltersValue());
  }
  public render() {
    const { keyword } = this.state;
    return (
      <div className="search-w bp3-input-group">
        <span className="bp3-icon bp3-icon-search" />
        <input
          className="bp3-input"
          value={keyword}
          type="text"
          placeholder="Search input"
          dir="auto"
          onChange={this.handleInputChange}
        />
      </div>
    );
  }
}
const mapStateToProps = (_, ownParams) => {
  return { searchKeyword: '' };
};
export default connect(mapStateToProps)(SearchFilter);

actionCreators.ts

export const SetFiltersValue = () => ({ type: 'SET_FILTER' });

单元测试:

import React from 'react';
import { shallow } from 'enzyme';
import configureStore from 'redux-mock-store';
import SearchFilter from './';
import { SetFiltersValue } from './actionCreators';
const initialState = { filtersParams: {} };
type State = typeof initialState;
const mockStore = configureStore<State>();
describe('SearchFilter', () => {
  let store;
  beforeEach(() => {
    store = mockStore(initialState);
  });
  it('t1', () => {
    const searchFilter = shallow(<SearchFilter store={store}></SearchFilter>).dive();
    const searchInputWrapper = searchFilter.dive();
    const searchInput = searchInputWrapper.find('input.bp3-input').first();
    expect(searchInputWrapper.state('keyword')).toBe('');
    const mockedEvent = {
      preventDefault: jest.fn(),
      target: { value: 'foo' }
    };
    searchInput.simulate('change', mockedEvent);
    expect(searchInputWrapper.state('keyword')).toBe('foo');
    expect(store.getActions()).toEqual([SetFiltersValue()]);
    expect(searchInputWrapper.html()).toMatchSnapshot();
  });
});

100% 覆盖率的单元测试结果:

 PASS  src/stackoverflow/54587960/index.spec.tsx
  SearchFilter
    ✓ t1 (28ms)
 › 1 snapshot written.
-------------------|----------|----------|----------|----------|-------------------|
File               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files          |      100 |      100 |      100 |      100 |                   |
 actionCreators.ts |      100 |      100 |      100 |      100 |                   |
 index.tsx         |      100 |      100 |      100 |      100 |                   |
-------------------|----------|----------|----------|----------|-------------------|
Snapshot Summary
 › 1 snapshot written from 1 test suite.
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 written, 1 total
Time:        4.367s, estimated 5s

反应组件快照:

// Jest Snapshot v1
exports[`SearchFilter t1 1`] = `"<div class=\"search-w bp3-input-group\"><span class=\"bp3-icon bp3-icon-search\"></span><input type=\"text\" class=\"bp3-input\" value=\"foo\" placeholder=\"Search input\" dir=\"auto\"/></div>"`;

以下是完成的演示: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/54587960

相关内容

  • 没有找到相关文章

最新更新