简体   繁体   中英

Unit testing a ThreeJS application with Jest

I am having difficulties testing a JavaScript file with Jest which encapsulate a lot of interactions with ThreeJS. I first tried not to mock ThreeJS, which did not work :

  ● TestSuite › Should instantiate a renderer attached to a specific element of the DOM

    TypeError: Cannot read property 'getExtension' of null

      36 |      */
      37 |     constructor(containerId: string) {
    > 38 |         this.renderer = new WebGLRenderer({ antialias: true });
      39 |         this.attachRenderer(containerId);
      40 |         this.createCamera();
      41 |         this.createScene();

That's normal, because we are testing in a browser-like environment which has no webgl context . So what I did to solve this problem was mocking three.js.

I then mocked my external module with jest.mock("three");

  ● TestSuite › Should instantiate a renderer attached to a specific element of the DOM

    TypeError: this.renderer.setSize is not a function

      64 |             throw new Error("Cannot find DOM element object matching the specified ID: " + containerId);
      65 |         }
    > 66 |         this.renderer.setSize(window.innerWidth, window.innerHeight);
      67 |         element.appendChild(this.renderer.domElement);
      68 |     }
      69 |

And that's expected behavior, since every mock from jest returns undefined , new WebGLRenderer(); returns undefined and I cannot do anything with it.

My current work-around is to define everything I uses in ThreeJS in my test file :

jest.mock("three", () => ({
    Scene: class Scene {
        public add(): void {
            return;
        }
    },
    WebGLRenderer: class WebGlRenderer {
        public render(): void {
            return;
        }
        public setSize(): void {
            return;
        }
    }
    // And a lot more...
}));

But I am well aware that this is not the optimal solution. Before that I was doing the same thing, but in a file in mocks/three.js ( https://jestjs.io/docs/en/manual-mocks ), which was also working fine but that does not satisfy my need.

Is there a way to test this file properly, without having to write tons of manual mocks of threejs ?

I am also working on webgl this and solved this in following way. https://github.com/AmitTeli/webgl-three-test

The summary of the approach is

  1. Move all the global variables like scene , renderer and camera to index.html
  2. Initialize them on loading of the page. eg in this reactjs example, they are initialized in componentDidMount() of the root component. Other functions can use this context. (You can check this by running yarn start )
  3. While doing the unit testing, initialize them in setupTest.js . We will need additional dev dependencies of headless webgl - gl and canvas
  4. With this setup now we can run the test in say App.test.js (You can check this by running yarn test )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM