如何通过带有React-Native的酶或玩笑来模拟后退按钮

时间:2019-02-12 11:54:36

标签: react-native jestjs enzyme

我无法通过将React / Jest与react-native代码一起使用来模拟硬件后退按钮。还提到我是反应原生的酶/笑话新手

我点击了以下链接并尝试实现。不幸的是,我无法做到这一点。

How to simulate android back button in react-native test

Sample.js,

import React, { Component } from "react";
import {
  View,
  Text,
  BackHandler,
  BackAndroid
} from "react-native";

  componentWillMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonPress);
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButtonPress);
  }

  handleBackButtonPress = () => {
    return true;
  };

sample.test.js,

import 'react-native';
import React from "react";
import  mockPressBack  from 'react-native';

jest.mock('BackHandler', () => {
    return {
        addEventListener: mockPressBack
    };
});

describe('sample verifies', ()=>{
      test('back button press', ()=> {
        const wrapper = shallow(<Sample />);
    const sampleData = wrapper.instance();
    sampleData.componentWillMount(); 
    });
});

实际结果: TypeError:_reactNative.BackHandler.addEventListener不是函数

预期结果: 它运行成功。

我在这里被打中。请帮助我。

谢谢。

1 个答案:

答案 0 :(得分:0)

实际上,建议对大多数(如果不是全部)依赖项进行模拟的单元测试。微小的问题是mocking适用于整个模块-因此,如果您需要模拟某些export但又要保留另一个additional efforts,则需要nuget

您只需要模拟BackHandler组件。但是如果你写类似

jest.mock('react-native');
// ...

您会收到一条错误消息

  

BackHandler.addEventListener不是函数

这是因为基本jest.mock()jest.fn()模拟函数替换了每个导出。但是BackHandler最初不是函数,而是对象。

因此,您需要手动模拟模块来为BackHandler提供值:

import { BackHandler } from 'react-native'; // it's needed to direct access mocked version

jest.mock('react-native', () => {
  BackHandler: { 
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
  }
});

describe('Sample', () => { 
  it('binds to BackHandler on mount and clean up on destroy', () => {
    const wrapper = shallow(<Sample />);
    expect(BackHandler.addEventListener).toHaveBeenCalledWith('hardwareBackPress');
    wrapper.unmount();
    expect(BackHandler.removeEventListener).toHaveBeenCalledWith('hardwareBackPress');
  });

要模拟hardwareBackPress,我建议几种不同的方法:

  1. 在提供实际存储回调的情况下模拟addEventListener / removeEventListener(此方法很明确,但需要其他代码-并且需要在测试用例之间进行清理)

    const callbacks = {};
    function helperTriggerListeners(eventName, event) { 
        (callbacks[eventName] || []).forEach(callback => callback(event));
    }
    
    jest.mock('react-native', () => {
      BackHandler: { 
        addEventListener: jest.fn().mockImplementation((eventName, callback) => {
          callbacks[eventName] = callbacks[eventName] || [];
          callbacks[eventName].psuh(callback);
        }),
        removeEventListener: jest.fn().mockImplementation((eventName, callback) => {
          const indexOf = (callbacks[eventName] || []).indexOf(callback);
          if (indexOf != -1) {
            callbacks[eventName] = callbacks[eventName].splice(indexOf, 1);
          }
        }),
      }
    });
    
    beforeEach(() => {
        // really important to ensure it's clean from data made in older runs
        callbacks = {};
        BackHandler.addEventListener.mockClear();
        BackHandler.removeEventListener.mockClear();
    });
    
    it('...', () => {
     helperTriggerListeners('hardwareBackPress', { /* mocked event if required */});
     expect(someOtherMockedService.someMethod).toHaveBeenCalled(); 
    
  2. 直接从addEventListener模拟日志中进行回调:

    beforeEach(() => {
        // really important otherwise you may call callbacks for component already unmounted 
        BackHandler.addEventListener.mockClear();
        BackHandler.removeEventListener.mockClear();
    });
    
    it('reacts on hardwareBackPress', () => {
      const wrapper = shallow(<Sample />);
      BackHandler.addEventListener.mock.calls.forEach(oneCall => {
        if (oneCall[0] === 'hardwareBackPress') oneCall[1]({ /*mocked Event object*/ });
      })
      expect(someOtherMockedService.someMethod).toHaveBeenCalled();