Как использовать jest.spyOn с компонентом функции React с использованием Typescript

Я разрабатываю приложение React с использованием Typescript и хуков, и я пытаюсь использовать Enzyme с Jest для тестирования компонентов функций. Я не могу использовать jest.spyOn для тестирования метода в моем компоненте. Метод jest.spyOn не разрешается правильно и показывает следующее сообщение при наведении

"Аргумент типа" validateBeforeSave"не может быть назначен параметру типа"context" | "setState" | "forceUpdate" | "render" | "componentDidMount" | "shouldComponentUpdate" | "componentWillUnmount" | "componentDidCatch" | "getSnapshotBeforeUpdate" | ... еще 6... | "UNSAFE_componentWillUpdate"'.ts(2345)"

Я пытался разыграть экземпляр как "Любой" -

const instance = wrapper.instance() as any;

Это, конечно, игнорирует проблему во время компиляции, но затем тест выдает ошибку времени выполнения, что функция не существует в компоненте.

Невозможно следить за свойством validateBeforeSave, поскольку оно не является функцией; вместо этого дано неопределенное

// Some function Component

const SomeComponent = (props: IMyComponentProps) => {
  const { classes } = props;

  // Component has state
  const [count, setCount] = useState(0);

  function validateBeforeSave(){

  }

  function handleClick() {
  validateBeforeSave();
  .
  .
  .
  }

  return (
   <div>
      <Button>
      className="saveBtn"
      onClick={handleClick}
      </Button>
    </div>
  );

  };

  // Unit test
  describe('SomeComponent' () => {
  it('validates model on button click', () => {
      const wrapper = mount(
        <MuiThemeProvider theme={theme}>
          <SomeComponent/>
        </MuiThemeProvider>,
      );
  const instance = wrapper.instance();
      const spy = jest.spyOn(instance, "validateBeforeSave");
  wrapper
        .find('.saveBtn')
        .at(0)
        .simulate('click');
      expect(spy).toHaveBeenCalledTimes(1);
    });
  }

Что мне здесь не хватает? Как spyOn работает с функциональными компонентами?

Я создал приложение с помощью шаблона create-реагировать на приложение, и оно имеет эти зависимости для тестовых пакетов

"devDependencies": {
    "ts-jest": "^23.10.3",
    "@types/jest": "24.0.9",
    "@types/enzyme": "^3.9.1",
    "@types/enzyme-adapter-react-16": "^1.0.2",
    "enzyme": "^3.9.0",
    "enzyme-adapter-react-16": "^1.11.2",
    "enzyme-to-json": "^3.3.5",
  }

3 ответа

Решение

Публикация моего комментария здесь снова, чтобы ответить на ваш вопрос: Ваш validateBeforeSave функция объявлена ​​в SomeComponent делая его закрытой / закрытой областью, недоступной снаружи. Вы можете передать эту функцию в качестве реквизита, а затем создать шпиона и передать его в качестве значения реквизита в своем тесте и проверить, была ли вызвана пропущенная функция (шпион) или нет.

Таким образом, вы бы изменили свою функцию примерно так:

// some validator function
function validateBeforeSave(){
  ...
}

// Some function Component

const SomeComponent = (props: IMyComponentProps) => {
  const { classes, validateBeforeSave } = props;

  // Component has state
  const [count, setCount] = useState(0);


  function handleClick() {
  validateBeforeSave();
  .
  .
  .
  }

  return (
   <div>
      <Button>
      className="saveBtn"
      onClick={handleClick}
      </Button>
    </div>
  );

};

И в вашем модульном тесте, что-то вроде этого:

  // Unit test
  describe('SomeComponent' () => {
  it('validates model on button click', () => {
      const validateSpy = jest.fn();
      const wrapper = mount(
        <MuiThemeProvider theme={theme}>
          <SomeComponent validateSpy={validateSpy}/>
        </MuiThemeProvider>,
      );
      const instance = wrapper.instance();
      wrapper
        .find('.saveBtn')
        .at(0)
        .simulate('click');
      expect(validateSpy).toHaveBeenCalledTimes(1);
    });
  }

Я также столкнулся с той же проблемой - мне понравилось ниже -

import * as React from 'react';

const SampleComponent = () => {
  const sampleMethod = () => {
    console.log('hello world');
  };

  return <button onClick={sampleMethod} type="button">Click Me</button>;
};

export default SampleComponent;

контрольная работа -

import React from 'react';
import SampleComponent from './';
import { shallow } from 'enzyme';

describe('SampleComponent', () => {
  test('should handle click correctly', () => {
    const logSpy = jest.spyOn(console, 'log');
    const wrapper = shallow(<SampleComponent></SampleComponent>);
    const button = wrapper.find('button');
    expect(button.text()).toBe('Click Me');
    button.simulate('click');
    expect(logSpy).toBeCalledWith('hello world');
  });
});

Мы можем шпионить за console.log, чтобы утверждать, что он должен вызываться или нет

Проверить - /questions/51048212/slezhka-za-metodom-funktsionalnyih-komponentov-react-s-pomoschyu-shutki-i-enzima/51048229#51048229

У меня была аналогичная проблема с имитацией метода обратного вызова с React 16.xx, метод экземпляра фермента возвращает значение null, что вы можете сделать, это передать напрямую jest.fn() в качестве опоры.

ПРИМЕР:

        it('should invoke callback with proper data upon checkbox click', () => {
    const spyCheckboxClick = jest.fn((id, item) => ({
      id,
      item,
    }))
    const component: any = enzyme.mount(
      <SectionColumn {...{
        ...mockProps,
        onCheckboxClick: spyCheckboxClick,
      }} />
    );
    expect(spyCheckboxClick).toHaveBeenCalledTimes(0);
    // perform click to checkbox
    const checkboxComponent = component.find('StyledCheckbox');
    const input = checkboxComponent.first().children();
    input.simulate('change');
    expect(spyCheckboxClick).toHaveBeenCalledTimes(1);
    expect(spyCheckboxClick()).toEqual(null)
 });
Другие вопросы по тегам