[Test] 使用 TestCafe 進行前端測試

End-to-End tests 或者說是 UI Tests 一直都是前端一道麻煩,但又是又極為必要的題目。通常要馬是請測試團隊進行人工測試,不然就是用很麻煩的方式寫測試腳本,而今天要介紹的 TestCafe 或許是一套更好的解決方案,其中光是使用與 jQuery 或 CSS 相近的選擇器,相信就已經降低的不少的學習門檻,並且針對目前的幾套主流框架,像是 React、Angular、Vue,都有提供各自的專用選擇器。

接下來就筆者會先快速展示入門案例,並且用 TestCafe 來測試以 React 開發的 To Do List 應用。

官方文件:https://github.com/DevExpress/testcafe

安裝

建議使用 yarn 進行安裝:

yarn add global testcafe  

或者你可以:

npm install -g testcafe  

入門案例

接著就可以玩一下官方的入門案例了,可建立一個 test1.js 檔並寫入以下內容。

import { Selector } from 'testcafe'; // first import testcafe selectors

fixture `Getting Started`// declare the fixture  
    .page `https://devexpress.github.io/testcafe/example`;  // specify the start page

//then create a test and place your code there
test('My first test', async t => {  
    await t
        .typeText('#developer-name', 'John Smith')
        .click('#submit-button')

        // Use the assertion to check if the actual header text is equal to the expected one
        .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!');
});

接著使用下列指令進行測試:

testcafe chrome test1.js  

若過程順利,你應該可以看到它自動啟動的 Chrome 並且到了 https://devexpress.github.io/testcafe/example 快速輸入 John Smith 按下按鈕,並回傳下圖中的結果:

看到這結果就代表這個測試案例已通過了。

實際導入

接著可以我們可以實際使用 TestCafe 來導入現有的專案中來試試,其中以 React 開發的 To Do List 為例。

本文範例:https://github.com/s890506/TestCafe-Example

第一步

請先自行下載或 git clone 至您的環境中,接者進入該專案目錄並使用 yarnnpm i 進行相依套件安裝,安裝完成後使用下列指令將其啟動:

npm start  

啟動完成後可以試用一下,基本上就是一個 To Do List 應用。

第二步

接著像是入門案例建立測試檔,並貼上下列內容。

import { Selector } from 'testcafe'  
import { waitForReact } from 'testcafe-react-selectors'

fixture `Getting Started`  
  .page `http://localhost:3000/`
  .beforeEach(async () => {
    await waitForReact()
  })

test('Create 1 task and check it item', async t => {  
  await t
    .typeText('input', 'task 1')
    .click('button')
    .expect(Selector('.alert').innerText).eql('task 1')
})

這邊會先等待 React render 完成才開始執行測試內容。

完整測試檔

最後的測試檔如下,您可以在專案的 src/App.e2e.js 中找到它。其中較特別的是在第四個測試案例中使用到官方所說的 Page Model 概念。由於每個測試案例都是一次新的沙箱,所以這時候您就可以將那些常用的 UI 操作以及選擇器寫在另一個 Class 中,之後就可以像是使用物件的方式來進行重複使用了。

import { Selector } from 'testcafe'  
import { waitForReact } from 'testcafe-react-selectors'

fixture `Getting Started`  
  .page `http://localhost:3000/`
  .beforeEach(async () => {
    await waitForReact()
  })

test('Check init display', async t => {  
  await t
    .expect(Selector('button').innerText).eql('Add')
    .expect(Selector('input').count).eql(1)
    .expect(Selector('.alert').count).eql(0)
})

test('Create 1 task and check it item', async t => {  
  await t
    .typeText('input', 'task 1')
    .click('button')
    .expect(Selector('.alert').innerText).eql('task 1')
})

test('Create 3 task and check it items', async t => {  
  await t
    .typeText('input', 'task 1')
    .click('button')
    .typeText('input', 'task 2')
    .click('button')
    .typeText('input', 'task 3')
    .click('button')
    .expect(Selector('.alert').count).eql(3)
    .expect(Selector('.alert').nth(0).innerText).eql('task 1')
    .expect(Selector('.alert').nth(1).innerText).eql('task 2')
    .expect(Selector('.alert').nth(2).innerText).eql('task 3')
})

test('Gradually delete tasks and check it item', async t => {  
  const page = new TodosPage();

  await page.fillForm(t)
  await t
    .click(Selector('.alert').nth(0))
    .expect(Selector('.alert').count).eql(2)
    .expect(Selector('.alert').nth(0).innerText).eql('task 2')
    .expect(Selector('.alert').nth(1).innerText).eql('task 3')
    .click(Selector('.alert').nth(1))
    .expect(Selector('.alert').nth(0).innerText).eql('task 2')
    .click(Selector('.alert').nth(0))
    .expect(Selector('.alert').count).eql(0)
})

class TodosPage {  
  constructor () {
  }

  async fillForm(t) {
    await t
      .typeText('input', 'task 1')
      .click('button')
      .typeText('input', 'task 2')
      .click('button')
      .typeText('input', 'task 3')
      .click('button')
  }
}

測試效果如下: img

ALL RIGHTS RESERVED. COPYRIGHT © 2018. Designed and Coded by Makee.io