Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何使用React测试库测试组件内部功能_Reactjs_React Testing Library - Fatal编程技术网

Reactjs 如何使用React测试库测试组件内部功能

Reactjs 如何使用React测试库测试组件内部功能,reactjs,react-testing-library,Reactjs,React Testing Library,我是测试新手,我正在尝试使用react测试库测试我的应用程序。我遇到的第一个问题是测试组件内部的函数,如事件处理程序。我发现很少有函数(事件处理程序)作为道具在组件中传递的例子,但如果可能的话,我不想这样做 我的组成部分: import React, { useState } from 'react'; import { Redirect } from 'react-router-dom'; import { connect } from 'react-redux'; import PropTy

我是测试新手,我正在尝试使用react测试库测试我的应用程序。我遇到的第一个问题是测试组件内部的函数,如事件处理程序。我发现很少有函数(事件处理程序)作为道具在组件中传递的例子,但如果可能的话,我不想这样做

我的组成部分:

import React, { useState } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import { login } from 'actions/auth';
import Wrapper from './styled/Wrapper';
import Button from './styled/Button';
import Title from './styled/Title';
import { FormWrapper, StyledForm, FormField } from './styled/Form'
import Input from './styled/Input';
import Link from './styled/Link';


const Login = (props) => {
    const [formData, setFormData] = useState({
        email: '',
        password: ''
    });

    const { email, password } = formData;

    const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });

    const onSubmit = e => {
        e.preventDefault();
        props.login(email, password);
    }

    if (props.isAuthenticated) {
        return <Redirect to='/' />
    }

    return (
        <Wrapper color='#F2F2F2'>
            <FormWrapper>
                <Title>Log In</Title>
                <StyledForm data-testid='auth-form' onSubmit={e => onSubmit(e)}>
                    <FormField>
                        <Input
                            placeholder='Email'
                            type='email'
                            name='email'
                            value={email}
                            onChange={e => onChange(e)}
                            required
                        />
                    </FormField>
                    <FormField>
                        <Input
                            placeholder='Password'
                            type='password'
                            name='password'
                            value={password}
                            onChange={e => onChange(e)}
                            required
                        />
                    </FormField>
                    <Button type='submit' marginTop='6%'>LOG IN</Button>
                </StyledForm>
                <p>Don't have an account? <Link to='/register'>Sign Up!</Link> </p>
            </FormWrapper>
        </Wrapper>
    )
}

Login.propTypes = {
    login: PropTypes.func.isRequired,
    isAuthenticated: PropTypes.bool
}

const mapStateToProps = state => ({
    isAuthenticated: state.auth.isAuthenticated
});

export default connect(mapStateToProps, { login })(Login);
import React,{useState}来自“React”;
从'react router dom'导入{Redirect};
从'react redux'导入{connect};
从“道具类型”导入道具类型;
从'actions/auth'导入{login};
从“./styled/Wrapper”导入包装器;
从“./styled/Button”导入按钮;
从“./styled/Title”导入标题;
从“./styled/Form”导入{FormWrapper,StyledForm,FormField}
从“./styled/Input”导入输入;
从“./styled/Link”导入链接;
常量登录=(道具)=>{
常量[formData,setFormData]=useState({
电子邮件:“”,
密码:“”
});
const{email,password}=formData;
const onChange=e=>setFormData({…formData[e.target.name]:e.target.value});
const onSubmit=e=>{
e、 预防默认值();
道具登录(电子邮件、密码);
}
如果(道具已验证){
返回
}
返回(
登录
onSubmit(e)}>
onChange(e)}
必修的
/>
onChange(e)}
必修的
/>
登录
没有帐户?注册吧

) } Login.propTypes={ 登录名:PropTypes.func.isRequired, IsAuthentication:PropTypes.bool } 常量mapStateToProps=状态=>({ isAuthenticated:state.auth.isAuthenticated }); 导出默认连接(mapstatetops,{login})(login);
我的测试文件:

import React from 'react';
import { render, cleanup, fireEvent } from '@testing-library/react';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import store from '../../store';

import Login from '../Login';


afterEach(cleanup);
const onChange = jest.fn();


test('<Login>', () => {

    const { queryByTestId, getByPlaceholderText, getByText, debug } =
        render(
            <Provider store={store}>
                <Router>
                    <Login />
                </Router>
            </Provider>);

    expect(queryByTestId('auth-form')).toBeTruthy();

    fireEvent.change(getByPlaceholderText('Email'), {
        target: { value: 'test@yahoo.com' },
    });
    fireEvent.change(getByPlaceholderText('Password'), {
        target: { value: 'testpassword' },
    });

    fireEvent.click(getByText('LOG IN'));
    expect(onChange).toHaveBeenCalledTimes(1);

});
从“React”导入React;
从'@testing library/react'导入{render,cleanup,firevent};
从'react redux'导入{Provider};
从“react Router dom”导入{BrowserRouter as Router};
从“../../store”导入存储;
从“../Login”导入登录名;
每次之后(清理);
const onChange=jest.fn();
测试(“”,()=>{
常量{queryByTestId,getByPlaceholderText,getByText,debug}=
渲染(
);
expect(queryByTestId('auth-form')).toBeTruthy();
fireEvent.change(GetByPlaceholder文本(“电子邮件”){
目标:{值:'test@yahoo.com' },
});
fireEvent.change(GetByPlaceholder文本(“密码”){
目标:{value:'testpassword'},
});
firevent.click(getByText('login'));
期望(一次变更)。已被催收时间(1);
});
测试输出:

 FAIL  src/components/__tests__/Login.test.js
  ✕ <Login> (125 ms)

  ● <Login>

    expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      32 | 
      33 |     fireEvent.click(getByText('LOG IN'));
    > 34 |     expect(onChange).toHaveBeenCalledTimes(1);
         |                      ^
      35 | 
      36 | });

      at Object.<anonymous>.test (src/components/__tests__/Login.test.js:34:22)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        6.013 s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.
src/components/_测试失败\u_/Login.test.js
✕  (125毫秒)
● 
expected(jest.fn())。toHaveBeenCalledTimes(expected)
预期呼叫数:1
收到的呼叫数:0
32 | 
33 | fireEvent.单击(getByText(“登录”);
>34 |预期(一旦改变)。已被催缴的时间(1);
|                      ^
35 | 
36 | });
at Object..test(src/components/__-tests\u_/Login.test.js:34:22)
测试套件:1个失败,共1个
测试:1次失败,共1次
快照:共0个
时间:6时01分
运行与更改的文件相关的所有测试套件。
手表用法:按w键可显示更多信息。

有没有一种方法可以使onSubmit函数在不作为道具通过测试的情况下对测试进行访问?

React测试库的要点是,编写类似于用户如何使用应用程序的测试非常容易。这是我们想要实现的,以给我们充分的信心,这也是业界提倡的。我们编写测试是为了提高对应用程序的信心,而不是提高覆盖率

考虑到上述情况,您不应该使用
来调用时间
,而是应该测试触发
onChange
功能的视觉结果。基于您共享的代码,我不知道成功登录后会呈现什么,但是对于我们的用例,让我们假设文本
Welcome,User渲染

您可以像现在一样触发事件,而不是使用
haveBeenCalled
进行测试,而是使用以下方法:

expect(getByText('Welcome,User!').toBeInTheDocument();


这将为您提供充分的信心,而不是在调用某个函数时进行测试,因为如果函数的实现不正确,您将无法获得足够的信心?

谢谢您的回答,很抱歉,我对我在测试中尝试执行的操作不够清楚。HavebeenCall只是为了让我获得更好的id测试失败的ea。我的目标是测试用户体验。我的onClick处理程序调用登录操作(redux)这会将请求发送到服务器并获取令牌。我需要以某种方式模拟这些函数和此响应,以便成功登录并检查之后显示的元素。对吗?如果我的操作方式错误,请纠正我。我看到您将测试组件包装在
中并注入存储区。这很好,比模拟更好的是,测试还将涵盖redux操作,这实际上是经常进行的,而不是单独编写操作、还原程序等的测试。根据您的代码和您所说的,重定向是基于身份验证的,而身份验证是基于后端的响应。您需要模拟您的响应,并在触发login、 登录页面将显示,然后可以按照我建议的方式进行断言。可以使用类似于
nock
的方法模拟HTTP响应。