带有Jest和酶的单元测试reactjs组件函数

问题描述 投票:0回答:1

我有一个问题,那就是如何为下面的功能编写单元测试,功能是登录用户并执行一系列操作,例如用户输入数据,按下(虚假操作)按钮并向服务器发送请求并向用户发送响应数据我是否使用Jest和Enzyme,但我不知道该怎么做,还是我在Reactjs中误解了单元测试?

export default function Login({ title }) {
  UseStyles(s, n);

  Login.propTypes = {
    title: PropTypes.string.isRequired,
  };

  const [email, setEmail] = useState('');
  const [pw, setPw] = useState('');
  const [error,setError] = useState('');
  const [checkLogin, setCheckLogin] = useState('');

  // set validation
  const [validEmail, setValidEmail] = useState('');
  const [validPw, setValidPw] = useState('');

  useEffect(() => {

    if(Cookie.get('token')){
      setCheckLogin('hadLogin');
      window.history.back()
    }
  },[]);

  // notification login success
  function Notify() {
    toast("Loading...", {
      position: "top-right",
      autoClose: 3000,
    });
  }

  function disableBtn() {
    const exist = Object.values(validator.fields).includes(false);
    if(exist){
      return true;
    }
    return false;
  }

  // when click login button
  // Want to write unit test
  function handleSubmit() { // this is funtion i want to write unit test
    if (!pw || !email)
    {
      !pw ? setError('Password is empty') : ''
      !email ? setError('Email is empty') : ''
      return;
    }
    AxiosConfig
      .post('/users/login', {
        email,
        password: pw,
      },)
      .then(res => {
        Cookie.set('token', res.data.token,{expires:1});
        Cookie.set('email', email,{expires:1});
        Cookie.set('roleName', 'user',{expires:1});
        Notify();
        window.location.href = `${BaseUrl}`
      })
      .catch(err => {
        setError(err.response.data);
      });
  }

  return (
    checkLogin !== 'hadLogin' ?
    (<div className={s.root}>
      <div className={s.container}>
        <h1>{title}</h1>
        <p className={s.lead}>
          Log in with your email address.
        </p>
        <div className={s.formGroup}>
          <a className={s.facebook}>
            <svg
              className={s.icon}
              width="30"
              height="30"
              viewBox="0 0 30 30"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path d="M22 16l1-5h-5V7c0-1.544.784-2 3-2h2V0h-4c-4.072 0-7 2.435-7 7v4H7v5h5v14h6V16h4z" />
            </svg>
            <span>Log in with Facebook</span>
          </a>
        </div>
        <div className={s.formGroup}>
          <a className={s.google}>
            <svg
              className={s.icon}
              width="30"
              height="30"
              viewBox="0 0 30 30"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d={
                  'M30 13h-4V9h-2v4h-4v2h4v4h2v-4h4m-15 2s-2-1.15-2-2c0 0-.5-1.828 1-3' +
                  '1.537-1.2 3-3.035 3-5 0-2.336-1.046-5-3-6h3l2.387-1H10C5.835 0 2 3.345 2 7c0' +
                  '3.735 2.85 6.56 7.086 6.56.295 0 .58-.006.86-.025-.273.526-.47 1.12-.47 1.735' +
                  '0 1.037.817 2.042 1.523 2.73H9c-5.16 0-9 2.593-9 6 0 3.355 4.87 6 10.03 6 5.882' +
                  '0 9.97-3 9.97-7 0-2.69-2.545-4.264-5-6zm-4-4c-2.395 0-5.587-2.857-6-6C4.587' +
                  '3.856 6.607.93 9 1c2.394.07 4.603 2.908 5.017 6.052C14.43 10.195 13 13 11' +
                  '13zm-1 15c-3.566 0-7-1.29-7-4 0-2.658 3.434-5.038 7-5 .832.01 2 0 2 0 1 0' +
                  '2.88.88 4 2 1 1 1 2.674 1 3 0 3-1.986 4-7 4z'
                }
              />
            </svg>
            <span>Log in with Google</span>
          </a>
        </div>
        <div className={s.formGroup}>
          <a className={s.twitter}>
            <svg
              className={s.icon}
              width="30"
              height="30"
              viewBox="0 0 30 30"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d={
                  'M30 6.708c-1.105.49-2.756 1.143-4 1.292 1.273-.762 2.54-2.56' +
                  '3-4-.97.577-2.087 1.355-3.227 1.773L25 5c-1.12-1.197-2.23-2-4-2-3.398 0-6' +
                  '2.602-6 6 0 .4.047.7.11.956L15 10C9 10 5.034 8.724 2 5c-.53.908-1 1.872-1' +
                  '3 0 2.136 1.348 3.894 3 5-1.01-.033-2.17-.542-3-1 0 2.98 4.186 6.432 7 7-1' +
                  '1-4.623.074-5 0 .784 2.447 3.31 3.95 6 4-2.105 1.648-4.647 2.51-7.53 2.51-.5' +
                  '0-.988-.03-1.47-.084C2.723 27.17 6.523 28 10 28c11.322 0 17-8.867 17-17' +
                  '0-.268.008-.736 0-1 1.2-.868 2.172-2.058 3-3.292z'
                }
              />
            </svg>
            <span>Log in with Twitter</span>
          </a>
        </div>
        <strong className={s.lineThrough}>OR</strong>
        <form method="post" >
          <div className={s.formGroup}>
            <label className={s.label} htmlFor="usernameOrEmail">
             Email address:
              <input
                className={s.input}
                id="usernameOrEmail"
                type="text"
                name="usernameOrEmail"
                maxLength={50}
                minLength={8}
                autoFocus // eslint-disable-line jsx-a11y/no-autofocus
                onChange={e => {setEmail(e.target.value)}}
                onBlur={e => setValidEmail(validator.fields.email)}
              />
              {/* Check validation */}
              {validator.message('email', email, 'required|email')}   {/* validator.message('field name', value to validate, 'validator rule') */}
              {/* Show validation error if having any */}
              <small className={s.validatorShow}>{validEmail === false ? validator.errorMessages.email : ''}</small>
            </label>
          </div>
          <div className={s.formGroup}>
            <label className={s.label} htmlFor="password">
              Password:
              <input
                className={s.input}
                id="password"
                type="password"
                name="password"
                onChange={e => setPw(e.target.value)}
                onBlur={e => {setValidPw(validator.fields.password); console.log(validator)}}
              />
               {/* Check validation */}
              {validator.message('password', pw, 'required|password')}
              {/* Show validation error if having any */}
              <small className={s.validatorShow}>{validPw === false ? validator.errorMessages.password : ''}</small>
            </label>
          </div>
          <div className={error ? s.alert : s.disable} >
              {error}
          </div>
          <div className={s.formGroup}>
          <ToastContainer/>
            <button className={disableBtn() ? s.buttonDisabled : s.button} type="button" onClick={handleSubmit} disabled={disableBtn()}>
              Log in
            </button>
          </div>
          <div className={s.link}>
            <a href="/forget">Forget Password</a>
          </div>
        </form>
      </div>
    </div>) : ''
  );
}
reactjs unit-testing enzyme jest react-starter-kit
1个回答
0
投票
您可以通过使用酶来安装组件并模拟执行您要测试的代码的按钮单击来实现此目的。

取自https://airbnb.io/enzyme/docs/api/ReactWrapper/simulate.html,并进行了更改以适合您的代码:

const wrapper = mount(<Login title="test" />); wrapper.find('.<INSERT WHATEVER s.button evaluates to>}').simulate('click');

现在,您还需要用玩笑来模拟Cookie和AxiosConfig。一种方法是使用jest.spyOn():https://jestjs.io/docs/en/jest-object#jestspyonobject-methodname和一些模拟函数:https://jestjs.io/docs/en/mock-function-api

import AxiosConfig from 'whatever-npm-module" import Cookie from 'whatever-npm-module" const axiosSpy = jest.spyOn(AxiosConfig, 'post').mockResolvedValue({ data: { token: 'testToken' }}); const cookieSpy = jest.spyOn(Cookie, 'set');

您现在可以检查发送到Cookie.set的内容,以帮助您以一些有趣的期望验证要测试的内容:https://jestjs.io/docs/en/expect

expect(cookieSpy).toHaveBeenNthCalledWith(1, 'testToken', {expires:1}); expect(cookieSpy).toHaveBeenNthCalledWith(2, whateverEmailIs, {expires:1}); ...

这是一个很好的起点,您可以通过使用beforeEach和afterEach来设置模拟,提供模拟返回值并清除这些返回值以测试您的错误情况,从而走得更远。
© www.soinside.com 2019 - 2024. All rights reserved.