Search code examples
typescriptjestjsthree.jswebglts-jest

Error creating WebGL context while testing TS in Jest


I'm trying to initialize WebGLRenderer in one of my test cases in Jest. But whenever I execute that test case, I'm greeted with this error:

 Error creating WebGL context.                                                                                                                
                                                                                                                                                 
       9 |                                                                                                                                       
      10 |   it('should set the main renderer', () => {                                                                                          
    > 11 |     const webglRenderer: WebGLRenderer = new WebGLRenderer({
         |                                          ^
      12 |       antialias: true,
      13 |       alpha: true,
      14 |       powerPreference: 'high-performance',

      at new WebGLRenderer (../../node_modules/three/build/three.js:19318:13)
      at Object.<anonymous> (src/tests/managers/three-manager/renderer-manager.test.ts:11:42)

I'm testing TS and didn't see any compile-time errors.

Full stack trace:

Error: Not implemented: HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)
        at module.exports (C:\..\Desktop\phoenix\node_modules\jsdom\lib\jsdom\browser\not-implemented.js:9:17)
        at HTMLCanvasElementImpl.getContext (C:\..Desktop\phoenix\node_modules\jsdom\lib\jsdom\living\nodes\HTMLCanvasElement-impl.js:42:5)
        at HTMLCanvasElement.getContext (C:\..\Desktop\phoenix\node_modules\jsdom\lib\jsdom\living\generated\HTMLCanvasElement.js:131:58)
        at getContext (C:\..Desktop\phoenix\node_modules\three\build\three.js:19279:29)
        at new WebGLRenderer (C:\..Desktop\phoenix\node_modules\three\build\three.js:19315:10)
        at Object.<anonymous> (C:\..\Desktop\phoenix\packages\phoenix-event-display\src\tests\managers\three-manager\renderer-manager.test.ts:11:42)
        at Promise.then.completed (C:\..Desktop\phoenix\node_modules\jest-circus\build\utils.js:391:28)
        at new Promise (<anonymous>)
        at callAsyncCircusFn (C:\..Desktop\phoenix\node_modules\jest-circus\build\utils.js:316:10)
        at _callCircusTest (C:\..\Desktop\phoenix\node_modules\jest-circus\build\run.js:218:40) undefined

      at VirtualConsole.<anonymous> (../../node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
      at module.exports (../../node_modules/jsdom/lib/jsdom/browser/not-implemented.js:12:26)
      at HTMLCanvasElementImpl.getContext (../../node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js:42:5)
      at HTMLCanvasElement.getContext (../../node_modules/jsdom/lib/jsdom/living/generated/HTMLCanvasElement.js:131:58)
      at getContext (../../node_modules/three/build/three.js:19279:29)
      at new WebGLRenderer (../../node_modules/three/build/three.js:19315:10)

Google Chrome 102.0.5005.115 (Official Build) (64-bit) (cohort: Stable) Revision 174dbe6e33bc81994fceb71d751be201d0b4803d-refs/branch-heads/5005_109@{#3} OS Windows 11 Version 21H2 (Build 22000.739)
JavaScript V8 10.2.154.8
User Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/102.0.0.0 Safari/537.36

chrome://gpu

WebGL: Hardware accelerated
WebGL2: Hardware accelerated
WebGPU: Hardware accelerated

Thanks in advance! :))


Solution

  • A good way to test WebGLRenderer using Jest would be to define a helper function:

    import createContext from 'gl';
    
    import * as THREE from 'three';
    import { createCanvas } from 'canvas';
    
    export default function createRenderer(
      options?: THREE.WebGLRendererParameters
    ) {
      const window = {
        innerWidth: 800,
        innerHeight: 600,
      };
      const context = createContext(1, 1);
      const canvas: HTMLCanvasElement = createCanvas(
        window.innerWidth,
        window.innerHeight
      ) as any;
    
      // Mock function to avoid errors inside THREE.WebGlRenderer():
      canvas.addEventListener = function () {};
    
      return new THREE.WebGLRenderer({ context, canvas, ...options });
    }
    

    Hope it helps. I took inspiration from this library: https://github.com/Bartozzz/jest-three