Skip to content

Commit

Permalink
Switch to node-canvas for running unit tests (#7223)
Browse files Browse the repository at this point in the history
* Switch to node-canvas for running unit tests

* Lint fixes

* Remove another skia-canvas reference

* Drop xhr2

* Update README for tests

* Update canvas

* Tweak canvas dependency

* Switch to @napi-rs/canvas

* Cleanup jsdom
  • Loading branch information
willeastcott authored Dec 20, 2024
1 parent d0318ba commit 32c018b
Show file tree
Hide file tree
Showing 27 changed files with 381 additions and 385 deletions.
639 changes: 342 additions & 297 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@babel/core": "^7.26.0",
"@babel/eslint-parser": "^7.25.9",
"@babel/preset-env": "^7.26.0",
"@napi-rs/canvas": "^0.1.65",
"@playcanvas/eslint-config": "^2.0.8",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^16.0.0",
Expand All @@ -81,9 +82,9 @@
"chai": "^5.1.2",
"eslint": "^9.17.0",
"fflate": "^0.8.2",
"global-jsdom": "^24.0.0",
"global-jsdom": "^25.0.0",
"globals": "^15.14.0",
"jsdom": "^24.1.3",
"jsdom": "^25.0.1",
"karma": "^6.4.3",
"karma-chrome-launcher": "^3.2.0",
"karma-mocha": "^2.0.1",
Expand All @@ -97,11 +98,9 @@
"rollup-plugin-visualizer": "^5.12.0",
"serve": "^14.2.4",
"sinon": "^19.0.2",
"skia-canvas": "^2.0.1",
"typedoc": "^0.27.5",
"typedoc-plugin-mdn-links": "^4.0.5",
"typescript": "^5.7.2",
"xhr2": "^0.2.1"
"typescript": "^5.7.2"
},
"scripts": {
"build": "node build.mjs",
Expand Down
9 changes: 4 additions & 5 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
# Unit Tests

PlayCanvas uses [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for unit testing. All tests run in Node and load the engine's source modules directly. This means that building the engine is not a requirement for running the tests. Node is missing some features required by the engine so a couple of mocks are used:
PlayCanvas uses [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for unit testing. All tests run in Node and load the engine's source modules directly. This means that building the engine is not a requirement for running the tests.

* [`canvas-mock`](https://github.com/playcanvas/canvas-mock) - implements `HTMLCanvasElement` (and `WebGL 1.0`).
* [`xhr2`](https://github.com/pwnall/node-xhr2) - implements `XMLHttpRequest`.
PlayCanvas depends on a browser environment for the full set of tests to run successfully. This is achieved via [jsdom](https://github.com/jsdom/jsdom).

## Running the Unit Tests

To run the tests, simply do:

```
npm run test
npm test
```

## Code Coverage
Expand Down Expand Up @@ -79,7 +78,7 @@ describe('SomeClass', function () {
Some tips:

* Group properties, then the constructor and then member functions in the test module.
* Alphabetize the API described in the test module (as it appears in the [API reference manual](https://developer.playcanvas.com/api/)).
* Alphabetize the API described in the test module (as it appears in the [API reference manual](https://api.playcanvas.com/modules/Engine.html)).
* [Avoid using arrow functions](https://mochajs.org/#arrow-functions) for `describe` and `it` calls.
* Try to make the call to `it` read as a proper sentence:
* Good: `it('returns null on failure', ...`
Expand Down
12 changes: 5 additions & 7 deletions test/fixtures.mjs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import globalJsdom from 'global-jsdom';
import handler from 'serve-handler';
import http from 'http';
import XMLHttpRequest from 'xhr2';
import { Image } from 'skia-canvas';

let cleanup;
let server;

export const mochaGlobalSetup = () => {
globalJsdom(undefined, {
cleanup = globalJsdom(undefined, {
resources: 'usable'
});
globalThis.Image = Image;

// Provide a polyfill for XMLHttpRequest required by the engine
global.XMLHttpRequest = XMLHttpRequest;

server = http.createServer((request, response) => {
return handler(request, response);
Expand All @@ -25,4 +21,6 @@ export const mochaGlobalSetup = () => {

export const mochaGlobalTeardown = () => {
server.close();

cleanup();
};
4 changes: 2 additions & 2 deletions test/framework/anim/controller/anim-controller.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AnimCurve } from '../../../../src/framework/anim/evaluator/anim-curve.j
import { INTERPOLATION_LINEAR } from '../../../../src/framework/anim/constants.js';
import { ANIM_LESS_THAN } from '../../../../src/framework/anim/controller/constants.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';
import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('AnimController', function () {
Expand All @@ -18,7 +18,7 @@ describe('AnimController', function () {
let controller;

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
const states = [
{
Expand Down
6 changes: 2 additions & 4 deletions test/framework/anim/evaluator/anim-evaluator.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ import { DefaultAnimBinder } from '../../../../src/framework/anim/binder/default
import { GraphNode } from '../../../../src/scene/graph-node.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('AnimEvaluator', function () {

it('AnimEvaluator: update with clip blending', function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
const app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });

// build the graph to be animated
Expand Down Expand Up @@ -90,7 +88,7 @@ describe('AnimEvaluator', function () {
});

it('AnimEvaluator: update without clip blending', function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
const app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });

// build the graph to be animated
Expand Down
6 changes: 2 additions & 4 deletions test/framework/application.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ import { ScriptRegistry } from '../../src/framework/script/script-registry.js';
import { XrManager } from '../../src/framework/xr/xr-manager.js';
import { NullGraphicsDevice } from '../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('Application', function () {

describe('#constructor', function () {

it('support no options', function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
const app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });

expect(app.assets).to.be.instanceOf(AssetRegistry);
Expand Down Expand Up @@ -56,7 +54,7 @@ describe('Application', function () {
describe('#destroy', function () {

it('destroys the application', function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
const app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });

app.destroy();
Expand Down
4 changes: 1 addition & 3 deletions test/framework/asset/asset-list-loader.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { AssetListLoader } from '../../../src/framework/asset/asset-list-loader.
import { Asset } from '../../../src/framework/asset/asset.js';
import { NullGraphicsDevice } from '../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('AssetListLoader', function () {
Expand All @@ -13,7 +11,7 @@ describe('AssetListLoader', function () {
const assetPath = 'http://localhost:3000/test/test-assets/';

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
4 changes: 1 addition & 3 deletions test/framework/asset/asset-localized.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ import { Application } from '../../../src/framework/application.js';
import { Asset } from '../../../src/framework/asset/asset.js';
import { NullGraphicsDevice } from '../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('LocalizedAsset', function () {

let app;

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
3 changes: 1 addition & 2 deletions test/framework/asset/asset-reference.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Asset } from '../../../src/framework/asset/asset.js';
import { AssetReference } from '../../../src/framework/asset/asset-reference.js';
import { NullGraphicsDevice } from '../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';
import { expect } from 'chai';
import { fake, restore } from 'sinon';

Expand All @@ -15,7 +14,7 @@ describe('AssetReference', function () {
let add;

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
parent = fake();
load = fake();
Expand Down
4 changes: 1 addition & 3 deletions test/framework/asset/asset-registry.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { Texture } from '../../../src/platform/graphics/texture.js';
import { http, Http } from '../../../src/platform/net/http.js';
import { NullGraphicsDevice } from '../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';
import { restore, spy } from 'sinon';

Expand All @@ -20,7 +18,7 @@ describe('AssetRegistry', function () {
beforeEach(function () {
retryDelay = Http.retryDelay;
Http.retryDelay = 1;
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
4 changes: 1 addition & 3 deletions test/framework/asset/asset.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import { Application } from '../../../src/framework/application.js';
import { Asset } from '../../../src/framework/asset/asset.js';
import { NullGraphicsDevice } from '../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('Asset', function () {

let app;

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
4 changes: 1 addition & 3 deletions test/framework/components/element/component.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { Application } from '../../../../src/framework/application.js';
import { Entity } from '../../../../src/framework/entity.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('ElementComponent', function () {
let app;

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
5 changes: 1 addition & 4 deletions test/framework/components/element/draw-order.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@ import { Entity } from '../../../../src/framework/entity.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';
import { ScreenComponent } from '../../../../src/framework/components/screen/component.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('ElementComponent Draw Order', function () {
let app;

beforeEach(function () {
const canvas = new Canvas(500, 500);
canvas.getBoundingClientRect = () => ({ left: 0, top: 0, width: 500, height: 500 });
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
5 changes: 1 addition & 4 deletions test/framework/components/element/element-masks.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ import { Application } from '../../../../src/framework/application.js';
import { Entity } from '../../../../src/framework/entity.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('ElementComponent Masks', function () {
let app;

beforeEach(function () {
const canvas = new Canvas(500, 500);
canvas.getBoundingClientRect = () => ({ left: 0, top: 0, width: 500, height: 500 });
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
});

Expand Down
4 changes: 1 addition & 3 deletions test/framework/components/element/image-element.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { TextureAtlas } from '../../../../src/scene/texture-atlas.js';
import { Vec2 } from '../../../../src/core/math/vec2.js';
import { Vec4 } from '../../../../src/core/math/vec4.js';

import { Canvas } from 'skia-canvas';
import { expect } from 'chai';
import { createSandbox } from 'sinon';

Expand All @@ -23,8 +22,7 @@ describe('ImageElement', function () {
let sandbox;

beforeEach(function (done) {
const canvas = new Canvas(300, 150);
canvas.getBoundingClientRect = () => ({ left: 0, top: 0, width: 300, height: 150 });
const canvas = document.createElement('canvas');
sandbox = createSandbox();
app = new Application(canvas, {
graphicsDevice: new NullGraphicsDevice(canvas)
Expand Down
4 changes: 1 addition & 3 deletions test/framework/components/element/text-element.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { Entity } from '../../../../src/framework/entity.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';
import { Vec2 } from '../../../../src/core/math/vec2.js';

import { Canvas } from 'skia-canvas';
import { expect } from 'chai';
import { restore } from 'sinon';

Expand All @@ -18,8 +17,7 @@ describe('TextElement', function () {
let fontAsset;

beforeEach(function (done) {
const canvas = new Canvas(300, 150);
canvas.getBoundingClientRect = () => ({ left: 0, top: 0, width: 300, height: 150 });
const canvas = document.createElement('canvas');
app = new Application(canvas, {
graphicsDevice: new NullGraphicsDevice(canvas)
});
Expand Down
4 changes: 1 addition & 3 deletions test/framework/components/layout-group/component.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { Application } from '../../../../src/framework/application.js';
import { Entity } from '../../../../src/framework/entity.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';
import { restore, spy, stub } from 'sinon';

Expand Down Expand Up @@ -32,7 +30,7 @@ describe('LayoutGroupComponent', function () {
};

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
system = app.systems.layoutgroup;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { Vec2 } from '../../../../src/core/math/vec2.js';
import { Vec4 } from '../../../../src/core/math/vec4.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

/** @import { ElementComponent } from '../../../../src/framework/components/element/component.js' */
Expand Down Expand Up @@ -62,7 +60,7 @@ describe('LayoutCalculator', function () {
};

beforeEach(function () {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });
calculator = new LayoutCalculator();

Expand Down
4 changes: 1 addition & 3 deletions test/framework/components/model/component.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { Entity } from '../../../../src/framework/entity.js';
import { LAYERID_WORLD, LAYERID_UI } from '../../../../src/scene/constants.js';
import { NullGraphicsDevice } from '../../../../src/platform/graphics/null/null-graphics-device.js';

import { Canvas } from 'skia-canvas';

import { expect } from 'chai';

describe('ModelComponent', function () {
Expand Down Expand Up @@ -47,7 +45,7 @@ describe('ModelComponent', function () {
};

beforeEach(function (done) {
const canvas = new Canvas(500, 500);
const canvas = document.createElement('canvas');
app = new Application(canvas, { graphicsDevice: new NullGraphicsDevice(canvas) });

loadAssets(() => {
Expand Down
Loading

0 comments on commit 32c018b

Please sign in to comment.