Hallo, ich bin neu im Bereich Unit-Tests. Ich habe eine Komponente, die eine Liste von Produkten rendert und diese Listen anzeigt. Ich habe in dieser Komponente auch eine Funktion, um diese Produkte nach Preisklasse zu filtern. Ich verwende ReactSlider, der im Grunde zwei Statusvariablen „priceFrom“ und „priceTo“ aktualisiert, und wenn sich diese Statusvariablen ändern, löse ich eine Funktion aus, die die Produkte basierend auf diesen Preisen filtert. Deshalb wollte ich im Scherz eine ähnliche Funktionalität testen. Kann man Witze machen? Wenn ja, wie kann ich dies erreichen, und wenn nicht, welche Alternative kann ich nutzen, um Unit-Tests dieser Komponente durchzuführen. Danke. Der Code für diese Komponente lautet wie folgt. Beachten Sie, dass im folgenden Code die FunktionfilterItemdie Produkte filtert und die Benutzeroberfläche aktualisiert, wenn derReactSlidereinen Wert aktualisiert.
import React, { useEffect, useState, useContext } from "react"; import { useParams } from "react-router-dom"; import styles from './productsList.module.css'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSpinner } from '@fortawesome/free-solid-svg-icons'; import Backdrop from "../../Others/Backdrop/backdrop"; import Modal from '../../Others/Modal/modal'; import ReactPaginate from 'react-paginate'; import ReactSlider from 'react-slider'; import { disableScroll } from "../../Others/HelperFunction/helperFunction"; import { ContextProvider } from "../../Others/AuthContext/authContext"; import './slider.css'; const ProductsList = () => { const context = useContext(ContextProvider); const productId = useParams().productId; const [sidebar, setSidebar] = useState(false); const [backdrop, setBackdrop] = useState(false); const [products, setProducts] = useState([]); const [filteredProducts, setFilteredProducts] = useState([]); const [error, setError] = useState(false); const [status, setStatus] = useState(''); const [modal, setModal] = useState(false); const [priceFrom, setPriceFrom] = useState(0); const [priceTo, setPriceTo] = useState(10000); const [itemOffset, setItemOffset] = useState(0); const [itemNotFound, setItemNotFound] = useState(false); const itemPerPage = 9; const endOffset = itemOffset + itemPerPage; let pageCount = 0; if (filteredProducts.length){ pageCount = Math.ceil(filteredProducts.length / itemPerPage); } else { pageCount = Math.ceil(products.length / itemPerPage); } const handlePageClick = (event) => { if (filteredProducts.length){ const newOffset = (event.selected * itemPerPage) % filteredProducts.length; setItemOffset(newOffset); } else { const newOffset = (event.selected * itemPerPage) % products.length; setItemOffset(newOffset); } } useEffect(() => { window.scrollTo(0, 0); if (context.data !== undefined){ const product = context.data[productId] !== undefined ? context.data[productId] : []; if (product.length){ setProducts(product); setStatus('success'); } else { setStatus('not found'); } } }, [context.data] ); useEffect(() => { window.scrollTo(0, 0); }, [itemOffset, filteredProducts.length]); useEffect(() => { if (backdrop){ disableScroll(); } else { window.onscroll = () => { } } }, [backdrop]) let defaultView = Array.from(Array(12).keys()).map(item => { return}); if (products.length){ if (!itemNotFound && filteredProducts.length){ defaultView = filteredProducts.slice(itemOffset, endOffset).map(item => { return }); } else if (itemNotFound) { defaultView = } else { defaultView = products.slice(itemOffset, endOffset).map(item => { return }); } } else if(status === 'not found') { defaultView =Nothing found based on your range
} const filterItem = () => { if (priceFrom && priceTo) { const filteredData = products.filter(item => Number(item.price) >= priceFrom && Number(item.price) <= priceTo); if (filteredData.length){ setItemNotFound(false) setFilteredProducts(filteredData); setSidebar(false); setBackdrop(false); } else { setItemNotFound(true); setItemOffset(0); setSidebar(false); setBackdrop(false); } } } const resetFilter = () => { setPriceFrom(0); setPriceTo(1000); setFilteredProducts([]); } const openSidebar = () => { if (!sidebar){ setSidebar(true); setBackdrop(true); } } const closeSidebar = () => { if (sidebar){ setSidebar(false); setBackdrop(false); } else { setBackdrop(false); } } let displayStatus =Nothing found
if (status === 'database error'){ displayStatus =Something went wrong
Please try again
} return ( <>Database error
Please try again or contact the admin
{displayStatus} > ) } export default ProductsList;Show Sidebar
Price Range
`Thumb value ${state.valueNow}`} renderThumb={(props, state) => {state.valueNow}} minDistance={1} onChange={([v1, v2]) => { setPriceFrom(v1); setPriceTo(v2); }} pearling />{products.length ? products[0].category : null}
{defaultView}
我可以为您提供一些与您的问题相关的建议
检查一个可以帮助您测试 React 元素的库(例如react-testing-libraryhttps://testing-library.com/docs/react-testing-library/intro/)
通常来自另一个库的东西不会被测试,因为我们假设库本身已经测试过它(在这种情况下是 ReactSlider 库
尝试将组件拆分为更小的组件,这样更容易测试(您可以使用 props),并且每个组件内部的依赖关系会更少
我们可以将这里的测试分为两种不同的测试E2E和单元测试,E2E是当您使用模拟用户交互的工具时,在这种情况下您可以模拟用户移动范围滑块,看看之后会发生什么(为此,您可以使用 cypress 或 selenium)这些工具像人类一样在浏览器中运行,单元测试允许您测试功能、组件输入和输出,在这里您可以也模拟点击和交互,但对于用户交互来说,它们不如 E2E 强大,因为单元测试(在本例中是开玩笑的工具)在 JSDOM 中运行测试,JSDOM 是真实浏览器的模拟(简单来说)
为了解决这个问题,我将执行以下操作
赛普拉斯:https://www.cypress.io/
硒:https://www.selenium.dev/
请记住,E2E 和单元测试是两种为您提供最佳服务的方法,具体取决于您要寻找的内容,每种方法都可以模拟用户交互,但其背后的引擎不同
希望对你有帮助