טוב, אז על Selenium WebDriver נכתב כבר המון. כמות ה-Tutorials הקיימים ברשת לנושא היא עצומה (גם כאן בבלוג הנוכחי ניתן ללמוד מהדרכות און-ליין על סלניום), בלוגים ופוסטים חדשים צצים כל הזמן כפטריות לאחר הגשם, ישנם פורומים המוקדשים אך ורק לסלניום וזה כבר די ידוע שהסביבה הזו הפכה כבר מזמן לסטנדרט בתחום הבדיקות האוטומטיות.
באופן אישי, יצא לי לעבור על כמה עשרות, אם לא מאות אתרים שונים המקדישים את תכולתם ל-Selenium , ראיתי המון (באמת המון) רקע תיאורטי, דוגמאות, הסברים, התקנות , קטעי קוד… הכל מלבד דבר אחד: איך באמת Selenium WebDriver בנוי בפועל מאחורי הקלעים ?
הרי אנחנו יודעים כי Selenium WebDriver הינן ספריות של קוד , אותן ספריות אשר מאפשרות לנו לבצע פעולות על דפדפנים מסוגים שונים , אבל איך ספריות הקוד הללו נראות ? כיצד הן בנויות ? מהי הארכיטקטורה שלהן ? אילו מערכות יחסים (relations) קיימות בין המחלקות השונות או הממשקים השונים אשר מרכיבים את ספריות הקוד הללו ?
החלטתי להקדיש הפעם את הפוסט לנושא זה, נושא שמשום מה אוהבים לא לדבר עליו: Inside Selenium WebDriver.
אך לפני כן נתחיל מכמה הערות:
1. ספריות הקוד הן עצומות, המון שעות אדם הושקעו בלתכנן, לעצב, לכתוב ולתקן אותן. בפוסט זה כמובן שלא אוכל לכסות את הכל, אלא רק את הבסיס והאיזורים החשובים (חלק מהם בכל אופן) עד שיגמר לי הדיו 🙂
2. ספריות הקוד של Selenium WebDriver ממומשות במגוון של שפות תכנות , בפוסט זה החלטתי להתמקד בשפה הפופולרית ביותר של סלניום – Java
3. אציג כאן את ספריות הקוד שהורדתי מהאינטרנט (זה הרי קוד פתוח – כל אחד יכול לעשות זאת) , אך ניתן גם לראות תצוגה שלהן בדף הדוקומנטציה של הפרוייקט: http://seleniumhq.github.io/selenium/docs/api/java/index.html
4. אציג כאן את גרסת 3.4.0 של Selenium WebDriver
5. התמונות חתוכות ואינן מראות את כל תכולת הקוד , מומלץ ללחוץ עליהן להגדלתן
זהו הפרוייקט, כך הוא נראה ב-File System:
אנו שמים לב כי ישנן ספריות עם שמות של דפדפנים כמו edge , firefox, chrome וכו'. בתוך ספריות אלו קיימות מחלקות שמטפלות בפונקציונליות של הדפדפן תחתיו הן יושבות , זאת אומרת, תחת ספריית edge יהיו מחלקות שמטפלות בפונקציונליות על דפדפן ה-edge וכן הלאה. בתמונה המוצגת למטה ניתן לראות את התוכן של ספריית ה-chrome:
למי שיצא כבר לכתוב אוטומציה עם Selenium WebDriver על דפדפן ה-Chrome לבטח מכיר את הפקודה:
WebDriver driver = new ChromeDriver();
שהיא למעשה הפקודה שפותחת לנו Session לדפדפן הכרום, איתו אנו אח"כ נעבוד ועליו נבצע את הפעולות. אך מהי בעצם שורת הקוד הזו ? מה היא אומרת ? למעשה יש כאן יצירת אובייקט בשם driver שהוא מסוג WebDriver ואנו מאתחלים אותו דרך ה-Constructor של ChromeDriver , רגע, מה ? שנייה, בואו נפרק את זה:
ה-WebDriver הינו ממשק (Interface) ואילו ה-ChromeDriver הינה מחלקה (Class) אשר יורשת מה-WebDriver (טוב נו, לא בדיוק, היא יורשת ממחלקה אחרת שמממשת את ה-WebDriver , אנחנו נגיע לזה עוד מעט) , בתוך מחלקת ה-ChromeDriver ישנו בנאי (Constructor) שזה למעשה לא אחרת מאשר מתודה בעלת אותה שם כמו המחלקה, למען האמת ישנם כמה בנאים שממומשים במחלקה זו (מה שנקרא : Method Overload או במקרה הזה: Constructor Overload), זוהי המחלקה:
שימו לב כי קיימות במחלקה זו מתודות שהן Deprecated (אינן נתמכות יותר)
אנו רואים כי מחלקה זו יורשת ממחלקה אחרת שנקראת: RemoteWebDriver , אז בואו נפתח אותה ונראה את תוכנה:
מה אנו רואים כאן ?
1. גם כאן אנו רואים מימוש של כמה בנאים.
2. ניתן לראות פה אפילו הערות של המפתחים על הקוד (דברים שדורשים פיתוח נוסף \ תיקון \ עידכון דוקומנטציה)
3. מחלקה זו מממשת שני ממשקים: JavaScriptExecutor ו-WebDriver
בואו כעת נפתח ונראה את ממשק (Interface) ה-WebDriver:
למי שכבר יצא לעבוד עם סלניום, לבטח מזהה כאן כמה מן המתודות, כמו ה-findElement שמחזירה אובייקט מסוג WebElement , כמו ה-findElements שמחזירה רשימה של WebElement או ה-getTitle שמחזיר מחרוזרת (String) ואחרים. ה-WebDriver הוא כאמור הממשק , כאן אנו רק מצהירים על המתודות והמימושים שלהם יתבצעו בהמשך הדרך במחלקות היורשות.
ניתן לראות כי ממשק זה מממש מממשק נוסף שנקרא: SearchContext. נפתח אותו:
ניתן לראות כאן את ההצהרות של findElement ו-findElements , אלו הן הפונקציות שדרכם אנחנו יכולים לזהות את הלאמנטים על הדף.
לממשק ה- SearchContext יש שני ממשקים אחרים מממשים: האחד הוא ה-WebDriver שכבר ראינו והשני הוא ה-WebElement:
בתמונה למעלה אנו רואים את ההירארכיה שדיברנו עליה: ה-ChromeDriver יורש מה-RemoteWebDriver שמממש את ה-WebDriver שמממש את ה-SearchContext ובמקביל יש לנו גם את ה-WebElement שמממש את ה-SearchContext ואת ה-RemoteWebElement שמממש את ה-WebElement , בואו נראה כעת את ממשק ה-WebElement ואחריו את מחלקת ה-RemoteWebElement:
גם כאן, אלו שיצא להם לעבוד כבר עם סלניום יכירו בטח חלק או את כל המתודות הקיימות כמו click , submit, isEnabled, getText ואחרים…
אז כאמור, ה-WebElement הינו ממשק שמי שמממש אותו היא מחלקת ה-RemoteWebElement , נפתח ונראה אותה:
שימו לב כי כאן נמצאים המימושים של פקודות ששייכות לאלמנטים, למשל פקודת ה-click , איך זה בדיוק עובד ?
אנחנו רואים כי פונקציית ה-click הינה פונקציה אשר קוראת לפונקציה נוספת שנקראת execute ואליה אנחנו שולחים את DriverCommand.CLICK_ELEMENT ועוד פרמטר של ImmutableMap שמייצג לנו את ה-sessionId (נראה אותו בהמשך…). מהו ה-DriverCommand ?
ה-DriverCommand הוא ממשק נוסף בו מוגדרים קבועים לפקודות אשר מוגדרות בפרוטוקול ה- WebDriver JSON , למעשה ה-WebDriver JSON wire protocol הינו הדרך של WebDriver לתקשר עם המימושים של הדרייבירם (ה-ChromeDriver , IEDriver, FireFoxDriver וכו'). ממשק זה אגב, נקרא גם ממשק ריק (אינו מכיל מתודות).
כך נראה ממשק ה-DriverCommand :
בשביל להבין כיצד זה עובד, נצטרך לפתוח את הפרוייקט של Json Wire Protocol באתר של GitHub .
כאן למשל נוכל לראות את הדוקומנטציה למימושים השונים של הפקודות המוכרות לנו מ-Selenium WebDriver כמו למשל פקודת ה-click , ה-clear וכו'
מעבר לזה, ניתן עוד להמשיך ולשוטט בנבכי המחלקות הממשקים והספריות השונות, כמו במחלקות ה-Exceptions למיניהן, סוגי ה-Waits, תחת ספריית ה- support בה קיימים המימושים של Page Factory , FindBy ועוד ועוד ועוד …
הנאה מובטחת לכולם 🙂
יוני