この記事は、GitHub Actions上でthree.jsの単体テスト方法を記録、共有するためのものです。
node.jsでWebGLを利用したコードを単体テストし、GitHub Actions上で処理します。ヘッドレスブラウザやelectronは使用しません。
この記事は、以下の読者を想定して書かれています。
JavaScriptの解説やJestのインストールガイドはこの記事には含まれません。
この記事は、以下の環境を想定して書かれています。記事を読む前に、お手元の環境をご確認ください。
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
GitHub Actions上の仮想環境はubuntu-latest、node.jsのバージョンは12から16までを想定しています。
また、テスティングフレームワークはJestを利用します。
"devDependencies": {
"jest": "^27.0.4",
}
GitHub Actionsでthree.jsを単体テストする最小限のリポジトリを作りました。
Jestはnode.jsで稼働するJavaScriptテスティングフレームワークです。Jestにはjsdomという、JavaScriptで記述されたDOM実装が含まれています。このjsdomを使ってCanvasを作成し、WebGLを利用するコードをテストします。
Jestでjsdomを利用するには、設定ファイルを作成し環境にjsdom
を指定します。
▼jest.config.js
module.exports = {
testEnvironment: "jsdom",
};
もしくは、jestコマンドに--env=jsdom
オプションを追加します。
▼package.json
"scripts": {
"test": "jest --env=jsdom"
}
jsdomは軽量化のため、標準設定ではCanvas要素をdiv要素で代用します。そのため、CanvasRenderingContext2DやWebGLRenderingContextはテストで使えません。
jsdomでWebGLをテストするためには、この2つの課題を解決しなければなりません。
jsdomでCanvas要素をサポートするために、node-canvasを利用します。
npm install canvas --save-dev
jsdomはnode-canvas
のインストールを自動で検知します。ユーザーがなにか設定をする必要はありません。
const canvas = document.createElement("canvas");
テストコード上でdocument.createElementを呼び出すと、node-canvas
からCanvas要素が返されます。
jsdomでWebGLRenderingContextをサポートするために、headless-glを利用します。headless-glはnode.js上でWebGLRenderingContextを作成するモジュールです。
npm install gl --save-dev
テストコードでは、以下のようにWebGLRenderingContextを生成します。
const gl = require('gl')(width, height)
width, heightには好きなサイズを指定できますが、THREE.WebGLRendererのsetSize関数で変更されてしまうため、最小限のサイズを指定します。
const gl = require('gl')(1, 1)
node-canvas
とheadless-gl
を使ってテストを作成します。
▼./__test__/Test.spec.js
const THREE = require("three");
jest.spyOn(console, "error").mockImplementation()
describe("Test", () => {
const canvas = document.createElement("canvas");
test("2d context should be exist", () => {
const context = canvas.getContext("2d");
expect(context).toBeTruthy();
})
test("generate webgl context", ()=>{
const gl = require("gl")(1,1);
expect(gl).toBeTruthy();
})
test("generate webgl renderer", ()=>{
const gl = require("gl")(1,1);
const renderer = new THREE.WebGLRenderer({context:gl, canvas:canvas});
renderer.setSize(640, 480);
expect(renderer.getContext()).toBeTruthy();
expect(renderer.getContext()).toBe(gl);
expect(renderer.domElement.width).toBe(640);
})
})
このテストで、以下の課題2点が確認できました。
また、CanvasとWebGLコンテキストを利用してWebGLRendererが生成できました。
ここまでで作成したテストはそのままではGitHub Actionsで動作しません。GitHub Actionsの仮想環境ubuntu-latest
には、headless-glが依存するいくつかのパッケージが含まれていないためです。
この問題のもっとも簡単な解決方法は、仮想環境のmacos-latest
かwindows-latest
への変更です。この2つの仮想環境は、headless-glの動作に必要なパッケージをすべて含んでいます。
jobs:
build:
runs-on: macos-latest
ただしmacos-latest
とwindows-latest
はLinuxにくらべ、それぞれ2倍と10倍のコストがかかります。
公式ドキュメント : GitHub Actionsの支払いについて
パブリックリポジトリでは、GitHub Actionsの費用は利用者に請求されません。しかしサーバー資源の浪費は避けるべきです。
GitHub Actionsのstepsでは、sudoコマンドが使えます。必要なパッケージをインストールすれば、ubuntu-latest
でheadless-glが動作します。
headless-glに必要なパッケージは以下の通りです。
このパッケージをインストールし、テスト実行前に仮想フレームバッファーXvfb
を起動します。
steps:
- uses: actions/checkout@v2
# ここでパッケージをインストール
- name: install apt packages for headless-gl
run: sudo apt-get install libxi-dev xvfb libgl1-mesa-dev
# ...中略...
# npm testの実行直前に xvfb-run --auto-servernum で仮想フレームバッファーXvfbを起動
- run: xvfb-run --auto-servernum npm test
参考 : Usage on GitHub Actions with xvfb
これでheadless-glが動作します。
以上、ありがとうございました。