React Enzyme setState не работает при попытке протестировать с помощью mount

Я пытаюсь протестировать этот блок кода в своем приложении React с помощью Jest и Enzyme:

  openDeleteUserModal = ({ row }: { row: IUser | null }): any => (
    event: React.SyntheticEvent
  ): void => {
    if (event) event.preventDefault();
    this.setState({ userToDelete: row, isDeleteUserModalOpen: true });
  };

Это тест:

    describe('OpenDeleteUserModal', () => {
      let wrapper: ReactWrapper;
      let instance: any;
      beforeEach(() => {
        wrapper = mount(
          <MemoryRouter>
            <Route render = {props => <UsersOverviewScreen {...props} {...defaultProps} />} />
          </MemoryRouter>
        );
        instance = getComponentInstance(wrapper);
        instance.openDeleteUserModal({ user: mockUser });
        wrapper.update();
      });
      it('should SET the isDeleteUserModalOpen to true', () => {
        expect(instance.state.isDeleteUserModalOpen).toBeTruthy();
      });
      it('should SET the userToDelete to mockUser', () => {
        expect(instance.state.userToDelete).toEqual(mockUser);
      });
    });

Тест и файл имеют .tsx, что означает, что необходим весь шаблон, касающийся React Router. Я получаю обратно false и undefined вместо true.

Я пытался имитировать щелчок, но безуспешно. Смотри ниже:

      it('should SET the isDeleteUserModalOpen to true', () => {
        const deleteUserButton = wrapper.find('renderUsers').find('button');
        deleteUserButton.simulate('click');
        jest.spyOn(instance, 'openDeleteUserModal');
        instance.openDeleteUserModal();
        expect(instance.openDeleteUserModal).toHaveBeenCalled();
        expect(instance.state.isDeleteUserModalOpen).toBeTruthy();
      });

Может кто-нибудь помочь мне понять, почему это не удается.

Можете поделиться журналом ошибок?

Dehan 09.04.2019 10:27
{Expected: true, Received: false}, for the first test. {Expected: MockUser, Recieved: undefined}. Это ошибка, которую я получаю с решением, которое я пробовал, или без него. Кажется, событие click не происходит.
user10104341 09.04.2019 11:05

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

user10104341 09.04.2019 12:25
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
5 052
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я просматривал энзим github образцы ферментных тестов. Попробуйте это

describe('OpenDeleteUserModal', () => {
  let wrapper: ReactWrapper;
  let instance: any;
  beforeEach(() => {
    wrapper = mount(
      <MemoryRouter>
        <Route render = {props => <UsersOverviewScreen {...props} {...defaultProps} />} />
      </MemoryRouter>
    );
    instance = getComponentInstance(wrapper);
    instance.openDeleteUserModal({ user: mockUser });
    // wrapper.update(); --don't think this is required but do check!
  });
  it('should SET the isDeleteUserModalOpen to true', () => {
    //expect(instance.state.isDeleteUserModalOpen).toBeTruthy();
    expect(wrapper.state('isDeleteUserModalOpen')).toBeTruthy();
  });
  it('should SET the userToDelete to mockUser', () => {
    //expect(instance.state.userToDelete).toEqual(mockUser);
    expect(wrapper.state('userToDelete')).toEqual(mockUser);
  });
});

This is most probably because setState() is an async operation. When your test line runs the relevant state might not have been initialized. Enzyme seems to have provided an API for this.

Для второй части это небольшая оговорка в Enzyme при тестировании стрелочных функций. Проверьте мой ответ здесь. Следующий код должен решить вашу проблему.

 it('should SET the isDeleteUserModalOpen to true', () => {
    const deleteUserButton = wrapper.find('renderUsers').find('button');
    deleteUserButton.simulate('click');

    //this returns an object which will record interactions on 'openDeleteUserModal'
    const spy = jest.spyOn(instance, 'openDeleteUserModal');
    //Force update on the component is required for the spy to 'latch onto' an arrow function
    instance.forceUpdate();

    instance.openDeleteUserModal();

    //You have to check your spy object not the instance method
    expect(spy).toHaveBeenCalled();

    expect(instance.state('isDeleteUserModalOpen')).toBeTruthy();
  });

Спасибо. Но это только часть решения. Мой OpenDeleteUserModal - это метод (функция внутри другой функции). Таким образом, он не вызывал вторую функцию, чтобы проверить данные, а вызов..

user10104341 09.04.2019 17:18

@DimitrisEfst Проверьте это сейчас

Dehan 09.04.2019 17:45

Я сделал еще несколько изменений.

Dehan 09.04.2019 17:50

Глядя на это несколько лет спустя. Спасибо за ваше объяснение. Но разве использование instance.state не считается анти-шаблоном? Из того, что я вижу в документах, они просят вас использовать оболочку для доступа к значениям состояния.

visylvius 06.06.2020 03:57

Однако я пришел сюда в поисках решения, если ответы не сработали для меня. Проконсультировавшись с документом Enzyme, я обнаружил, что setState() отлично работает для меня. Ниже приведено мое решение с setState(), нам не нужно вызывать Обновлять(), так как setState() повторно отображает компонент.

describe('OpenDeleteUserModal', () => {
  let wrapper: ReactWrapper;
  let instance: any;
  beforeEach(() => {
    wrapper = mount(
      <MemoryRouter>
        <Route render = {props => <UsersOverviewScreen {...props} {...defaultProps} />} />
      </MemoryRouter>
    );
    
  });
  it('should SET the isDeleteUserModalOpen to true', () => {
    expect(wrapper.setState({isDeleteUserModalOpen: true}).toBeTruthy();
  });
  it('should SET the userToDelete to mockUser', () => {
    expect(wrapper.setState({userToDelete: mockUser})).toEqual(mockUser);
  });
});

Другие вопросы по теме