تست نویسی در ری اکت و هرچیزی که باید راجبش بدونیم! راهنمای جامع تست نویسی در React !

تست نویسی در ری اکت برعکس اسم وحشتناکی که داره و تصور اشتباهی که درمورد سخت بودنش وجود داره، خیلی خیلی آسونه! هرجا بحث تست نویسی در React میشه، همه فکر میکنن این یه مبحث خیلی سخت و پیچیدس!دقیقا به همین دلیل تصمیم به انتشار این مقاله گرفتیم تا تست نویسی در ریکت رو به ساده ترین شکل ممکن بررسی کنیم 🙂اگه React Developer هستی و چیزی درمورد تست نویسی در React نمیدونی و میخوای یه Level-Up خفن داشته باشی، این مقاله رو مطالعه کن چون به ساده ترین شکل ممکن تست نویسی در ری اکت رو آموزش دادیم 🙂با فِرانت اِندی همراه باشید 🙂تست نویسی چیست ؟زمانیکه یک اپیکیشن میسازیم، اپیکیشن ما از صدها یا هزاران بخش، تابع و کلاس مختلف تشکیل میشه.ما باید به یک روشی مطمئن بشیم که تمامی این بخش ها دارن بخوبی کار میکنن و هیچ مشکلی ندارن.این روش، تست نویسی هست 🙂تست نویسی به ما اجازه میده عملکرد اجزای مختلف اپیکیشن خودمون رو تست کنیم و اطمینان حاصل کنیم که همه چیز داره درست کار میکنه.در حقیقت ما باید برای هر جز اپیکیشن خودمون یک تست واحد ( unit test ) بنویسیم تا مطمئن بشیم اون بخش داره درست کار میکنه ( مثلا برای هر تابع )چرا تست نویسی ؟تست نویسی باعث میشه مطمئن بشیم تیکه کد های ما همونطور که ازشون انتظار داریم، کار میکنن.تست نویسی در ری اکت شامل چه چیزایی میشه ؟درکل تست هایی که مینویسیم باید موارد زیر رو پوشش بدن :تست نویسی کامپوننت هایی که Props دارنتست نویسی کامپوننت هایی که Props ندارنتست نحوه re-Render شدن کامپوننت با تغییر Stateتست واکنش کامپوننت نسبت به تعاملات کاربرچه چیزی رو نمیتونیم تست کنیم ؟تست نویسی در React خیلی خوب و ضروریه اما نباید هرچیزی رو تست کرد!بریم ببینیم تست نویسی در ری اکت تو چه مواردی کاربرد نداره ..نیازی به تست عملکرد واقعی نیست:درواقع نیازی نیست عملکرد واقعی یک تابع رو چک کنیم فقط کافیه اون رو بصورت کلی تست کنیم تا از عملکرد صحیح کلی اون تابع اطمینان حاصل کنیم.نیازی به تست کتابخانه های خارجی نیست :اگه از کتابخانه های خارجی و شخص ثالث استفاده میکنید نیازی نیست که شما عملکرد اونارو تست کنید! درحقیقت توسعه دهنده های اون کتابخانه، باید اون کتابخانه رو تست کنن.مثلا اگه از کتابخانه Axios در ری اکت استفاده میکنید، نیازی نیست برای این کتابخانه تست نویسی ری اکت انجام بدید.اگه درک این موارد براتون سخته، اصلا نگران نباشید چون تو ادامه با ذکر مثال این موارد رو بررسی میکنیم 🙂تست نویسی در ری اکتتست نویسی در ری اکت یکی از اون مباحث پیشرفته و خیلی مهم هست که کمتر کسی بهش توجه میکنه!شاید یکم زمانبر باشه، اما تست نویسی در ریکت باعث میشه از عملکرد صحیح اپیکیشن خودمون اطمینان حاصل کنیم.تست نویسی در React شامل موارد زیر میشه :تست رندر کامپوننتتست تعامل کاربر با یک اِلِمان کامپوننتتست درست بودن یک ادعاخب دیگه تئوری صحبت کردن کافیه 🙂 بریم یکم کد ببینیم.ایجاد یک پروژه ری اکت برای تست نویسیبرای بررسی بهتر تست نویسی در ریکت ، ما میخوایم یک پروژه React ایجاد کنیم.برای اینکار ، به کمک CRA یا همون create-react-app یک پروژه ری اکتی میسازیم. سپس از کتابخانه Jest در ری اکت کمک میگیریم.همچنین به کتابخانه react testing library نیاز داریم.نکته ای که وجود داره این هست که با نصب React ، هر دو این کتابخانه ها برای ما نصب میشن.اگه به فایل package.json پروژه خودمون مراجعه کنیم، میبینیم که هر 2 پکیج مورد نیاز برای تست نویسی در React بصورت پیشفرض برای ما نصب شده :&quotdependencies&quot: { &quot@testing-library/jest-dom&quot: &quot^5.16.5&quot, &quot@testing-library/react&quot: &quot^13.4.0&quot, &quotreact&quot: &quot^18.2.0&quot, &quotreact-dom&quot: &quot^18.2.0&quot, &quotreact-scripts&quot: &quot5.0.1&quot, &quotweb-vitals&quot: &quot^2.1.4&quot},این مورد تو خط 2 و 3 مشخصه.مورد بعدی که باید ازش مطمئن بشیم، وجود 2 خط کد زیر در فایل setupTests.js هست :import '@testing-library/jest-dom';import '@testing-library/jest-dom/extend-expect';اگه 2 خط کد بالا، تو فایل setupTests.js وجود داشت عالیه. حالا باید بخش scripts در فایل package.json رو بصورت زیر تغییر بدیم ( اضافه کردن کامند تست در ری اکت ) :&quotscripts&quot: { &quotstart&quot: &quotreact-scripts start&quot, &quotbuild&quot: &quotreact-scripts build&quot, &quottest&quot: &quotreact-scripts test --watchAll --coverage&quot, &quoteject&quot: &quotreact-scripts eject&quot},خط 4 تیکه کد بالا باعث میشه تست ما درحالت اجرا نمایش داده بشه و بصورت کامل پوشش داده بشه.برای تغییر پوشش دادن تست توی Jest میتونیم کد زیر رو اضافه کنیم : ( برای پوشش 70% )&quotjest&quot: { &quotcoverageThreshold&quot: { &quotglobal&quot: { &quotlines&quot: 70 } }}خب دیگه تنظیمات Jest و تست نویسی در ری اکت تموم شد 🙂 بریم که یه تست بنویسیم . . .تست نویسی در ری اکتفرض کنیم کامپوننت زیر رو داریم و میخوایم براش تست نویسی انجام بدیم:const FirstTest = () => { return ( <div> <h2> First test </h2> </div> )}بنظر شما برای کامپوننت بالا چه تستی باید بنویسیم ؟!تو کامپوننت بالا ما میتونیم این مورد رو تست کنیم که آیا اِلِمان h2 رندر میشه یا خیر! ( تو خط 4 )حالا این سوال پیش میاد که برای اِلِمان h2 چطور تست نویسی انجام بدیم ؟ما میتونیم تست نویسی در ریکت رو در پوشه –tests– داخل پوشه src قرار بدیم.فایل تست ما باید پسورد زیر رو داشته باشه :.test.js/jsxدرواقع اجرا کننده تست ( test runner ) فقط همین فایل هارو شناسایی و اجرا میکنه.الان شاید سوال برامون پیش بیاد که یک فایل تست، چه شکلیه ؟تیکه کد زیر فایل FirstTest.test.jsx هست که بالاتر کامپوننتش رو نوشته بودیم :import { render, screen } from '@testing-library/react'import FirstTest from '../components/FirstTest';test(&quotExample 1 renders successfully&quot, () => { render(<FirstTest/>); const element = screen.getByText(/first test/i); expect(element).toBeInTheDocument();})در مرحله اول از متود ()test استفاده کردیم که یک individual test محسوب میشه. این متود 2 آرگومان ورودی از ما میگیره:آرگومان اول نام تست هست.آرگومان دوم یک callBack هست.تو خط شماره 4 از متود test استفاده کردیم.حالا باید کامپوننتی که قصد تست کردنش رو داریم، به کمک متود render تست کنیم ( در خط 5 )حالا به کمک آبجکت screen میتونیم یک اِلِمان رو بگیریم. ( تو این مثال ما اِلِمان h2 رو توی خط 7 گرفتیم )نکته : ما از regex برای گرفتن اِلِمان خودمون استفاده کردیم ( تو خط 7 )حالا باید یک ادعا بسازیم. ما میخوایم ادعا کنیم که اِلِمان ما توی صفحه render شده.این ادعا رو توی خط 9 به کمک expect ایجاد کردیم . این ادعا با موفقیت انجام شده ( pass شده )تو مثال بالا ما فقط این ادعا رو مطرح کردیم که اِلِمان h2 توی صفحه رندر شده، اما میتونیم ادعا های بیشتری هم بکنیم.تست نویسی در ریکت برای دیتاهای دریافتی از سروربیاید سناریویی رو در نظر بگیریم که داریم از Back-End اطلاعاتی رو دریافت میکنیم و نمایش میدیم :import React from 'react'const TestWithMockData = ({data}) => { return ( <div> <ul> {data.map(item => ( <li key={item.id}> {item.id} {item.first_name}, {item.last_name}, {item.email} </li> ))} </ul> </div> )}export default TestWithMockDataتو کامپوننت بالا ما داریم یکسری data رو بصورت Props دریافت میکنیم و نمایش میدیم. تست نویسی در چنین شرایطی ( که Props داریم ) مستلزم ساخت مقداری Data تستی ( Mock Data ) هست.( اگه با Props آشنا نیستید، پیشنهاد میکنم مقاله Props در ریکت رو مطالعه کنید )این Data ها دقیقا مشابه Data های Back-End هستن :const mockData = [{ &quotid&quot: 1, &quotfirst_name&quot: &quotFletcher&quot, &quotlast_name&quot: &quotMcVanamy&quot, &quotemail&quot: &quotmmcvanamy0@e-recht24.de&quot, &quotage&quot: 30 }, { &quotid&quot: 2, &quotfirst_name&quot: &quotClarice&quot, &quotlast_name&quot: &quotHarrild&quot, &quotemail&quot: &quotcharrild1@dion.ne.jp&quot,}]نکته درمورد Mock Data دیتا های اصلی بک اند شما ممکنه هزاران عدد باشه اما Mock Data شما چند عدد باشه کافیه ( صرفا برای تست میخوایمشون )خب بریم که تست نویسی در React برای کامپوننت بالایی رو انجام بدیم ..این تست رو توی تیکه کد زیر میشه دید :test(&quotList renders successfully&quot, () => { render(<TestWithMockData data={mockData} />) expect(screen.getByText(/fletcher/i)).toBeInTheDocument();})تست نویسی برای Data های ساختگی با سناریوی متفاوت ( Mock Data )بیاید کامپوننت بالا رو با سناریوی متفاوتی در نظر بگیریم. تو کامپوننت زیر یک Props به اسم displayUnorderdList داریم که رندر شرطی رو برامون انجام میده.همچنین برای سن بیشتر از 50 سال، عبارت senior و سن کمتر از 50 عبارت Not Senior رو نمایش میدیم :import React from 'react'const TestWithMockData = ({data, displayUnorderedList, handleClick}) => { return ( <div> {displayUnorderedList ? <ul> {data.map(item => ( <li key={item.id}> {item.id} {item.first_name}, {item.last_name}, <a ={() => { console.log(&quotemail link clicked&quot) handleClick() }}>{item.email}</a> {item.age > 50 ? 'Senior' : 'Not senior'} </li> ))} </ul> : <ol> {data.map(item => ( <li key={item.id}> Last name: {item.last_name} </li> ))} </ol> } </div> )}export default TestWithMockDataما برای کامپوننت بالا ( TestWithMockData )َ تست نویسی انجام دادیم. پس اگه به کنسول خودمون نگاهی بندازیم با صحنه زیر مواجه میشیم :اگه به بخش Uncovered نگاهی بندازیم، میبینیم که نوشته خط 9 توسط تست پوشش داده نشده. و تست ما ناموفق بوده چون نتونسته متن fletcher رو پیدا کنه (این متن رو توی تست بهش داده بودیم که پیدا کنه ).برای اینکه بتونیم تموم بخش کامپوننت رو پوشش بدیم باید بصورت زیر تست بنویسیم :test(&quotOrdered list renders&quot, () => { render(<TestWithMockData data={mockData} displayUnorderedList={false} />) expect(screen.getByText(/McVanamy/i)).toBeInTheDocument()})خب حالا تست ما کل کامپوننت رو پوشش میده 🙂تو تصویر زیر نتیجه رو میشه دید :البته باتوجه به عکس بالا میشه فهمید که هنوز خط 15 پوشش داده نشده. پس باید Mock Data خودمون رو بصورت زیر تغییر بدیم تا یک سن بیشتر از 50 داشته باشیم : { &quotid&quot: 3, &quotfirst_name&quot: &quotAmby&quot, &quotlast_name&quot: &quotEmmer&quot, &quotemail&quot: &quotaemmer2@buzzfeed.com&quot, &quotage&quot: 67}حالا دیگه تمومه و کل کامپوننت ما تحت پوشش تست ما هست 🙂تست نویسی در ری اکت برای تعاملات کاربر ( User Interactions )لطفا برای مطالعه ادامه مقاله + تیکه کد ها و مثالهای بیشتر روی لینک زیر کلیک کنید :تست نویسی در ری اکت