У нас есть компонент корзины в приложении React:
import { useDispatch, useSelector } from "react-redux";
import ItemList from "./ItemList";
import { clearCart } from "../slice/cartSlice";
const Cart = () => {
const dispatch = useDispatch();
const cartItems = useSelector((store) => store.cart.items);
const handleClearCart = () => {
console.info("Here in the handle clear cart onClick event handler");
console.info("clearCart function is ", clearCart);
dispatch(clearCart());
};
return (
<div>
<h1>Cart</h1>
{cartItems.length != 0 && (
<button onClick = {handleClearCart}>
Clear Cart
</button>
)}
{cartItems.length ? (
<div>
<ItemList items = {cartItems} />
</div>
) : (
<h3> Your cart is empty !</h3>
)}
</div>
);
};
export default Cart;
Это CartSlice, который мы используем:
import { createSlice, current } from "@reduxjs/toolkit";
const cartSlice = createSlice({
name: "cart",
initialState: { items: [] },
reducers: {
addItem: (state, action) => {
state.items.push(action.payload);
},
removeItem: (state, action) => {
const filteredList = state.items.filter(
(item, index) => index != action.payload
);
return {
...state,
items: filteredList,
};
},
clearCart: (state) => {
console.info("Here in the clear cart reducer");
state.items.length = 0;
},
},
});
export const { addItem, removeItem, clearCart } = cartSlice.actions;
export default cartSlice.reducer;
В пользовательском интерфейсе, когда мы нажимаем кнопку «Очистить корзину», она очищается и отображается сообщение «Ваша корзина пуста».
Мы пытаемся написать модульный тест для него в библиотеке тестирования Jest/React. Вот наша попытка:
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import mockStoreInfo from "../__mocks__/storeMock";
import Cart from "../src/components/Cart";
test("should clear cart when click on clear cart in cart component", async () => {
render(
<Provider store = {storeMock}>
<Cart />
</Provider>
);
const clearCartButton = screen.getByRole("button", { name: "Clear Cart" });
expect(clearCartButton).toBeInTheDocument();
console.info("clearCart button is", clearCartButton);
fireEvent.click(clearCartButton);
expect(await (screen.getByText(" Your cart is empty !"))).toBeInTheDocument();
});
Судя по тому, что мы видим, кнопка clear Cart
регистрируется и является действительной кнопкой. Также вызывается функция handleClearCart
, и мы также можем распечатать тело функции clearCart
. Однако мы не видим журнал консоли действия clearCart
в CartSlice, что указывает на то, что оно не вызывается и, следовательно, тест на утверждение Your cart is empty !
не пройден. Мы не уверены, почему действие не отправляется при нажатии этой кнопки. Может ли кто-нибудь нам помочь?
PS: Структура DOM, которую мы получаем в результате неудачного теста, указывает на то, что корзина не была очищена. Вот ДОМ:
<body>
<div>
<div class = "cart-container" data-testid = "cart">
<h1 class = "cart-heading">Cart</h1>
<button class = "clear-cart" data-testid = "clear-cart">Clear Cart</button>
<div class = "cart-items" data-testid = "cart-items-list">
<div>
<div class = "menu-item">
<div class = "sc-guDLey byrpfT">
<div class = "menu-header">
<span> Al Fungi Gourmet-Pizza </span>
<span> - ₹ 549 </span>
</div>
<p class = "accordion-body-description">
Gourmet mushroom pizza on a cheesy Mozzarella base with
jalapenos & cherry tomatoes.
</p>
</div>
<div class = "sc-beySPh fSyZNZ">
<img
class = "accordion-image"
src = "https://res.cloudinary.com/swiggy/image/upload/fl_lossy,f_auto,q_auto,w_508,h_320,c_fill/4ffebb537f043e94e09e928f48e640e9"
/>
<button class = "accordion-button-delete">Remove -</button>
</div>
</div>
<div class = "menu-item">
<div class = "sc-guDLey byrpfT">
<div class = "menu-header">
<span> Butterscotch Mousse Cake </span>
<span> - ₹ 103.81 </span>
</div>
<p class = "accordion-body-description">
Sweet temptation! Butterscotch flavored mousse
</p>
</div>
<div class = "sc-beySPh fSyZNZ">
<img
class = "accordion-image"
src = "https://res.cloudinary.com/swiggy/image/upload/fl_lossy,f_auto,q_auto,w_508,h_320,c_fill/e91002ccf7239fffeceaab4956a15a3a"
/>
<button class = "accordion-button-delete">Remove -</button>
</div>
</div>
<div class = "menu-item">
<div class = "sc-guDLey byrpfT">
<div class = "menu-header">
<span> Choco Lava Cake </span>
<span> - ₹ 109 </span>
</div>
<p class = "accordion-body-description">
Chocolate lovers delight! Indulgent, gooey molten lava inside
chocolate cake
</p>
</div>
<div class = "sc-beySPh fSyZNZ">
<img
class = "accordion-image"
src = "https://res.cloudinary.com/swiggy/image/upload/fl_lossy,f_auto,q_auto,w_508,h_320,c_fill/517791a68253a9a5084664b470f6e115"
/>
<button class = "accordion-button-delete">Remove -</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
🤔 А знаете ли вы, что...
React - это библиотека JavaScript, разработанная компанией Facebook.
redux-mock-store
устарело; на самом деле он не управляет никакими состояниями или действиями, отправленными процессом. Сейчас общепринятой рекомендацией и практикой является создание настоящего хранилища Redux при модульном тестировании.
Пример:
import React from 'react';
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { configureStore } from "@reduxjs/toolkit"; // <-- create real store
import { Provider } from 'react-redux';
import reducer from '../path/to/rootReducer'; // <-- import reducer
import Cart from "../src/components/Cart";
const preloadedState = {
// any initial state necessary for the unit tests
};
const store = configureStore({
preloadedState,
reducer,
});
const Providers = ({ children }) => (
<Provider store = {store}>
{children}
</Provider>
);
test(
"should clear cart when click on clear cart in cart component",
async () => {
render(<Cart />, { wrapper: Providers });
const clearCartButton = screen.getByRole(
"button",
{ name: "Clear Cart" }
);
expect(clearCartButton).toBeInTheDocument();
console.info("clearCart button is", clearCartButton);
fireEvent.click(clearCartButton);
expect(
await screen.getByText(" Your cart is empty !")
).toBeInTheDocument();
}
);
Дополнительную общую информацию и стратегии тестирования см. в документации Redux Написание тестов.