הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

הפונקציה getByRole ב react-testing-library

אחד הדברים שהכי קשה להכיל במעבר ל react-testing-library הוא החשיבות הגדולה שמפתחי הספריה מעניקים ל Accessibility Roles. בעוד רוב ספריות הבדיקה נותנות לנו להגיע לאלמנטים באיזו צורה שאנחנו רוצים (דרך CSS או אפילו XPath), כשמגיעים ל react-testing-library מגלים ש getByCSS זו לא פונקציה אמיתית שם.

השינוי הטכני הזה נובע משינוי תפיסה לגבי תפקיד הבדיקה ומה אנחנו רוצים לבדוק: בעוד ספריות בדיקה מסורתיות רוצות לבדוק שדברים מגיעים ל DOM בצורה נכונה, ב react-testing-library אנחנו רוצים לבדוק יותר מזה, אנחנו רוצים לבדוק שאנחנו מבינים את העמוד שלנו כמו שמשתמש מבין אותו. המעבר ל getByRole מהווה שינוי בנקודת המבט.

שימו לב לקטע הבא לדוגמה שהצגתי בוובינר אתמול:

export default function SimpleList({ items }) {
  const [filter, setFilter] = useState('');

  return (
    <>
      <input
        type="search"
        value={filter}
        onChange={(e) => setFilter(e.target.value)}
        name="filter-list"
      />
      <ul>
        {items.filter(item => item.text.includes(filter)).map((item, idx) => (
          <li
            key={item.id}
            className={(idx + 1) % 2 === 0 ? "even" : "odd"}
          >
            {item.text}
          </li>
        ))}
      </ul>
    </>
  );
}

בספריית בדיקות רגילה הייתי יכול להשתמש ב CSS כדי להגיע לאלמנט ה input ולמשל לקרוא ל:

document.querySelector('input[name="filter-list"]')

אבל במעבר ל react-testing-library ובפרט אם אני מוכן לקבל את השגעונות שלהם ולהשתמש ב getByRole אני אגלה שקשה לי לתפוס את אלמנט ה input הזה. הקוד הבא יעבוד:

const el = screen.getByRole('searchbox');

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

המעבר ל getByRole מכריח אותי לחשוב כמו המשתמש - איך המשתמש יודע על איזו תיבה מדובר? איך המשתמש יודע איפה להכניס את הקלט? משתמש לא רואה את המאפיין name או את הקלאסים של התיבה. הוא יכול לראות את הטקסט שרשום בה אבל בדרך כלל הוא יראה את ה Label שמשויך לתיבת הקלט. וכבר אנחנו רואים את הבעיה בקומפוננטה: ל input אין label שמסביר מה היא עושה.

תיקון של הקוד והוספת label נראה כך:

export default function SimpleList({ items }) {
  const [filter, setFilter] = useState('');

  return (
    <>
      <label>Filter List

        <input
          type="search"
          value={filter}
          onChange={(e) => setFilter(e.target.value)}
        />
      </label>

      <ul>
        {items.filter(item => item.text.includes(filter)).map((item, idx) => (
          <li
            key={item.id}
            className={(idx + 1) % 2 === 0 ? "even" : "odd"}
          >
            {item.text}
          </li>
        ))}
      </ul>
    </>
  );
}

ושימו לב לקסם - עכשיו אפשר להשתמש בטקסט ב label כדי לזהות את ה input שהסתכלנו עליו:

screen.getByRole('searchbox', { name: 'Filter List' } );

חידת ראיונות עבודה: הפונקציה Array.fill ואוביקטים ב JavaScript

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

אנחנו יודעים שהפונקציה Array.prototype.fill ממלאת מערך בערך שנעביר לה, ולכן הקוד הבא מחזיר 40:

new Array(4).fill(10).reduce((acc, val) => acc + val);

ואנחנו גם יודעים שאפשר לשנות חלק מהערכים אחרי שהפעלנו fill כך שלדוגמה הקוד הבא יחזיר 50:

const data = new Array(4).fill(10);
data[0] += 10;

data.reduce((acc, val) => acc + val);

אבל מה יקרה אם ננסה לעשות את אותו טריק עם אוביקטים... מה יחזיר הקוד הבא? ולמה?

data.reduce((acc, val) => acc + val.value, 0)

שלום GraphQL

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

בפוסט זה נדבר על הבעיות של REST, על GraphQL ונראה דוגמאות קוד ראשונות לעבודה עם GraphQL.

המשך קריאה

מדריך מקוצר ל Service Worker

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

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

המשך קריאה

מה יש לך נגד for...in

אחת הלולאות שהיו פעם פופולריות ב JavaScript אבל בשנים האחרונות מתכנתים כמעט והפסיקו להשתמש בהן היא לולאת for...in. לולאה זו נועדה לרוץ על כל המפתחות של אוביקט למשל כדי להדפיס את כל תוכן האוביקט או לחפש מפתח של ערך מסוים.

בדוגמא מעשית נניח שיש לנו אוביקט שמחזיק כתובות מייל של משתמשים:

const email = {
    bob: 'bob@gmail.com',
    jane: 'jane@gmail.com',
    dave: 'dave@hotmail.com',
};

אז נוכל להשתמש בלולאת for...in כדי להדפיס את כל האנשים שיש להם כתובת מייל בג'ימייל:

for (let name in email) {
    const address = email[name];
    if (address.endsWith('@gmail.com')) {
        console.log(name);
    }
}

אבל - לולאת for...in כוללת גם מוקש קטן. המפתחות שחוזרים הם לא רק המפתחות מהאוביקט שאתם סורקים, אלא גם המפתחות מכל ה Prototypes של אותו אוביקט. לכן הקוד הבא ידפיס 3:

let count = 0;
const one = { a: 10, b: 20 };
const two = Object.create(one);
two.c = 30;

for (let k in two) {
    // count the keys
    count ++;
}

console.log(count);

הלולאה ספרה שני מפתחות מהאוביקט one ועוד מפתח אחד מהאוביקט two וכך הגיעה ל-3. כשיש לנו אוביקט ביד לא תמיד אנחנו יודעים לצפות מי ה Prototype שלו ואיזה מאפיינים הגיעו מאותו Prototype, ולכן לולאות for...in עלולות לרוץ על יותר מפתחות ממה שציפינו.

בקוד JavaScript חדש אנחנו מעדיפים להשתמש בפונקציה Object.keys שמחזירה רק את המפתחות של האוביקט שהעברתם לה. קוד מקביל עם Object.keys יראה כך והפעם ידפיס 1:

let count = 0;
const one = { a: 10, b: 20 };
const two = Object.create(one);
two.c = 30;

for (let k of Object.keys(two)) {
    // count the keys
    count ++;
}

console.log(count);

שני מסלולי בוטקמפ חדשים

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

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

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

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

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

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

מסלול בוטקמפ ללימוד ריאקט ייפתח בתאריך 14.06.2020 למשך שלושה שבועות. מפגשי העבודה יתקיימו בימי ראשון ורביעי בין השעות 9:00 ל-11:00 בבוקר בתאריכים: 14/06, 17/06, 21/06, 24/06, 28/06, 01/07. מחיר הקורס 970 ש"ח וזה כולל חודש מנוי לתקופה של הקורס (אם אתם כבר מנויים החודש הזה יתווסף לכם אוטומטית לתקופת המנוי). הצטרפות לבוטקמפ בקישור: https://www.tocode.co.il/quickjoin2?term=15.

מסלול בוטקמפ ללימוד פייתון יפתח בתאריך 14.06.2020 למשך שלושה שבועות. מפגשי העבודה יתקיימו בימי ראשון ורביעי בין השעות 13:00 ל-15:00 בצהריים בתאריכים: 14/06, 17/06, 21/06, 24/06, 28/06, 01/07. מחיר הקורס 970 ש"ח וזה כולל חודש מנוי לתקופה של הקורס (אם אתם כבר מנויים החודש מתווסף אוטומטית לתקופת המנוי). הצטרפות לבוטקמפ פייתון בקישור: https://www.tocode.co.il/quickjoin2?term=16.

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

מבוא זריז ל Redux

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

(וכן - ניסיתי את MobX, לא נפלתי מהכסא, ואני נשאר עם רידאקס). מוכנים? נמשיך לקוד.

המשך קריאה

טיפ HTML - הגדרת type על כפתור בטופס

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

<form>
  <label>
    type something:
    <input type="text" name="text" />
  </label>

  <button>Save</button>
</form>

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

תשמחו לגלות שלמאפיין type יש עוד שני ערכים אפשריים: אם נגדיר בתור type את הערך reset נקבל כפתור שיאפס את כל הפקדים לערך ברירת המחדל שלהם, ויותר מעניין - אם נגדיר בתור type את הערך button הכפתור פשוט לא יעשה כלום כשלוחצים עליו. בצורה כזו לא תצטרכו לקרוא ל preventDefault מה JavaScript שלכם כדי למנוע את הגשת הטופס. בקוד זה נראה כך:

<form>
  <label>
    type something:
    <input type="text" name="text" />
  </label>

  <button type="button">Save</button>
</form>

חדש באתר: קורס Webpack

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

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

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

בקורס החדש תמצאו קצת מעל 4 שעות של וידאו המכסים המון סוגים של פרויקטים ופרדיגמות תכנות ווב כמו: React, TypeScript, CSS Modules, Mocha, Scss ועוד.

בנוסף אנחנו צוללים להגדרות ולמנגנונים הבסיסיים של וובפאק עצמו כדי להבין איך עובד Lazy Loading, תמיכה ב Browser Cache, כיווץ קוד JS ו CSS, החלפת מודולים (HMR), מחיקת קוד מת (Tree Shaking) ועוד.

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

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

תהנו מהקורס, ינון