Jest / React - Как проверить результаты обновления состояния useState в функции - PullRequest
0 голосов
/ 22 февраля 2020

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

const [cart, setCart] = useState([]);

const onUpdateItemQuantity = (cartItem, quantityChange) => {
    const newCart = [...cart];
    const shouldRemoveFromCart = quantityChange === -1 && cartItem.count === 1;
    ...
    if (shouldRemoveFromCart) {
      newCart.splice(cartIndex, 1);
    } else {
      ...
    }
    setCart(newCart); //the useState function is called
}

Итак, в шутку, у меня есть функция, которая проверяет, когда пользователь устанавливает количество товара в корзине на ноль, но он еще не удаляет товар из корзины, я предполагаю, потому что он еще не получил результаты setCart(newCart):

test('on decrement item from 1 to 0, remove from cart', () => {
      const [cartItemToDecrement] = result.current.cartItems;
      const productToDecrement = result.current.products.find(
        p => p.id === cartItemToDecrement.id
      );

      act(() => {
        result.current.decrementItem(cartItemToDecrement);
      });

      act(() => {
        result.current.decrementItem(cartItemToDecrement);
      });

      ...

      expect(result.current.cartItems).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            id: cartItemToDecrement.id,
            count: cartItemToDecrement.count - 2,
            inventory: productToDecrement.inventory + 2
          })
        ])
      ); 
    });
  });

Этот тест проходит успешно, потому что в корзине теперь есть товар, количество которого упало до нуля. Но на самом деле это не должно происходить, потому что из операции splice в onUpdateItemQuantity наш массив cartItems теперь не должен вообще включать объект. Как мне проверить в моем шутливом тесте, что это удаление происходит (код реакции работает правильно).

Ответы [ 4 ]

1 голос
/ 27 февраля 2020

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

Но из вашего вопроса есть 2 подсказки, которые могут помочь сэкономьте ваше время.

  1. Возможно, вы знаете, setCart из useState не является синхронным, поэтому, если вы попытаетесь получить доступ к cart из useState в том же кадре, это не должны отражать изменения, даже если вы обеспечили setCart вызов. useEffect - хорошее решение. Вы можете найти do c из useEffect [https://reactjs.org/docs/hooks-effect.html] [1] , любое изменение должно быть отражено в useEffect, возможно, вы можете поставить свой тест там.

  2. Добавьте дополнительную переменную myCart для хранения cart и функцию setMyCart. Вместо того, чтобы звонить setCart в своем коде, звоните setMyCart. setMyCart, как,

  function setMyCart(newCart)
  {
     myCart = newCart;
     setCart(myCart); // this is for triggering React re-render
  }

, затем используйте myCart, который может немедленно отразить изменение для тестирования.

Единственная цель дополнительного кода во 2-м пункте, когда мы все еще полагаемся на механизм повторного рендеринга React, мы используем собственный Model myCart для наших конкретных логик c состояние cart от React, которое не только для View, но и используется для наших логи c в неподходящих случаях.

0 голосов
/ 02 марта 2020

Если вам нужно протестировать каждое обновление состояния с помощью useState (), вы можете сделать это, внедрив функцию useEffect, специально прослушивающую это изменение состояния, в вашем случае, cart:

useEffect(() => {
    test(...)
), [cart]);

И так Вы можете выполнить тест внутри функции useEffect ().

Это обеспечит правильное значение корзины и будет вызываться при каждом обновлении корзины.

0 голосов
/ 02 марта 2020

Совершенно неясно, как называется onUpdateItemQuantity. И даже то, что он делает точно. Тем не менее, вы утверждаете, что toEqual(...[{...,count:cartItemToDecrement.count - 2,...}]...) проходит. Это, вероятно, означает, что onUpdateItemQuantity вызывается внутри decrementItem, внутри onUpdateItemQuantity есть что-то вроде newCart[cartIndex].count--, а если toEqual() проходит, это означает, что setState() успешно обновляет состояние и после act() у вас актуализированное состояние . И , если имя теста правильное и начальное значение cartItemToDecrement.count === 1, это должно означать, что cartItemToDecrement.count - 2 === -1 и вы никогда не go внутри if (shouldRemoveFromCart). Так что, возможно, проблема не в тесте, а в коде.

0 голосов
/ 25 февраля 2020

Тестирование на изменения состояния является сложной задачей, потому что оно не дает какого-либо конкретного c результата (кроме того, что влияет на ваш рендеринг).

Ключ заключается в том, чтобы ограничить область тестирования вашими обязанностями по сравнению с Тестирование Реакт. React отвечает за то, чтобы useState правильно обновлял состояние. Вы несете ответственность за правильное использование данных и отправку верных данных. Поэтому вместо проверки useState проверьте, как ваш компонент реагирует на заданное состояние, и убедитесь, что вы устанавливаете правильное состояние.

Ответ на mock useState. Дайте ему реализацию, которая возвращает начальное значение, переданное ей, с помощью фиктивной функции, которая позволяет вам прочитать, какие данные сохраняются.

Более подробный ответ здесь:

https://dev.to/theactualgivens/testing-react-hook-state-changes-2oga

HTH!

...