pico-gltest
pico-gltest is a testing framework focused on WebGL applications. It is designed to run in a browser without any build steps, making it straightforward to use across browsers and platforms. It uses puppeteer to run headlessly via the command line which allows it to run automated tests for both WebGL 1 and 2 applications. A slimple test suite using pico-gltest might look like the following:
;
Usage
Installation
To install, simply run:
npm i -D pico-gltest
Running
Assuming tests are in a file test.js
, they can be run directly as follows:
npx gltest test.js
By default, gltest
will read configuration from gltest.config.json
in the current directory, from which it will read the following options:
- tests (default:
[]
): List of tests to run. - outputDir (default:
"gltest-results/"
): Directory to output results into. This includes an HTML page that will be run by puppeteer, but it can also simply be opened in a browser. - serverPort (default:
7171
): Port to run the local server on for puppeteer testing. - headless (default:
true
): Whether to run headless. - assetDir (default:
null
): Directory to load assets from. Contents from this directory will be available to tests in the subdirectoryassets/
. - coverage (default:
false
): Whether to produce coverage results that are consumable by Istanbul. - coverageExcludeFiles (default:
[]
): Files to exclude from coverage results. This can be useful for excluding utility or library files from coverage reports. Note that files in tests are always excluded from coverage reports.
Full gltest
command line usage is as follows:
gltest [--help] [--version] [--config PATH] [--coverage {true/false}] [--headless {true/false}] [--server-port PORT] [--output-dir PATH] [--asset-dir PATH] [TEST FILES...]
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: Path to config file (default:
"gltest.config.json"
) - --output-dir (default:
"gltest-results/"
): Directory to output results into. This will be run by puppeteer, but can also simply be opened in a browser. - --server-port (default:
7171
): Port to run the local server on for puppeteer testing. - --headless (default:
true
): Whether to run headless. - --coverage (default:
false
): Whether to produce coverage results that are consumable by Istanbul. - --asset-dir (default:
null
): Directory to load assets from. Contents from this directory will be available to tests in the subdirectoryassets/
.
Writing Tests
Tests are defined for pico-gltest
using the glTest
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:
;
A single test can be selected to run on its own using glTest.only
:
glTest;
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.noOk(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.glParameterEqual(gl, parameter, expected, message)
: Check if the WebGLparameter
(passed togl.getParameter
) matchesexpected
.t.glParameterNotEqual(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.
;