Enzyme: Cannot read property 'call' of undefined for configure adapter for Jest

Created on 3 Aug 2018  ·  11Comments  ·  Source: enzymejs/enzyme

Thanks for reporting an issue to us! We're glad you are using and invested in Enzyme.
Before submitting, please read over our commonly reported issues to prevent duplicates!

All common issues

Notoriously common issues

If you haven't found any duplicated issues, please report it with your environment!

Current behavior

● Test suite failed to run

We've recently updated a lot of packages(including jest, react etc.) but not enzyme. However this bug start appearing in the test setup file while it has not been changed.

    TypeError: Cannot read property 'call' of undefined

      6 | configure({ adapter: new Adapter()});
      7 |

      at forEach (node_modules/foreach/index.js:7:27)
      at defineProperties (node_modules/define-properties/index.js:52:19)
      at Object.<anonymous> (node_modules/object.assign/index.js:11:27)
      at Object.<anonymous> (node_modules/enzyme/build/ReactWrapper.js:23:15)
      at Object.<anonymous> (node_modules/enzyme/build/index.js:3:21)
      at Object.<anonymous> (test/config/setup-test.js:8:15)

This is the setup-test file.

/* Setup Enzyme with appropriate react adapter for testing */
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';


configure({ adapter: new Adapter()});

I logged all the way down at /foreach/index.js where the call fails.

var hasOwn = Object.prototype.hasOwnProperty;
var toString = Object.prototype.toString;

module.exports = function forEach (obj, fn, ctx) {
    if (toString.call(fn) !== '[object Function]') {

Weird thing is that toString is undefined, but hasOwn is a defined function.

This is our jest file

{
  "rootDir": "../../",
  "verbose": true,
  "setupFiles": ["<rootDir>/test/config/setup-test.js", "<rootDir>/test/config/setup-jsdom.js"],
  "testURL": "http://localhost/",
  "reporters": ["default", "jest-junit"],
  "roots": [
    "client",
    "test/unit/client"
  ],
  "moduleFileExtensions": [
    "js",
    "jsx"
  ],
  "moduleDirectories": [
    "node_modules"
  ],
  "modulePaths": [
    "client",
    "test/utils"
  ],
  "moduleNameMapper": {
    "\\.(css|less|scss)$": "<rootDir>/test/utils/empty-style-mock.js",
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/utils/empty-svg-mock.js"
  },
  "transformIgnorePatterns": [],
  "unmockedModulePathPatterns" : [
    "./node_modules/jasmine-reporters"
  ]
}

Expected behavior

Your environment

MAC OSX 10.13.6

API

  • [ ] shallow
  • [ ] mount
  • [ ] render

Version

enzyme: "3.3.0",
enzyme-adapter-react-16: "1.1.1"
react: "16.4.1"
node: "v8.11.1"
jest: "23.1.0"
jsdom: "11.12.0"

Adapter

  • [x] enzyme-adapter-react-16
  • [ ] enzyme-adapter-react-15
  • [ ] enzyme-adapter-react-15.4
  • [ ] enzyme-adapter-react-14
  • [ ] enzyme-adapter-react-13
  • [ ] enzyme-adapter-react-helper
  • [ ] others ( )

All 11 comments

Um, that makes no sense - Object.prototype.toString is undefined? Can you share your setup files?

@ljharb We have two files "setupFiles": ["/test/config/setup-test.js", "/test/config/setup-jsdom.js"]. First one is provided above:

/* Setup Enzyme with appropriate react adapter for testing */
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';


configure({ adapter: new Adapter()});

This the second one:
I removed this file just to test, and nothing changes, still the same error.

const jsdom = require('jsdom');
const {JSDOM} = jsdom;
const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
const {window} = dom;

function copyProps(src, target) {
  const props = Object.getOwnPropertyNames(src)
    .filter(prop => typeof target[prop] === 'undefined')
    .map(prop => Object.getOwnPropertyDescriptor(src, prop));
  Object.defineProperties(target, props);
}

global.window = window;
global.window.localStorage = {
  storage: new Map(),
  constructor() {
    this.storage = new Map();
  },
  setItem(key, value) {
    this.storage.set(key, value);
  },
  getItem(key) {
    return this.storage.get(key);
  },
  removeItem(key) {
    this.storage.delete(key);
  },
  clear() {
    this.constructor();
  }
};
global.document = window.document;
copyProps(window, global);

yeah that shouldn't cause any problems. can you try console.logging typeof Object.prototype.toString in a few places before the error, and see if you can pinpoint where it goes undefined?

@ljharb I think I narrowed the problem down.

var hasOwn = Object.prototype.hasOwnProperty;
var toString = Object.prototype.toString;
console.log('foreach/index.js')
console.log(Object.prototype.hasOwnProperty);
console.log(hasOwn);
console.log(Object.prototype.toString);
console.log(typeof Object.prototype.toString)
console.log(toString)
console.log(typeof toString)

log:

  console.log node_modules/foreach/index.js:5
    foreach/index.js

  console.log node_modules/foreach/index.js:6
    [Function: hasOwnProperty]

  console.log node_modules/foreach/index.js:7
    [Function: hasOwnProperty]

  console.log node_modules/foreach/index.js:8
    [Function: toString]

  console.log node_modules/foreach/index.js:9
    function

  console.log node_modules/foreach/index.js:10
    undefined

  console.log node_modules/foreach/index.js:11
    undefined

hmm, this doesn't make sense

That's super crazy - in ancient IE, toString isn't allowed as a variable name, but that shouldn't apply to any version of node.

Looks like toString is not reserved in javascript but is recommended to avoid it. I also changed the var name to toStringfn, looks like it is defined now.

var hasOwn = Object.prototype.hasOwnProperty;
var toStringfn = Object.prototype.toString;
console.log('foreach/index.js')
console.log(Object.prototype.hasOwnProperty);
console.log(hasOwn);
console.log(Object.prototype.toString);
console.log(typeof Object.prototype.toString)
console.log(toStringfn)
console.log(typeof toStringfn)
  console.log node_modules/foreach/index.js:5
    foreach/index.js

  console.log node_modules/foreach/index.js:6
    [Function: hasOwnProperty]

  console.log node_modules/foreach/index.js:7
    [Function: hasOwnProperty]

  console.log node_modules/foreach/index.js:8
    [Function: toString]

  console.log node_modules/foreach/index.js:9
    function

  console.log node_modules/foreach/index.js:10
    [Function: toString]

  console.log node_modules/foreach/index.js:11
    function

I'm thinking maybe jest think this is not node? Even if it's plain javascript it shouldn't be undefined... still investigating :(

I'm happy to update define-properties to use for-each instead of foreach, which i suspect won't have this problem (i maintain for-each and define-properties); it'd be great to get a repro case tho on https://github.com/ljharb/define-properties :-) (and then we can close this one)

I just tried renamed the function and ran the test, was able to by pass that specific error but ran into another toString related error. Not sure if it's related, will debug a bit more before opening the issue, just incase it's something from my setup

 Test suite failed to run

    TypeError: Function.prototype.toString requires that 'this' be a Function
        at toString (<anonymous>)

      6 | configure({ adapter: new Adapter()});
      7 |

      at Object.<anonymous> (node_modules/lodash/_baseIsNative.js:28:54)
      at Object.<anonymous> (node_modules/lodash/_getNative.js:3:20)
      at Object.<anonymous> (node_modules/lodash/_defineProperty.js:3:17)
      at Object.<anonymous> (node_modules/lodash/_baseAssignValue.js:3:22)
      at Object.<anonymous> (node_modules/lodash/_assignValue.js:3:23)
      at Object.<anonymous> (node_modules/lodash/assign.js:3:19)
      at Object.<anonymous> (node_modules/cheerio/lib/options.js:3:14)
      at Object.<anonymous> (node_modules/cheerio/lib/cheerio.js:8:22)
      at Object.<anonymous> (node_modules/cheerio/index.js:7:28)
      at Object.<anonymous> (node_modules/enzyme/build/ReactWrapper.js:27:16)
      at Object.<anonymous> (node_modules/enzyme/build/index.js:3:21)
      at Object.<anonymous> (test/config/setup-test.js:8:15)

and this is the code

/** Used for built-in method references. */
var funcProto = Function.prototype,
    objectProto = Object.prototype;

/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;

/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;

/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);

This really does seem like there's something odd in your setup :-/

@nicoxxie I'm going to close this, but I'm very interested in understanding why this is breaking for you, so it'd be great if you could follow up as you discover more.

Not sure if it's related, but I received a similar error (TypeError: Cannot read property 'prototype' of undefined) when using Enzyme + Jest. In the end, it turned out to have to do with how / what I exported from the component I was testing.

Simply put, the component was wired up via redux, but I wanted to shallow test it, so changed this:

class MyComponent extends Component {
  …
}
…
…
export default withRouter(connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent))

to this:

export class MyComponent extends Component {
  …
}
…
…
export default withRouter(connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent))

...but shallow-wrapping in my test (as below) kept failing with the mentioned error message

import {MyComponent as UnConnectedMyComponent} from '../question';
...
const wrapper = shallow(
  <UnConnectedMyComponent />
);

HOWEVER, then I realized that I had another, unnecessary export, before my class export in MyComponent:

export const myConstant = 'FOO'
…
…
export class MyComponent extends Component {
  …
}
…
…
export default withRouter(connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent))

So, in the end, what was failing was that I duplicate exports from the component I was testing.

Not sure if this helps, but removing the export const myConstant = 'FOO' sorted my issue at least!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

potapovDim picture potapovDim  ·  3Comments

thurt picture thurt  ·  3Comments

modemuser picture modemuser  ·  3Comments

heikkimu picture heikkimu  ·  3Comments

blainekasten picture blainekasten  ·  3Comments