> ## Content Index
> Fetch the complete content index at: https://blog.hinablue.me/llms.txt
> Use this file to discover other available public pages before exploring further.

# [測試] e2e 的測試方法 Day 1
- URL: https://blog.hinablue.me/ce-shi-e2e-de-ce-shi-fang-fa-day-1/
- Published: 2018-01-04T04:32:52.000Z
- Updated: 2026-07-06T18:48:33.000Z
- Author: Hina Chen
- Tags: JavaScript, Test, NightwatchJS, 測試

上一篇解釋了虛擬碼的概念，這次直接進入撰寫測試的方法。當然，需要一點工具來輔助我們，這裡我們使用 [nightwatch.js](http://nightwatchjs.org/?ref=blog.hinablue.me) 來當作測試的框架。

如果不是使用 nightwatch.js 的人，可以左轉沒關係。

---

## 環境

**萬事起頭難，建立環境這件事情最難！** 雖然我們使用 nightwatch.js 來當做測試框架，但是我們還是需要具備一些基礎知識，好方便我們操作。首先，我們需要的有，

1. 可以運行 [NodeJS](https://nodejs.org/en/?ref=blog.hinablue.me) 的環境
2. 可能需要安裝 [Java SDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.html?ref=blog.hinablue.me)
3. [selenium-server-standalone](https://goo.gl/hvDPsK?ref=blog.hinablue.me) 獨立執行檔 (\* *1*)
4. [Firefox driver](https://github.com/mozilla/geckodriver/releases?ref=blog.hinablue.me)

接著，我們這邊可以來建立一個相對簡易的測試環境，我們需要的目錄與檔案結構如下，

1. `specs`
2. `bin`
3. `package.json`
4. `nightwatch.conf.js`
5. `runner.js`

我們可以先下載上述的[獨立執行檔](https://goo.gl/hvDPsK?ref=blog.hinablue.me)，把他放到 `bin` 目錄底下備用。另外，如果你需要使用 Firefox 來運行測試環境，也請把 [Firefox driver](https://github.com/mozilla/geckodriver/releases?ref=blog.hinablue.me) 放到 `bin` 目錄底下。

底下的設定檔都可以照抄沒關係，更詳細的設定可以察看 nightwatch.js，或是上網 Google 也可以（欸

首先 `package.json` 會寫入我們所需要安裝的一些套件，

```json
{
  "scripts": {
    "test": "node runner.js"
  },
  "dependencies": {
    "babel-register": "^6.22.0",
    "chromedriver": "^2.27.2",
    "cross-env": "^3.1.4",
    "cross-spawn": "^5.0.1",
    "lodash": "^4.17.4",
    "mocha": "^3.2.0",
    "nightwatch": "^0.9.12",
    "selenium-server": "^3.0.1"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

```

接著 `runner.js` 提供啟動測試的程序，

```javascript
process.env.NODE_ENV = 'staging'

var opts = process.argv.slice(2)

if (opts.indexOf('--config') === -1) {
  opts = opts.concat(['--config', 'nightwatch.conf.js'])
}

if (opts.indexOf('--env') === -1) {
  opts = opts.concat(['--env', 'chrome'])
}

var spawn = require('cross-spawn')
var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })

runner.on('exit', function (code) {
  process.exit(code)
})

runner.on('error', function (err) {
  throw err
})

```

暫停，我們先在終端機執行一些套件的安裝，

```
npm run install

```

安裝好之後，我們來編輯一下 `nightwatch.conf.js` 這個設定檔，可以參考官方的 [簡單範例](http://nightwatchjs.org/gettingstarted?ref=blog.hinablue.me#installation) 來進行一些修改，

```javascript
{
  "src_folders" : ["specs"],
  "output_folder" : "reports",
  "custom_commands_path" : "",
  "custom_assertions_path" : "",
  "page_objects_path" : "",
  "globals_path" : "",

  "selenium" : {
    "start_process" : true,
    // "server_path" : require('selenium-server').path,
    "server_path" : "./bin/selenium-server-standalone-3.8.1.jar",
    "log_path" : "",
    "port" : 4444,
    "cli_args" : {
      "webdriver.chrome.driver" : require('chromedriver').path,
      "webdriver.gecko.driver" : "./bin/geckodriver"
    }
  },

  "test_settings" : {
    "default" : {
      "launch_url" : "http://localhost",
      "selenium_port"  : 4444,
      "selenium_host"  : "localhost",
      "silent": true,
      "screenshots" : {
        "enabled" : false,
        "path" : ""
      }
    },

    "chrome" : {
      "desiredCapabilities": {
        "browserName": "chrome"
      }
    },
    
    "firefox" : {
      "desiredCapabilities": {
        "browserName": "firefox"
      }
    }
  }
}

```

然後我們就能進入 `specs` 當中開始寫測試了。

\* *1* 獨立執行檔僅只是官方建議，其實也可以使用 `package.json` 當中的 `selenium-server` 套件來執行（例如上述註解掉的那一段）。

## 開始寫測試之前

畢竟是叫做 End-to-End 測試，所以必須還是要有一些基本的能力，

1. 理解 [HTML / DOM](https://developer.mozilla.org/zh-TW/docs/Web/HTML?ref=blog.hinablue.me)
2. 理解 [CSS](https://developer.mozilla.org/zh-TW/docs/Web/CSS?ref=blog.hinablue.me) 選擇器
3. 理解 [JavaScript](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript?ref=blog.hinablue.me)
4. 會一些簡易的 Chrome DevTools 操作
5. 翻閱大量的 nightwatch.js 的 [API 官方文件](http://nightwatchjs.org/api?ref=blog.hinablue.me)

所以，在這個大前提之下，你必須對於 DOM 有一定的認知，才能知道你要怎麼做。我們先回到上一次所說的虛擬碼，要把虛擬碼轉換成測試用的程式碼之前，先思考一下該怎麼認識 *畫面上的東西*。

這次就不說販賣機了，就說 Google 的首頁好了。假設我們有一段虛擬碼是這個樣子的，

1. 打開 [https://google.com](https://google.com/?ref=blog.hinablue.me)
2. 輸入搜尋的關鍵字「閃光洽」
3. 按下「搜尋」按鈕
4. 找到第一筆搜尋結果
5. 第一筆搜尋結果要包含「閃光洽」的字樣

以上的動作都是透過滑鼠與鍵盤，在你的瀏覽器中操作的步驟。那麼，我們該怎麼透過測試方法，自動幫我操作？我們可以理解的方式是，

1. ~~叫同事幫我操作（不是~~

由於網頁是由一大堆 HTML 標籤所組成，他組合出來的叫做 DOM (文件物件模型，Document Object Model)。所以，我們需要的能力是 *查找 DOM* 來找到我們想要的 *物件*。

以上述的例子來說，*輸入關鍵字* 這件事情，就會有一下的步驟，

1. 先在 DOM 找到 **可以輸入關鍵字** 的地方
2. 然後輸入關鍵字「閃光洽」

那麼，我們要怎麼找到 *可以輸入關鍵字* 的地方？首先，你需要複習一點 CSS 選擇器，例如，

1. `#E` ID 選擇器
2. `.E` 類別選擇器
3. `E F` 子嗣選擇器
4. `[E="F"]` 屬性選擇器

那麼，我們可以利用 Chrome DevTools 來簡易的驗證選擇器，與確認我們是否有 *選到* 我們想要選的東西。我們分成幾個步驟來說明 DevTools 的操作，

1. 打開 Chrome 後，打開 [https://google.com](https://google.com/?ref=blog.hinablue.me)
2. 在搜尋的輸入框的地方，按下滑鼠右鍵，點選「檢視」

![google-dev-tools-1](https://blog.hinablue.me/content/images/2018/01/google-dev-tools-1.png)

1. 這個時候會開出 DevTools 的工具，會出現剛剛你「檢視」的元件

![google-dev-tools-2](https://blog.hinablue.me/content/images/2018/01/google-dev-tools-2.png)

1. 我們可以在上面那個區塊任一點一下，按下 `Command + F`，會出現搜尋框

![google-dev-tools-3](https://blog.hinablue.me/content/images/2018/01/google-dev-tools-3.png)

1. 這個地方我們可以用來驗證我們的選擇器，是否可以選我們想要的元件，例如說，我們輸入 `input[type="text"]`

![google-dev-tools-4](https://blog.hinablue.me/content/images/2018/01/google-dev-tools-4.png)

1. 就這麼剛好選到我們要的東西了呢（啾咪

接著我們先略過輸入關鍵字這件事情，假設我們輸入好了，要去按搜尋的按鈕。所以，我們就要找到那個按鈕。我們一樣可以使用 DevTools 來找到那顆按鈕，一樣是在按鈕上「檢視」，來察看那顆按鈕有什麼樣的屬性可以供我們使用。

![google-dev-tools-5](https://blog.hinablue.me/content/images/2018/01/google-dev-tools-5.png)

以上，我們使用了 CSS 選擇器，並透過 DevTools 來輔助我們選到想要的元件。這樣，對於選擇元件這件事情，在這裡就有一個基本的認識。會選擇元件之後，我們就可以來寫第一次的簡單測試了。

## nightwatch.js 簡易測試

在 `specs` 資料夾中，我們可以建立一個檔案叫做 `test.js` 用來寫我們的第一個測試。這個檔案有一個規則，就是必須被包含在 `module.exports = { }` 裡面，至於為什麼？~~不要問，很可怕！~~

```javascript
module.exports = {
    '我的第一個測試': function (browser) {
        browser
            .url('https://google.com')
            .waitForElementVisible('input[type="text"]', 1000)
            .setValue('input[type="text"]', '閃光洽')
            .click('input[jsaction="sf.chk"]')
            .pause(1000)
            .waitForElementVisible('#rso .g:first-child', 1000)
            .assert.containsText('#rso .g:first-child', '閃光洽')
            .end();
    }
}

```

我們逐步來說明上述的測試代碼做了什麼事情，

1. `browser` 在 nightwatch.js 當中，會回傳一個參數，這個參數就是測試用的瀏覽器物件，所有的動作都會基於這個瀏覽器物件來做操作。
2. `.url('https://google.com')` 請這個瀏覽器打開 `https://google.com` 這個網址
3. `.waitForElementVisible` 是 nightwatch.js 提供的一個方法，用意是，等待你指定的選擇器 `input[type="text"]` 所選到的 *元件* 出現在畫面上，最久等待 1000 毫秒。
4. `.setValue` 顧名思義，是將某個數值填入選擇器，通常會用於 `input` 類型的標籤，這個方法可以指定一個值給這個元件。例如我們要輸入搜尋的關鍵字，就會使用這個方法。
5. `.click` 模擬滑鼠點擊選擇器 `input[jsaction="sf.chk"]` 所選到的元件 (\* *2*)
6. `.pause` 暫停操作 1000 毫秒。為何會需要暫停？因為送出關鍵字之後，要等待回應，等待的時間我們就可以先暫停操作。
7. `.assert.containsText` 這是屬於 `assert` 的一組方法，用意是檢查指定選擇器 `#rso .g:first-child` 的 **所有** 文字內容，是否有包含你所指定的文字。
8. `.end()` 測試做完了，關閉測試用的瀏覽器。

以上是簡易的測試步驟，所有的相關文件後續會有比較詳細的介紹。當然測試當中可能還是會遇到一些 nightwatch.js 奇怪的雷，我會慢慢找時間分享給大家。

\* *2* 點擊這個動作有比較特別的條件，之後會另外有篇幅來講講這個雷。

## 小結

~~不覺得，用 nightwatch.js 來搶票好像不錯嗎（欸~~