還記得 HTML element 嗎?應用 HTML Tag 作標記的頁面元素,我們可以透過 Locator 的應用,讓 WebDriver 找出個該元素來執行操作。一般來說 Locator 都是用 Element 的 Tag 和 Attribute 資料來定位。然而 Locator 的種類有很多種,Locator 的選用會影響執行的效能,也會影響維護性,因此需要學習如何選用對的 Locator。
我們需要用到 Browser 的 DevTools 來輔助尋找頁面 Element 的資料,一般都是用 F12 打開。
點開 Elements Tab,選取目標 Element 後,再看 Element Tag 內有什麼資訊可以用來做 Locator。
先看 Locator 有哪些種類,才知道找到 Element 之後要怎樣選用 Locator。
對應到 element 的 ID attribute,一般來說都是 Unique,也相對少被更動。
# Example: <div id="wpfront-notification-bar-spacer">Testing</div>
elem = driver.find_element(By.ID, 'wpfront-notification-bar-spacer')
對應到 element 的 Name attribute,非 Unique,會出現在 HTML form。
# Example: <input type="text" name="username />
elem = driver.find_element(By.NAME, 'username')
是指網頁中超連結的可見文字
# 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')
同樣是指網頁中超連結的可見文字,但只需要部分文字符合。
# Example: <a href="https://www.example.com">Click here to visit Example</a>
elem = driver.find_element(By.PARTIAL_LINK_TEXT, 'visit Example')
指 element 的 class attribute,一樣用作定義 Element 的 CSS 樣式,非 Unique。CSS Class 跟外觀有關係,而外觀是蠻常作調整的內容,所以被改的機率比前 2 者稍為高。
# Example: <div class="entry-content"></div>
elem = driver.find_element(By.CLASS_NAME, 'entry-content')
就是 Element Tag,用到的機率很低,因為同頁相同的 Tag 太多。
# Example: <button type="submit"></button>
elem = driver.find_element(By.TAG_NAME, 'button')
使用 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
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,分別會得到相對路徑和絕對路徑的寫法。
非常不建議使用 Absolution XPATH ,可讀性極低的同時,頁面每次作任何修改,路徑都一定會跟著改變,那就只能一直跟著改了,時間再多都不夠用。
所以要學習使用 Relative Path,寫的時候也要注意可讀性,避免使用 index 讀取資料。
寫 Relative Path 的小技巧:
- 從目標 Element 中觀察是否有 唯一 且有 代表性的資料 可以使用。
- 若目標 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>
ancestor
軸:選擇指定元素的 所有祖先 元素。
I.e. //Leaf_E/ancestor::*
取得 <Branch_C>
, <Tree_B>
Element
child
軸:選擇指定元素的 所有直接子元素。
I.e. //Tree_B/child::*
取得 <Branch_C>
和 <Branch_D>
Element
I.e. //Tree_B/child::Branch_C
取得 <Branch_C>
Element
descendant
軸:選擇指定元素的 所有後代元素(包括子孫元素)。
I.e. //Tree_B/descendant::*
取得 <Branch_C>
, <Branch_D>
, <Leaf_E>
, <Leaf_F>
Element
I.e. //TreeB/descendant::Leaf_F
取得 <Leaf_F>
Element
following
軸:選擇文檔中在指定元素 之後的所有元素。
I.e. //Tree_A/following::*
取得 <Tree_B>
, <Branch_C>
, <Leaf_E>
, <Leaf_F>
, <Branch_D>
Element
following-sibling
軸:選擇指定元素 之後的所有同級元素。
I.e. //Tree_A/following-sibling::*
取得 <Tree_B>
Element
parent
軸:選擇指定元素的 父元素。
I.e. //Branch_C/parent::*
取得 <Tree_B>
Element
preceding
軸:選擇文檔中在指定元素之前的所有元素。
I.e. //Branch_D/preceding::*
取得 <Branch_C>
, <Leaf_F>
, <Leaf_E>
, <Tree_B>
, <Tree_A>
Element
preceding-sibling
軸:選擇指定 元素之前的所有同級元素。
I.e. //Branch_D/preceding-sibling::*
取得 <Branch_C>
Element
主要以 寫法簡單,且 不容易被改動的資料 為優先。一般來說 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。
知道怎樣選用 Locator 來找 HTML Element,然後要學習怎樣操作 Element 來達到自動化的目的。
透過 find_element()
可以取得 WebElement,WebElement 內建一些 method 可以對 element 作一些操作。以下介紹一些常用的操作:
點擊
elem.click()
輸入資料
elem.send_key('abc')
清除 Text Box 的資料,一般會在輸入資料先作清空
elem.clear()
截取 element 的 screenshot,並存成檔案
elem.screenshot('filename.png')
截取 element 的 screenshot,但不會生成檔案
elem.screenshot_as_png()
取得 element 的文本資料
elem.text
取得 element 指定的 attribute 資料
elem.get_attribute(”id”)
判斷 checkbox / radio button 是否已被選取
elem.is_selected()
判斷互動元件是否已啟用
elem.is_enabled()
透過這些操作,我們可以使用 Selenium 模擬人手操作來完成我們的測試步驟。
推薦 2 個可以練習 Web UI Automation 網站:
可以用來練習怎樣應用 Element 找 Locator,並操作看看。