Jest: bug: issues with lazy-loaded modules

Created on 15 Jan 2017  路  12Comments  路  Source: facebook/jest

What is the current behavior?

iconv-lite is lazy-loading a file, when the encodings are actually needed. Somehow this lazy-loading does not work, and the lazy-loading isn't happening.

I'm using [email protected], [email protected] on OSX 10.11.4, with auto-mocking disabled, and testEnvironment is set to node.

Please see: https://github.com/sidorares/node-mysql2/issues/489

If I force loading the file that is supposed to be lazy-loaded, the code works fine, but if not, I get the following error:

PROJECT_FOLDER/node_modules/jest-runtime/build/index.js:439
    const wrapper = this._environment.runScript(script)[
                                                       ^

TypeError: Cannot read property 'Object.<anonymous>' of null
    at Runtime._execModule (PROJECT_FOLDER/node_modules/jest-runtime/build/index.js:439:56)
    at Runtime.requireModule (PROJECT_FOLDER/node_modules/jest-runtime/build/index.js:296:14)
    at Runtime.requireModuleOrMock (PROJECT_FOLDER/node_modules/jest-runtime/build/index.js:365:19)
    at Object.getCodec (PROJECT_FOLDER/node_modules/iconv-lite/lib/index.js:61:27)
    at Object.getDecoder (PROJECT_FOLDER/node_modules/iconv-lite/lib/index.js:118:23)
    at Object.<anonymous>.exports.decode (PROJECT_FOLDER/node_modules/mysql2/lib/parsers/string.js:19:23)
    at Packet.Object.<anonymous>.Packet.readNullTerminatedString (PROJECT_FOLDER/node_modules/mysql2/lib/packets/packet.js:371:23)
    at Function.Object.<anonymous>.Handshake.fromPacket (PROJECT_FOLDER/node_modules/mysql2/lib/packets/handshake.js:19:31)
    at ClientHandshake.Object.<anonymous>.ClientHandshake.handshakeInit (PROJECT_FOLDER/node_modules/mysql2/lib/commands/client_handshake.js:83:38)
    at ClientHandshake.Object.<anonymous>.Command.execute (PROJECT_FOLDER/node_modules/mysql2/lib/commands/command.js:39:20)

What is the expected behavior?

That the lazy-loading happens, and the test would run without throwing.

Needs More Info

Most helpful comment

Found a workaround, see my node-mysql2 comment.

All 12 comments

Can you provide a minimal repro for this issue? As a workaround you can mock iconv-lite or this lazy-loaded module with

jest.mock('lazy-module', () => 'some MOCK')

@thymikee I'll try to make a minimal repo.. mocking doesn't really seem an option, as it is an internal file inside iconv-lite, so it would require me to mock the whole of iconv-lite (with the real implementation, otherwise the code would be broken)

@danieljuhl Can you provide a gist on how you force eager loading? Do you put

import iconv from 'iconv-lite';
import encodings from 'iconv-lite/encodings';
iconv.encodings = encodings;

in the testSetup file?

I'm having the same issue too:

/Users/cj/Sync/npmjs/vues/node_modules/jest-runtime/build/index.js:439
    const wrapper = this._environment.runScript(script)[
                                                       ^

TypeError: Cannot read property 'Object.<anonymous>' of null
    at Runtime._execModule (/Users/cj/Sync/npmjs/vues/node_modules/jest-runtime/build/index.js:439:56)
    at Runtime.requireModule (/Users/cj/Sync/npmjs/vues/node_modules/jest-runtime/build/index.js:296:14)
    at Runtime.requireModuleOrMock (/Users/cj/Sync/npmjs/vues/node_modules/jest-runtime/build/index.js:365:19)
    at WatcherManager.Object.<anonymous>.WatcherManager.getDirectoryWatcher (/Users/cj/Sync/npmjs/vues/node_modules/watchpack/lib/watcherManager.js:12:25)
    at WatcherManager.watchFile (/Users/cj/Sync/npmjs/vues/node_modules/watchpack/lib/watcherManager.js:26:14)
    at EventEmitter.<anonymous> (/Users/cj/Sync/npmjs/vues/node_modules/watchpack/lib/watchpack.js:36:49)
    at Array.map (native)
    at EventEmitter.watch (/Users/cj/Sync/npmjs/vues/node_modules/watchpack/lib/watchpack.js:35:28)
    at NodeWatchFileSystem.watch (/Users/cj/Sync/npmjs/vues/node_modules/webpack/lib/node/NodeWatchFileSystem.js:50:16)
    at Watching.Object.<anonymous>.Watching.watch (/Users/cj/Sync/npmjs/vues/node_modules/webpack/lib/Compiler.js:100:47)

My problem is webpack-dev-middleware, the offending line in my sourcecode is:

  const webpackDevMiddleware = require('webpack-dev-middleware')(webpackCompiler, {
    noInfo: true, publicPath: webpackConfig.output.publicPath, quiet: true
  })

setting lazy to true on webpackDevMiddleware gets rid of the error.

Seems like a problem with that module.

I've tried both the webpack and the iconv solutions, and I am still getting the error.

Are there any other solutions available to try?

I'm seeing the issue setting up JSDOM for Enzyme testing...

I just got into the same problem.

The thing is that my 'simple' tests are working if I run just a testsuite with following tests yarn test __tests__/simple.test.js

import ptypeToMeth from '../../src/mappings/ptype-to-meth-list'

describe('Testing PType to Meth List Mappings', () => {
  it('CC should return all creditcard meth_ids', () => {
    expect(ptypeToMeth('CC')).toEqual([1, 2, 3, 4, 5, 6])
  })
})

When I run another testsuite (file) which includes the mysql2 library it works. yarn test __tests__/something-with-mysql.test.js

If I run BOTH testsuites at the same time yarn test I am getting following error

/Users/tobias.lins/Repos/mpay24-rest/node_modules/jest-runtime/build/index.js:510
    const wrapper = this._environment.runScript(transformedFile.script)[
                                                                       ^

TypeError: Cannot read property 'Object.<anonymous>' of null
    at Runtime._execModule (/Users/tobias.lins/Repos/mpay24-rest/node_modules/jest-runtime/build/index.js:510:72)
    at Runtime.requireModule (/Users/tobias.lins/Repos/mpay24-rest/node_modules/jest-runtime/build/index.js:329:14)
    at Runtime.requireModuleOrMock (/Users/tobias.lins/Repos/mpay24-rest/node_modules/jest-runtime/build/index.js:405:19)
    at Object.getCodec (/Users/tobias.lins/Repos/mpay24-rest/node_modules/iconv-lite/lib/index.js:65:27)
    at Object.getDecoder (/Users/tobias.lins/Repos/mpay24-rest/node_modules/iconv-lite/lib/index.js:122:23)
    at Object.<anonymous>.exports.decode (/Users/tobias.lins/Repos/mpay24-rest/node_modules/mysql2/lib/parsers/string.js:9:23)
    at Packet.Object.<anonymous>.Packet.readNullTerminatedString (/Users/tobias.lins/Repos/mpay24-rest/node_modules/mysql2/lib/packets/packet.js:371:23)
    at Function.Object.<anonymous>.Handshake.fromPacket (/Users/tobias.lins/Repos/mpay24-rest/node_modules/mysql2/lib/packets/handshake.js:18:31)
    at ClientHandshake.Object.<anonymous>.ClientHandshake.handshakeInit (/Users/tobias.lins/Repos/mpay24-rest/node_modules/mysql2/lib/commands/client_handshake.js:98:38)
    at ClientHandshake.Object.<anonymous>.Command.execute (/Users/tobias.lins/Repos/mpay24-rest/node_modules/mysql2/lib/commands/command.js:40:20)
error Command failed with exit code 1.

Found a workaround, see my node-mysql2 comment.

@cj I'm seeing the same issue/use-case as you.

@opatut => I took your solution and expanded it to solve mine and @cj issue. Adding the below to setupTestFrameworkScriptFile seemed to solve the issues with instantiating the webpackMiddlewareInstance. While a bit hacky, it is better than polluting a code base with exceptions/handlers for purely testing-scenarios (e.g. non-prod).

require('node_modules/readdirp/stream-api.js')
require('node_modules/watchpack/lib/DirectoryWatcher.js')

Just a note for anyone else reading this over, I was able to determine the culprit modules by modifying node_modules\jest-runtime\build\index.js (source here: https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js#L516) @=>

    let _fName

    try {
      this._environment.runScript(transformedFile.script)[
      ScriptTransformer.EVAL_RESULT_VARIABLE];
    } catch (err) {
      _fName = `filename[${filename}], isInternalModule[${isInternalModule}]`
    }

    if (_fName !== undefined) throw _fName

Hopefully this issue can nonetheless be solved outside of these hacky fixes :D.

While a bit hacky, it is better than polluting a code base with exceptions/handlers for purely testing-scenarios (e.g. non-prod).

I guess it can be considered a shortcoming of a testing environment if it does not simulate production behaviour appropriately, so of course there should be no change required in the "broken" upstream packages but it's actually jest's fault and this is the right place to fix it.

Though I have no idea what might be causing the problems... Maybe inconsistent caching behaviour across different packages/within a package's modules? Uh-oh!

Was this page helpful?
0 / 5 - 0 ratings