✕ סגור 
צור קשר
תודה על ההתעניינות .

Thank you! Your submission has been received!

Oops! Something went wrong while submitting the form

בדיקות אוטומטיות בריאקט: עבודה עם enzyme ו-Jest

רן בר זיק
|
קלה
|
Mar 28, 2019
alt="facebook"alt="linkedin"
להרשמה לניוזלטר

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

אחד מכלי העזר היותר חשובים שיש לנו ב-Jest זו הרכיב enzyme שהוא כרגע (נכון לגרסה 16 של ריאקט וגרסה 24 של jest) חיצוני. אבל הוא מספיק חשוב כדי שיהיה לו מקום משלו בדוקומנטציה של create react app וגם jest. בגדול הרכיב הזה עוזר לנו לבצע רינדור לקומפוננטה ולראות איך היא מתנהגת ואפילו יותר מכך – אנו יכולים ממש להתחייב למבנה של קומפוננטה ולפלט שלה.

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

npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer

מדובר במודולים שהולכים עם enzyme ודורשים יצירת קובץ הגדרות. יוצרים קובץ ב-src/setupTests.js זה קובץ ההגדרות שאפשר באמת להתפרע איתו אבל כרגע זה מה שנשים בו. תזכרו שה-configure זה אובייקט שאפשר לעשות איתו המון. מה עכשיו? רק את זה:

import { configure } from 'enzyme';

import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

מהנקודה הזו אפשר לבדוק.

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

import React from 'react';

class MyComponent extends React.Component {

 render() {

     return <p>Hello world!</p>

 }

}

export default MyComponent;

ואיך הבדיקה שלה נראתה

import React from 'react';

import ReactDOM from 'react-dom';

import MyComponent from './MyComponent';

it('renders without crashing', () => {

 const div = document.createElement('div');

 ReactDOM.render(<MyComponent />, div);

 expect(div.innerHTML).toEqual('<p>Hello world!</p>');

});

בואו ונמיר את הבדיקה הזו בבדיקה יותר מחוכמת וגם יותר עמידה. איך? עם enzyme. שימו לב:

import React from 'react';

import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

it('renders without crashing', () => {

 const myComponent = shallow(<MyComponent />);

 expect(myComponent.contains(<p>Hello world!</p>)).toEqual(true);

});

אז מה יש לנו כאן

אנחנו מייצרים את האלמנט באמצעות shallow. אם יש לקומפוננטה עוד קומפוננטות בתוכן – הן לא ירונדרו! דבר שהוא מאוד חשוב בבדיקות יחידה כי הבדיקות האלו צריכות להיות מבודדות לחלוטין (אם אני רוצה שגם הקומפוננטות הבנות ירונדרו, אני משתמש ב-mount). שנית, אני משתמש כאן בסינטקס עם JSX וזה נחמד ופשוט. אבל יש הרבה יותר! יש לי גם את ה-API המלא של Enzyme שמאפשר לי לעשות דברים יותר מעניינים כמו למשל לבצע find ו-traversing באותו סינטקס של. jQuery הנה דוגמה שבה אני בודק רק את הטקסט:

it('renders without crashing', () => {

 const myComponent = shallow(<MyComponent />);

 expect(myComponent.text()).toContain('Hello');

});

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

import React from 'react';

import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

let element; // "global element to be populated in the beforeEach"

// The description of the test suite

describe('MyComponent Component is working normally', () => {

 // Setup

 beforeEach(() => {

   element = shallow(<MyComponent />);

 });

 it('Checks if there is hello', () => {

   expect(element.text()).toContain('Hello');

 });

 it('Checks if there is world', () => {

   expect(element.text()).toContain('world');

 });

});

יש לנו כאן בעצם describe שעוטף את הכל והוא בעצם שם כולל ל׳סט הבדיקות׳. יש לנו beforeEach שרץ לפני כל בדיקה. במקרה הזה אנחנו יוצרים את הקומפוננטה ומאכלסים אותה לתוך משתנה גלובלי שאותו אנו בודקים. זה הכל! איזה יופי  

אם כבר יצא לכם לראות בדיקות אוטומטיות ו-unit test, אתם בטח תגידו ״וואו! זה ממש דומה ל-Jasmine!״ – ופה בעצם אין לי יותר מדי מה לתרום לכם חוץ מלומר לכם להשתמש ב-enzyme. אבל אם העולם של בדיקות אוטומטיות חדש לכם – תעזבו את כל מה שאתם עושים. כן, כן. תיצרו create react app – תיצרו create react app ותכניסו את MyComponent ותכתבו לו את הבדיקות לעיל. בדיקות אוטומטיות הן קריטיות לכל מוצר ומוצר.

אז ראינו את דוגמת ה-hello world. בואו ונרחיב את זה מעט. נוסיף props לקומפוננטה שלנו. איך עושים את זה בעולם האמיתי? ממש ככה. ראשית הקומפוננטה, לא משהו שיפיל אתכם עם עברתם את המאמרים הקודמים:

import React from 'react';

class MyComponent extends React.Component {

 constructor(props) {

   super(props);

   this.props = props;

 }

 render() {

     return <p>Hello {this.props.greeting}!</p>

 }

}

export default MyComponent;

ואיך הבדיקות הולכות בעולם האמיתי

אם אני רוצה להוסיף props, הדרך הטובה ביותר היא ליצור אובייקט של כל ה-props ואז להשתיל אותו בקומפוננטה ככה:

import React from 'react';

import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

let element; // global element to be populated in the beforeEach.

let props; // "props" is global because I need to access it.

// The description of the test suite

describe('MyComponent Component is working normally', () => {

 // Setup

 beforeEach(() => {

   // Here I put the props, in this case greeting

   props = {

     greeting: 'Galaxy',

   };

   element = shallow(<MyComponent {...props} />);

 });

 it('Checks if there is hello', () => {

   expect(element.text()).toContain('Hello');

 });

 it('Checks if there is world', () => {

   expect(element.text()).toContain(props.greeting);

 });

});

שימו לב שהקוד הזה נראה מבלבל בהתחלה. אולי בגלל הסינטקס של השלוש נקודות […] שהוא בעצם destrdeconstructucture. ואני משתמש בו כדי לקחת את כל האובייקט החביב של ה-props ולדחוף אותו אל הקומפוננטה. בגלל שה-props שלי הוא בסקופ העליון של הבדיקה, אני יכול להשתמש בו גם בבדיקה השנייה בלי להידרש למחרוזות טקסט מיותרות.

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

מאת: רן בר זיק, מתכנת ובלוגר

?DevOps רוצים להתעדכן בתכנים נוספים בנושאי

הירשמו עכשיו לניוזלטר שלנו ותמיד תישארו בעניינים > להרשמה

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

אחד מכלי העזר היותר חשובים שיש לנו ב-Jest זו הרכיב enzyme שהוא כרגע (נכון לגרסה 16 של ריאקט וגרסה 24 של jest) חיצוני. אבל הוא מספיק חשוב כדי שיהיה לו מקום משלו בדוקומנטציה של create react app וגם jest. בגדול הרכיב הזה עוזר לנו לבצע רינדור לקומפוננטה ולראות איך היא מתנהגת ואפילו יותר מכך – אנו יכולים ממש להתחייב למבנה של קומפוננטה ולפלט שלה.

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

npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer

מדובר במודולים שהולכים עם enzyme ודורשים יצירת קובץ הגדרות. יוצרים קובץ ב-src/setupTests.js זה קובץ ההגדרות שאפשר באמת להתפרע איתו אבל כרגע זה מה שנשים בו. תזכרו שה-configure זה אובייקט שאפשר לעשות איתו המון. מה עכשיו? רק את זה:

import { configure } from 'enzyme';

import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

מהנקודה הזו אפשר לבדוק.

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

import React from 'react';

class MyComponent extends React.Component {

 render() {

     return <p>Hello world!</p>

 }

}

export default MyComponent;

ואיך הבדיקה שלה נראתה

import React from 'react';

import ReactDOM from 'react-dom';

import MyComponent from './MyComponent';

it('renders without crashing', () => {

 const div = document.createElement('div');

 ReactDOM.render(<MyComponent />, div);

 expect(div.innerHTML).toEqual('<p>Hello world!</p>');

});

בואו ונמיר את הבדיקה הזו בבדיקה יותר מחוכמת וגם יותר עמידה. איך? עם enzyme. שימו לב:

import React from 'react';

import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

it('renders without crashing', () => {

 const myComponent = shallow(<MyComponent />);

 expect(myComponent.contains(<p>Hello world!</p>)).toEqual(true);

});

אז מה יש לנו כאן

אנחנו מייצרים את האלמנט באמצעות shallow. אם יש לקומפוננטה עוד קומפוננטות בתוכן – הן לא ירונדרו! דבר שהוא מאוד חשוב בבדיקות יחידה כי הבדיקות האלו צריכות להיות מבודדות לחלוטין (אם אני רוצה שגם הקומפוננטות הבנות ירונדרו, אני משתמש ב-mount). שנית, אני משתמש כאן בסינטקס עם JSX וזה נחמד ופשוט. אבל יש הרבה יותר! יש לי גם את ה-API המלא של Enzyme שמאפשר לי לעשות דברים יותר מעניינים כמו למשל לבצע find ו-traversing באותו סינטקס של. jQuery הנה דוגמה שבה אני בודק רק את הטקסט:

it('renders without crashing', () => {

 const myComponent = shallow(<MyComponent />);

 expect(myComponent.text()).toContain('Hello');

});

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

import React from 'react';

import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

let element; // "global element to be populated in the beforeEach"

// The description of the test suite

describe('MyComponent Component is working normally', () => {

 // Setup

 beforeEach(() => {

   element = shallow(<MyComponent />);

 });

 it('Checks if there is hello', () => {

   expect(element.text()).toContain('Hello');

 });

 it('Checks if there is world', () => {

   expect(element.text()).toContain('world');

 });

});

יש לנו כאן בעצם describe שעוטף את הכל והוא בעצם שם כולל ל׳סט הבדיקות׳. יש לנו beforeEach שרץ לפני כל בדיקה. במקרה הזה אנחנו יוצרים את הקומפוננטה ומאכלסים אותה לתוך משתנה גלובלי שאותו אנו בודקים. זה הכל! איזה יופי  

אם כבר יצא לכם לראות בדיקות אוטומטיות ו-unit test, אתם בטח תגידו ״וואו! זה ממש דומה ל-Jasmine!״ – ופה בעצם אין לי יותר מדי מה לתרום לכם חוץ מלומר לכם להשתמש ב-enzyme. אבל אם העולם של בדיקות אוטומטיות חדש לכם – תעזבו את כל מה שאתם עושים. כן, כן. תיצרו create react app – תיצרו create react app ותכניסו את MyComponent ותכתבו לו את הבדיקות לעיל. בדיקות אוטומטיות הן קריטיות לכל מוצר ומוצר.

אז ראינו את דוגמת ה-hello world. בואו ונרחיב את זה מעט. נוסיף props לקומפוננטה שלנו. איך עושים את זה בעולם האמיתי? ממש ככה. ראשית הקומפוננטה, לא משהו שיפיל אתכם עם עברתם את המאמרים הקודמים:

import React from 'react';

class MyComponent extends React.Component {

 constructor(props) {

   super(props);

   this.props = props;

 }

 render() {

     return <p>Hello {this.props.greeting}!</p>

 }

}

export default MyComponent;

ואיך הבדיקות הולכות בעולם האמיתי

אם אני רוצה להוסיף props, הדרך הטובה ביותר היא ליצור אובייקט של כל ה-props ואז להשתיל אותו בקומפוננטה ככה:

import React from 'react';

import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

let element; // global element to be populated in the beforeEach.

let props; // "props" is global because I need to access it.

// The description of the test suite

describe('MyComponent Component is working normally', () => {

 // Setup

 beforeEach(() => {

   // Here I put the props, in this case greeting

   props = {

     greeting: 'Galaxy',

   };

   element = shallow(<MyComponent {...props} />);

 });

 it('Checks if there is hello', () => {

   expect(element.text()).toContain('Hello');

 });

 it('Checks if there is world', () => {

   expect(element.text()).toContain(props.greeting);

 });

});

שימו לב שהקוד הזה נראה מבלבל בהתחלה. אולי בגלל הסינטקס של השלוש נקודות […] שהוא בעצם destrdeconstructucture. ואני משתמש בו כדי לקחת את כל האובייקט החביב של ה-props ולדחוף אותו אל הקומפוננטה. בגלל שה-props שלי הוא בסקופ העליון של הבדיקה, אני יכול להשתמש בו גם בבדיקה השנייה בלי להידרש למחרוזות טקסט מיותרות.

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

מאת: רן בר זיק, מתכנת ובלוגר

?DevOps רוצים להתעדכן בתכנים נוספים בנושאי

הירשמו עכשיו לניוזלטר שלנו ותמיד תישארו בעניינים > להרשמה

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
רן בר זיק
בואו נעבוד ביחד
צרו קשר