Simple minds think alike

より多くの可能性を

【Electron】Circle CIでSpectronのE2Eテストを動くように

先日Circle CIのチュートリアルに「Automated testing with continuous integration for Electron applications」という記事が追加されていたのでやってみました。

ちょっと前にGithub ActionsでSpectronのE2Eテストを自動で動かせるようにならないか試してみたところ、以下のようなエラーが発生していてChromeが起動しなかったので、今度はCircle CIでやってみたいと思っていたので良いタイミングでした。

また、今後CypressはElectronをサポートする予定とないGithub issueでコメントしているので、改めてSpectronを試してみようと思いました。

Client initialization failed after ***0 attempts: 
RuntimeError Client initialization failed after ***0 attempts: 
Error: unknown error: 
Chrome failed to start: 
exited abnormally. (chrome not reachable)

環境

  • Node.js (>= 11)がインストールされていること
  • CircleCIアカウントがあること
  • GitHubアカウントがあること

テストするElectronアプリケーションを作る

まずは、create-electron-appでアプリケーションを作ります。

$ npx create-electron-app electron-test-app

できたアプリケーションのディレクトリに移動しておきます。

$ cd electron-test-app 

Electronのバージョン10.0.1が出てその変更の影響か、そのままではテスト実行時に以下のエラーが発生していました。ローカル環境のChromeのバージョンを上げる必要がありそうです。

Failed to create session.
    session not created: 
    This version of ChromeDriver only supports Chrome version 83

今回は、Electronのバージョンを9.2.0に下げてやってみました。バージョン変更後、npm startで起動します。

$ yarn upgrade electron@9.2.0
$ npm start

こんな画面が表示されたかと思います。

devtools(画面右側ペイン)が開いていると、テストを実行した時に止まったままになってしまうので、コードを修正しdevtoolsが動かないようにします。

一度、コンソールから起動したElectronアプリケーションをCtrl-Cで停止し、electron-test-app/src/index.jsテキストエディタで開いて、mainWindow.webContents.openDevTools()の箇所をコメントアウトします。

// electron-test-app/src/index.js

19:  // Open the DevTools.
20:  // mainWindow.webContents.openDevTools(); // ←ここをコメントアウト

再度、npm startでアプリケーションを起動すると、今度はdevtoolsが起動しなくなります。

JestとSpectronをセットアップする

以下を作ったアプリケーションに追加します。

以下のコマンドを実行し、アプリケーションにJestとSpectronを追加します。

$ npm install --save-dev jest spectron

アプリケーションのルート直下にあるpackage.jsonを修正し、jestのテストが実行されるようにします。

// package.json

{
    〜〜〜
    "scripts" : {
        〜〜〜
        "test" : "jest"
    }
    〜〜〜
}

テストコードを作る

srcディレクトリに__tests__ディレクトリを作成し、その中にAppTest.jsを作ります。 Jestがデフォルトで__tests__ディレクトリの中のjs/ts/jsxファイルをテストとして実行してくれます。(参照)

こんなテストファイルを追加してみます。テストしている内容に関しては説明を割愛します。

const Application = require("spectron").Application;
const electronPath = require("electron");
const path = require("path");

let app;

beforeAll(() => {
  app = new Application({
    path: electronPath,

    args: [path.join(__dirname, "../../")]
  });

  return app.start();
}, 10000);

afterAll(function () {
  if (app && app.isRunning()) {
    return app.stop();
  }
});

test("アプリケーションウィンドウが表示されること", async function () {
  let windowCount = await app.client.getWindowCount();

  expect(windowCount).toBe(1);
});

test("ヘッダーが適切なテキストになっていること", async function () {
  const headerElement = await app.client.$("h1");

  let headerText = await headerElement.getText();

  expect(headerText).toBe("💖 Hello World!");
});

テストを実行して、うまく動くことを確認します。

$ npm run test

Circle CI上でプロジェクトを作成

Githubリポジトリを作ってPushしておきます。

$ git init && git add . && git commit -m 'initial commit'
$ git push 

次にCircle CIのProjects画面上でSet Up Projectを押して、アプリケーションのプロジェクトをセットアップします。

言語毎にCIの実行内容を記述したymlファイルのテンプレートが用意されていますがElectronはないので、Use Existing Configを押します。

とりあえずStart Buildingを押して、一度セットアップを終えます。

CIの実行内容を作成

セットアップが終わったら、再度ローカルの開発環境に戻り.circleci/config.ymlというymlファイルを作成します。

$ mkdir .circleci && touch .circleci/config.yml

ymlファイルをテキストエディタで以下のように編集して、再度GithubにpushするとCircle CIで自動的にテストが行われるようになります。

version: 2.1
jobs:
  build:
    working_directory: ~/repo
    docker:
      - image: circleci/node:11-browsers
    steps:
      - checkout
      - run:
          name: Update NPM
          command: "sudo npm install -g npm"
      - restore_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
      - run:
          name: Install Dependencies
          command: npm install
      - save_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules
      - run:
          name: Run tests
          command: npm run test

Cicle CIの画面に戻って、Pipelinesを開くと正常にテストが動いているのを確認できます。

参考資料