آموزش مقدماتی تست نویسی در ری اکت (React Testing)

سلام دوستان. با یک مقاله دیگر در زمینه توسعه ری اکت همراه شما هستیم.
یکی از مباحث پیشرفته در مسیر یادگیری کتابخانه React.js نحوه تست نویسی یا Testing در ری اکت می باشد. در این پست ابتدا انواع تست نویسی را بیان کرده و درباره React-Testing-Library و JEST بطور مفصل صحبت خواهیم کرد. در نهایت، TDD و متدهای پیدا کردن المان در DOM را شرح خواهیم داد.
انواع تست نویسی:
تست نرم افزار انواع مختلفی دارد.
1- تست واحد-یونیت تست (Unit Test):
همانطور که از نامش مشخص است، تست را بر روی یک واحد مجزا و ایزوله از پروژه اجرا می کند. مانند یک متد یا کامپوننت در React.js
در این نوع تست نمی خواهیم تست را بر روی تعامل بین واحدهای مختلف نرم افزار خود اعمال کنیم. بلکه تست فقط روی کامپوننت های مستقل انجام می شود. در یونیت تست باید مطمئن شویم که یونیت موردنظر بطور کامل از سایر کامپوننت ها مستقل عمل می کند. تا اگر تست ما fail شد نیاز نباشد سایر یونیت های نرم افزار را برای رفع مشکل چک کنیم. پس باید تمام وابستگی ها یا dependency ها را در کامپوننت ری اکت شبیه سازی یا mock کنیم.
2- تست ادغام (Integration Test):
در این نوع تست برخلاف حالت قبل، تست را بر روی تعامل و ادغام واحدها با هم اجرا می کنیم. یعنی اینکه چند واحد یا یونیت چطور با یکدیگر کار می کنند. مثلا تعامل بین کامپوننت ها در ری اکت یا بین مایکرو سرویس ها با هم.
3- تست عملکردی (Functional Test):
در تست عملکردی، یک رفتار یا عملکرد مشخص از نرم افزار مورد تست و ارزیابی قرار می گیرد. دقت کنید که عبارت functional در اینجا ربطی به تابع ندارد. به عنوان مثال، فرض کنید می خواهید نحوه عملکرد ارسال فرم یا form submission را تست کنید. این فرم ممکن است از چند واحد یا کامپوننت در reactjs تشکیل شده باشد. اما ما در این تست می خواهیم تست کنیم ببینیم آیا ثبت نام کاربران بدرستی کار می کند یا خیر.
4- تست End to End یا E2E:
در تست e2e به یک مرورگر و یک سرور نیاز داریم. این نوع تست معمولا با ابزارهای خاصی مانند Cypress یا Selenium انجام می شود.
نکته: نوع تستی که React Testing Library ارائه می دهد Functional Test می باشد و ما هم در ادامه این مقاله می خواهیم بصورت Functional Test و همچنین TDD یا Test-Driven Development تست ها را تعریف و اجرا کنیم. درباره TDD در ادامه مقاله توضیح داده شده است.
تفاوت بین Jest و React Testing Library:
در واقع React Testing Library یک ویرچوال دام (Virtual-DOM) برای عملیات تست می سازد و ابزارهایی را برای کار با این محیط در اختیار ما قرار می دهد. مثلا می توان یک المان را توسط متد getByText در DOM پیدا کرد یا رویداد کلیک را بر روی یک المان اجرا کرد و…
در بخش زیر برخی از ویژگی های React Testing Library و JEST را بیان کرده ایم:
- React-Testing-Library:
رندر کردن کامپوننت ها در Virtual DOM. مانند متد render
سرج در المان های Virtual DOM مانند متد getByText
تعامل و interact با virtual-dom مانند کلیک روی یک المان
- JEST:
تست را پیدا می کند، اجرا می کند و موفقیت یا شکست آن را تعیین می کند.
npm test -> start jest with watch mode
چونکه تنها تستی که داریم App.test.js است، مطابق تصویر زیر، این تست با موفقیت پاس شده است:
برای خروج از jest watch mode حرف q را تایپ کرده و اینتر بزنید.
تست پیش فرض موجود در این فایل :
test('renders learn react link', () => { render(<App />); const linkElement = screen.getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); });
درباره assertion:
دستوری است در تست نویسی که باعث می شود تست ما به خطا بخورد یا با موفقیت پاس شود. مثال:
expect(linkElement).toBeInTheDocument();
متد expect یکی از مقادیر تعریف شده پیش فرض در Jest است. که در مثال فوق، linkElement آرگومان ورودی آن است. عبارت toBeInTheDocument هم matcher نامیده میشود که نوعی از Jest-DOM می باشد.
چند مثال از Assertion:
در دستور زیر گفتیم محتوای متنی المنت باید برابر hello باشد. در غیر اینصورت تست ما fail می شود:
expect(element.textContent).toBe('hello');
در مثال زیر گفتیم که انتظار داریم طول آرایه کاربران برابر 7 باشد:
expect(usersArray).toHaveLength(7);
درباره Jest-DOM:
Jest-DOM به همراه پکیج create-react-app نصب می شود و از فایل src/setupTests.js استفاده می کند. در مثال های قبلی matcher ها را دیدیم. مانند toBeInTheDocument. این matcher ها نوعی از Jest-DOM هستند. کلا با المان های DOM کار می کنند. مثلا اینکه یک المان در DOM وجود داشته باشد یا خیر. یا یک چک باکس تیک خورده باشد یا خیر.
مثال های دیگر از MATCHER ها: toBeVisible و toBeChecked
درباره JEST:
همانطور که در ابتدای مقاله گفتیم، React-Testing-Library وظیفه رندر کردن المان، سرچ المان و تعامل با المان های Virtual-DOM را بر عهده دارد. اما برای اجرای تست نیاز به یک Test-Runner دارد. اینجا جایی است که JEST پا به میدان می گذارد!
دقت کنید که JEST فقط یک Test Runner نمی باشد. JEST توسط Testing-Library پیشنهاد شده است و در واقع ابزار پیشنهادی و توصیه شده است که به همراه پکیج Create-React-App نصب می شود.
وقتی دستور npm test را در ترمینال اجرا می کنیم، در واقع در پشت صحنه دستور react-scripts test اجرا می شود که jest را در watch mode اجرا می کند.
واچ مد در Jest چیست؟
در واقع watch mode تغییرات فایل ها را از آخرین commit به بعد زیر نظر می گیرد. و تست را برای فایل هایی اجرا می کند که از آخرین کامیت به بعد تغییر کرده باشند. پس اگر فایلی تغییر نکرده باشد، هیچ تستی بطور پیش فرض اجرا نمی شود. مگر اینکه با وارد کردن حرف a اعلام کنیم که می خواهیم تمام تست ها اجرا شوند.
Jest چگونه کار می کند؟
یک متد test دارد که گلوبال است و دو آرگومان می گیرد:
- شرح تست با فرمت رشته (string description)
- فانکشن تست (test function)
اگر تابع تست با موفقیت اجرا شود و هیچ خطایی نداشته باشد، تست ما هم با موفقیت PASS می شود. وگرنه FAIL خواهد شد.
نکته: اگر تابع تست خالی باشد، یعنی بدنه تابع هیچ کدی نداشته باشد، تست با موفقیت پاس می شود.
و اگر بخواهیم در بدنه تابع دستوری تعریف کنیم که تست را بطور عمدی FAIL کنیم می توان کد زیر را نوشت:
throw new Error('test failed');
اما معمولا ما بطور عمدی یک تست را fail نمی کنیم، بلکه از assertion ها استفاده می کنیم. مانند toBe که در بخش قبل مطرح کردیم.
TDD یا Test-Driven Development چیست؟
بطور کلی TDD یعنی ابتدا تست را بنویسیم سپس کدنویسی کنیم. یعنی کدی بنویسیم که باعث شود تست ما PASS شود. تست TDD به Red-Green Testing هم معروف است. یعنی تستی که می نویسیم ابتدا با رنگ قرمز یعنی FAIL مواجه می شویم و سپس کدی می نویسیم که رنگ تست را به سبز یعنی PASS تبدیل کند.
به تصویر زیر توجه کنید:
مشاهده می کنید که از چپ به راست، ابتدا یک سری کدهای shell می نویسیم، سپس تست ها را تعریف می کنیم، سپس این تست ها مسلما FAIL می شوند، سپس کدنویسی می کنیم و در نهایت تست ها PASS می شوند.
یکی از مزایای TDD اینست که چون تست را ابتدا نوشتید و سپس شروع به کدنویسی می کنید، با هر تغییر در کدتان، تست JEST را که در Watch-mode است بطور خودکار کد شما را بررسی می کند و fail یا pass شدن آن را اعلام می کند. بدون اینکه نیاز باشد پس از هر بار تغییر در کدتان، تست را بصورت دستی اجرا کنید.
متدهای یافتن المان موردنظر در DOM:
برای نوشتن تست در React Testing Library نیاز داریم که ابتدا المان موردنظر را در Virtual DOM پیدا کنیم سپس از expect استفاده کنیم. روش های زیادی برای رسیدن به المان دلخواه وجود دارد که مربوط به Accessibility می باشد. در این بخش می خواهیم اولویت بندی این روش ها را بیان کنیم.
1- کوئری هایی که توسط همه کاربران قابل دسترسی می باشند:
- متد getByRole: وقتی می خواهیم یک المان را در DOM بوسیله نقش یا Role آن پیدا کنیم، باید از این متد استفاده کنیم. با مراجعه به سایت مرجع w3.org می توانید لیست کاملی از role ها را در html مشاهده کنید. فرض کنید می خواهیم یک تگ لینک (anchor tag) را در DOM پیدا کنیم. کافیست کد زیر را در REACT-TESTING-LIBRARY تعریف کنیم. در این کد گفتیم که تگ لینکی را در dom پیدا کن که مقدار تکست آن برابر Login باشد:
import {render, screen} from '@testing-library/react' render(<MyComponent />) const loginLink = screen.getByRole('link', {name: 'Login'})
- متد getByLabelText: این متد بیشتر در فرم ها کاربرد دارد. زمانی که می خواهیم یک المان را بر اساس متن برچسب یا Label Text آن پیدا کنیم، از این متد استفاده می کنیم.
- متد getByPlaceholderText: دقت کنید که placeholder جایگزینی برای label نیست اما اگر placeholder تنها چیزی است که دسترسی دارید می توانید از این متد برای یافتن المان موردنظر خود استفاده کنید.
- متد getByText: برای دسترسی به المان های متنی خارج از فرم، مانند div, p, span که غیر تعاملی (non-interactive) هستند بکار می رود.
- متد getByDisplayValue: اگر بخواهیم المانی را در فرم بر اساس مقدار ورودی آن پیدا کنیم از این متد استفاده می کنیم. فرض کنید می خواهیم مقدار ورودی یک input را در فرم تست کنیم. براحتی می توان از این متد بهره برد.
2- کوئری های معنایی (Semantic):
اگر نتوانستید از هیچکدام از روش های فوق برای دسترسی به المان مورد نظرتان اسفاده کنید می توانید به سراغ کوئری های معنایی یا semantic queries بیایید. دو روش زیر:
- متد getByAltText: اگر المان مورد نظرتان می تواند شامل اتریبیوت alt باشد، پس می توانید از این متد برای یافتن آن در DOM استفاده کنید.
- متد getByTitle: دقت کنید که اتریبیوت title نه برای screen-reader ها قابل خواندن است و نه برای یوزرهای عادی. بنابراین زیاد پیشنهاد نمی شود.
3- بر اساس آیدی:
- متد getByTestId: دقت کنید که مقدار آیدی المان در خروجی کار نه قابل دیدن است و نه قابل شنیدن. پس سعی کنید ابتدا المان خود را بر اساس روش های فوق، مانند role یا text، پیدا کنید و اگر نتوانستید به سراغ این متد بیایید.
نکته: برای مطالعه بیشتر در این زمینه می توانید به وب سایت test-library مراجعه فرمایید.
در اینجا به پایان مقاله می رسیم. در این آموزش سعی کردیم مفاهیم مقدماتی و اساسی تست نویسی در ری اکت را بطور جامع بررسی کنیم. در مقالات بعدی از آکادمی راهکارینو، با مثال های عملی و کاربردی از تست نویسی با JEST همراه شما عزیزان خواهیم بود. امیدوارم مطالب مطرح شده در این پست آموزشی از آکادمی راهکارینو برای شما مفید بوده باشه. لطفا نظرات و سوالات خود را از طریق فرم دیدگاه پایین مقاله با ما در میان بگذارید.
دیدگاهتان را بنویسید