Using GoJS in unit tests

Hi,

Since GoJS 2.0 has support for browser-less environments like Node, I decided to incorporate some unit tests for our diagram handling functions. However, I am unable to use it - I get following error:

TypeError: Cannot set property ‘fillStyle’ of null
at node_modules/gojs/release/go.js:828:107
at Object. (node_modules/gojs/release/go.js:2076:265)

I’m running unit tests through Jest with TypeScript. Here’s the code of sample unit test using GoJS that doesn’t work:

import * as go from 'gojs';
const $ = go.GraphObject.make;
const myPalette = $(go.Palette, '', { viewSize: new go.Size(100, 100) });
const model = [
    { key: 'A', group: '' }
];
myPalette.model = new go.GraphLinksModel(model);    
describe('palette', () => {
    test('should have nodedataarray created from model', () => {
        expect(myPalette.model.nodeDataArray).toHaveLength(model.length);
    });
});

Do you have any idea why this error is thrown and what we can do to be able to use GoJS functionalities through Jest?

I’m using GoJS from NPM, version “2.0.0-beta6”. Version of Jest is “23.6.0”, and ts-jest “23.10.4”.

I am unfamiliar with Jest, does it try to emulate having a DOM in any way? Or is it a totally headless environment, and there should be no HTML canvas, no drawing, etc?

According to docs, they use jsdom to emulate DOM environment inside NodeJS. For example, they are using it like this with jQuery: DOM Manipulation · Jest

from the type of error (cannot set fillStyle of null) the implication is that the canvas context is null. This might be happening if the canvas itself is unsupported. You may need to add more dependencies to get it to work, perhaps this:

Canvas support

jsdom includes support for using the canvas package to extend any <canvas> elements with the canvas API. To make this work, you need to include canvas as a dependency in your project, as a peer of jsdom . If jsdom can find the canvas package, it will use it, but if it’s not present, then <canvas> elements will behave like <div> s. Since jsdom v13, version 2.x of canvas is required; version 1.x is no longer supported.

Can you make sure that’s added as a peer dependency (of jsdom), and try again?

I’ve finally ended up using https://www.npmjs.com/package/jest-canvas-mock , but I can’t say that’s the solution I like. I even had to provide a DIV element (which is now also emulated) so GoJS can perform not visible rendering. Now the following code works

import * as go from 'gojs';

const $ = go.GraphObject.make;
const fakeDiv = document.createElement('div');
const myPalette = $(go.Palette, fakeDiv, { viewSize: new go.Size(100, 100) });
const model = [
    { key: 'A', group: '' }
];
myPalette.model = new go.GraphLinksModel(model);

describe('palette', () => {
    test('should have nodedataarray created from model', () => {
        expect(myPalette.model.nodeDataArray).toHaveLength(model.length);
    });
});

I thought that with a new version there will be a possibility to just use GoJS functionality without the need of simulating Canvas, even when the rest of the DOM is simulated. I think it would be nice to have a possibility, that when instead of DIV element or id, the empty string is provided (like in docs) GoJS works in DOM-less mode even when there is DOM available.

Yes, GoJS can now work totally DOM-less, but only when it detects no DOM at all. I will add an option to turn off any DOM so that your test system will work without needing this mock canvas. I will let you know when the next Beta is released.

Note that some things depend on the DOM to measure, like text and pictures, and you may need to give go.TextBlocks and go.Pictures a desiredSize in order to keep testing consistent, if you are testing them.

@tswistak we have just published gojs@2.0.0-beta7, which has two new static functions:

Diagram.isUsingDOM()

Diagram.useDOM(value)

Before creating any Diagrams, try calling:

Diagram.useDOM(false);

And GoJS will act as if its in a DOM-less environment, even if it detects a root.document.

1 Like

Thanks very much for the change. Unfortunately, something is still wrong. I’ve updated GoJS, turned off Canvas simulation and still get the same error. Now the code looks like this:

import * as go from 'gojs';

go.Palette.useDOM(false);
const $ = go.GraphObject.make;
const myPalette = $(go.Palette, '', { viewSize: new go.Size(100, 100) });
const model = [
    { key: 'A', group: '' }
];
myPalette.model = new go.GraphLinksModel(model);

describe('palette', () => {
    test('should have nodedataarray created from model', () => {
        expect(myPalette.model.nodeDataArray).toHaveLength(model.length);
    });
});

And the error:

    TypeError: Cannot set property 'fillStyle' of null

        > 1 | import * as go from 'gojs';
            | ^
          2 | 
          3 | go.Palette.useDOM(false);
          4 | const $ = go.GraphObject.make;
    
          at node_modules/gojs/release/go.js:756:107
          at Object.<anonymous> (node_modules/gojs/release/go.js:2069:265)
          at Object.<anonymous> (src/common/palette/__tests__/sample-gojs.spec.ts:1:1)

I’ve tried setting useDOM both for Palette and Diagram and in both it wasn’t working.

EDIT: I’ve tried something different and decided to remove import declaration in favor of adding gojs to Jest’s setupFiles (list of modules that are loaded for every test suite). Now the error is thrown on every unit test, even those that aren’t using GoJS, so it looks that the error is thrown on the module import level, before I’m able to setup useDOM to false.
I’ve also tried to change import to require, but it also throws error in the same place.

@tswistak Sorry, I made too many assumptions about Jest in my testing. Please try again with this version of the library: [EDIT: obsolete] (note: previously I had 7b up)

I tested it with Node and Jest (and in browser turning off DOM). If it works for you, I’ll make a new beta release.

It looks that everything is working fine. The test case I’ve provided works with the version you gave in the last post.
Thanks a lot!

Thanks for testing. We’ll release a new beta soon-ish. Feel free to use that provisional version for now.

We’ve just released beta 8, which should work as you expect now.

npm i gojs@beta should work to use it, if you like.

1 Like

I am not able to install npm i gojs@beta it shows below error.

kishanoza@Kishans-MacBook-Air-2 % npm i gojs@beta  
npm ERR! code ETARGET
npm ERR! notarget No matching version found for gojs@beta.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/kishanoza/.npm/_logs/2022-07-01T10_47_42_487Z-debug-0.log

That tag was used 4 years ago for the version 2.0 beta branch. Use the latest version now.