glcheck
glcheck is a WebGL-focused testing framework. It runs unit and render tests using puppeteer which allows it to run automated tests and generate coverage reports for both WebGL 1 and 2 applications.
Usage
To install, simply run:
npm i -D glcheck
Run using:
npx glcheck
By default, glcheck
will read configuration from glcheck.config.json
in the current directory, from which it will read the following options:
- unitTests (default:
[]
): List of JavaScript files to run as unit tests. - unitTestDir (default:
"glcheck-tests/unit-tests/"
): Directory to output unit test results into. This includes an HTML page that will be run by puppeteer, but it can also simply be opened in a browser. - assetDir (default:
null
): Directory to load assets from. Contents from this directory will be available to unit tests in the subdirectoryassets/
. - renderTests (default:
[]
): List of HTML files to run as render tests. - referenceImageDir (default:
"glcheck-tests/reference-images/"
): Directory containing render test reference images. - renderTestThreshold (default:
0.99
): Match threshold between 0 and 1 for render tests. - renderTimeout (default:
5000
): Timeout for each render test in milliseconds. - saveRenderFailures (default:
false
): Whether to save render failure and diff images for render tests. - renderFailureDir (default:
"glcheck-tests/render-failures/"
): Where to save render failure and diff images for render tests. - serverPort (default:
7171
): Port to run the local server on for puppeteer. - headless (default:
true
): Whether to run headless. - coverage (default:
true
): Whether to generate coverage results that are consumable by Istanbul. - coverageFiles (default:
[]
): Files to include in coverage results. - only (default:
null
): Only run the provided test file (can be a glob pattern to run multiple files).
Full glcheck
command line usage is as follows:
glcheck [--help] [--version] [--config PATH] [--unit-test-dir PATH] [--asset-dir PATH] [--reference-image-dir PATH] [--render-test-threshold VAL] [--render-timeout TIME] [--save-render-failures {true/false}] [--render-failure-dir PATH] [--server-port PORT] [--coverage {true/false}] [--headless {true/false}] [--only PATH]
Command line arguments will always override options from the config file:
- --help: Show a help message and exit.
- --version: Show version number and exit.
- --config (default:
"glcheck.config.json"
): Path to config file. - --unit-test-dir (default:
"glcheck-results/"
): Directory to output unit test results into. This includes an HTML page that will be run by puppeteer, but it can also simply be opened in a browser. - --asset-dir (default:
null
): Directory to load assets from. Contents from this directory will be available to unit tests in the subdirectoryassets/
. - --reference-image-dir (default:
"glcheck-tests/reference-images/"
): Directory containing render test reference images. - --render-test-threshold (default:
0.99
): Match threshold between 0 and 1 for render tests. - --render-timeout (default:
5000
): Timeout for each render test in milliseconds. - --save-render-failures (default:
false
): Whether to save render failure and diff images for render tests. - --render-failure-dir (default:
"glcheck-tests/render-failures/"
): Where to save render failure and diff images for render tests. - --server-port (default:
7171
): Port to run the local server on for puppeteer. - --headless (default:
true
): Whether to run headless. - --coverage (default:
true
): Whether to generate coverage results that are consumable by Istanbul. - --only (default:
null
): Only run the provided test file (can be a glob pattern to run multiple files).
Unit Tests
A simple unit test suite using glcheck might look like the following:
;
Unit tests are defined using the glcheck
function. The general structure is as follows:
;
The arguments to the test function are a tester object (described below) and a DOM canvas element. Each test will create a fresh canvas for testing and tear it down afterwards.
Test functions can also be async:
;
The tester object's done
method indicates that the test has completed and can also be used in async contexts:
t.done()
: Indicate that a test has completed.
; ;
The tester object exposes the following basic assertions:
t.ok(actual, message)
: Check the truthiness ofactual
.t.notOk(actual, message)
: Check the falsiness ofactual
.t.equal(actual, expected, message)
: Check thatactual
andexpected
are shallowly equal.t.notEqual(actual, expected, message)
: Check thatactual
andexpected
are not shallowly equal.t.deepEqual(actual, expected, message)
: Check thatactual
andexpected
are deeply equal (e.g. for objects and arrays).t.notDeepEqual(actual, expected, message)
: Check thatactual
andexpected
are not deeply equal (e.g. for objects and arrays).t.throws(fn, message)
: Check thatfn
throws an exception.t.doesNotThrow(fn, message)
: Check thatfn
does not throw an exception.
;
The tester object also exposes WebGL-specific assertions:
t.parameterEqual(gl, parameter, expected, message)
: Check if the WebGLparameter
(passed togl.getParameter
) matchesexpected
.t.parameterNotEqual(gl, parameter, expected, message)
: Check if the WebGLparameter
(passed togl.getParameter
) does not matchexpected
.t.pixelEqual(gl,[ uv=[0.5, 0.5],] expected, message)
: Check if the currently bound framebuffer has the valueexpected
at the pixel indicated byuv
.uv
is a two-element array with[0, 0]
indicating the bottom-left of the canvas, and[1, 1]
indicating the top-right.t.pixelNotEqual(gl,[ uv=[0.5, 0.5],] expected, message)
: Check if the currently bound framebuffer does not have the valueexpected
at the pixel indicated byuv
.uv
is a two-element array with[0, 0]
indicating the bottom-left of the canvas, and[1, 1]
indicating the top-right.t.bufferEqual(gl, binding, expected, message)
(WebGL 2-only): Check if the buffer bound tobinding
contains the values inexpected
. Matching will be done based on the array type ofexpected
and will default toFloat32Array
.t.bufferNotEqual(gl, binding, expected, message)
(WebGL 2-only): Check if the buffer bound tobinding
does not contain the values inexpected
. Matching will be done based on the array type ofexpected
and will default toFloat32Array
.
;
Finally, the tester object exposes the async helper loopUntil
for tests that require asynchrony:
t.loopUntil(fn)
: Returns a promise that starts arequestAnimationFrame
loop, callingfn
on each frame and resolving when it returns true.
;
Render Tests
Render tests are run by providing a list of HTML files to render in the configuration file:
To be usable as a render test, a page must simply indicate when it has completed rendering by setting the global glcheck_renderDone
to true
:
windowglcheck_renderDone = true;
NOTE: It recommended to stop animations once glcheck_renderDone
is set to ensure consistent results.
glcheck also exposes a helper function glcheck_setRAFCount
to pages loaded as render tests to simplify controlling animations and signaling that a render is complete.
glcheck_setRAFCount(n)
: InstrumentrequestAnimationFrame
to only loopn
times and setglcheck_renderDone
afterwards.
This can be helpful in instrumenting a page to stop rendering when used as a render test, but render normally otherwise.
if windowglcheck_setRAFCount window; ;