酶按钮模拟无法按预期工作

Posted

技术标签:

【中文标题】酶按钮模拟无法按预期工作【英文标题】:Enzyme button simulate doesn't work as expected 【发布时间】:2019-12-24 12:43:55 【问题描述】:

我有以下 react-native 测试代码。

import  shallow  from 'enzyme';
import React from 'react';

import 
  BorderlessButton,
  InputBox,
  ProgressBar,
 from 'components';

import Name from '../name.component';

describe('Name component', () => 
  let wrapper: any;

  const mockOnPress = jest.fn();
  const mockSaveStep = jest.fn();

  const mockProps: any = 
    errors: null,
    values: [ givenName: 'givenName', familyName: 'familyName' ],
  ;

  beforeEach(() => 
    wrapper = shallow(<Name signUpForm=mockProps saveStep=mockSaveStep />);
  );

  it('should render Name component', () => 
    expect(wrapper).toMatchSnapshot();
  );

  it('should render 2 <InputBox />', () => 
    expect(wrapper.find(InputBox)).toHaveLength(2);
  );

  it('should render a <ProgressBar />', () => 
    expect(wrapper.find(ProgressBar)).toHaveLength(1);
  );

  it('should render a <BorderlessButton /> with the text NEXT', () => 
    expect(wrapper.find(BorderlessButton)).toHaveLength(1);
    expect(wrapper.find(BorderlessButton).props().text).toEqual('NEXT');
  );

  it('should press the NEXT button', () => 
    wrapper.find(BorderlessButton).simulate('click');
    expect(mockOnPress).toHaveBeenCalled();
  );
);

但是最后一个测试不能正常工作。如何模拟此按钮单击?这给了我一个错误提示

期望(jest.fn()).toHaveBeenCalled()。 预期的模拟函数已被调用,但未被调用。

这是组件。

class NameComponent extends Component 
  componentDidMount() 
    const  saveStep  = this.props;
    saveStep(1, 'Name');
  

  disableButton = () => 
    const 
      signUpForm: 
        errors, values,
      ,
     = this.props;

    if (errors && values && errors.givenName && errors.familyName) 
      if (errors.givenName.length > 0 || values.givenName === '') return true;
      if (errors.familyName.length > 0 || values.familyName === '') return true;
    
  

  handleNext = () => 
    navigationService.navigate('PreferredName');
  

  resetForm = () => 
    const  resetForm  = this.props;
    resetForm(SIGN_UP_FORM);
    navigationService.navigate('LoginMain');
  

  render() 
    const  name, required  = ValidationTypes;
    const  step  = this.props;

    return (
      <SafeAreaView style= flex: 1 >
        <KeyboardAvoidingView style= flex: 1 
          behavior=Platform.OS === 'ios' ? 'padding' : null
          enabled>
          <ScreenContainer
            navType=ScreenContainer.Types.LEVEL_THREE
            levelThreeOnPress=this.resetForm>

            <View style=styles.container>
              <View style= flex: 1 >
                <SinglifeText
                  type=SinglifeText.Types.H1
                  label='Let’s start with your legal name'
                  style=styles.textLabel
                />

                <View style=styles.names>
                  <InputBox
                    name='givenName'
                    form=SIGN_UP_FORM
                    maxLength=22
                    placeholder='Given name'
                    containerStyle=styles.givenNameContainer
                    inputContainerStyle=styles.inputContainer
                    errorStyles=styles.inputError
                    keyboardType=KeyBoardTypes.default
                    validations=[required, name]
                  />
                  <InputBox
                    name='familyName'
                    form=SIGN_UP_FORM
                    maxLength=22
                    placeholder='Family name'
                    inputContainerStyle=styles.inputContainer
                    errorStyles=styles.inputError
                    keyboardType=KeyBoardTypes.default
                    validations=[required, name]
                  />
                </View>

                <SinglifeText
                  type=SinglifeText.Types.HINT
                  label='Please use the same name you use with your bank'
                  style=styles.hint
                />
              </View>
            </View>
          </ScreenContainer>

          <ProgressBar presentage=(step / MANUAL_SIGNUP_STEP_COUNT) * 100 />

          <View style=styles.bottomButtonContainer>
            <BorderlessButton
              text='NEXT'
              disabled=this.disableButton()
              onPress=this.handleNext
            />
          </View>

        </KeyboardAvoidingView>
      </SafeAreaView>
    );
  

我该如何解决这个问题??

【问题讨论】:

当您说“无法正常工作”时,您是什么意思?错误是什么? 我要测试的方法是,您还必须模拟单击按钮时将触发的函数并更改为 expect(function).toHaveBeencall(); 你能添加整个测试代码吗?这将帮助我们了解真正的问题出在哪里。 用完整的测试代码更新了帖子。 您调用的实际点击功能是什么?我猜 mockpress 只是一个模拟名称。您也可以发布组件代码吗?只是想看看你在 onclick 事件上调用了哪个函数。 【参考方案1】:

您创建了函数mockOnPress(),但从未将mockOnPress() 注入到组件中。

在您编写的组件中,NameComponent 有一个子BorderlessButton 组件,其中onPress=this.handleNext 行是硬编码的。handleNext() 在其他地方定义为:

handleNext = () => 
    navigationService.navigate('PreferredName');

为了测试按钮的功能是否正常,我看到了两个可行的选项。一种是使用依赖注入。您可以让它执行作为道具传入的代码,而不是对按钮进行硬编码以调用navigationService.navigate('PreferredName')。以以下为例:

it('Button should handle simulated click', function (done) 
  wrappedButton = mount(<MyButton onClick=() => done()>Click me!</BaseButton>)
  wrappedButton.find('button').simulate('click')

请注意,您可以采用上面示例中提供的原则,并将您希望在 onClick 上发生的功能作为道具传递给您的 NameComponent,并将其扩展为您的示例。

您有另一个选择,是测试单击按钮是否会导致您想要发生的副作用。如前所述,按下按钮应调用navigationService.navigate('PreferredName')。这是预期的效果吗?如果是这样,您可以更改测试以验证是否以某种方式调用了 navigationService.navigate('PreferredName')

【讨论】:

以上是关于酶按钮模拟无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

为啥 iOS7 模拟器无法启动或按预期启动...?

try/catch 的 Bash 模拟未按预期工作

在“if”语句中没有调用模拟函数 - 用玩笑和酶反应应用程序测试?

模拟 React useRef 或带有酶和玩笑的功能组件内的函数?

笑话测试库 - 模拟拒绝承诺不能按预期在 useAsync() 中工作

kafka 消费者组 ID 无法按预期工作