【问题标题】:Testing TextInput Component in react-native在 react-native 中测试 TextInput 组件
【发布时间】:2019-01-15 22:48:44
【问题描述】:

我在使用 jest 和 enzyme 测试 react-native 中的 TextInput 变化时遇到了一些问题。

我处理用户输入的组件基本上看起来像这样(简化):

class Search extends React.PureComponent {
  onSearchTextChange = input => {
    // do something awesome
  };
  render() {
    return (
      <View>
        <TextInput
          onChangeText={debounce(this.onSearchTextChange, 800)}
        />
      </View>
    );
  }
}

我想测试文本输入行为。这是测试现在的样子:

it('should render a text input and react to user input', done => {
  const mockOnSearchTextChange = jest.fn();
  Search.prototype.onSearchTextChange = mockOnSearchTextChange;

  const tree = shallow(<Search />);
  const textInput = tree.find('TextInput');
  expect(textInput).toHaveLength(1);
  textInput.simulate('changeText', { target: { value: 'test' } });
  expect(mockOnSearchTextChange).not.toHaveBeenCalled();
  setTimeout(() => {
    expect(mockOnSearchTextChange).toHaveBeenCalledWith('test');
    done();
  }, 1500);
});

运行此测试时,我收到此错误消息

预期的模拟函数已被调用: [“测试”]

但它没有被调用。

所以模拟函数永远不会按预期调用。我错过了什么?

【问题讨论】:

    标签: javascript react-native jestjs enzyme


    【解决方案1】:

    无需添加其他库。 Jest 和 Enzyme 可以执行所需的测试。下面是 SearchBar 组件的定义,它接收一个函数作为道具。使用输入的文本调用该函数。

    const SearchBar = ({onSearch}) => {
      return (
        <View>
          <TextInput
            onChangeText={text => onSearch(text)}
          />
        </View>
      );
    };
    

    可以进行如下测试

        const onSearch = jest.fn();
        const wrapper = shallow(<SearchBar onSearch={onSearch} />);
        wrapper.find('TextInput').simulate('changeText', 'test search text');
        expect(onSearch).toHaveBeenCalledWith('test search text');
    

    【讨论】:

      【解决方案2】:

      我可以使用 react-native-testing-library 做到这一点。

      // ...
      import { render, act, fireEvent } from 'react-native-testing-library'
      // ...
      it ('does stuff', () => {
        const mock = jest.fn()
        const component = render(<Search onSearchTextChange={mock}/>)
        fireEvent.changeText(component.findByType(TextInput), 'test')
        expect(mock).toHaveBeenCalledWith('test')
      })
      
      

      【讨论】:

        【解决方案3】:

        您可以在 TextInput Field 和 accessibilityLabel 中添加和 testID 作为道具之一, 为 ios 和 android 兼容性添加, 这是 TextInput 代码。

           <TextInput
                 placeholder='Email Address'
                 testID='#email'
                 accessibilityLabel='#email'
                 blurOnSubmit={ false }
                 onEndEditing={this.onSubmitLogin}
                 >
                 </TextInput>
        

        在你的测试文件中做一个浅层渲染,在这里

            describe('Your component', () => {
             it('Component: renders correctly', () => {
             const tree = renderer.create(<YourComponent/>).toJSON();
             expect(tree).toMatchSnapshot();
          });
          it('Has  TextInput', () => {
           const tree2 = renderer.create(<YourComponent/>).toJSON();
           expect(findElement(tree2, '#email')).toBeDefined();
         });
        
        });
        

        然后定义上面描述的函数findElement。 使用 console.warn 你应该看到你的 TextInput 道具和你的 testID

           const findElement = function (tree2, element) {
           let result = undefined
           console.warn(tree2.children)
           for(node in tree2.children){
           if(tree2.children[node].props.testID = element) {
           result = true
           }
          }
           return result
         }
        

        它将测试所有可用的 TextInputs …… 注意:如果嵌套的 TextInput 只有一层深度(仅在一个视图内),浅层渲染才会起作用,请参阅此处 - https://medium.com/@AidThompsin/heres-how-you-unit-test-textinput-with-react-native-63e1f7692b17

        【讨论】:

          猜你喜欢
          • 2016-04-12
          • 2018-08-07
          • 1970-01-01
          • 1970-01-01
          • 2020-12-29
          • 2021-12-27
          • 2019-10-30
          • 2018-11-08
          • 2021-01-11
          相关资源
          最近更新 更多