用 Spectron 對 Electron App 做測試
Tags: electron, spectron
Published: 2021-10-30 09:33:48

## Electron

Electron 是 Node.js 生態圈的框架，用於開發跨平台**桌面**應用，目標平台可以是 Mac / Linux / Windows，可以視為把 web app 包裝成執行檔在自己的視窗內運行，並且透過 Electron 框架讓這支 app 有與作業系統層溝通的能力，包括存取檔案、週邊裝置等，很多目前[原生 web API 無法實現的能力](https://whatwebcando.today/)都可以透過 Electron 辦到。

最知名的 Electron 應用應該就是 VSCode 了，這款當代最棒的編輯器也是運用了 Electron 框架達成在桌面端跨平台的能力。

## Electron 的測試

對最大宗的 Windows 平台的 Windows Forms 這類的原生桌面應用來說，市場上已經有許多 [RPA](https://www.ibm.com/tw-zh/automation/rpa) 工具可以用於自動化測試，但因為 Electron 在介面元件上並未調用系統原生元件，而是由 HTML 元素來構成介面，而那些 RPA 工具都無法抓取到 HTML 元件，導致 RPA 完全無用武之地。

既然沒有 GUI 測試工具可以用，只能回歸寫 code 測 code 這招，Electron 有自己的測試框架 [Spectron](https://www.electronjs.org/spectron)，Spectron 也可以搭配 [Mocha](https://mochajs.org/) 等其它 JavaScript 測試框架使用，網路上爬文一下可以發現大部分也都就是 Spectron 配 Mocha 這樣的組合。

<figure>

![Mocha & Matcha](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rdj1usfgxte8oage7og.png)
<figcaption>Mocha & Matcha</figcaption>
<figcaption>來源：<a href="https://dictionary.cambridge.org/zht/">劍橋詞典</a></figcaption>
</figure>

## Spectron + Mocha

### Electron App

像做菜節目一樣，前面都要先備料，我們必須先有一支 Electron app 來當作我們的測試 app，這裡我們用 [Mini Diary](https://minidiary.app/) 這個 app 當作待測的目標，因為它夠簡單又夠複雜，所謂夠簡單－它的 app 本身功能簡單，操作也簡單；所謂夠複雜－它是 Electron 加 React 的架構，又搭配了一些 React 生態圈的套件；另一個夠複雜－它除了提供原始碼外，也幫我們打包好了各個平台上的安裝檔。

在這裡我們用 Mini Diary 的 macOS 套件包來使用，依照通用的流程安裝，它會被安裝到 /Applications/ 目錄內，主程式就是 「/Applications/Mini Diary.app/Contents/MacOS/Mini Diary」 這支檔案。

### 版次搭配

前面提過 Electron app 是由 HTML 構成，為了在桌面前端 render 出這些 HTML，Electron app 裡面有包了一個 Chromium 做為前端的 renderer。而 Electron 的測試框架－Spectron，裡面也有一個 ChromeDriver 做為與 Electron 溝通的介面，就像純 web 常用的自動化測試工具 Selenium 也是透過 ChromeDriver 來操控 Chrome 一樣。

因為有 Chromium 與 ChromeDriver，就會有版次搭配的問題，兩者必須是相匹配的版次才可以成功的運作。

在 Electron 方面，[electron-releases](https://github.com/electron/releases) 這個專案內有列出各版本的 Electron 與 Chromium 的對應關係，以 Mini Diary 來說，它的 Electron 是 8.3.0 版，透過 Electron / Chromium 版次表，可以查到對應的 Chromium 版次是 80。

在 Spectron 方面，它的專案文件同時也列出了 [Spectron 與 Electron 的對應表](https://github.com/electron-userland/spectron)，透過查表可以知道 Electron 8.x 須與 Spectron 10.x 相互搭配。

### 專案建置

這裡我們為測試另建一個專案，叫做 minidiary-test，建立同名資料夾後，git init 和 npm init 一下，接著把 Mocha 和 Spectron 裝起來：

```sh
npm install mocha spectron
```

記得前面說的版次搭配性問題，有必要的話需指定 spectron 的版次。

### 測試程式

```javascript
const Application = require("spectron").Application
const assert = require("assert");
 
describe("My Test App", function () {
    // SETUP section
    let app;
    this.timeout(20000)
    before(function () {
        app = new Application({
            path: `/Applications/Mini Diary.app/Contents/MacOS/Mini Diary`,
        });
        return app.start()
            .catch(console.error)
    });
    // shutdown after all tests
    after(function () {
        if (app && app.isRunning()) {
            return app.stop();
        }
    });
    // TESTS section
    // test 1
    it("Should have the correct title", async function () {
        const title = await app.client.getTitle();
 
        assert.equal(title, "Mini Diary");
    });
});
```

能測試 Electron 的關鍵就在上面程式碼內的 `app`，把 `app` 定義出來後，就可以利用 Spectron 的 API 去存取 Electron app 的各項屬性，再配合 Mocha 的測試架構即可讓我們做到 Electron app 測試自動化。除了 `app` 以外的部分，`describe()`、`it()` 等都是 Mocha 的測試用函示，關於 Mocha 的用法請自行參閱 Mocha 的網站或其他大大們的文章。

跑看看測試：

```sh
npx mocha test/test.js
```

結果正常的話應該像這樣：

```
My Test App
  ✓ Should have the correct title
1 passing (4s)
```

在上面的範例程式碼中，只有很簡單的確認 app 的標題是否為 Mini Diary，在實際的測試場景中顯然會更複雜，應該會有大量的調用 Sepctron API 對 app 進行自動化操作以及確認 app 視窗內的屬性值是否與預期相符，以及需要用 Chrome 開發者工具來查找元素與操作 console 等，~~這部分只能先富奸了~~。

### Spectron & WebdriverIO

[WebdriverIO](https://webdriver.io/) 是一個 JavaScript 的測試套件，它提供了一層 API 讓我們可以調用瀏覽器與網頁，雖然前面都沒提到它，但其實它也算是 Spectron 的一部分，在安裝 Spectron 的時候 WebdriverIO 也會被裝進專案內。Spectron 就是利用了 WebdriverIO 的 API 來提供給我們操控 Chromium 與 Electron app 頁面的能力，可以更具體地說，Spectron 只是對 WebdriverIO API 做了一層封裝，在 WebdriverIO API 文件內能調用的函式也都可以在 Spectron 上面做調用。

附帶提醒，延續前面提到的版次問題，新舊版的 Spectron 依賴的 WebdriverIO 也會有新舊版的問題，確認一下專案 package.json 內 `webdriverio` 套件的版次，並且查閱 API 文件時也要注意文件版次與專案內安裝的 `webdriverio` 版次要相符。

回歸正題，想要在測試腳本裡面去操控頁面元素的話，就必須利用 Spectron 的 API（也就是被封裝過的 WebdriverIO API）。

首先是選擇器，先上範例：

```javascript
let accountField = app.client.$('.account-input');
accountField.setValu('user1');
```

看到熟悉的 `$()` 錢字號函數與後面的 CSS 選擇器語法，和 jQuery 長一樣，雖然長一樣，不過 WebdriverIO 並不依賴 jQuery，只是借鑒錢字號這樣的函數命名而已，大概是希望提高對開發者的親切感吧。

在上面的範例的第二行，把元素抓到之後，就可以操作它，除了範例內做的填值之外，取值、點擊等都可以被實現。詳細的可調用的函式，請參考 WebdriverIO 文件。

## 參考資料

- [Glue42 Desktop: Mocha and Spectron](https://docs.glue42.com/developers/testing-your-app/mocha-and-spectron/index.html)
- [使用 Mocha + Spectron 测试 Electron 打包的桌面版程序（1）](https://blog.csdn.net/DaxiaLeeSuper/article/details/78065263)
- [使用 Mocha + Spectron 测试 Electron 打包的桌面版程序（2）PO 模型](https://blog.csdn.net/DaxiaLeeSuper/article/details/78107686)
- [Spectron For Electron Apps Automation](https://blog.francium.tech/spectron-for-electron-apps-automation-4c2062e37beb)
- [Electron in Action: Chapter 13. Testing applications with Spectron](https://livebook.manning.com/book/electron-in-action/chapter-13/)

## 其它測試工具

- [TestComplete](https://smartbear.com/product/testcomplete/overview/)：Windows 桌面端收費商業應用，可以拿來測 Electron，好像很厲害，也很貴的貴。
- [Squish](https://www.froglogic.com/squish/)：跨平台自動化測試工具，也是很貴的貴。