Издевательство над текущим значением react ref в шутку для неглубокого теста

#javascript #reactjs #jestjs #enzyme #ref

#javascript #reactjs #jestjs #фермент #ссылка

Вопрос:

Я пытаюсь издеваться this.ref.current.value как часть теста функции в моем компоненте React. В настоящее current время равно нулю, потому что я выполняю неглубокое монтирование своего компонента. Я пытаюсь найти способ издеваться над тем, что current.value возвращается для моего ref, чтобы я мог протестировать другую часть функции, значение refs на самом деле не имеет значения для этого теста.

Фактическая функция:

 copyDefinitionTarget = selectedInput => () => {
    // get and select the input value
    const copyText = this[`${selectedInput}`].current.value;

    // copy to clipboard
    navigator.clipboard.writeText(copyText);
  };
 

Тестовый код:

 it('calls navigator.clipboard appropriately to copy the text in copyDefinitionTarget', () => {
    component = shallow(<Alert {...props} />);

    component
      .dive()
      .find('Item')
      .dive()
      .find('Button')
      .simulate('click');

    expect(navigator.clipboard.writeText).toHaveBeenCalled();
  });
 

Сбой теста:

 TypeError: Cannot read property 'value' of null

      50 |     // get and select the input value
    > 51 |     const copyText = this[`${selectedInput}`].current.value;
 

Есть ли какой-нибудь способ сделать это? Я забочусь о тестировании того, что navigator.clipboard вызывался не так, как он был вызван.

Обновление, потому что я изменил свой код для использования this.ref вместо stringRefName фактической функции:

 copyDefinitionTarget = selectedInput => () => {
    // get and select the input value
    const copyText = selectedInput.current.value;
    // copy to clipboard
    navigator.clipboard.writeText(copyText);
  };
 

Тестовый код:

 it('calls navigator.clipboard appropriately to copy the text in copyDefinitionTarget', () => {
    component = shallow(<Alert {...props} />);
instance = component.instance();

    // we are clicking on the first Alert Item
    // so mock that ref specifically
    instance.firstNameRef = {
      current: {
        value: 'stuff'
      }
    };

    component
      .dive()
      .find('Item')
      .dive()
      .find('Button')
      .simulate('click');

    expect(navigator.clipboard.writeText).toHaveBeenCalled();
  });
 

Вызов функции:

 <Item
 inputRef={this.firstNameRef}
 inputValue={`${realmName}`}
 copyDefinitionTarget={this.copyDefinitionTarget(this.firstNameRef)}
/>
 

Ответ №1:

Вы могли бы пойти дальше и сделать что-то вроде этого:

 const component = shallow(<Alert {...props} />);
const selectedInput = 'ref';
component.instance()[selectedInput] = {
  current: {
    value: 'stuff'
  }
}
navigator.clipboard = {writeText: jest.fn()}
component
  .dive()
  .find('Item')
  .dive()
  .find('Button')
  .simulate('click');
expect(navigator.clipboard.writeText).toHaveBeenCalled();
 

Примечание: я не уверен, какой selectedInput должна быть строка, вы можете передать любую строку, которая подходит в соответствии с вашим реальным кодом компонента.

Поскольку ref существует как свойство экземпляра компонента, вы можете просто передать любой объект, который вы хотите, пока он выглядит current.value , затем вы можете заменить функцию копирования на макет, имитировать щелчок, а затем посмотреть, был ли writeText вызван.

Комментарии:

1. Это сработало, спасибо! Просто примечание для всех, кто использует это const selectedInput = 'ref' ; "ref" должен быть тем, что является ссылкой для ввода, на который вы ориентируетесь, в моем случае это было firstNameRef

2. Итак, я обновил свой вызов функции для использования this вместо string, так что теперь onClick есть copyDefinitionTarget={this.copyDefinitionTarget(this.firstNameRef)} , и макет больше не работает. Знаете ли вы, как мне нужно будет обновить свой тест, чтобы он снова заработал? Я пробую несколько разных способов, но он продолжает говорить, что текущее значение возвращается к нулевому коду: « component.instance().firstNameRef = { current: { value: ‘stuff’ } }; «

3. @caraclarke как теперь выглядит функция copyDefinitionTarget? И как именно выглядит тест с вашими изменениями. Не могли бы вы обновить вопрос, пожалуйста?

4. обновил вопрос новым кодом, он вернулся к тому, чтобы выдать мне исходное сообщение об ошибке теста, которое было «Не удается прочитать значение свойства ‘value’ null» и когда я пытаюсь утешить. в журнале selectedInput для моего теста написано {current: null}

5. @caraclarke я предполагаю, что дочерний компонент получает свойство до того, как оно было установлено извне в тесте, вы могли бы попробовать вызвать component.update() перед попыткой щелчка

Ответ №2:

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

Фактический код:

   // get the value from ref
  getRefValue = ref => ref.current.value;

  // copy value
  copyDefinitionTarget = selectedInput => () => {
    // get and select the input value
    const copyText = this.getRefValue(selectedInput);
    // copy to clipboard
    navigator.clipboard.writeText(copyText);
  };
 

Тестовый код:

 it('calls navigator.clipboard appropriately to copy the text in copyDefinitionTarget', () => {
    component = shallow(<MetadataAlert {...props} />);
    instance = component.instance();

    jest.spyOn(instance, 'getRefValue').mockImplementationOnce(() => '💻');

    component
      .dive()
      .find('Item')
      .dive()
      .find('Button')
      .simulate('click');

    expect(navigator.clipboard.writeText).toHaveBeenCalled();
  });