jest: testing with the library "gl" (aka headless-gl) breaks if you have more than one test file

What is the current behavior?

I have written 2 identical tests.

  • Each test individually passes.
  • Putting the 2 tests in a same file, passes.
  • but if each test is put in 2 files. it breaks.

Repository that reproduce the bug:

https://github.com/gre/jest-multi-tests-gl-issue

What is the expected behavior?

The tests should pass. (it passes in a same file!)

–debug

jest version = 16.0.2
test framework = jasmine2
config = {
  "rootDir": "/Users/gre/Desktop/jest-multi-tests-gl-issue",
  "name": "-Users-gre-Desktop-jest-multi-tests-gl-issue",
  "setupFiles": [],
  "testRunner": "/Users/gre/Desktop/jest-multi-tests-gl-issue/node_modules/jest-jasmine2/build/index.js",
  "scriptPreprocessor": "/Users/gre/Desktop/jest-multi-tests-gl-issue/node_modules/babel-jest/build/index.js",
  "usesBabelJest": true,
  "automock": false,
  "bail": false,
  "browser": false,
  "cacheDirectory": "/var/folders/3q/zjl78zks3bv7_8lfw8r505x40000gn/T/jest",
  "clearMocks": false,
  "coveragePathIgnorePatterns": [
    "/node_modules/"
  ],
  "coverageReporters": [
    "json",
    "text",
    "lcov",
    "clover"
  ],
  "globals": {},
  "haste": {
    "providesModuleNodeModules": []
  },
  "mocksPattern": "__mocks__",
  "moduleDirectories": [
    "node_modules"
  ],
  "moduleFileExtensions": [
    "js",
    "json",
    "jsx",
    "node"
  ],
  "moduleNameMapper": {},
  "modulePathIgnorePatterns": [],
  "noStackTrace": false,
  "notify": false,
  "preset": null,
  "preprocessorIgnorePatterns": [
    "/node_modules/"
  ],
  "resetModules": false,
  "testEnvironment": "jest-environment-jsdom",
  "testPathDirs": [
    "/Users/gre/Desktop/jest-multi-tests-gl-issue"
  ],
  "testPathIgnorePatterns": [
    "/node_modules/"
  ],
  "testRegex": "(/__tests__/.*|\\.(test|spec))\\.jsx?$",
  "testURL": "about:blank",
  "timers": "real",
  "useStderr": false,
  "verbose": null,
  "watch": false,
  "cache": true,
  "watchman": true,
  "testcheckOptions": {
    "times": 100,
    "maxSize": 200
  }
}
 PASS  ./b.test.js
 FAIL  ./a.test.js
  ● foo

    TypeError: framebufferTexture2D(GLenum, GLenum, GLenum, WebGLTexture, GLint)

      at WebGLRenderingContext.framebufferTexture2D (node_modules/gl/webgl.js:2297:11)
      at Object.<anonymous>.test (a.test.js:4:12)
      at process._tickCallback (internal/process/next_tick.js:103:7)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        1.435s
Ran all test suites.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 21 (2 by maintainers)

Most upvoted comments

Yeah, I worked on it all morning… It is bizarre…

I can’t run the test a second time within the same Jest process instance. If I quit the jest process and start again its ok.

As you mentioned, destroying contexts doesn’t help, you can actually create many, many contexts in a loop without issue.

At the moment it’s working because I changed the function that tests for the type error. It’s situated in node_modules/gl/webgl.js.

function checkObject (object) {
  return typeof object === 'object' ||
  !object
}

All I have done is loosen the void check from object === void 0 to !object. Now it runs, at least it can create a gl context.

More work to do tomorrow.

I believe I know what the issue is, it is that how the library is being instantiated. There are a lot of jit overriding happening and privatizing of the native methods. The refactor I’m working on here: https://github.com/stackgl/headless-gl/issues/166 should resolve it as it no longer overwrites the methods, but just properly calls them using super.method() when overloading.

@mcrawshaw @mourner @gre

I found the reason, but I don’t know how to fix it. I’m not sure this is the bug of gl or jest.

In gl/webgl.js, there is such a piece of code:

var gl = nativeGL.WebGLRenderingContext.prototype
// ...
var _framebufferTexture2D = gl.framebufferTexture2D    // native function
gl.framebufferTexture2D = function framebufferTexture2D(
    target,
    attachment,
    textarget,
    texture,
    level ) {
    // ...
    if ( !checkObject( texture ) ) {
        throw new TypeError( 'framebufferTexture2D(GLenum, GLenum, GLenum, WebGLTexture, GLint)' )
    }
    // ...
}

In another place in gl/webgl.js, there is such a piece of code:

// line 
for ( var i = 0; i < ATTACHMENTS.length; ++i ) {
    _framebufferTexture2D.call(
        context,
        gl.FRAMEBUFFER,
        ATTACHMENTS[ i ],
        gl.TEXTURE_2D,
        0,    //  -> as parameter `texture`
        0 )
}

under normal circumstances, _framebufferTexture2D.call should be executed the native function, however, when running with jest, it is possible to call the overridden method(the js function)

checkObject( texture ) -> checkObject( 0 );
function checkObjectA (object) {
  return typeof object === 'object' ||
  !object
}
function checkObjectB (object) {
  return typeof object === 'object' ||
  (object === void 0)
}

checkObjectA( 0 );  // true
checkObjectB( 0 );  // false