iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0

學習原因:

還記得 HTML element 嗎?應用 HTML Tag 作標記的頁面元素,我們可以透過 Locator 的應用,讓 WebDriver 找出個該元素來執行操作。一般來說 Locator 都是用 Element 的 Tag 和 Attribute 資料來定位。然而 Locator 的種類有很多種,Locator 的選用會影響執行的效能,也會影響維護性,因此需要學習如何選用對的 Locator。

學習目標:

  • 認識各種 Locator 的應用
  • 怎樣挑選對的 Locator

我們需要用到 Browser 的 DevTools 來輔助尋找頁面 Element 的資料,一般都是用 F12 打開。
點開 Elements Tab,選取目標 Element 後,再看 Element Tag 內有什麼資訊可以用來做 Locator。

https://ithelp.ithome.com.tw/upload/images/20230917/20162038QFBi6D8fng.png

先看 Locator 有哪些種類,才知道找到 Element 之後要怎樣選用 Locator。

1. ID

對應到 element 的 ID attribute,一般來說都是 Unique,也相對少被更動。

# Example: <div id="wpfront-notification-bar-spacer">Testing</div>

elem = driver.find_element(By.ID, 'wpfront-notification-bar-spacer')

2. Name

對應到 element 的 Name attribute,非 Unique,會出現在 HTML form。

# Example: <input type="text" name="username />

elem = driver.find_element(By.NAME, 'username')

3. Link Text

是指網頁中超連結的可見文字

# Example: <a href="https://www.example.com">Click here to visit Example</a>

elem = driver.find_element(By.LINK_TEXT, 'Click here to visit Example')

4. Partial Link Text

同樣是指網頁中超連結的可見文字,但只需要部分文字符合。

# Example: <a href="https://www.example.com">Click here to visit Example</a>

elem = driver.find_element(By.PARTIAL_LINK_TEXT, 'visit Example')

5. Class Name

指 element 的 class attribute,一樣用作定義 Element 的 CSS 樣式,非 Unique。CSS Class 跟外觀有關係,而外觀是蠻常作調整的內容,所以被改的機率比前 2 者稍為高。

# Example: <div class="entry-content"></div>

elem = driver.find_element(By.CLASS_NAME, 'entry-content')

6. Tag Name

就是 Element Tag,用到的機率很低,因為同頁相同的 Tag 太多。

# Example: <button type="submit"></button>

elem = driver.find_element(By.TAG_NAME, 'button')

7. CSS Selector

使用 CSS 的選擇器語法來指定元素,含有多種選擇器:

  • 元素選擇器:

    使用 Tag Name 作選擇器。例如:div 會選擇所有 <div> element。

  • CSS Class 選擇器:

    .標記。例如:.classname 會選擇所有帶有指定 class 的element。

  • ID 選擇器:

    #標記。例如:#elementId 會選擇具有指定 ID 的element。

  • 屬性選擇器:

    使用 Element Attribute 作為選擇器選。例如:[name="username"] 會選擇具有 name 屬性值為 "username" 的 element。

  • 子元素選擇器:

    選擇某個 element 的直接 child element。例如:ul > li 會選擇所有在 <ul> element 下的 <li> child element。

  • 後代選擇器:

    選擇某個 element 的後代 element。例如:div p 會選擇所有在 <div> 元素內部的 <p> element。

  • 組合選擇器:

    結合多個選擇器來選擇 element。例如:div.menu 會選擇所有帶有 menu class 的 <div> element。

例子:

<div class="container">
  <h1>Welcome to My Website</h1>
  <p class="intro">This is the homepage of my website.</p>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>
</div>
# 通過 **後代選擇器** 定位標題
header = driver.find_element(By.CSS_SELECTOR, '.container h1')
print(header.text)

# 通過 **類選擇器** 定位段落
intro = driver.find_element(By.CSS_SELECTOR, '.intro')
print(intro.text)

# 通過 **組合選擇器** 定位段落
intro = driver.find_element(By.CSS_SELECTOR, 'div.container p.intro')
print(intro.text)

# 通過 **子元素選擇器** 定位列表項目,取得多於一個 Element 時,會存成 List
items = driver.find_elements(By.CSS_SELECTOR, 'div.container ul > li')
for item in items:
    print(item.text)

Output :

Welcome To My Website
This is the homepage of my website.
This is the homepage of my website.
Item 1
Item 2
Item 3

7. XPath

XPath(XML Path Language)是一種用於在 XML 文件中定位元素的語言。它使用路徑表示法來定位 Element,這些路徑類似於文件系統中的路徑。XPath 表達式可以從根元素開始,沿著元素的層次結構進行導航,以定位所需的元素。

XPath 有 2 種寫法:

  • Absolution XPath (絕對路徑) : 從最頂層開始,逐層列出

    /html/body/div/div[2]/div/div[2]/main/article/div/div/div[2]

  • Relative XPath (相對路徑):是相對於當前元素的路徑,描述元素在當前上下文中的位置

    //*[@id="customer_login"]

現在 Chrome Browser 的 DevTools,點選 Element 後點右鍵,可以直接 Copy Element 的 XPath。當中可以選擇 XPath 或 Full XPath,分別會得到相對路徑和絕對路徑的寫法。

https://ithelp.ithome.com.tw/upload/images/20230917/20162038PDjfnxwl9P.png

非常不建議使用 Absolution XPATH ,可讀性極低的同時,頁面每次作任何修改,路徑都一定會跟著改變,那就只能一直跟著改了,時間再多都不夠用。

所以要學習使用 Relative Path,寫的時候也要注意可讀性避免使用 index 讀取資料

寫 Relative Path 的小技巧:

  1. 從目標 Element 中觀察是否有 唯一 且有 代表性的資料 可以使用。
  2. 若目標 Element 沒有足夠的資訊可定位,再往上一層的 Element 看,再利用 Parent 的關係指到目標 Element。
    • 選用 唯一性的資料 可明確定位
    • 選用 有代表性的資料 可以提高可讀性,而且這種資料多半都是由 Developer 定義,隨機變動的機率相對小。

我們來看一些例子,同樣是應用這個 HTML 檔

<div class="container">
  <h1>Welcome to My Website</h1>
  <p class="intro">This is the homepage of my website.</p>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>
</div>
# 通過元素名稱定位標題
header = driver.find_element(By.XPATH, '//h1')
print(header.text)

# 通過 class 屬性值定位段落
intro = driver.find_element(By.XPATH, '//p[@class="intro"]')
print(intro.text)

# 通過父子關係定位列表項目
intro = driver.find_elements(By.XPATH, '//div[@class="container"]/ul/li')
for item in items:
    print(item.text)

XPath Axes (軸)

是 XPath 語言中的一個概念,用於描述 Element 之間的相對位置。它允許你在元素之間進行更靈活的導航和查詢。

軸可以看作是一個指向特定方向的概念,它可以幫助你在文檔中定位特定元素。XPath 定義了一些不同的軸,每個軸都有不同的用途和功能。

以下是一些常見的 XPath 軸:

<!-- 下文會利用這 XML 檔來作例子解釋: -->
<Tree_A/>
<Tree_B>
    <Branch_C>
        <Leaf_E/>
        <Leaf_F/>
    </Branch_C>
    <Branch_D/>
</Tree_B>
  1. ancestor 軸:選擇指定元素的 所有祖先 元素。

    I.e. //Leaf_E/ancestor::* 取得 <Branch_C>, <Tree_B> Element

  2. child 軸:選擇指定元素的 所有直接子元素

    I.e. //Tree_B/child::* 取得 <Branch_C><Branch_D> Element

    I.e. //Tree_B/child::Branch_C 取得 <Branch_C> Element

  3. descendant 軸:選擇指定元素的 所有後代元素(包括子孫元素)

    I.e. //Tree_B/descendant::* 取得 <Branch_C>, <Branch_D>, <Leaf_E>, <Leaf_F> Element

    I.e. //TreeB/descendant::Leaf_F 取得 <Leaf_F> Element

  4. following 軸:選擇文檔中在指定元素 之後的所有元素

    I.e. //Tree_A/following::* 取得 <Tree_B>, <Branch_C>, <Leaf_E>, <Leaf_F>, <Branch_D> Element

  5. following-sibling 軸:選擇指定元素 之後的所有同級元素

    I.e. //Tree_A/following-sibling::* 取得 <Tree_B> Element

  6. parent 軸:選擇指定元素的 父元素

    I.e. //Branch_C/parent::* 取得 <Tree_B> Element

  7. preceding 軸:選擇文檔中在指定元素之前的所有元素

    I.e. //Branch_D/preceding::* 取得 <Branch_C>, <Leaf_F> , <Leaf_E>, <Tree_B>, <Tree_A> Element

  8. preceding-sibling 軸:選擇指定 元素之前的所有同級元素

    I.e. //Branch_D/preceding-sibling::* 取得 <Branch_C> Element

Locator 的選擇策略 (Locator Strategy)

主要以 寫法簡單,且 不容易被改動的資料 為優先。一般來說 ID 會是最好的選擇,因為他是唯一值,且比較少會被改動。

而我個人的取向會是:ID > Name > ClassName > CSS Selector / XPath ,其他 Locator 看情況選用。

當中 CSS Selector 跟 XPath 會視情況來選用,這 2 者都很萬用,幾乎都可以定位到所有的 Element。

但對於簡單的定位,CSS Selector 的語法會相對簡潔。

而複雜的定位,因為有 XPath Axes 的概念,XPath 相對簡單。

還有一個原因會讓你可能選用 CSS Selector 是前端工程師都會應用,大家溝通上可能會比較方便,也讓你求救有援~

如情況許可,其實會建議在所需的 Element 加一個獨有的 attribute 供 automation test 使用,避免被其他人修改,且讓整個定位語法都相對簡單得多。
I.e. <div data-test-id=”test_only”></div>

但這可能需要請 Developer 協助,或是自行修改再請 Developer Review。

對 Web Element 的操作

知道怎樣選用 Locator 來找 HTML Element,然後要學習怎樣操作 Element 來達到自動化的目的。

透過 find_element() 可以取得 WebElement,WebElement 內建一些 method 可以對 element 作一些操作。以下介紹一些常用的操作:

  1. 點擊

    elem.click()

  2. 輸入資料

    elem.send_key('abc')

  3. 清除 Text Box 的資料,一般會在輸入資料先作清空

    elem.clear()

  4. 截取 element 的 screenshot,並存成檔案

    elem.screenshot('filename.png')

  5. 截取 element 的 screenshot,但不會生成檔案

    elem.screenshot_as_png()

  6. 取得 element 的文本資料

    elem.text

  7. 取得 element 指定的 attribute 資料

    elem.get_attribute(”id”)

  8. 判斷 checkbox / radio button 是否已被選取

    elem.is_selected()

  9. 判斷互動元件是否已啟用

    elem.is_enabled()

透過這些操作,我們可以使用 Selenium 模擬人手操作來完成我們的測試步驟。

推薦 2 個可以練習 Web UI Automation 網站:

  1. https://demo.applitools.com/
  2. https://www.saucedemo.com/
  3. http://demostore.supersqa.com/

可以用來練習怎樣應用 Element 找 Locator,並操作看看。


上一篇
Day 15: Selenium - 基本概念和操作
下一篇
Day 17: Selenium - Implicit & Explicit Wait
系列文
從 0 開始培育成為自動化測試工程師的學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言