はじめに
この記事は、GitHub Actions上でthree.jsの単体テスト方法を記録、共有するためのものです。
node.jsでWebGLを利用したコードを単体テストし、GitHub Actions上で処理します。ヘッドレスブラウザやelectronは使用しません。
想定する読者
この記事は、以下の読者を想定して書かれています。
- JavaScriptの開発経験がある
- Jestを使ったことがある
- three.jsを使ったことがある
- リポジトリをGitHubで管理している / 管理したい
JavaScriptの解説やJestのインストールガイドはこの記事には含まれません。
想定する環境
この記事は、以下の環境を想定して書かれています。記事を読む前に、お手元の環境をご確認ください。
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
また、テスティングフレームワークはJestを利用します。
"devDependencies": {
"jest": "^29.3.1",
}
先に結論だけ
GitHub Actionsでthree.jsを単体テストする最小限のリポジトリを作りました。
WebGLを利用した単体テスト
Jestはnode.jsで稼働するJavaScriptテスティングフレームワークです。Jestはjsdomという、JavaScriptで記述されたDOM実装と連携します。このjsdomを使ってCanvasを作成し、WebGLを利用するコードをテストします。
Jestでjsdomを利用する
Jestでjsdomを利用するには、まずJestとjest-environment-jsdom
をインストールします。
npm i -D jest jest-environment-jsdom
次に設定ファイルを作成し環境にjsdom
を指定します。
▼jest.config.js
module.exports = {
testEnvironment: "jest-environment-jsdom",
};
もしくは、jestコマンドに--env=jest-environment-jsdom
オプションを追加します。
▼package.json
"scripts": {
"test": "jest --env=jest-environment-jsdom"
}
課題
jsdomは軽量化のため、標準設定ではCanvas要素をdiv要素で代用します。そのため、CanvasRenderingContext2DやWebGLRenderingContextはテストで使えません。
- Canvas要素のサポート
- WebGLRenderingContextのサポート
jsdomでWebGLをテストするためには、この2つの課題を解決しなければなりません。
Canvas要素のサポート
jsdomでCanvas要素をサポートするために、node-canvasを利用します。
npm install canvas --save-dev
jsdomはnode-canvas
のインストールを自動で検知します。ユーザーがなにか設定をする必要はありません。
const canvas = document.createElement("canvas");
テストコード上でdocument.createElementを呼び出すと、node-canvas
からCanvas要素が返されます。
WebGLRenderingContextのサポート
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コンテキストのサポート
また、CanvasとWebGLコンテキストを利用してWebGLRendererが生成できました。
GitHub Actionsで実行する
ここまでで作成したテストは、そのままGitHub Actionsで動作しません。GitHub Actionsの仮想環境ubuntu-latest
には、headless-glが依存するいくつかのパッケージが含まれていないためです。
headless-glはビルド済みのバイナリを配布していますが、2024/01/05の時点では、node.js v20向けのバイナリは配布されていません。node.js v20環境でテストを行う場合は、依存パッケージをaptからインストールし、ビルドしなければなりません。
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- run: sudo apt-get update
- name: Install dependencies for headless-gl
run: sudo apt-get install -y build-essential libxi-dev libglu1-mesa-dev libglew-dev pkg-config
# npm ciの途中で、headless-glのビルドが始まる
- run: npm ci
# npm testの実行直前に xvfb-run --auto-servernum で仮想フレームバッファーXvfbを起動
- run: xvfb-run --auto-servernum npm test
各OSで必要とされるパッケージは、headless-glのREADMEを参照してください。
参考記事
以上、ありがとうございました。