我有一个简单的购物车功能,当用户单击以增加或减少购物车中商品的数量时,调用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
}
所以开个玩笑,我有一个函数可以测试用户何时将购物车中的商品数量设置为零,但它尚未从购物车中删除该商品,我想是因为它尚未收到{ {1}}:
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
数组现在应该根本不包含对象。我如何在玩笑测试中验证此删除操作正在发生(反应代码正常工作)。
答案 0 :(得分:1)
由于您提供的上下文对我来说还不够,因此我不太了解测试与您的onUpdateItemQuantity
之间的关系。
但是从您的问题来看,有2条线索可以帮助您节省时间。
您可能知道setCart
中的useState
是不同步的,因此,如果您尝试在同一帧中从cart
访问useState
,即使您确保setCart
被调用,也不会反映出更改。 useEffect
是一个很好的解决方案。您可以找到useEffect
[https://reactjs.org/docs/hooks-effect.html][1]的文档,任何更改都应反映在useEffect
中,也许您可以在此处进行测试。
添加一个额外的变量myCart
来存储cart
和一个函数setMyCart
。而不是在代码中调用setCart
,而是调用setMyCart
。 setMyCart
就像是
function setMyCart(newCart)
{
myCart = newCart;
setCart(myCart); // this is for triggering React re-render
}
然后使用myCart
可以立即反映出更改以进行测试。
第二点附加代码的唯一目的是,当我们仍然依赖React的重新渲染机制时,我们将自己的Model
myCart
用于我们的特定逻辑,而不是{ React的{1}}状态不仅适用于cart
,而且在不适当的情况下也用于我们的逻辑。
答案 1 :(得分:0)
测试状态变化是一个挑战,因为它不会产生任何特定的输出(除非影响您的渲染)。
与测试React相比,关键是将测试范围缩小到您的职责范围。 React负责确保useState
正确更新状态。您的责任是确保正确使用数据并将正确的数据发送回去。因此,不用测试useState
,而是测试组件如何响应给定的状态,并确保设置正确的状态。
模拟useState
的答案。为它提供一个返回传递给它的初始值的实现,并带有一个模拟函数,使您可以读取正在保存的数据。
更详细的答案在这里:
https://dev.to/theactualgivens/testing-react-hook-state-changes-2oga
HTH!
答案 2 :(得分:0)
目前还不清楚onUpdateItemQuantity
的调用方式。甚至它的确切作用。即便如此,您声称toEqual(...[{...,count:cartItemToDecrement.count - 2,...}]...)
通过了。这可能意味着onUpdateItemQuantity
在decrementItem
内部被调用,在onUpdateItemQuantity
内部被称为newCart[cartIndex].count--
,如果toEqual()
通过,则意味着{{ 1}}成功更新了状态,并且在setState()
您具有已实现的状态之后。并且如果测试的名称正确,并且初始值为act()
,则应表示cartItemToDecrement.count === 1
,并且您永远都不会进入cartItemToDecrement.count - 2 === -1
。所以也许问题不在于测试,而在于代码。
答案 3 :(得分:0)
如果您需要使用useState()测试每个状态更新,则可以通过实现一个useEffect函数来进行此操作,该函数专门侦听该状态更改,例如您的购物车:
useEffect(() => {
test(...)
), [cart]);
因此您可以在useEffect()函数中进行测试。
这将确保您拥有正确的cart值,并且每次购物车更新时都会调用它。