Skip to main content

Jest

Jest is one of the more popular JavaScript testing frameworks. Due to some default behaviour and limitations of Jest, you might run into some of the following issues when working with JointJS and Jest, so we hope the information below can get you up and running quickly.

Import and Export errors with ES modules

Jest now ships with experimental support for ECMAScript Modules. This wasn't always the case, and depending on your version of Jest, and your particular Jest configuration, you may run into some errors regarding this.

As a result, if you encounter errors such as SyntaxError: Unexpected token import / export or SyntaxError: Cannot use import statement outside a module, one solution is to configure Jest with the transformIgnorePatterns option.

Generally, this option can be configured in your respective Jest config file, but if you are using Create React App, you might have to use the option in an npm script.

You can see how we added the option to our CRA React application.

"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!@joint)/\"",
"eject": "react-scripts eject"
},

JSDOM and SVG APIs

Jest uses JSDOM, and JSDOM doesn't support a lot of SVG APIs. As JointJS uses SVG rendering, it's necessary to create some basic mocks when testing with Jest.

The following is an incomplete set of mocks which you can copy to your own Jest setup file such as setupTests.ts. These mocks were required in order to address missing functionality in JSDOM.

We describe the mocks as "incomplete", because all of the SVG APIs are not covered, and it's likely you might need to extend the following list if you are confronted with an error such as TypeError: ... is not a function. We hope these examples can provide you with some inspiration when creating your own mocks.

// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';

// Mock method which is not implemented in JSDOM
window.SVGPathElement = jest.fn();

// Mock SVGAngle which is used for sanity checks in Vectorizer library
Object.defineProperty(window, 'SVGAngle', {
writable: true,
value: jest.fn().mockImplementation(() => ({
new: jest.fn(),
prototype: jest.fn(),
SVG_ANGLETYPE_UNKNOWN: 0,
SVG_ANGLETYPE_UNSPECIFIED: 1,
SVG_ANGLETYPE_DEG: 2,
SVG_ANGLETYPE_RAD: 3,
SVG_ANGLETYPE_GRAD: 4,
}))
});

beforeEach(()=>{

Object.defineProperty(global, 'ResizeObserver', {
writable: true,
value: jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}))
});

Object.defineProperty(global.SVGElement.prototype, 'getComputedTextLength', {
writable: true,
value: jest.fn().mockImplementation(() => 200),
});

Object.defineProperty(global.SVGSVGElement.prototype, 'createSVGMatrix', {
writable: true,
value: jest.fn().mockImplementation(() => ({
martix: jest.fn(() => [[]]),
a: 0,
b: 0,
c: 0,
d: 0,
e: 0,
f: 0,
flipX: jest.fn().mockImplementation(() => global.SVGSVGElement),
flipY: jest.fn().mockImplementation(() => global.SVGSVGElement),
inverse: jest.fn().mockImplementation(() => global.SVGSVGElement),
multiply: jest.fn().mockImplementation(() => global.SVGSVGElement),
rotate: jest.fn().mockImplementation(() => ({
translate: jest.fn().mockImplementation(() => ({
rotate: jest.fn(),
})),
})),
rotateFromVector: jest.fn().mockImplementation(() => global.SVGSVGElement),
scale: jest.fn().mockImplementation(() => global.SVGSVGElement),
scaleNonUniform: jest.fn().mockImplementation(() => global.SVGSVGElement),
skewX: jest.fn().mockImplementation(() => global.SVGSVGElement),
skewY: jest.fn().mockImplementation(() => global.SVGSVGElement),
translate: jest.fn().mockImplementation(() => ({
multiply: jest.fn().mockImplementation(() => ({
multiply: jest.fn().mockImplementation(() => global.SVGSVGElement),
})),
})),
})),
});

Object.defineProperty(global.SVGSVGElement.prototype, 'createSVGPoint', {
writable: true,
value: jest.fn().mockImplementation(() => ({
x: 0,
y: 0,
matrixTransform: jest.fn().mockImplementation(() => ({
x: 0,
y: 0,
})),
})),
});

Object.defineProperty(global.SVGSVGElement.prototype, 'createSVGTransform', {
writable: true,
value: jest.fn().mockImplementation(() => ({
angle: 0,
matrix: {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0,
multiply: jest.fn(),
},
setMatrix: jest.fn(),
setTranslate: jest.fn(),
})),
});

});

A similar example can be found in our example React application setupTests.ts file.

If you do have to create your own mocks, you can view the limited list of supported SVG nodes in JSDOM. Generally, if the SVG functionality you are trying to mock isn't found on one of the supported SVG nodes in JSDOM, mocking it on SVGElement seems to work from our experience, but you might have to try some other solutions too.

Stay in the know

Be where thousands of diagramming enthusiasts meet

Star us on GitHub