Electron 使用 Jest + Webdriver 进行自动化测试

嗯 ~~~ 再写完了 Bittly 的新需求之后,原本 Jest 的单元测试总感觉还是有点不太放心, 所以打算再加上使用 Webdriver 来实实在在的测试 UI 界面。 开发这种事情,我不喜欢由测试驱动,而是由测试来保证同样的错误不会出现第二次,所以一般都是开发完成之后再写单元测试。

Electron 项目使用 Webdriver 来进行 UI 测试和普通的 Web 项目没什么大区别,基本流程都是一样。

安装 chromewebdriver

npm install electron-chromedriver@17.0.0 --save-dev

需要注意的是, webdriver 的版本需要与 electron 项目中使用的 chrome 版本相匹配, 在一开始的时候我没有注意,导致测试的时候出现提示说 webdriver 支持最低版本的 chrome 高于我项目中使用的版本。

The major version of this library tracks the major version of the Electron versions released. So if you are using Electron 2.0.x you would want to use an electron-chromedriver dependency of ~2.0.0 in your package.json file.

@link https://www.npmjs.com/package/electron-chromedriver

根据 electron-chromedriver 的说明,我们只需要将主版本号进行对应即可。

安装完成之后即可通过 ./node_modules/.bin/chromedriver 启动。例如:

PS D:\bittly\app> ./node_modules/.bin/chromedriver --log-level=INFO
Starting ChromeDriver 98.0.4758.74 (2bee2cb92d553708966882df183bb533ac105e7c-refs/heads/main@{#963777}) on port 9515
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.

一开始的时候建议加上 `–log-level=INFO` 参数,这样输出的内容会详细些,当后续基本没什么问题的时候可以取消该参数。

安装 selenium-webdriver

上面一个安装包指示下载了 chromedriver 的可执行文件,我们需要安装另外一个库来操作webdriver。

npm install selenium-webdriver --save-dev

electron-chromedriver 和 selenium-webdriver 安装完成之后即可使用 webdriver 来操作 electron 项目了。例如:

// index.js
const webdriver = require('selenium-webdriver')

const driver = new webdriver.Builder()
  // The "9515" is the port opened by chrome driver.
  .usingServer('http://localhost:9515')
  .withCapabilities({
    'goog:chromeOptions': {
      // Here is the path to your Electron binary.
      binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
    }
  })
  .forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
  .build()

driver.get('http://www.google.com')
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
driver.findElement(webdriver.By.name('btnG')).click()
driver.wait(() => {
  return driver.getTitle().then((title) => {
    return title === 'webdriver - Google Search'
  })
}, 1000)

driver.quit()

这是 Electron 官方的一个示例,展示了如何使用 webdriver 来操作 electron 应用。 可直接使用 node index.js 来执行。 这里需要说明的是 /Path-to-Your-App.app/Contents/MacOS/Electron 这个路径。 这个路径实际上是 打包完成之后的 electron 可执行文件的路径, 例如,Bittly 的路径可以是 “D:/bittly/app/dist_electron/win-unpacked/Bittly.exe”。

在 Jest 中使用

其实安装上述两个包之后,就可以直接在测试用例中写代码了。 例如:

import webdriver from 'selenium-webdriver'
describe('@/src/modules/environment/Main.vue', () => {
    it('webdriver ui', async () => {
        let webdriver = await new webdriver.Builder()
            .usingServer('http://localhost:9515')
            .withCapabilities({
                'goog:chromeOptions': {
                    binary: 'D:/bittly/app/dist_electron/win-unpacked/Bittly.exe'
                }
            })
            .forBrowser('chrome')
            .build();
        
        let locator = webdriver.By.css('.project');
        await webdriver.wait(webdriver.until.elementLocated(locator, 60000));
        await webdriver.findElement(locator).click();
        expect(await webdriver.getTitle()).toBe("Bittly");
        await webdriver.quit();
    }, 60000);
});

这么一个 Hello World 测试就完成了, 运行则可以执行 npm run test:unit -t test.spec.js 来执行。

当然,后面要封装或者使用第三方库就看个人喜好了。