Как смоделировать вызов функции, который вызывает вызов - PullRequest
0 голосов
/ 25 сентября 2019

У меня есть код реакции, как показано ниже

handleSubmit(event) {
  event.preventDefault();

    this.setState({ isDone: true });

    ...do some operations...

    this.getName();
}

Вышеуказанный handleSubmit является частью компонента GetNames, который, в свою очередь, вызывает другую функцию, как показано ниже, снова часть того же компонента.

getName() {
   var urlendPoint = new URL(propertiesInFile.urltoPing)

    var params = {
      firstName: this.state.firstName,
      lastName: this.state.lastName
    }

    urlendPoint.search = new URLSearchParams(params)

    fetch(urlendPoint).then(response => response.json()).then((data) => {
        // ...perform some actions...
    })
      .catch(error => {
        alert("Please check the names and try again");
      });
}

Я пишу тестовые случаи для функций, описанных выше, но не понимаю, как имитировать данные выборки.Ниже приведен мой тестовый пример

describe('GetNames submit', () => {
    let wrapper = shallow(<GetNames />).instance();
    let getDetailsSpy;

    beforeEach(() => {
        getDetailsSpy = jest.spyOn(GetDetails.prototype, 'getDetails');
        wrapper = shallow(<GetDetails></GetDetails>);
    });

    afterEach(() => {
        jest.resetAllMocks();
    });

    it('check submit', () => {

      expect(wrapper.find('form')).toHaveLength(1);
      const formEventMocked = { preventDefault: jest.fn() };
      const state = {
        firsName: 'test1',
        lastName: 'test2',
        isDone: false
      };
      wrapper.setState(state);
      wrapper.find('form').simulate('submit', formEventMocked);

     fetch.mockResponse(() => getName().then(res => ({body: res})));

      expect(getDetailsSpy).toBeCalledTimes(1);
      expect(formEventMocked.preventDefault).toBeCalledTimes(1);
      expect(wrapper.state('loading')).toBeTruthy();
    });
});

. Выше я смоделировал ответ getDetails, но тест завершился неудачно с ошибкой ReferenceError: fetch is not defined при вызове выборки.

Как создать этот контрольный пример, в котором я могу вернуть результат вызова выборки или вызвать метод и проверить его, используя фиктивные объекты для выборки всех?

1 Ответ

0 голосов
/ 25 сентября 2019

Вы можете использовать wrapper.instance().someMethod для проверки getName метода Component.

Я использую модуль node-fetch для среды nodejs, для среды браузера, то же самое.Вы можете использовать jest.mock метод mock node-fetch или window.fetch модуль вручную.

index.tsx:

import React, { Component } from 'react';
import fetch from 'node-fetch';
import console = require('console');

export interface ISomeComponentState {
  firstName: string;
  lastName: string;
  isDone: boolean;
  [key: string]: any;
}

export class SomeComponent extends Component<any, ISomeComponentState> {
  constructor(props) {
    super(props);

    this.state = {
      firstName: '',
      lastName: '',
      isDone: false
    };
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
  }

  public render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <label>
            firstName:
            <input
              type="text"
              name="firstName"
              placeholder="enter your first name"
              value={this.state.firstName}
              onChange={this.handleInputChange}
            />
          </label>
          <label>
            lastName:
            <input
              type="text"
              name="lastName"
              placeholder="enter your last name"
              value={this.state.lastName}
              onChange={this.handleInputChange}
            />
          </label>
          <div>
            <input type="submit" value="Submit" />
          </div>
        </form>
      </div>
    );
  }

  private handleInputChange(event: React.ChangeEvent<HTMLInputElement>) {
    const target = event.target;
    const name = target.name;
    const value = target.value;

    this.setState({ [name]: value });
  }

  private handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();

    this.setState({ isDone: true });

    const nameMatch = () => {
      return !(this.state.firstName.match('^Cel.*') && this.state.firstName.endsWith('on'));
    };

    if (nameMatch()) {
      alert('Please enter a valid name');
      return;
    }

    if (!this.state.lastName.endsWith('on')) {
      alert('check lastname too');
      return;
    }
    this.getFullName();
  }

  private getFullName() {
    // const urlendPoint = new URL('https://github.com/mrdulin');

    const params = {
      firstName: this.state.firstName,
      lastName: this.state.lastName
    };

    const urlendPoint = `https://github.com/mrdulin?fistName=${params.firstName}&lastName=${params.lastName}`;

    // (urlendPoint as any).search = new URLSearchParams(params);

    return fetch(urlendPoint)
      .then(response => response.json())
      .then(data => data)
      .catch(error => {
        alert('Please check the names and try again');
      });
  }
}

index.spec.tsx:

import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
import { SomeComponent, ISomeComponentState } from './';
import console = require('console');
import fetch from 'node-fetch';

const { Response } = jest.requireActual('node-fetch');

jest.mock('node-fetch', () => jest.fn());

describe('SomeComponent', () => {
  describe('#handleSubmit', () => {
    let wrapper: ShallowWrapper;
    let getFullNameSpy;
    let alertSpy;
    beforeEach(() => {
      alertSpy = jest.spyOn(window, 'alert');
      getFullNameSpy = jest.spyOn(SomeComponent.prototype as any, 'getFullName');
      wrapper = shallow(<SomeComponent></SomeComponent>);
    });
    afterEach(() => {
      jest.resetAllMocks();
      getFullNameSpy.mockRestore();
    });
    it('check submit', () => {
      expect(wrapper.find('form')).toHaveLength(1);
      getFullNameSpy.mockResolvedValueOnce('fullName');
      const formEventMocked = { preventDefault: jest.fn() };
      const state: ISomeComponentState = {
        firstName: 'Cel.du.on',
        lastName: 'lin.on',
        isDone: false
      };
      wrapper.setState(state);
      expect(wrapper).toMatchSnapshot();
      wrapper.find('form').simulate('submit', formEventMocked);
      expect(getFullNameSpy).toBeCalledTimes(1);
      expect(formEventMocked.preventDefault).toBeCalledTimes(1);
      expect(wrapper.state('isDone')).toBeTruthy();
    });

    it('should alert when first name is invalid', () => {
      expect(wrapper.find('form')).toHaveLength(1);
      const formEventMocked = { preventDefault: jest.fn() };
      const state: ISomeComponentState = {
        firstName: 'du',
        lastName: 'lin.on',
        isDone: false
      };
      wrapper.setState(state);
      expect(wrapper).toMatchSnapshot();
      wrapper.find('form').simulate('submit', formEventMocked);
      expect(alertSpy).toBeCalledWith('Please enter a valid name');
      expect(formEventMocked.preventDefault).toBeCalledTimes(1);
      expect(wrapper.state('isDone')).toBeTruthy();
    });

    it('should alert when last name is invalid', () => {
      expect(wrapper.find('form')).toHaveLength(1);
      const formEventMocked = { preventDefault: jest.fn() };
      const state: ISomeComponentState = {
        firstName: 'Cel.du.on',
        lastName: 'lin',
        isDone: false
      };
      wrapper.setState(state);
      expect(wrapper).toMatchSnapshot();
      wrapper.find('form').simulate('submit', formEventMocked);
      expect(alertSpy).toBeCalledWith('check lastname too');
      expect(formEventMocked.preventDefault).toBeCalledTimes(1);
      expect(wrapper.state('isDone')).toBeTruthy();
    });
  });

  describe('#getFullName', () => {
    let wrapper: ShallowWrapper;
    let alertSpy;
    beforeEach(() => {
      alertSpy = jest.spyOn(window, 'alert');
      wrapper = shallow(<SomeComponent></SomeComponent>);
    });
    it('should fetch data correctly', async () => {
      (fetch as jest.MockedFunction<typeof fetch>).mockResolvedValueOnce(
        new Response(JSON.stringify({ data: 'mocked data' }))
      );
      wrapper.setState({ firstName: 'du', lastName: 'lin' });
      const actualValue = await (wrapper.instance() as any).getFullName();
      expect(actualValue).toEqual({ data: 'mocked data' });
      expect(fetch).toBeCalledWith(`https://github.com/mrdulin?firstName=du&lastName=lin`);
    });

    it('should alert when fetch data error', async () => {
      const mockedFetchError = new Error('some error');
      (fetch as jest.MockedFunction<typeof fetch>).mockRejectedValueOnce(mockedFetchError);
      wrapper.setState({ firstName: 'lin', lastName: 'du' });

      const actualValue = await (wrapper.instance() as any).getFullName();
      expect(actualValue).toBeUndefined();
      expect(fetch).toBeCalledWith(`https://github.com/mrdulin?firstName=lin&lastName=du`);
      expect(alertSpy).toBeCalledWith('Please check the names and try again');
    });
  });
});

Результат модульного теста с отчетом о покрытии:

 PASS  src/stackoverflow/58085900/index.spec.tsx
  SomeComponent
    #handleSubmit
      ✓ check submit (17ms)
      ✓ should alert when first name is invalid (5ms)
      ✓ should alert when last name is invalid (3ms)
    #getFullName
      ✓ should fetch data correctly (3ms)
      ✓ should alert when fetch data error (2ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    89.19 |      100 |       90 |    88.24 |                   |
 index.tsx |    89.19 |      100 |       90 |    88.24 |       58,59,60,62 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   3 passed, 3 total
Time:        4.925s, estimated 6s

Вот демо: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58085900

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...