1

好的,所以我对如何使用酶/玩笑测试我的组件的功能有点困惑。仍在学习如何测试我的组件 - 我可以编写简单的测试,但现在我需要让它们更复杂。

我想知道测试我的组件的函数是否被正确调用以及它们是否按预期更新状态道具的最佳方法。我发现很棘手的是我的函数和状态都存在于我的组件的道具中。

如果我需要使用间谍,我希望最好知道如何使用 Jest,但是如果像 Sinon 或 Jasmine 这样的部门更适合我愿意接受的工作(请告诉我为什么这样我可以更好地理解)。

例如,我有一个UserDetails组件

const UserDetails = ({
 userInfo,
 onUserInfoUpdate,
 className,
 error,
 title,
 primaryBtnTitle,
 submit,
 secondaryBtnTitle,
 secondaryBtnFunc,
 ...props
}) => (
 <div className={className}>
   <div className="user-details-body">
     <Section title="User details">
       <TextInput
         className="firstName"
         caption="First Name"
         value={userInfo.first}
         onChange={onUserInfoUpdate('first')}
         name="first-name"
         min="1"
         max="30"
         autoComplete="first-name"
       />
       <TextInput
         className="lastName"
         caption="Last Name"
         value={userInfo.last}
         onChange={onUserInfoUpdate('last')}
         name="last-name"
         min="1"
         max="30"
         autoComplete="last-name"
       />
     </Section>
   </div>

   <div className="errorBar">
     {error && <Alert type="danger">{error}</Alert>}
   </div>

   <ActionBar>
     <ButtonGroup>
       <Button type="secondary" onClick={secondaryBtnFunc}>
         {secondaryBtnTitle}
       </Button>
       <Button type="primary" onClick={submit}>
         {primaryBtnTitle}
       </Button>
     </ButtonGroup>
   </ActionBar>
 </div>  

TextInput包括:

<label className={className}>
 {Boolean(caption) && <Caption>{caption}</Caption>}
 <div className="innerContainer">
   <input value={value} onChange={updateValue} type={type} {...rest} />     
 </div>
</label>

这是我的index.js文件的示例代码,它将我的 withState 和 withHandlers 组合到我的组件中:

import UserDetails from './UserDetails'
import { withState, withHandlers, compose } from 'recompose'

export default compose(
  withState('error', 'updateError', ''),
  withState('userInfo', 'updateUserInfo', {
    first: '',
    last: '',
  }),
  withHandlers({
    onUserInfoUpdate: ({ userInfo, updateUserInfo }) => key => e => {
      e.preventDefault()
      updateCardInfo({
        ...cardInfo,
        [key]: e.target.value,
      })
    },
    submit: ({ userInfo, submitUserInfo }) => key => e => {
      e.preventDefault()
      submitUserInfo(userInfo) 
      //submitUserInfo is a graphQL mutation
      })
    }  
  }) 
)

到目前为止,我的测试文件如下所示:

import React from 'react'
import { mount } from 'enzyme' 
import UserDetails from './'
import BareUserDetails from './UserDetails'

describe('UserDetails handlers', () => {
  let tree, bareTree

  beforeEach(() => {
    tree = mount(
      <ThemeProvider theme={theme}>
        <UserDetails />
      </ThemeProvider>
    )
    bareTree = tree.find(BareUserDetails)
  })

  it('finds BareUserDetails props', () => {
    console.log(bareTree.props())
    console.log(bareTree.props().userInfo)
    console.log(bareTree.find('label.firstName').find('input').props())
  })

})

控制台日志向我返回了关于我在调用它们时期望看到的正确信息:

//console.log(bareTree.props())
   { error: '',
      updateError: [Function],
      userInfo: { first: '', last: '' },
      updateUserInfo: [Function],
      onUserInfoUpdate: [Function] }

//console.log(bareTree.props().userInfo)
   { first: '', last: '' }

//console.log(bareTree.find('label.firstName').find('input).props()
   { value: '',
      onChange: [Function],
      type: 'text',
      name: 'first-name',
      min: '1',
      max: '30',
      autoComplete: 'first-name' }

现在的问题是我如何使用它们,以及最好的方法。我什至使用我的函数还是只是检查是否调用了 onChange?

更新(有点)

我已经尝试过了,我得到以下信息:

  it('Input element updates userInfo with name onChange in FirstName input', () => {
    const firstNameInput = bareTree.find('label.firstName').find('input)
    ccNameInput.simulate('change', {target: {value: 'John'}})
    expect(ccNameInput.prop('onChange')).toHaveBeenCalled()
  })

在我的终端中,我得到:

 expect(jest.fn())[.not].toHaveBeenCalled()

    jest.fn() value must be a mock function or spy.
    Received:
      function: [Function anonymous]

但是,如果我尝试使用 Jest 创建一个 spyOn,则会收到一个错误,即它无法读取“未定义”的函数。

我试过了spy = jest.spyOn(UserDetails.prototypes, 'onUpdateUserInfo')spy = jest.spyOn(BareUserDetails.prototypes, 'onUpdateUserInfo')他们都抛出了错误。

4

1 回答 1

3

我相信您可能应该分别测试哑组件(UserDetails)和 HOC。对于哑组件,您想要渲染组件shallow并注入道具。要模拟 onUserInfoUpdate,你需要做const onUserInfoUpdate = jest.fn();

你想要一些类似......的东西。

import React from 'react'
import { shallow } from 'enzyme' 
import UserDetails from './UserDetails'

const onUserInfoUpdate = jest.fn(); // spy
const props = {
  onUserInfoUpdate,
  // list all your other props and assign them mock values
};

describe('UserDetails', () => {
  let tree;

  beforeAll(() => {
    tree = shallow(<UserDetails {...props} />)
  });

  it('should invoke the onUserInfoUpdate method', () => {
    const firstNameInput = tree.find('label.firstName').find('input');
    firstNameInput.simulate('change', { target: { value: 'John' } });

    expect(onUserInfoUpdate).toHaveBeenCalledWith('first');
  });
});
于 2018-03-16T10:50:45.147 回答