React / Jest / Enzyme如何模拟组件中服务的API调用?

时间:2019-08-26 15:01:01

标签: reactjs mocking jestjs enzyme

我有以下内容:

import { runningSince } from '../../services/requestService'

export class Header extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            startDate: null
        }
    }

    async getDataInicializacao() {
        try {
            const response = await runningSince();
            const dtInicializacao = new Date(response.data.data.runningSince);
            this.setState(() => ({ startDate: dtInicializacao}));
        } catch (error) {
            console.log(error)
            this.setState(() => ({ startDate: "Offline" }))
        }
    }

    componentDidMount() {
        this.getDataInicializacao();
    }

    render() { ... }
}

因此,runningSince()是一个异步函数,它调用和API。我的疑问是,如何模拟runningSince()方法?我已经整理过了,requestServiceMock.js

export default {
    runningSince() {
        return Promise.resolve({
            "data": {
              "runningSince": "2019-08-26T11:55:03.696Z"
            }
        })
    }
}

测试:

...
jest.mock('../../services/requestService');

describe('<Header />', () => {

  it('Check running since date-time', () => {
    const wrapper = shallow(<Header handleShutdown={() => {}} />);
    expect(wrapper.find('header .status table tr > td:first-child > span').text().trim()).toEqual('26/08/2019 08:55:03');
  });
});

但这无法正常工作,感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

这是解决方案:

index.tsx

import React from 'react';
import { runningSince } from './requestService';

interface IHeaderState {
  startDate: string | null | Date;
}

export class Header extends React.Component<{}, IHeaderState> {
  constructor(props) {
    super(props);
    this.state = {
      startDate: null
    };
  }

  public async getDataInicializacao() {
    try {
      const response = await runningSince();
      const dtInicializacao = new Date(response.data.runningSince);
      this.setState(() => ({ startDate: dtInicializacao.toString() }));
    } catch (error) {
      console.log(error);
      this.setState(() => ({ startDate: 'Offline' }));
    }
  }

  public componentDidMount() {
    this.getDataInicializacao();
  }

  public render() {
    return <div>{this.state.startDate}</div>;
  }
}

requestService.ts

export async function runningSince() {
  return {
    data: {
      runningSince: 'real data'
    }
  };
}

index.spec.tsx

import React from 'react';
import { Header } from './';
import { shallow, mount } from 'enzyme';
import * as requestService from './requestService';

jest.mock('./requestService.ts', () => {
  return {
    runningSince: jest.fn()
  };
});

describe('Header', () => {
  it('t1', done => {
    const mockedData = {
      data: {
        runningSince: '2019-08-26T11:55:03.696Z'
      }
    };
    (requestService.runningSince as jest.MockedFunction<typeof requestService.runningSince>).mockResolvedValueOnce(
      mockedData
    );
    const wrapper = shallow(<Header></Header>);
    setImmediate(() => {
      expect(wrapper.state()).toEqual({ startDate: new Date(mockedData.data.runningSince).toString() });
      expect(wrapper.text()).toEqual(new Date(mockedData.data.runningSince).toString());
      expect(wrapper).toMatchSnapshot();
      done();
    });
  });
});

带有覆盖率报告的单元测试结果:

 PASS  src/stackoverflow/57660437/index.spec.tsx
  Header
    ✓ t1 (18ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    85.71 |      100 |    85.71 |     87.5 |                   |
 index.tsx |    85.71 |      100 |    85.71 |     87.5 |             22,23 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        5.837s

以下是完整的演示:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57660437