【问题标题】:Testing a component that uses context测试使用上下文的组件
【发布时间】:2021-07-29 03:43:35
【问题描述】:

我正在尝试为我的应用程序的Login 组件编写测试,并希望测试用户是否可以输入电子邮件和密码字段,然后提交它们。有两个复杂性:它有一个到另一个组件,它使用上下文导入一个名为loginUser. 的函数我通过制作自定义renderWithRouter 函数来解决第一个问题,但我无法解决第二个问题,因为组件无法在上下文之外使用 loginUser 函数。我收到此错误:Error: Uncaught [TypeError: Cannot read property 'then' of undefined] 因为loginUser 未定义。知道如何解决这个问题吗?这里是Login.tsx

import React, { useState } from 'react';
import { useAuth } from 'context/authContext'
import { useHistory, Link } from 'react-router-dom'
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button'

export const Login = (props: any) => {
  const { setUser, loginUser } = useAuth()
  const [email, setEmail] = useState<string>();
  const [password, setPassword] = useState<string>();
  const [errors, setErrors] = useState<boolean>()
  const history = useHistory()

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    loginUser({
      email,
      password
    }).then((result: any) => {
      console.log(result)
      if (result.message === 'login error') {
        setErrors(true)
      } else {
        history.push('/dashboard/home')
      }
    })
  }

  return(
    <div className="login-wrapper">
      <h1>Please Log In</h1>
      <div className='form-wrapper'>
        <Form onSubmit={handleSubmit}>
          <Form.Group controlId="formBasicEmail">
            <Form.Label>Email address</Form.Label>
            <Form.Control
              isInvalid={errors ? true : false} 
              type="email" 
              placeholder="Enter email" 
              onChange={e => setEmail(e.target.value)}/>
          <Form.Control.Feedback type="invalid">
            {errors ? 'either you don\'t have an account or the email and password do not match' : null}
          </Form.Control.Feedback>
            <Form.Text className="text-muted">
              umm..
            </Form.Text>
          </Form.Group>
          <Form.Group controlId="formBasicPassword">
            <Form.Label>Password</Form.Label>
            <Form.Control 
              type="password" 
              placeholder="Password" 
              onChange={e => setPassword(e.target.value)}
            />
          </Form.Group>
          <Button variant="primary" type="submit">
            Submit
          </Button>
          <div>
            <Link to='/register'>new user? click here to register</Link>
          </div>
        </Form>
      </div>
    </div>
  )
}

还有 Login.test.tsx:

  test("allows user to input their email", () => {
    const onSubmit = jest.fn();
    
    renderWithRouter(<Login />)
    const input = screen.getByLabelText("Email address")
    const pwd = screen.getByLabelText("Password")
    const button = screen.getByText("Submit")

    fireEvent.change(input, { target: { value: "t@t.com"}})
    fireEvent.change(pwd, { target: { value: "123456"}})
    fireEvent.click(button)

    expect(onSubmit).toBeCalled()
  })
})

【问题讨论】:

标签: reactjs typescript jestjs react-testing-library


【解决方案1】:

还没有运行它,但重构为这样的东西,然后测试LoginForm 组件。

import React, { useState } from 'react';
import { useAuth } from 'context/authContext'
import { useHistory, Link } from 'react-router-dom'
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button'

interface LoginFormProps {
  onSubmit: (email: string, password: string) => void;
  errors: boolean;
}
export const LoginForm: React.FC<LoginFormProps> = ({onSubmit, errors}) => {
  const [email, setEmail] = useState<string>();
  const [password, setPassword] = useState<string>();
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    onSubmit(email, password)
  }
  return(
    <div className="login-wrapper">
      <h1>Please Log In</h1>
      <div className='form-wrapper'>
        <Form onSubmit={handleSubmit}>
          <Form.Group controlId="formBasicEmail">
            <Form.Label>Email address</Form.Label>
            <Form.Control
              isInvalid={errors ? true : false} 
              type="email" 
              placeholder="Enter email" 
              onChange={e => setEmail(e.target.value)}/>
          <Form.Control.Feedback type="invalid">
            {errors ? 'either you don\'t have an account or the email and password do not match' : null}
          </Form.Control.Feedback>
            <Form.Text className="text-muted">
              umm..
            </Form.Text>
          </Form.Group>
          <Form.Group controlId="formBasicPassword">
            <Form.Label>Password</Form.Label>
            <Form.Control 
              type="password" 
              placeholder="Password" 
              onChange={e => setPassword(e.target.value)}
            />
          </Form.Group>
          <Button variant="primary" type="submit">
            Submit
          </Button>
          <div>
            <Link to='/register'>new user? click here to register</Link>
          </div>
        </Form>
      </div>
    </div>
  )
}

export const Login = (props: any) => {
  const { setUser, loginUser } = useAuth()
  const [errors, setErrors] = useState<boolean>(false)
  const history = useHistory()

  const handleSubmit = (email, password) => {
    loginUser({
      email,
      password
    }).then((result: any) => {
      console.log(result)
      if (result.message === 'login error') {
        setErrors(true)
      } else {
        history.push('/dashboard/home')
      }
    })
  }

  return(
    <LoginForm onSubmit={handleSubmit} errors={errors} />
  )
}

【讨论】:

  • 谢谢!我确实尝试过,但我认为根本问题仍然存在:现在当我在测试中对新的 组件调用 fireEvent.click 时,它会引发错误,因为未定义 loginUser
  • 你传递一个模拟函数作为提交处理程序?您尝试测试组件的哪一部分有点令人困惑。
  • 道歉 - 对测试真的很陌生,我正在挣扎。我想测试用户是否可以输入他们的电子邮件和密码,然后单击提交按钮以提交该信息。
猜你喜欢
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-25
相关资源
最近更新 更多