כיצד לבדוק אפליקצית React עם Jest וספריית בדיקות React

המחבר בחר את Vets Who Code לקבל תרומה כחלק מתוכנית כתיבה למענה עמותות.

הקדמה

השגת כיסוי בדיקות יציב הוא חיוני לבניית ביטחון באפליקציה האינטרנטית שלך. Jest הוא רץ בדיקות JavaScript שמספק משאבים לכתיבה והרצת בדיקות. ספריית בדיקות React מציעה סט של עזרים לבדיקות שמבוססות על אינטראקציות משתמש ולא על פרטי יישום הרכיבים. גם Jest וספריית בדיקות React מגיעים מוכנים מראש עם Create React App ונמצאים תחת המנחה שבדיקת האפליקציות צריכה לדמות את אופן השימוש בתוכנה.

במדריך זה, תבדוק קוד אסינכרוני ואינטראקציות בפרוייקט דוגמא הכולל מגוון אלמנטים של ממשק משתמש. תשתמש ב-Jest כדי לכתוב ולהריץ בדיקות יחידה, ותממש ספריית בדיקות React כספריית DOM (Document Object Model) עוזרת לטיפול באינטראקציה עם רכיבים.

דרישות מוקדמות

כדי להשלים את המדריך הזה, תצטרך:

  • Node.js גרסה 14 או יותר גדולה מותקנת על המחשב המקומי שלך. כדי להתקין את Node.js על macOS או Ubuntu 18.04, עקוב אחר השלבים ב- איך להתקין את Node.js וליצור סביבת פיתוח מקומית ב-macOS או בקטע ה- התקנה באמצעות PPA של איך להתקין את Node.js על Ubuntu 18.04.

  • גרסת npm 5.2 או גבוהה יותר על המחשב המקומי שלך, אשר תזדקק להשתמש ב-Create React App וב-npx בפרוייקט הדוגמה. אם לא התקנת את npm לצד Node.js, עשה זאת כעת. עבור Linux, השתמש בפקודה sudo apt install npm.

    • כדי שחבילות npm יעבדו במדריך זה, התקן את החבילה build-essential. עבור Linux, השתמש בפקודה sudo apt install build-essential.
  • Git מותקן על המחשב המקומי שלך. ניתן לבדוק האם Git מותקן על המחשב שלך או לעבור דרך תהליך ההתקנה עבור מערכת ההפעלה שלך באמצעות איך להתקין Git על Ubuntu 20.04.

  • יכולת בקוד React, אותה תוכל לפתח עם סדרת המדריכים איך לכתוב קוד ב־React.js. מאחר והפרויקט הדגמה מופעל עם Create React App, אין צורך להתקין אותו בנפרד.

  • יכולת קלה עם Jest כמרוץ או סביבה לבדיקות יכולה להיות מועילה אך אינה דרושה. מאחר ו־Jest מותקן מראש עם Create React App, אין צורך להתקין אותו בנפרד.

שלב 1 — הגדרת הפרויקט

בשלב זה, תבצעו העתקת פרויקט דוגמה ותפעילו את אוסף הבדיקות. הפרויקט הדוגמתי משתמש בשלושה כלים עיקריים: Create React App, Jest, ו־React Testing Library. Create React App משמש להקמת אפליקציית React דו־צדדית. Jest משמש כמנהל הבדיקות, ו־React Testing Library מספק עזרים לבניית בדיקות סביב התנהגות משתמש.

כדי להתחיל, תעתיקו את פרויקט ה־React App המוכן מ־GitHub. תעבדו עם האפליקציה Doggy Directory, שהיא פרויקט דוגמה המשתמש ב־Dog API לבניית מערכת חיפוש והצגה של אוסף תמונות של כלבים בהתבסס על גזע מסוים.

כדי להעתיק את הפרויקט מ־GitHub, תפתחו את הטרמינל ותריצו את הפקודה הבאה:

  1. git clone https://github.com/do-community/doggy-directory

תראו פלט דומה לזה:

Output
Cloning into 'doggy-directory'... remote: Enumerating objects: 64, done. remote: Counting objects: 100% (64/64), done. remote: Compressing objects: 100% (48/48), done. remote: Total 64 (delta 21), reused 55 (delta 15), pack-reused 0 Unpacking objects: 100% (64/64), 228.16 KiB | 3.51 MiB/s, done.

שנו אל תיקיית doggy-directory:

  1. cd doggy-directory

התקינו את תלות הפרויקט:

  1. npm install

הפקודה npm install תתקין את כל תלות הפרויקט המוגדרות בקובץ package.json.

לאחר התקנת התלות, תוכלו להציג את הגרסה המופעלת של האפליקציה או שתריצו את האפליקציה מקומית באמצעות הפקודה הבאה:

  1. npm start

אם בחרתם להפעיל את האפליקציה מקומית, היא תיפתח ב־http://localhost:3000/. תראו את הפלט הבא בטרמינל:

Output
Compiled successfully! You can now view doggy-directory in the browser. Local: http://localhost:3000 On Your Network: http://network_address:3000

לאחר הפעלתה, עמוד הנחיתה של האפליקציה ייראה כמו כך:

התלויות של הפרויקט הותקנו, והאפליקציה כעת רצה. הבא, פתח טרמינל חדש והפעל את הבדיקות עם הפקודה הבאה:

  1. npm test

הפקודה npm test מתחילה את הבדיקות במצב צפיה אינטרקטיבית עם Jest כמנוהל הבדיקות שלו. כאשר במצב צפיה, הבדיקות מריצות מחדש באופן אוטומטי לאחר שינוי בקובץ. הבדיקות ירוצו בכל פעם שתשנה קובץ וידעו אותך אם השינוי עבר את הבדיקות.

לאחר הרצת npm test לפעם הראשונה, תראה את הפלט הבא בטרמינל:

Output
No tests found related to files changed since last commit. Press `a` to run all tests, or run Jest with `--watchAll`. Watch Usage › Press a to run all tests. › Press f to run only failed tests. › Press q to quit watch mode. › Press p to filter by a filename regex pattern. › Press t to filter by a test name regex pattern. › Press Enter to trigger a test run.

עכשיו שיש לך את היישום דוגמה ואת סט הבדיקות רצים, תוכל להתחיל בבדיקות בעמוד הנחיתה.

שלב 2 — בדיקת עמוד הנחיתה

בדרך כלל, Jest יחפש קבצים עם הסיומת .test.js וקבצים עם הסיומת .js בתיקיות __tests__. כאשר אתה מבצע שינויים בקבצי הבדיקה הרלוונטיים, הם יזוהו באופן אוטומטי. כאשר מקרי הבדיקה משתנים, הפלט יעדכן באופן אוטומטי. קובץ הבדיקה המוכן עבור פרויקט הדוגמה doggy-directory מוגדר עם קוד מינימלי לפני שתוסיף פרדיגמות בדיקה. בשלב זה, תכתוב בדיקות כדי לוודא שעמוד הנחיתה של האפליקציה תעלה לפני ביצוע חיפוש.

פתח src/App.test.js בעורך שלך כדי לראות את הקוד הבא:

src/App.test.js
import { render, screen } from '@testing-library/react';
import App from './App';

test('renders the landing page', () => {
  render(<App />);
});

A minimum of one test block is required in each test file. Each test block accepts two required parameters: the first argument is a string representing the name of the test case; the second argument is a function that holds the expectations of the test.

בתוך הפונקציה, קיימת שיטת render שמספקת React Testing Library לעיבוד הרכיב שלך לתוך ה- DOM. עם הרכיב שברצונך לבדוק מוצג ב- DOM של סביבת הבדיקה, כעת ניתן להתחיל לכתוב קוד לאמת את הפונקציונליות הצפויה.

תוסיפו בלוק בדיקה לשיטת ה- render שיבדוק האם הדף הראשי מוצג בדיוק לפני שהופעלו קריאות ל- API או נעשו בחירות. הוסיפו את הקוד המודגש מתחת לשיטת ה- render:

src/App.test.js
...
test('renders the landing page', () => {
  render(<App />);
  
  expect(screen.getByRole("heading")).toHaveTextContent(/Doggy Directory/);
  expect(screen.getByRole("combobox")).toHaveDisplayValue("Select a breed");
  expect(screen.getByRole("button", { name: "Search" })).toBeDisabled();
  expect(screen.getByRole("img")).toBeInTheDocument();
});

הפונקציה expect משמשת כל פעם שברצונך לאמת תוצאה מסוימת, והיא מקבלת ארגומנט יחיד המייצג את הערך שהקוד שלך מייצר. רוב הפונקציות expect משווקות עם פונקציות matcher כדי לאמת משהו על ערך מסוים. לרוב מהאמינציות הללו, תשתמשו במאמץ נוסף מסופק על ידי jest-dom כדי לבדוק בקלות רבה את האספקטים הנפוצים שנמצאים ב- DOM. לדוגמה, .toHaveTextContent הוא המאמץ לפונקציית expect בשורה הראשונה, בזמן ש- getByRole("heading") הוא הבורר ללכידת האלמנט ב- DOM.

React Testing Library מספקת את האובייקט screen כדי לגשת בצורה נוחה לשאילתות הרלוונטיות הנדרשות לאמות בסביבת הבדיקה של DOM. כברירת מחדל, מספקת React Testing Library שאילתות שמאפשרות לך לאתר אלמנטים בתוך ה- DOM. קיימות שלושה קטגוריות עיקריות של שאילתות:

  • getBy* (השימוש הנפוץ ביותר)
  • queryBy* (שימוש כאשר נבדקת החסרות של אלמנט מבלי לזרוק שגיאה)
  • findBy* (שימוש כאשר נבדקת קוד אסינכרוני)

כל סוג שאילתה משרת למטרה מסוימת שתוגדר במהלך המדריך. בשלב זה, תתמקד בשאילתת ה-getBy*, שהיא סוג השאילתה הנפוץ ביותר. כדי לראות רשימה מפורטת של השונות של שאילתות, תוכל לבדוק את גליון העבודה של ריאקטגליון המשאבים של שאילתות.

למטה נמצא תמונה עם הערות של דף הנחיתה של ספריית הכלבים המציינות את כל אזור המכיל נתונים שבהם הבדיקה הראשונה (על הצגת דף הנחיתה) מתמקדת בהם:

כל פונקציית expect מערכת נגד הבא (מוצג בתמונה העם ההערות למעלה):

  1. אתה מצפה שהאלמנט עם תפקיד הכותרת יהיה לו התאמה חלקית של ספריית הכלבים.
  2. אתה מצפה שהקלט של הבחירה יהיה עם ערך התצוגה מדויק של בחר גזע.
  3. אתה מצפה שלכפתור ה-חיפוש יהיה לא מאופשר מאחר ובחירה לא נעשתה.
  4. אתה מצפה שהתמונה המציינת תהיה נוכחת במסמך מאחר וחיפוש לא בוצע.

כאשר סיימת, שמור את הקובץ src/App.test.js. מאחר והבדיקות רצות במצב צפיה, השינויים ירשמו אוטומטית. אם השינויים לא נרשמים באופן אוטומטי, עשוי להיות עליך לעצור ולהפעיל מחדש את ערכת הבדיקות.

עכשיו, כאשר אתה מסתכל על הבדיקות שלך בטרמינל, תראה את הפלט הבא:

Output
PASS src/App.test.js ✓ renders the landing page (172 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 2.595 s, estimated 5 s Ran all test suites related to changed files. Watch Usage: Press w to show more.

בשלב זה, כתבת בדיקת תחילתית כדי לאמת את תצוגת הדף הראשית של עמוד הנחיית הכלבים. בשלב הבא, תלמד כיצד לפענח שיחת API מזוייפת לבדיקת קוד אסינכרוני.

שלב 3 — מופעל את שיטת הfetch

בשלב זה, תבקש לבדוק גישה אחת להפעיל את שיטת הfetch ב-JavaScript. בעוד שישנן דרכים רבות להשיג זאת, המימוש הזה ישתמש בשיטות ה-spyOn ו-mockImplementation של Jest.

כאשר אתה תלווה על API חיצוניים, יש סיכוי שה-API שלהם ייפול או ייקח זמן עד שהוא יחזיר תגובה. מסתירת שיטת ה-fetch מספקת סביבה עקבית וניחושית, נותנת לך יותר ביטחון בבדיקות שלך. מנגנון מסתירת API הוא נחוץ כדי להריץ באופן תקין בדיקות שמשתמשות ב-API חיצוני.

הערה: במאמץ לשמור על פשטות הפרויקט הזה, תסימול של שיטת fetch יתבצע. עם זאת, מומלץ להשתמש בפתרון עוצמתי יותר כמו Mock Service Worker (MSW) כאשר מתבצע תסימול של קוד אסינכרוני עבור קודבייסים גדולים ומוכנים להפקה.

פתח src/mocks/mockFetch.js בעורך שלך כדי לבדוק איך פעולת השיטה mockFetch עובדת:

src/mocks/mockFetch.js
const breedsListResponse = {
    message: {
        boxer: [],
        cattledog: [],
        dalmatian: [],
        husky: [],
    },
};

const dogImagesResponse = {
    message: [
        "https://images.dog.ceo/breeds/cattledog-australian/IMG_1042.jpg ",
        "https://images.dog.ceo/breeds/cattledog-australian/IMG_5177.jpg",
    ],
};

export default async function mockFetch(url) {
    switch (url) {
        case "https://dog.ceo/api/breeds/list/all": {
            return {
                ok: true,
                status: 200,
                json: async () => breedsListResponse,
            };
        }
        case "https://dog.ceo/api/breed/husky/images" :
        case "https://dog.ceo/api/breed/cattledog/images": {
            return {
                ok: true,
                status: 200,
                json: async () => dogImagesResponse,
            };
        }
        default: {
            throw new Error(`Unhandled request: ${url}`);
        }
    }
}

השיטה mockFetch מחזירה אובייקט שדומה בצורה למה ששיחות של fetch היו מחזירות בתגובה לקריאות ל- API באפליקציה. שימוש בשיטת mockFetch נחוץ כדי לבדוק את הפונקציונליות האסינכרונית בשני אזורים של אפליקציית ״מדריך הכלבים״: תיבת הבחירה שממלאה את רשימת הגזעים והקריאה ל- API לקבלת תמונות של כלבים כאשר מבוצעת חיפוש.

סגור את src/mocks/mockFetch.js. עכשיו שהבנת איך שיטת mockFetch תשמש בבדיקות שלך, תוכל לייבא אותה לקובץ הבדיקות שלך. הפונקציה mockFetch תיעבר כארגומנט לשיטת mockImplementation ואז תשמש כיישום זדוני של API של fetch.

בתוך src/App.test.js, הוסף את השורות המודגשות כדי לייבא את שיטת mockFetch:

src/App.test.js
import { render, screen } from '@testing-library/react';
import mockFetch from "./mocks/mockFetch";
import App from './App';

beforeEach(() => {
   jest.spyOn(window, "fetch").mockImplementation(mockFetch);
})

afterEach(() => {
   jest.restoreAllMocks()
});
...

קטע הקוד הזה יקים ויתפרק את המימוש המזוייף כך שכל בדיקה תתחיל משטח משחק שווה.

jest.spyOn(window, "fetch"); יוצר פונקציה מזויפת שתעקוב אחר קריאות לשיטת fetch המצורפת למשתנה הגלובלי window ב- DOM.

.mockImplementation(mockFetch); מקבל פונקציה שתשמש ליישום של השקול המזויף. מכיוון שפקודה זו מחליפה את היישום המקורי של fetch, היא תופעל בכל פעם שייקרא fetch בתוך קוד האפליקציה.

כאשר סיימת, שמור את קובץ src/App.test.js.

כעת, כאשר אתה מסתכל על הבדיקות שלך בטרמינל, תקבל את הפלט הבא:

Output
console.error Warning: An update to App inside a test was not wrapped in act(...). When testing, code that causes React state updates should be wrapped into act(...): act(() => { /* fire events that update state */ }); /* assert on the output */ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act at App (/home/sammy/doggy-directory/src/App.js:5:31) 18 | }) 19 | .then((json) => { > 20 | setBreeds(Object.keys(json.message)); | ^ 21 | }); 22 | }, []); 23 | ... PASS src/App.test.js ✓ renders the landing page (429 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 1.178 s, estimated 2 s Ran all test suites related to changed files.

האזהרה מעדכנת אותך שעדכון במצב התרחש כאשר לא ציפית לכך. מבחינת פלט, הבדיקות גם מעידות על הצלחת הדמייה של שיטת fetch.

בשלב זה, אתה מדמה את שיטת fetch ומשתלב עם שיטת בדיקה. למרות שהבדיקה עוברת בהצלחה, עליך עדיין לטפל באזהרה.

שלב 4 — תיקון האזהרה act

בשלב זה, תלמד כיצד לתקן את האזהרה act שעלתה אחרי השינויים בשלב 3.

האזהרה act מתרחשת מכיוון שאתה מדמה את שיטת fetch, וכאשר הרכיב מתקין, הוא בוצע בקריאת API כדי לאחזר את רשימת הגזעים. רשימת הגזעים מאוחסנת במשתנה מצב הממלא את אלמנט ה-option בתוך קלט הבחירה.

התמונה למטה מציגה איך נראה קלט הבחירה לאחר שהופעלה קריאת ה-API בהצלחה לאחזור את רשימת הגזעים:

האזהרה מתווצגת מכיוון שהמצב מוגדר לאחר שבלוק הבדיקה מסיים לעשות render לרכיב.

כדי לתקן את הבעיה הזו, הוסף את השינויים המסומנים למקרה הבדיקה ב־src/App.test.js:

src/App.test.js
...
test('renders the landing page', async () => {
   render(<App />);
   
   expect(screen.getByRole("heading")).toHaveTextContent(/Doggy Directory/);
   expect(screen.getByRole("combobox")).toHaveDisplayValue("Select a breed");
   expect(await screen.findByRole("option", { name: "husky"})).toBeInTheDocument();
   expect(screen.getByRole("button", { name: "Search" })).toBeDisabled();
   expect(screen.getByRole("img")).toBeInTheDocument();
});

המילת המפתח async מספרת ל־Jest שקוד אסינכרוני רץ כתוצאה מקריאת ה־API שמתרחשת כאשר הרכיב מתקין.

A new assertion with the findBy query verifies that the document contains an option with the value of husky. findBy queries are used when you need to test asynchronous code that is dependent on something being in the DOM after a period of time. Because the findBy query returns a promise that gets resolved when the requested element is found in the DOM, the await keyword is used within the expect method.

כשתסיים, שמור את השינויים שבוצעו ב־src/App.test.js.

עם ההוספות החדשות, תראה כי האזהרה של act אינה נמצאת יותר בבדיקות שלך:

Output
PASS src/App.test.js ✓ renders the landing page (123 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 0.942 s, estimated 2 s Ran all test suites related to changed files. Watch Usage: Press w to show more.

בשלב זה, למדת כיצד לתקן את האזהרה של act שעשויה להתרחש בעת עבודה עם קוד אסינכרוני. בשלב הבא, תוסיף מקרה בדיקה שני כדי לוודא את הפונקציונליויות האינטראקטיביות של אפליקציית דוגי דירקטורי.

שלב 5 — בדיקת תכונת החיפוש

בשלב האחרון, תכתוב מקרה בדיקה חדש כדי לוודא את תכונת החיפוש והתצוגה של התמונות. תשתמש בפניה רחבה של שאילתות ושיטות API כדי להשיג את כיסוי הבדיקה המתאים.

חזור לקובץ src/App.test.js בעורך שלך. בראש הקובץ, יבא את ספריית הלייבררי user-event ואת השיטה האסינכרונית waitForElementToBeRemoved לתוך קובץ הבדיקות עם הפקודות המודגשות הבאות:

src/App.test.js
import { render, screen, waitForElementToBeRemoved } from '@testing-library/react';import userEvent from '@testing-library/user-event'; 
...

תשתמש בייבואים אלו מאוחר יותר בחלק זה.

לאחר השיטה האיתחולית test(), הוסף בלוק בדיקת אסינכרונית חדש ועצב את הרכיב App עם הבלוק הבא של קוד:

src/App.test.js
...
test("should be able to search and display dog image results", async () => {
   render(<App />);
})

עם הרכיב מוצג, כעת אתה יכול להוסיף פונקציות שבודקות את התכונות האינטראקטיביות של אפליקציית ספר הכלבים.

עדיין ב־src/App.test.js, הוסף את הבלוקים המודגשים שבתוך השיטה השנייה של test():

src/App.test.js
...
test("should be able to search and display dog image results", async () => {
   render(<App />);
   
   //מדמה בחירת אופציה ובודק את ערכה
   const select = screen.getByRole("combobox");
   expect(await screen.findByRole("option", { name: "cattledog"})).toBeInTheDocument();
   userEvent.selectOptions(select, "cattledog");
   expect(select).toHaveValue("cattledog");
})

הקטע המודגש למעלה ידמה את הבחירה של גזע כלב ויבדוק כי הערך הנכון מוצג.

השאילתה getByRole תתפס את האלמנט הנבחר ותשייך אותו למשתנה select.

בדומה לכיצד תיקנת את אזהרת ה־act בשלב 4, השתמש בשאילתת findByRole כדי לחכות להופעת האופציה cattledog במסמך לפני שתמשיך להצהיב אקציה נוספת.

האובייקט userEvent שיובא לפני כן ידמה אירועי משתמש רגילים. בדוגמה זו, שיטת selectOptions מבצעת בחירה באפשרות cattledog שהמתינו לה בשורה הקודמת.

השורה האחרונה מאמתת כי המשתנה select מכיל את ערך cattledog שנבחר למעלה.

הקטע הבא שתוסיף לבלוק test() ב-Javascript יפעיל את בקשת החיפוש למצוא תמונות כלבים על סמך הגזע שנבחר ויאמת את קיומו של מצב טעינה.

הוסף את השורות המודגשות:

src/App.test.js
...
test("should be able to search and display dog image results", async () => {
   render(<App />);
    
   //...מדמה בחירת אפשרות ומאמת את ערכה

  //מדמה את התחלת בקשת החיפוש
   const searchBtn = screen.getByRole("button", { name: "Search" });
   expect(searchBtn).not.toBeDisabled();
   userEvent.click(searchBtn);

   //מצב הטעינה מוצג ונמחק בעת הצגת התוצאות
   await waitForElementToBeRemoved(() => screen.queryByText(/Loading/i));
})

השאילתה getByRole מאתרת את כפתור החיפוש ומשבצת אותו למשתנה searchBtn.

הבודק toBeDisabled matcher של jest-dom יאמת כי כפתור החיפוש אינו מנוטרל כאשר נבחרת אפשרות גזע.

השיטה click על אובייקט ה-userEvent מדמה לחיצה על כפתור החיפוש.

הפונקציה waitForElementToBeRemoved הפונקציה העזר המסונכרנת שיובאה לפני תחכה להופעה ולהיעלמות של ההודעה Loading בזמן ביצוע של קריאת API חיפוש. queryByText בתוך קולבאק של waitForElementToBeRemoved תבדוק את חוסר ההופעה של אלמנט מבלי לזרוק שגיאה.

התמונה למטה מציגה את מצב הטעינה שיוצג בעת ביצוע חיפוש:

באשף הבא, הוסף את הקוד ה-Javascript הבא כדי לוודא את התצוגה של התמונה וספירת התוצאות:

src/App.test.js
...
test("should be able to search and display dog image results", async () => {
   render(<App />)
   
   //...הדמיה בחירה של אפשרות ואימות הערך שלה
   //...הדמיה של קריאת בקשת חיפוש מתחילה
   //...הצגת מצב הטעינה מוצגת ומוסרת פעם אחת שהתוצאות מוצגות
          
   //וודא תצוגת תמונה וספירת תוצאות
   const dogImages = screen.getAllByRole("img");
   expect(dogImages).toHaveLength(2);
   expect(screen.getByText(/2 Results/i)).toBeInTheDocument();
   expect(dogImages[0]).toHaveAccessibleName("cattledog 1 of 2");
   expect(dogImages[1]).toHaveAccessibleName("cattledog 2 of 2");
})

השאילתה getAllByRole תבחר את כל התמונות של הכלב ותשייך אותם למשתנה dogImages. הגרסה *AllBy* של השאילתה מחזירה מערך המכיל אלמנטים מרובים התואמים לתפקיד המסופק. הגרסה *AllBy* שונה מהגרסה ByRole, שיכולה להחזיר רק אלמנט יחיד.

המימוק של fetch הכיל שני כתובות URL של תמונה בתגובה. בעזרת התאמת האורך toHaveLength של Jest, תוכל לוודא שישנן שתי תמונות המוצגות.

השאילתה getByText תבדוק כי ספירת התוצאות המתאימה מופיעה בפינה הימנית.

שתי אסרציות באמצעות המתאימות toHaveAccessibleName תאמת כי הטקסט המורשה הוא מקושר עם התמונות האישיות.

A completed search displaying images of the dog based on the breed selected along with the number of results found will look like this:

כאשר אתה משלב את כל החלקים של קוד ה-Javascript החדש, קובץ ה־App.test.js ייראה כמו זה:

src/App.test.js
import {render, screen, waitForElementToBeRemoved} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import mockFetch from "./mocks/mockFetch";
import App from './App';

beforeEach(() => {
   jest.spyOn(window, "fetch").mockImplementation(mockFetch);
})

afterEach(() => {
   jest.restoreAllMocks();
});

test('renders the landing page', async () => {
   render(<App />);

   expect(screen.getByRole("heading")).toHaveTextContent(/Doggy Directory/);
   expect(screen.getByRole("combobox")).toHaveDisplayValue("Select a breed");
   expect(await screen.findByRole("option", { name: "husky"})).toBeInTheDocument()
   expect(screen.getByRole("button", { name: "Search" })).toBeDisabled();
   expect(screen.getByRole("img")).toBeInTheDocument();
});

test("should be able to search and display dog image results", async () => {
   render(<App />);

   //הדמיה בחירת אפשרות ווידוי של ערך
   const select = screen.getByRole("combobox");
   expect(await screen.findByRole("option", { name: "cattledog"})).toBeInTheDocument();
   userEvent.selectOptions(select, "cattledog");
   expect(select).toHaveValue("cattledog");

   //מפעיל את בקשת החיפוש
   const searchBtn = screen.getByRole("button", { name: "Search" });
   expect(searchBtn).not.toBeDisabled();
   userEvent.click(searchBtn);

   //מציג מצב טעינה ומסיר אותו לאחר הצגת התוצאות
   await waitForElementToBeRemoved(() => screen.queryByText(/Loading/i));

   //מאמת תצוגת תמונות וספירת תוצאות
   const dogImages = screen.getAllByRole("img");
   expect(dogImages).toHaveLength(2);
   expect(screen.getByText(/2 Results/i)).toBeInTheDocument();
   expect(dogImages[0]).toHaveAccessibleName("cattledog 1 of 2");
   expect(dogImages[1]).toHaveAccessibleName("cattledog 2 of 2");
})

שמור את השינויים שנעשו בקובץ src/App.test.js.

כאשר אתה בודק את הבדיקות שלך, הפלט הסופי בטרמינל יכיל כעת את הפלט הבא:

Output
PASS src/App.test.js ✓ renders the landing page (273 ms) ✓ should be able to search and display dog image results (123 ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 4.916 s Ran all test suites related to changed files. Watch Usage: Press w to show more.

בשלב הסופי הזה, הוספת בדיקה שמאמת את פונקציות החיפוש, הטעינה והתצוגה של אפליקציית ה-Doggy Directory. עם הטענה הסופית שנכתבה, אתה עכשיו יודע שהאפליקציה שלך עובדת.

מסקנה

במהלך המדריך הזה, כתבת תרחישי מבחן באמצעות Jest, ספריית בדיקות ה-React Testing והתאמתיות jest-dom. בנייה באופן תרשים, כתבת נבחנים על פי איך משתמש פועל עם ה-UI. גם למדת על ההבדלים בין שאילתות ה-getBy*, findBy* ו- queryBy* וכיצד לבדוק קוד אסינכרוני.

כדי ללמוד עוד על הנושאים שנזכרו לעיל, ראה את התיעוד הרשמי של Jest, ספריית בדיקות ה-React Testing, ו-jest-dom. תוכל גם לקרוא את Common Mistakes with React Testing Library של Kent C. Dodd כדי ללמוד על הפרקטיקות הטובות בעת עבודה עם ספריית בדיקות ה-React Testing. למידע נוסף על שימוש בבדיקות snapshot באפליקציית React, ראה איך לכתוב בדיקות Snapshot.

Source:
https://www.digitalocean.com/community/tutorials/how-to-test-a-react-app-with-jest-and-react-testing-library