סייפרס, אוטומציה והאתגרים בלהיות מאמצים מוקדמים

זה התחיל בתור PoC קטן, ואז עברנו מסלניום לסייפרס. הנה התובנות שלי

מקור: Pexels, עיבוד תמונה

מאת איתי קוטלר

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

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

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

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

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

  • תשתית סייפרס חיה ובועטת שמריצה עשרות טסטים
  • תשתית CI/CD שמשלבת Docker ו-TeamCity
  • קיצור זמן הריצה ביותר מ70%

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

סייפרס

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

מדוע סייפרס?

“Are you tired of tests behaving badly? We were.”

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

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

קופצים למים

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

JavaScript ואני הפכנו לחברים קרובים, קראתי המון על node.js ולאט לאט תשתית הסייפרס הפכה  לאובססיה קטנה (אולי גדולה) שלי. ערכנו אינספור ישיבות עם מפתחי ה-Frontend בכדי להבין את הצרכים, הקשיים וההעדפות שלהם בכתיבת טסטים וכמובן איך להקל עליהם.

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

בעיות ופתרונות

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

חלונות קופצים – popup windows

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

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

/**
 * This command stubs the popup window and opens it in the same browser
 * @param {string} path: Expected path in the url
 * @param {url}: URL to navigate to, default - the current url
 */
export function stubOpenWindow({ path, url }) {
  cy.url().should("contain", path)
    .then((currentUrl) => {
      url = (url === undefined) ? currentUrl : url;
      cy.visit(url, {
        onBeforeLoad(win) {
          cy.stub(win, "open").as("windowOpen").returns(win);
        },
      });
    });
}

בעיית ה-iframe

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


/**
* Search for an element inside an Iframe
* @param {string} iframe: iframe selector
* @param {string} findBy: selector inside the iframe
*/
Cypress.Commands.add("getElementInIframe", ({ iframe, findBy }) => {
 const maxRetries = 3;
 const sleep = 5000;
 let numOfRetries = 0;
 let app;

 function isModalLoaded() {
   if (numOfRetries < maxRetries) {
     numOfRetries++;
     cy.get(iframe)
       .then(($iFrame) => {
         app = $iFrame.contents().find(findBy);
         const resp = !!app.length;
         if (resp === true) {
           expect(resp).to.eq(true);
           return cy.wrap(app);
         } else {
           cy.wait(sleep);
           isModalLoaded();
         }
       });
   } else {
     assert.isNotOk(true, `Failed to get Iframe '${iframe}' after ${maxRetries} retries`);
   }
 }

 isModalLoaded();
});

שימוש ב support/index.js

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

הנה כמה דוגמאות שרצות בתחילת כל טסט:

  1. קביעת ברירת המחדל לעדיפות של סלקטור שתחזור עבור כל אלמנט.
  2. יצירת אימייל פרטני לצרכי בדיקות וצירוף ה-baseURL על פי צורכי המוצר שלנו.
  3. לוגין לממשקי הניהול שלנו על מנת לדמות סטאטוסים שונים של משתמשים.
  4. וידוא של כל בקשת HTTP ע״י שימוש ב ()cy.server  ו ()cy.route
  5. מאחר ורוב הטסטים שלנו הם E2E, וכל שלב ‘it‘ תלוי בזה שלפניו, בזמן כשלון ננקוט בפעולות הבאות:
    1. הכשלה של כל הריצה
    2. עצירה של אפליקציית סייפרס 
    3. יציאה מסודרת מהמערכת הנבדקת ומחיקת המשתמש ע״י פונקציית ()afrerEach
afterEach(function() {
 if (this.currentTest.state === "failed" && Cypress.env("FAIL_FAST")) {
   logoutAndSuspendUser.call(this);
   Cypress.runner.stop();
 } else {
   cy.waitForAllAjaxResponder()
 }
});

6. ניקוי סביבת הבדיקות ע״י logout, מחיקת כל קבצי ה-cookies וה-local storage ולבסוף, מחיקת המשתמש ע״י פונקצית ()after.

שימוש בפקודות מותאמות אישית – custom commands

פונקציות שכיחות כגון  login & logout נבצע ע״י הפקודות המותאמות של סייפרס.

מנגנון הניסוי החוזר – Retry Mechanism

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

דוגמה לפקודת logout עם מנגנון הניסוי החוזר: 


/**
* Logout from the current application by adding "/logout" to the current windows location
*/
Cypress.Commands.add("logout", () => {
 const maxRetries = 3;
 const sleep = 3000;
 let numOfRetries = 0;

 function logoutFromDashboard() {
   if (numOfRetries < maxRetries) {
     numOfRetries++;
     cy.window()
       .then((win) => {
         win.location = "/logout";
       })
       .then(() => {
         cy.url().then((url) => {
           if (!url.includes("/login")) {
             cy.wait(sleep);
             logoutFromDashboard();
           } else {
             expect(url).to.include("/login");
             cy.clearCookie("csrftoken_local");
           }
         });
       });
   } else {
     assert.isNotOk(true, `Failed to logout after ${maxRetries} retries`);
   }
 }

 logoutFromDashboard();
});

CI/CD

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

בחרנו להשתמש ב- Docker משתי סיבות עיקריות:

  1. Docker ידועים ביכולת האינטגרציה הקלה שלהם
  2. סייפרס מספקים מגוון אימג׳ים של Docker

הרצה מקבילית נעשתה בעזרת שימוש בחבילת concurrent.futures של פייתון.

  • הגדרנו ריצה ב TeamCity שיריץ Packer
  • הריצה בונה את האימג׳ של ה-Docker ו״דוחפת״ אותו ל-AWS ECR. הריצה מתבצעת אחת לשבוע.
  • בתחילת הריצה הקוד יפנה תחילה לאימג׳ האחרון שנמצא ב-Repository של ECR ויעדכן אותו עם השינויים האחרונים.
  • ברגע שה-Docker מוכן, נשתמש בחבילת הפייתון concurrent.futures להרצת הטסטים במקביל, כאשר כל thread מריץ טסט בודד.
  • מספר ה threads נקבע בקונפיגורציה ב-TeamCity

מחשבות לסיום

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

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

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

הכותב הוא Automation Developer ב-Fundbox 

כתב אורח

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

הגב

7 תגובות על "סייפרס, אוטומציה והאתגרים בלהיות מאמצים מוקדמים"

avatar
Photo and Image Files
 
 
 
Audio and Video Files
 
 
 
Other File Types
 
 
 

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

סידור לפי:   חדש | ישן | הכי מדורגים
...
Guest

סייפרס עובד מעולה אבל רק בכרום. מה קורה אם רוצים לבדוק דפדפנים אחרים?

נתנאל
Guest

כרגע אין תמיכה בדפדפנים אחרים אבל יש תכנון לתמוך בעוד דפדפנים בהמשך. למי שcross browser testing קריטי לו, לא יכול להשתמש בCypress לעת עתה.

אייל חנאנל
Guest

איתי קוטלר התותח אוהב אותך

נתנאל
Guest

תודה, כתבה מעניינת!

סשה מה-QA
Guest

תענוג לקרוא את זה ובעברית. תודה תביאו עוד בבקשה

ספאזי
Guest

כתבה מדהימה, נהנתי לקרוא. תודה! ושרק תמשיכו…

ואדים
Guest

פוסט מעניין מאוד, לגבי אפשרות לעבוד עם מספר חלונות בדפדפן הייתי ממליץ על LeanFT של MicroFocus

wpDiscuz

תגיות לכתבה: