סביבת עבודה לפיתוח מונחה בדיקות בריאקט

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

האתגר הגדול ביותר בפיתוח מונחה בדיקות הוא איך לכתוב קוד כך שיהיה קל לבדוק אותו. מתכון בטוח לכשלון בפיתוח מונחה בדיקות, או כתיבת בדיקות יחידה באופן כללי, הוא לנסות לשלב בדיקות יחידה במערכת קיימת הכתובה באופן שאינו ערוך לבדיקות. התוצאה היא בדיקות יחידה ריקות: כלומר בדיקות יחידה שלא בודקות שום דבר בעל משמעות. 
ריאקט בתור ספריית פקדים פותרת בעייה זו באופן מבריק. מאחר וכל פקד בריאקט מגדיר בצורה ברורה את הממשק שלו לעולם החיצון, יהיה לכם מאוד קשה לכתוב פקד שקשה לבדוק אותו. אין תלויות נסתרות, אין מצב גלובלי ואפילו אין DOM. הפקד שלכם מקבל state ו properties ומגיב בהתאם באמצעות פונקציית render.

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

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

1. לאן אנו רוצים להגיע

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

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

webstorm IDE with karma

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

2. מבנה עץ הפרויקט

פיתוח מונחה בדיקות מחייב קובץ בדיקה לכל פקד. מיד נראה את הפורמט של קבצי הבדיקה אך לפני כן נעשה קצת סדר בקבצים. עץ הפרויקט שלנו יצטרך לכלול כעת גם את הפקדים השונים וגם את קבצי הבדיקות שלהם. אני משתמש ב webpack ו require כדי לנהל תלויות בין פקדים. 

המוצר עצמו מתחיל בקובץ HTML (יכול גם להיות jsp, php או כל קובץ אחר שנוצר בצד השרת). קובץ ה HTML של הפרויקט טוען קובץ js יחיד שנקרא bundle.js ומיוצר באמצעות webpack. תיקיית js מכילה קובץ זה. הוראות הייצור של הקובץ נמצאות בקובץ webpack.config.js. פקדי ריאקט של הפרויקט נשמרים בתיקיית src/components וקובץ הקוד הראשי נשמר בתור src/app.js. עד לכאן זהו מבנה רגיל של פרויקט ריאקט.

קבצי הבדיקות נשמרים בתיקיית spec. לכל פקד ב src/components יש קובץ בדיקה מתאים בתיקיית spec המסתיים בסיומת מיוחדת באמצעותה אנו מזהים שמדובר בקובץ בדיקות. אני בחרתי בסיומת -test. לכן אם יש לנו פקד עבור רשימת מדינות הפקד יורכב מקובץ מקור שישמר כ src/components/countries.js וקובץ בדיקות שישמר כ spec/countries-test.js.

ספריות צד-שלישי מנוהלות באמצעות npm ונשמרות בתיקיית node_modules. 

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

כך נראה מבנה העץ המלא:

js/
  - bundle.js
node_modules/
  - underscore/
  - react/
  - ...
spec/
  - countries-test.js
src/
  - components/
    - countries.js
  - app.js

karma.conf.js
package.json
tests.webpack.js
webpack.config.js

 

3. קוד הבדיקות

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

var React = require('react');
var TestUtils = require('react/lib/ReactTestUtils');
var expect = require('chai').expect;
var Countries = require('components/countries');


describe('countries', function () {

  it('renders each country provided in props', function() {
    var clist = ["England", "France", "Germany"];

    var countries = TestUtils.renderIntoDocument(<Countries items={clist}/>);
    var items = TestUtils.scryRenderedDOMComponentsWithTag(countries, 'LI');

    expect(items.length).to.eq(3);
    expect(items.map((item) => item.props.children)).to.eql(clist);
  });
});

פרט לצ׳אי ומוקה חדי העין שביניכם יבחינו בתוסף TestUtils. ספריה זו הינה חלק מספריית React וכוללת מספר פונקציות להפעלת פקד בסביבת בדיקות. כך למשל הפונקציה renderIntoDocument מרנדרת את הפקד למסמך, והפונקציה scryRenderedDOMComponentsWithTag מחזירה רשימה של אלמנטים מסוג מסוים. כך אפשר לבדוק שפקד רשימת המדינות אכן רינדר 3 אלמנטי li עם שמות המדינות שהעברנו לו.

4. הפעלת הבדיקות באמצעות Karma

הספריה הבאה ברשימה היא karma. זוהי ספריית ״דבק״ הכוללת כלי לשורת הפקודה שמריץ בדיקות בדפדפן ומדווח חזרה את התוצאות. סביבת הפיתוח Webstorm יודעת לעבוד עם קארמה כך שבלחיצת כפתור אפשר להפעיל את הבדיקות ולראות את התוצאות בתוך סביבת הפיתוח עצמה. 
כל שעלינו לעשות הוא לבנות קובץ הגדרות karma.conf.js שיכיל את פרמטרי הבדיקות. כך נראה הקובץ בפרויקט הדוגמא:

var webpack = require('webpack');
var RewirePlugin = require("rewire-webpack");

module.exports = function (config) {
  config.set({
    customLaunchers: {
      chrome_react: {
        base: 'Chrome',
        flags: ['--load-extension=/Users/ynonperek/Library/Application Support/Google/Chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/0.13.1_1/']
      }
    },

    browsers: [ 'chrome_react' ],

    singleRun: true,

    frameworks: [ 'mocha', 'chai-sinon' ],

    files: [
      'tests.webpack.js'
    ],

    preprocessors: {
      'tests.webpack.js': [ 'webpack', 'sourcemap' ]
    },

    reporters: [ 'dots' ],

    webpack: {
      devtool: 'inline-source-map',
      resolve: {
        modulesDirectories: ['.', 'node_modules', 'src']
      },
      module: {
        loaders: [
          { test: /\.js$/, loader: 'babel-loader', exclude: /(node_modules|bower_components)/ }
        ]
      },
      plugins: [
        new RewirePlugin()
      ]
    },

    webpackServer: {
      noInfo: true
    }

  });
};

בשורת הדפדפנים ניתן לראות שאני משתמש בדפדפן כרום עם תוסף של ריאקט לצורך הבדיקות. את הקוד לטעינת התוסף יש להגדיר באופן ידני תוך ציון הנתיב המלא לתוסף וזה תפקידה של שורה 9. מי שירצה להשתמש בפרויקט הדוגמא יצטרך להחליף את הנתיב לנתיב בו מותקנת React Chrome Extension אצלכם בסביבה (או למחוק את השורה לחלוטין ולעבוד בלי התוסף).

בשורת ה Frameworks ניתן לראות את השימוש ב mocha, chai ו sinon. קארמה יטען את שלוש הספריות לפני טעינת קבצי הבדיקה כך שנוכל להשתמש בהן בבדיקות שלנו.
בשורות הבאות תמצאו את ההגדרות ל webpack, כולל איזה מודולים לטעון באמצעות babel, היכן לאתר מודולים ופלאגינים שונים בהם השתמשתי (במקרה זה הפלאגין rewire שעליו ארחיב בפוסט אחר). 

הפעלת הבדיקות באמצעות קארמה ו Webstorm היא פשוטה: כפתור ימני על הקובץ karma.conf.js ובחירה מהתפריט באפשרות ״Run karma.conf.js״. קארמה ו Webstorm ידאגו לשאר.

5. סיכום וקריאה נוספת

קוד מלא של פרויקט דוגמא עם כל קבצי ההגדרות זמין לשימושכם בגיטהאב שלי בקישור:
https://github.com/ynonp/react-tdd-demo

את ההשראה לפוסט קיבלתי מפוסט דומה שהציג setup קצת יותר בסיסי אבל גם טוב ואפשר למצוא אותו כאן:
http://qiita.com/kimagure/items/f2d8d53504e922fe3c5c

כאן תמצאו פוסט מפורט על מוקה, סינון וצ׳אי (ללא ריאקט):
https://nicolas.perriault.net/code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/

ולסיום התיעוד על React.TestUtils:
https://facebook.github.io/react/docs/test-utils.html

*** רוצים ללמוד ריאקט בצורה מסודרת ולעומק? יש לנו קורס אונליין שיעזור לכם להשתלט על העניינים בזריזות ולהתחיל לכתוב קוד ריאקט ופלוקס נכון מהרגע הראשון. לפרטים נוספים:
tocode.co.il/bundles/react-by-example