繁体   English   中英

用jestjs mock模拟axios.get时reactjs空数据

[英]reactjs empty data when mocking axios.get with jestjs mock

我正在开发一个反应应用程序,我第一次决定实施测试。 我从更简单的组件开始,但我仍然遇到了麻烦,但现在我想测试更复杂的组件,尤其是通过 axios 调用 API。

我的应用程序如下所示:

import * as React from "react";
import Axios from "axios";
import { AnyData } from "../../interface/AnyDataInterface";

interface IProps {
}

interface IState {
  loading: boolean | undefined,
  myData: AnyData | undefined
}

export default class Home extends React.Component <IProps, IState> {
  constructor (props: IProps){
    super(props);
    this.state = {
      loading: true,
      myData: {
        field: undefined,
        ...
      }
    };
  }

  fetchData = ():void => {
    this.setState({ loading: true });
    Axios.get<AnyData>('my-url')
      .then(res => {
        if (res.status === 200 && res != null) {
          this.setState({ myData:{... res.data} });
          this.setState({ loading: false });
        } else {
          console.log('problem when fetching the logs from backend');
                }
        })
      .catch(error => {
        console.log(error);
      });
  }

  render():JSX.Element {
    return(
      <div className="container">
        <div>
            <button role="button" onClick={this.fetchData}>Search</button>
        </div>
        {this.state.loading == true ? <p>Wait</p>:
          <div role="composite">
            { Some child component that will render data }
          </div>
        }
      </div>
    );
  }
}

我的测试如下所示:

import axios from 'axios';
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';

import Home from './Home';

jest.mock('axios');

describe('Home component', () => {
 test('it can be clicked', async () => {
    const fakeData = [{
      some_field: some_data,
      ...
    }];

    axios.get = jest.fn().mockResolvedValue(() => 
      Promise.resolve({data: fakeData}));

    render(<Home />);

    fireEvent.click(screen.getByRole('button'));
    await waitFor(() => {
      expect(axios.get).toBeCalledWith("my-url");
    });

    await waitFor(() => {
      //Both expect should pass, if the title is there the data should also appear
      expect(screen.getByText('some title text')).toBeInTheDocument(); //Pass without error
      expect(screen.getByText('the data from fakeData that should be there')).toBeInTheDocument(); //Send me an error because jest is unable to find some_data
    });
 });
});

当我编写这个测试时,它每次都失败,但问题不在我的测试中,问题出在我的数据获取函数中。 .then我有一个条件如下: if (res.status === 200 && res != null) {res.status === 200是一个从未满足的条件。

所以我删除了这个条件,通话正常进行。 但是我不得不更改我通常没有问题的代码的一部分,有没有办法模拟响应的状态呢? 这样我就可以把这个条件放回我的函数中。

我现在出现了另一个问题,在我的测试中,我的组件很好地显示了“点击后”的信息,但是出现的每个字段都有其相应的空数据,数据似乎没有通过,尽管.then通过并且没有将我发送到.catch

对我来说奇怪的是,通过在我的数据获取函数中删除条件res.status === 200并保留条件res != null ,测试仍然通过(同样的空数据问题)。 最后,通过添加一个console.log("data: ", res); 在我的.then在我的组件的 fetch data 函数中,当测试执行时,我得到以下日志: data: [Function (anonymous)]

我不知道这是否可以解释这种行为,但我的测试是在 javascript 中,而我的类和函数是在打字稿中。 但是我在测试中填写的数据具有正确的形式(与我班级中请求的类型相同)所以打字稿应该看到类型匹配并且没有特别的问题

如果有人知道如何回答这些问题中的任何一个,那真的会对我有所帮助,我已经在这个测试上拖延了一段时间,它开始让我发疯。

编辑:

我刚刚意识到,在我的组件中的 fetchData() 中,我试图访问res.data但我在测试中发送的假数据采用fakeData = [{...}]的形式。 这可能是我的对象为空的原因吗?

我试图在我的测试中将这个假数据更改为: fakeData = [{ data: { ...}}]但是我在调​​用axios的get方法时仍然遇到空响应的问题。

编辑:

我尝试将测试文件更改为 .tsx 文件,并将测试中的“fakeData”更改为:

jest.mock('axios');

describe('Home component', () => {
 test('it can be clicked', async () => {
    const fakeData: AnyData = {
      "some_field": some_data,
      ...
    };

    const fakeConfig: AxiosRequestConfig<any> = {
      "maxBodyLength": -1
    };

    const fakeHeaders: AxiosResponseHeaders= {
      "access-control-allow-credentials": "true",
      "access-control-allow-headers": "*",
      "access-control-allow-methods": "*",
      "access-control-allow-origin": "some-url",
      "access-control-expose-headers": "scrollId",=
      "content-type": "application/json; charset=utf-8",
      ....
      "x-powered-by": "Express"
    }

    const res: AxiosResponse<AnyData, any> = { 
      config: fakeConfig,
      data: fakeData,
      headers: fakeHeaders,
      status: 200,
      statusText: "OK",
     };

    axios.get = jest.fn().mockResolvedValue(() => 
      Promise.resolve({res: res}));

    render(<Home />);

    fireEvent.click(screen.getByRole('button'));
    await waitFor(() => {
      expect(axios.get).toBeCalledWith("my-url");
    });
     
    ...
 });
});

但即使使用这种方法,它仍然不起作用,但我真的觉得问题出在我发送的数据的格式上,我看不出我的数据与fetchData()中请求的数据有何不同。 至于我数据中的字段,我确定它们很好,所以我猜问题出在res.data的读取上。

当我通过将myDataconsole.log放入fetchData()进行新测试时,我得到以下数据: { some_field: undefined, ... }

如果您花时间帮助我,请提前致谢。

我终于在考试中意识到了自己的错误。 这是在重写 axios.get 方法。

有效的代码如下:

jest.mock('axios');

describe('Home component', () => {
 test('it can be clicked', async () => {
    const fakeData: AnyData = {
      "some_field": some_data,
      ...
    };

    const fakeConfig: AxiosRequestConfig<any> = {
      "maxBodyLength": -1
    };

    const fakeHeaders: AxiosResponseHeaders= {
      "access-control-allow-credentials": "true",
      "access-control-allow-headers": "*",
      "access-control-allow-methods": "*",
      "access-control-allow-origin": "some-url",
      "access-control-expose-headers": "scrollId",=
      "content-type": "application/json; charset=utf-8",
      ....
      "x-powered-by": "Express"
    }

    const res: AxiosResponse<AnyData, any> = { 
      config: fakeConfig,
      data: fakeData,
      headers: fakeHeaders,
      status: 200,
      statusText: "OK",
     };

    (axios.get as jest.Mock).mockResolvedValue(res); //THE LINE THAT CHANGE EVERYTHING

    render(<Home />);

    fireEvent.click(screen.getByRole('button'));
    await waitFor(() => {
      expect(axios.get).toBeCalledWith("my-url");
    });
     
    ...
 });
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM