利用 Rize 來進行 UI 測試或 E2E 測試

gplane發表於2019-03-01

之前我曾經在《Rize – 一個可以讓你簡單、優雅地使用 puppeteer 的 Node.js 庫》一文簡單介紹過 Rize 這個庫。當時僅僅是介紹這個庫本身,關於如何使用,我沒有給太多的指導。

這篇文章講的是如何使用 Rize 來做 UI 測試或 E2E 測試。

在正式開始之前,先給可能沒了解過 Rize 的同學做個簡單的介紹:Rize 是一個提供了相對頂層並且可鏈式呼叫的 API 的庫,可與 puppeteer 一起使用。目前開源在 GitHub,地址是 github.com/g-plane/riz…,歡迎大家前往 GitHub 給個 star。

安裝

首先是安裝 Rize 和 puppeteer。

如果您使用 Yarn:

$ yarn add --dev rize puppeteer
複製程式碼

如果您使用 npm:

$ npm install --save-dev rize puppeteer
複製程式碼

考慮到國內的網路原因,您可能需要使用國內的 Chromium 映象:

對於 Linux 或 macOS 使用者:

PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org yarn add --dev puppeteer rize
複製程式碼

Windows 使用者:

SET PUPPETEER_DOWNLOAD_HOST=https://storage.googleapis.com.cnpmjs.org yarn add --dev puppeteer rize
複製程式碼

(npm 使用者同理)

由於安裝 puppeteer 的時候會下載 Chromium,所以整個過程可能比較費時,需要耐心等待。

約定

我們假定要被測試的頁面是這樣的:

<html>
    <head>
        <title>標題</title>
    </head>
    <body>
        <div class="greeting">
            Hello World!
        </div>
        <a href="">Another Page</a>
        <button id="btn">Click Me</button>
        <input type="checkbox" name="cb1" checked />
		<input type="checkbox" name="cb2" />
    </body>
</html>
複製程式碼

開始編寫測試

首先是匯入。我們推薦使用 ES2015 的 import 語法:

import Rize from `rize`
複製程式碼

當然您也可以用 CommonJS 方式:

const Rize = require(`rize`)
複製程式碼

第一件事是構造一個 Rize 例項:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
  })
})
複製程式碼

然後要轉到要被測試的頁面。我們假定前面設定的頁面執行在 http://localhost:8000/ 上,那麼我們可以:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
   })
})
複製程式碼

斷言

斷言頁面標題

我們可以使用 assertTitle 方法來斷言當前頁面的標題:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
   })
})
複製程式碼

斷言文字內容

可以使用 assertTitle 方法來斷言當前頁面存在指定的文字:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
   })
})
複製程式碼

我們還可以明確在某個元素中存在指定文字,只需給出該元素的 CSS 選擇器即可:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
   })
})
複製程式碼

斷言是否存在指定的類名

我們可以斷言某個元素存在指定的類名:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
   })
})
複製程式碼

還可以斷言不存在指定的類名:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
   })
})
複製程式碼

斷言表單狀態

我們可以斷言一些表單控制元件的狀態,例如核取方塊(checkbox)選中或未選中:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
      .assertChecked(`[name="cb1"]`)     // 斷言已選中
      .assertNotChecked(`[name="cb2"]`)  // 斷言未選中
   })
})
複製程式碼

與頁面互動

在實際測試的過程中,我們不僅僅需要進行一些斷言,還需要與頁面進行互動。

例如,我們以上面的頁面為例,我們可以單擊那個按鈕:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
      .assertChecked(`[name="cb1"]`)     // 斷言已選中
      .assertNotChecked(`[name="cb2"]`)  // 斷言未選中
      .click(`#btn`)
   })
})
複製程式碼

也可以單擊某個連結,我們只需要給出該連結上的文字:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
      .assertChecked(`[name="cb1"]`)     // 斷言已選中
      .assertNotChecked(`[name="cb2"]`)  // 斷言未選中
      .click(`#btn`)
      .clickLink(`Another Page`)
   })
})
複製程式碼

當然,我們還能與表單進行互動。例如,勾選某個核取方塊:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
      .assertChecked(`[name="cb1"]`)     // 斷言已選中
      .assertNotChecked(`[name="cb2"]`)  // 斷言未選中
      .click(`#btn`)
      .clickLink(`Another Page`)
      .check(`[name="cb2"]`)
   })
})
複製程式碼

或者取消勾選某個核取方塊:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
      .assertChecked(`[name="cb1"]`)     // 斷言已選中
      .assertNotChecked(`[name="cb2"]`)  // 斷言未選中
      .click(`#btn`)
      .clickLink(`Another Page`)
      .check(`[name="cb2"]`)
      .uncheck(`[name="cb1"]`)
   })
})
複製程式碼

關閉瀏覽器

在完成所有工作之後,需要退出瀏覽器:

describe(`UI test`, () => {
  it(`example test`, async () => {
    const rize = new Rize()
    rize
      .goto(`http://localhost:8000/`)
      .assertTitle(`標題`)
      .assertSee(`Hello World!`)
      .assertSeeIn(`.greeting`, `Hello World!`)
      .assertClassHas(`div`, `greeting`)
      .assertClassMissing(`div`, `greet`)
      .assertChecked(`[name="cb1"]`)     // 斷言已選中
      .assertNotChecked(`[name="cb2"]`)  // 斷言未選中
      .click(`#btn`)
      .clickLink(`Another Page`)
      .check(`[name="cb2"]`)
      .uncheck(`[name="cb1"]`)
    await rize.end()
   })
})
複製程式碼

更多

實際上 Rize 的功能遠不只上面那些。想要獲取更多資訊,可以前往以下頁面:

Rize 的 GitHub 倉庫:github.com/g-plane/riz… (歡迎 star)

Rize 的文件教程:rize.js.org/

Rize 所有的 API 參考:https://rize.js.org/api/classes/index.rize.html

相關文章