This package has been deprecated

Author message:

pico-gltest has been renamed to glcheck

pico-gltest

0.0.14 • Public • Published

pico-gltest

Build Status Coverage Status License NPM

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:

 
glTest("Test myApp", (t, canvas) => {
    const gl = canvas.createContext("webgl2");
 
    gl.enable(gl.DEPTH_TEST);
    t.glParameterEqual(gl, gl.DEPTH_TEST, true, "Depth test enabled");
    t.glParameterNotEqual(gl, gl.DEPTH_TEST, false, "Depth test not disabled");
 
    gl.clearColor(1, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    t.pixelEqual(gl, [255, 0, 0, 255], "Framebuffer is red");
    t.pixelNotEqual(gl, [0, 0, 255, 255], "Framebuffer is not blue");
 
    // Buffer tests are WebGL 2-only
    const buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), gl.STATIC_READ);
    t.bufferEqual(gl, gl.ARRAY_BUFFER, [1, 2, 3, 4], "Buffer data counts up");
    t.bufferNotEqual(gl, gl.ARRAY_BUFFER, [4, 3, 2, 1], "Buffer data does not count down");
 
    t.done();
});
 

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 subdirectory assets/.
  • 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 subdirectory assets/.

Writing Tests

Tests are defined for pico-gltest using the glTest function. The general structure is as follows:

 
glTest("My test", (t, canvas) => {
 
    // Write some tests
 
    t.done();
});
 

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:

 
glTest("My test", async (t, canvas) => {
 
    const data = await getAsyncData();
 
    // Write some tests
 
    t.done();
});

A single test can be selected to run on its own using glTest.only:

 
glTest.only("Test I'm writing now", (t, canvas) => {
 
    // Write some tests
 
    t.done();
});

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.
glTest("Basic", async (t, canvas) => {
    t.ok(true, "ok");
    t.done();
});
 
glTest("Async", async (t, canvas) => {
    setTimeout(() => {
        t.ok(true, "ok");
        t.done();
    }, 50);
});

The tester object exposes the following basic assertions:

  • t.ok(actual, message): Check the truthiness of actual.
  • t.noOk(actual, message): Check the falsiness of actual.
  • t.equal(actual, expected, message): Check that actual and expected are shallowly equal.
  • t.notEqual(actual, expected, message): Check that actual and expected are not shallowly equal.
  • t.deepEqual(actual, expected, message): Check that actual and expected are deeply equal (e.g. for objects and arrays).
  • t.notDeepEqual(actual, expected, message): Check that actual and expected are not deeply equal (e.g. for objects and arrays).
  • t.throws(fn, message): Check that fn throws an exception.
  • t.doesNotThrow(fn, message): Check that fn does not throw an exception.
glTest("Basic assertions", (t, canvas) => {
    t.ok(true, "ok");
    t.equal(1, 1, "equal");
    t.deepEqual({a: 1, b: 2}, {a: 1, b: 2}, "deepEqual");
 
    // deepEqual considers all array types equivalent
    t.deepEqual([1, 2, 3, 4], new Float32Array([1, 2, 3, 4]), "deepEqual different array types");
 
    t.throws(() => {throw "Throw";}, "throws");
 
    t.done();
});

The tester object also exposes WebGL-specific assertions:

  • t.glParameterEqual(gl, parameter, expected, message): Check if the WebGL parameter (passed to gl.getParameter) matches expected.
  • t.glParameterNotEqual(gl, parameter, expected, message): Check if the WebGL parameter (passed to gl.getParameter) does not match expected.
  • t.pixelEqual(gl,[ uv=[0.5, 0.5],] expected, message): Check if the currently bound framebuffer has the value expected at the pixel indicated by uv. 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 value expected at the pixel indicated by uv. 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 to binding contains the values in expected. Matching will be done based on the array type of expected and will default to Float32Array.
  • t.bufferNotEqual(gl, binding, expected, message) (WebGL 2-only): Check if the buffer bound to binding does not contain the values in expected. Matching will be done based on the array type of expected and will default to Float32Array.
glTest("GL assertions", (t, canvas) => {
    const gl = canvas.getContext("webgl2");
 
    t.glParameterEqual(gl, gl.DEPTH_TEST, true, "glParameterEqual");
    t.glParameterEqual(gl, gl.VIEWPORT, [10, 20, 30, 40], "glParameterEqual array");
    
    t.pixelEqual(gl, [255, 0, 0, 255], "pixelEqual center");
    t.pixelEqual(gl, [0.25, 0.75], [255, 0, 0, 255], "pixelEqual upper-left");
 
    // Buffer assertions are WebGL 2-only
    const floatBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, floatBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), gl.STATIC_READ);
    t.bufferEqual(gl, gl.ARRAY_BUFFER, [1, 2, 3, 4], "bufferEqual");
 
    const byteBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, byteBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array([5, 6, 7, 8]), gl.STATIC_READ);
 
    // bufferEqual will respect the type of the "expected" array passed
    t.bufferEqual(gl, gl.ARRAY_BUFFER, new Uint8Array([5, 6, 7, 8]), "bufferEqual bytes");
 
    t.done();
});

Finally, the tester object exposes the async helper loopUntil for tests that require asynchrony:

  • t.loopUntil(fn): Returns a promise that starts a requestAnimationFrame loop, calling fn on each frame and resolving when it returns true.
glTest("loopUntil helper", async (t, canvas) => {
    const gl = canvas.getContext("webgl2");
    const query = gl.createQuery();
 
    gl.beginQuery(gl.ANY_SAMPLES_PASSED_CONSERVATIVE, query);
    // ...
    gl.endQuery(query);
 
    await t.loopUntil(() => gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE));
 
    t.equal(gl.getQueryParameter(this.query, GL.QUERY_RESULT), expected, "Query results");
 
    t.done();
});

Package Sidebar

Install

npm i pico-gltest

Weekly Downloads

0

Version

0.0.14

License

MIT

Unpacked Size

236 kB

Total Files

14

Last publish

Collaborators

  • tsherif