簡介

先前在我們的網頁測試系列中

開始使用 Nightwatch 進行網頁測試
探索如何開始使用 Nightwatch 進行網頁測試,這是一個強大且不妥協的測試自動化框架。學習如何安裝 Nightwatch、設定您的測試環境,並編寫基本的端對端測試。

我們學習了如何使用 Nightwatch 設定測試環境,並成功編寫了我們的第一個端對端測試。以下是快速回顧:
安裝: npm init nightwatch
編寫: browser.navigateTo('/').assert.textEquals('h1', '<TEXT>')
執行: npx nightwatch test

本文概述

僅檢查文字不足以作為端對端測試,來確保網站和網頁應用程式的可靠性。網頁由複雜的元素組成,並且涉及大量的使用者互動。在本教學中,我們將教您如何從我們編寫的第一個測試繼續,來測試一些常見的場景。

編寫網頁測試主要圍繞這 3 個組成部分:

  • 尋找元素
  • 與元素互動
  • 測試元素及其屬性

我們將涵蓋測試的這三個主要方面,以便能夠為以下場景編寫測試。

  • 點擊「Get Started」按鈕,並驗證是否已進入安裝頁面。
  • 點擊搜尋,輸入查詢「frame」,等待結果,按下向下箭頭到第二個結果,然後按下 Enter。驗證是否已進入 .parentFrame() 文件頁面。

您也可以觀看本文的影片教學

尋找 👀

網頁測試的第一步是尋找我們要測試的頁面中的 DOM 元素。Nightwatch 允許您使用各種選擇器來尋找元素。最常見的方法是使用 CSS 選擇器。您可以使用 .element.find() API 來執行此操作。

除此之外,您還可以通過下面顯示的各種其他方法在頁面上搜尋元素。在以下範例中,我們將使用 .find().findByText().findByPlaceholderText()。您可以在此處瞭解更多有關所有可用的選擇器。

Element find APIs
元素尋找 API
💡
若要在您的編輯器中取得建議,您可以安裝我們的 VSCode 擴充功能

您也可以通過鏈接所有尋找 API 來深入搜尋元素。這真的讓您更容易取得您想要的確切元素。

範例

browser.element.find('main').find('.hero').findByText('Get Started')

等待

有時我們要尋找的元素尚未準備好,我們可能需要等待它。一個很好的例子是在輸入框中輸入內容並等待結果填充。您可以使用 .waitUntil(<status>) API 來執行此操作。

💡
API 參考

.find(<string>) - 字串應該是有效的 CSS 選擇器

.findByText(<string>)

.findByPlaceholderText(<string>)

.waitUntil(<string>) - <string> 可以是以下任何一個:"visible""not.visible""selected""not.selected""enabled""not.enabled""disabled"

範例

// Find the element with class "DocSearch-Modal" and wait for it to be visible
browser.element.find('.DocSearch-Modal').waitUntil('visible')

現在我們已經學習如何尋找元素,我們可以繼續與之互動。

互動 ✍️

下一步是與網頁互動。最常見的場景是使用者點擊按鈕或填寫表單。當測試動態網頁應用程式或網站時,測試的這一部分變得至關重要。

Nightwatch 可透過元素互動 API browser.element.find().<interaction_api>() 來協助您模擬這些動作。這些是可用的互動 API:clear、click、dragAndDrop、sendKeys、setAttribute、setProperty、submit、update、upload、submitForm、updateValue、uploadFile、clickAndHold、doubleClick、rightClick 和 moveTo。

除此之外,您還可以使用 .perform() 執行複雜的使用者操作。但在本部落格的範圍內,我們只會使用 .click().sendKeys()

💡
API 參考

.click() - 點擊我們找到的元素

.sendKeys(<string | [...keycodes]>) - 要傳送到所選元素的鍵盤輸入

→ arg: <string> 要作為鍵盤輸入發送的文字。例如,.sendKeys("hello world!")

→ arg: <[...keycodes]> 您也可以傳送字串和鍵盤代碼的列表,包括在 browser.keys.<special_key> 下找到的特殊按鍵。例如,.sendKeys([browser.Keys.TAB, "hello", browser.Keys.ENTER])。您可以在此處找到特殊按鍵的清單。

範例

// Find the button "Get Started" and click it
browser.element.findByText('Get Started').click()

// Find the input box with placeholder "Search docs" and type "frame"
browser.element.findByPlaceholderText('Search docs').sendKeys('frame')

// Press the down arrow and press Enter
browser.element.findByPlaceholderText('Search docs').sendKeys([browser.Keys.ARROW_DOWN, browser.Keys.ENTER])

現在我們已經學習如何與元素互動,我們可以繼續驗證元素的各個方面。

斷言 ✅

最後一步是測試我們要尋找的內容是否與網頁上顯示的內容相符。這涉及獲取我們需要的元素的屬性並驗證它。

尋找屬性

元素最常測試的方面是其文字、屬性(包括類別)和值(對於輸入元素)。這可以使用 .getText().getAttribute().getValue() 來實現。您可以在此處閱讀更多關於所有元素狀態的資訊。

測試

一旦我們找到我們需要的值,下一步就是測試它。測試可以根據以下三種方法,以您喜歡的寬鬆或嚴格方式編寫:equalscontainsmatches

💡
.assert.equals(<str>) - 接受一個字串並檢查它是否完全相同。

.assert.contains(<str>) - 接受一個字串並檢查輸入是否存在為子字串。

.assert.matches(<regex>) - 接受一個 regex 作為輸入並針對它進行驗證。

範例

// Check if the h1 text contains "Install Nightwatch"
browser.element.find('h1').getText().assert.contains('Install Nightwatch')

// Check if the "autocomplete" attribute of the input box is exactly "off"
browser.element.findByPlaceholderText('Filter by title').getAttribute('autocomplete').assert.equals('off')
💡
您可以使用 .verify 而不是 .assert 來記錄失敗並繼續測試中的其他斷言。

否定

若要檢查某個事物是否「不」相等或「不」包含,只需在 .assert 後面加入 .not 即可。

// Check if the h1 does not text contains "Selenium"
browser.element.find('h1').getText().assert.not.contains('Selenium')

元素狀態

您可以在 .assert 之後使用 .visible().present().selected().enabled() 來斷言元素的狀態。這與我們在等待部分先前學習的 .waitUntil 狀態非常相似,並且可以互換使用。

// Check if the element with class "DocSearch-Dropdown-Container" is present
browser.element.find('.DocSearch-Dropdown-Container').assert.present()

文件狀態

您可以使用 browser.assert.url[Contains/Matches/Equals](<string>)browser.assert.title[Contains/Matches/Equals](<string>) 來斷言文件的標題和 URL。

// Check if the title contains "Getting Started"
browser.assert.titleContains('Getting Started')
💡
Nightwatch 會自動重試失敗的斷言最多半秒,這可以在 nightwatch.json 檔案中的 globals 物件中設定。閱讀更多

將所有內容整合在一起 🧩

使用我們到目前為止學到的所有內容,讓我們為這兩種情境編寫測試。

情境:點擊「Get Started」應導向安裝頁面

程式碼

  it('Should lead to the installation page on click of Get Started', function (browser) {
    browser.navigateTo('/')
    browser.element.findByText('Get Started').click()
    browser.element.findByPlaceholderText('Filter by title').waitUntil('visible')
    browser.element.find('h1').getText().assert.equals('Install Nightwatch')
    browser.assert.titleEquals('Getting Started | Developer Guide | Nightwatch.js')
    browser.assert.urlContains('nightwatchjs.org/guide/quickstarts')
    browser.element.findByPlaceholderText('Filter by title')
      .getAttribute('autocomplete').assert.equals('off')
    ;
    browser.end()
  })

說明

首先,我們使用 .navigateTo('/') 導航到首頁。這是可能的,因為先前在我們專案的設定中,我們將專案的 base_url 設定為 Nightwatch 首頁。您可以在 nightwatch.conf.js 檔案中編輯此設定。導航完成後,我們找到文字為「Get Started」的按鈕並點擊它。對於在前端路由且不會重新載入頁面的連結,建議等待動作完成。在這裡,我們將等待左側搜尋欄變成可見。然後,我們將透過斷言標題、URL 和 h1 元素來檢查安裝頁面。我們也將斷言搜尋欄的「autocomplete」屬性,以展示屬性斷言。

💡
browser.end() 會關閉瀏覽器視窗。最好以關閉瀏覽器來結束測試。
情境:應允許搜尋並顯示正確的結果

程式碼

  it('Should allow search and show correct results', function (browser) {
    browser.navigateTo('/')
    browser.element.find('#docsearch').click()
    browser.element.find('.DocSearch-Modal').waitUntil('visible')
    
    const search_input = browser.element.findByPlaceholderText('Search docs') 
    search_input.sendKeys('frame')
    browser.element.find('.DocSearch-Dropdown-Container').assert.present()
    search_input.sendKeys([browser.Keys.ARROW_DOWN, browser.Keys.ENTER])

    browser.element.find('h1').getText().assert.contains('.frameParent')
    browser.end()
  })

說明

我們將導航到首頁,找到搜尋圖示並點擊它。我們將等待模態視窗開啟並可見。然後,我們將在搜尋輸入欄中輸入文字「frame」。我們透過檢查 ".DocSearch-Dropdown-Container" 的存在來等待結果載入,一旦結果載入,我們將按下向下箭頭並輸入。這將導向第二個結果 .frameParent() 的文件,並且我們驗證 h1 文字以確認這一點。

最終檔案

最終的 home.spec.js 應該如下所示。

describe('Nighwatch homepage', function () {
    
  it('Should have the correct title', function(browser) {
    browser
      .navigateTo('/')
      .assert.textEquals('h1', 'Introducing Nightwatch v3')
      .end()
    ;
  })
    
  it('Should lead to the installation page on click of Get Started', function (browser) {
    browser.navigateTo('/')
    browser.element.findByText('Get Started').click()
    browser.element.findByPlaceholderText('Filter by title').waitUntil('visible')
    browser.element.find('h1').getText().assert.equals('Install Nightwatch')
    browser.assert.titleEquals('Getting Started | Developer Guide | Nightwatch.js')
    browser.assert.urlContains('nightwatchjs.org/guide/quickstarts')
    browser.element.findByPlaceholderText('Filter by title')
      .getAttribute('autocomplete').assert.equals('off')
    ;
    browser.end()
  })

  it('Should allow search and show correct results', function (browser) {
    browser.navigateTo('/')
    browser.element.find('#docsearch').click()
    browser.element.find('.DocSearch-Modal').waitUntil('visible')
    
    const search_input = browser.element.findByPlaceholderText('Search docs') 
    search_input.sendKeys('frame')
    browser.element.find('.DocSearch-Dropdown-Container').assert.present()
    search_input.sendKeys([browser.Keys.ARROW_DOWN, browser.Keys.ENTER])

    browser.element.find('h1').getText().assert.contains('.frameParent')
    browser.end()
  })

})

讓我們使用我們在上一篇文章中學習的相同命令來執行測試。

npx nightwatch test

瀏覽器完成測試後,輸出應該如下所示。

Test output
測試輸出
💡
乾杯! 您的測試已通過。

接下來

網頁測試中的進階技術和情境

今天您學習如何使用這三種技術 → 尋找、互動和斷言來測試網路上的常見使用案例。在我們的網頁測試系列下一章中,我們將學習網頁測試中的進階技術,例如測試掛鉤、多標籤互動、iFrame、複製/貼上、使用 async/await、執行用戶端 JS、模擬地理位置、處理影子 DOM、動作 API 等等。請繼續關注我們即將推出的關於網頁測試中進階技術和情境的文章。

加入我們的社群 💬

如果您有任何問題,請隨時造訪我們的 Discord 伺服器 並打個招呼。我們的社群隨時提供支援、分享見解,並協助您處理任何與測試相關的諮詢。我們歡迎您積極參與,並期待在我們的 Discord 社群中與您聯繫。您也可以透過 Twitter 與我們聯繫。

測試愉快!🎉

影片教學

Basics of Writing Nightwatch Web Tests - Video Tutorial
撰寫 Nightwatch 網頁測試的基本概念 - 影片教學