Hoobajoob
Hoobajoob

Reputation: 2888

Jest virtual mock: how do I troubleshoot this failure?

So I have this import statement in a module that I'm trying to test using jest 25.1 running on node 11.1.0. The import statement is for a module that is only available when running on the jvm's nashorn runtime, so I'm using jest's virtual mock to control the behavior in the unit tests. Here's what the import statement looks like in the module under test:

import RequestBuilder from 'nashorn-js/request_builder'

...and after the other lines in the import block, this:

const request = RequestBuilder.create('some-string')
.sendTo('some-other-string')
.withAction('yet-another-string')
.getResultWith( consumer => consumer.result( consumer.message().body() ) )

export const functionA = () => {...} // uses 'request' variable

export const functionB = () => {...} // uses 'request' variable

In the corresponding .spec file, I have this virtual mock setup:

const mockGetResultWith = {
  getResultWith: jest.fn()
}
const mockWithAction = {
  withAction: jest.fn().mockImplementation(() => mockGetResultWith)
}
const mockSendTo = {
  sendTo: jest.fn().mockImplementation(() => mockWithAction)
}
const mockBuilder = {
  create: jest.fn().mockImplementation(() => mockSendTo)
}
jest.mock(
  'nashorn-js/request_builder',
  () => mockBuilder,
  { virtual: true }
)

require('nashorn-js/request_builder')

import { functionA, functionB } from './module-under-test'

I have been trying unsuccessfully to get past this failure from jest:

  ● Test suite failed to run

    TypeError: Cannot read property 'create' of undefined

      35 | }
      36 | 
    > 37 | const verify = RequestBuilder.create('some-string')
         |                               ^
      38 | .sendTo('some-other-string')
      39 | .withAction('yet-another-string')
      40 | .getResultWith( consumer => consumer.result( consumer.message().body() ) )

I've tried all kinds of different mock structures, using require vs import, etc, but haven't found the magic bullet.

As near as I can tell, it does not appear that the RequestBuilder import statement is even invoking the virtual mock. Or at least, if I add console.log() statements to the virtual mock factory function, I never see those log messages in the output.

Anybody have any idea what I'm missing or what else to try? I have pretty much the same pattern in use in other parts of the code, where this setup works, but for some mystical reason with this module, I can't get the virtual mock working. Any help is greatly appreciated.

Upvotes: 0

Views: 644

Answers (1)

Hoobajoob
Hoobajoob

Reputation: 2888

So, the problem here turned out to be jest's implementation of import vs require in the .spec file.

By changing this line:

import { functionA, functionB } from './module-under-test'

To this:

const module = require('./module-under-test')
const functionA = module.functionA
const functionB = module.functionB

The module under test now loads successfully, and the tests run as expected.

I have no explanation for this, and haven't been able to find jest documentation describing why I'd get any different behavior between require vs import. In fact, I have the mock configuration setup before any import statements as described here:

https://github.com/kentcdodds/how-jest-mocking-works

If anybody out there understands what's going on with this import behavior, or has a link describing what I'm missing, I'd sure appreciate the info.

Upvotes: 1

Related Questions