jest: automocking: true is broken

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

Running this in my tests:

import { enums } from './index';

describe('test', () => {
  it('should not blow up ', () => {
    expect(true).toEqual(true);
  });
});

Here is what my index.js looks like

//Lots of other imports
...
export const enums = {
  Foo: 'foo',
};
... 
// Lot's of other things

Here is what happens when I run jest:

 FAIL  src/modules/foo/index.spec.js
  ● Test suite failed to run

    TypeError: Cannot read property 'role' of undefined

      29 |               }
      30 |
    > 31 |               return `${foo}/${bar.splice(0, 1)[0]}`;
      32 |             }
      33 |
      34 |             return `${foo}/${bar}`;

      at Object.<anonymous> (src/utils/fooHelper.js:31:31)
      at Object.<anonymous> (src/modules/baz/index.js:58:20)
      at Object.<anonymous> (src/modules/bar/index.js:50:18)
      at Object.<anonymous> (src/modules/foo/index.js:66:13)
      at Object.<anonymous> (src/modules/foo/index.spec.js:3:14)

So given that I can’t use automocking: false, I tried setting it to true which gives this error:

 FAIL  src/modules/foo/index.spec.js
  ● Test suite failed to run

    Failed to get mock metadata: /Users/emmettharper/Dev/foo/node_modules/core-js/library/modules/_global.js

    See: http://facebook.github.io/jest/docs/manual-mocks.html#content

      at Runtime._generateMock (node_modules/jest-runtime/build/index.js:498:15)
      at Object.<anonymous> (node_modules/core-js/library/modules/_export.js:1:103)
      at Object.<anonymous> (node_modules/core-js/library/modules/_iter-define.js:3:15)

Setting:

    "unmockedModulePathPatterns": [
      "<rootDir>/node_modules/core-js"
    ]

Also just presents another error:

 FAIL  src/modules/bar/components/__tests__/bar.spec.js
  ● Test suite failed to run

    TypeError: Cannot set property 'DEFAULT_TIMEOUT_INTERVAL' of undefined

      at Object.<anonymous>.exports.create (node_modules/jest-jasmine2/build/jasmine/jasmine_light.js:40:31)

And setting unmocking jest-jasmine2 doesn’t seem to fix it.

If the current behavior is a bug, please provide the steps to reproduce and either a repl.it demo through https://repl.it/languages/jest or a minimal repository on GitHub that we can yarn install and yarn test.

run node scripts/test.js --env=jsdom

What is the expected behavior?

Ideally I could just grab a simple enum from a file with out jest resolving everything (I have a massive app). But if that’s too complicated then I would love for automock to work out of the box.

Please provide your exact Jest configuration

// package.json
  "jest": {
    "automock": true,
    "collectCoverageFrom": ["src/**/*.{js,jsx}"],
    "setupFiles": ["<rootDir>/scripts/testPolyfills.js"],
    "setupTestFrameworkScriptFile": "<rootDir>/scripts/setupTests.js",
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.js?(x)",
      "<rootDir>/src/**/?(*.)(spec|test).js?(x)"
    ],
    "testURL": "http://localhost",
    "transform": {
      "^.+\\.jsx$": "babel-jest",
      "^.+\\.js$": "babel-jest",
      "^.+\\.css$": "<rootDir>/scripts/jest/cssTransform.js",
      "^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/scripts/jest/fileTransform.js"
    },
    "transformIgnorePatterns": [
      "node_modules/(?!(redux-persist|@pivotusventures/vip-ui-components|react-select)/)"
    ],
    "modulePaths": ["<rootDir>/src"],
    "moduleNameMapper": {
      "^react-native$": "react-native-web",
      "^src(.*)$": "<rootDir>/src$1"
    },
    "moduleFileExtensions": ["web.js", "mjs", "js", "json", "web.jsx", "jsx", "node"],
    "unmockedModulePathPatterns": [
      "<rootDir>/node_modules/core-js",
      "<rootDir>/node_modules/jest-jasmine2"
    ]
  }


// scripts/setupTests.js
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  clear: jest.fn(),
};

global.localStorage = localStorageMock;

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


// scripts/testPolyfills.js
'use strict';

if (typeof Promise === 'undefined') {
  // Rejection tracking prevents a common issue where React gets into an
  // inconsistent state due to an error, but it gets swallowed by a Promise,
  // and the user has no idea what causes React's erratic future behavior.
  require('promise/lib/rejection-tracking').enable();
  window.Promise = require('promise/lib/es6-extensions.js');
}

// fetch() polyfill for making API calls.
require('whatwg-fetch');

// Object.assign() is commonly used with React.
// It will use the native implementation if it's present and isn't buggy.
Object.assign = require('object-assign');

// In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet.
require('raf').polyfill(global);


// scripts/test.js
'use strict';

// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

// Load environment variables from .env file. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set.
// https://github.com/motdotla/dotenv
require('dotenv').config({ silent: true });

const jest = require('jest');
const argv = process.argv.slice(2);

// Watch unless on CI or in coverage mode
if (!process.env.CI && argv.indexOf('--coverage') < 0) {
  argv.push('--watch');
}

jest.run(argv);

Run npx envinfo --preset jest in your project directory and paste the results here

Environment:
  OS: macOS Sierra 10.12.6
  Node: 8.9.4
  Yarn: 1.3.2
  npm: 5.6.0
  Watchman: 4.9.0
  Xcode: Xcode 9.2 Build version 9C40b
  Android Studio: 3.1 AI-173.4697961

Thanks!

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 16
  • Comments: 20

Most upvoted comments

I’m having the same problem. Here is another error that can occure:

    TypeError: Cannot read property 'default' of undefined

      at node_modules/react-native/Libraries/vendor/emitter/EventSubscription.js:15:21
      at Object.<anonymous> (node_modules/react-native/Libraries/vendor/emitter/EventSubscription.js:22:2)
      at Object.require (node_modules/react-native/Libraries/vendor/emitter/EmitterSubscription.js:13:27)

Maybe that helps to make this issue better queryable 😃

The note on the automock config says:

Node modules are automatically mocked when you have a manual mock in place (e.g.: mocks/lodash.js). More info here.

Which is also broken: https://github.com/facebook/jest/issues/12777

So, I think in general automocking has had a lot of regressions.

@cpojer @aaronabramov @SimenB can we shed some light on this issue, please? 😄 When using automock: true, Jest will throw errors on certain node modules. Manually mocking using jest.mock("name_of_node_module") works but requires us to write a bunch of jest.mocks which is not very scalable. Maybe there is a simple fix?

I would expect that automock:true calls jest#mock under the hood for all imported modules, so seems strange why one works over the other.

Here’s a super simple example, as requested:

This works when config is { automock: false, testEnvironment: "node" }

const admin = require("firebase-admin");

jest.mock("firebase-admin");

test("hello", () => {
    expect(true).toBe(true);
});

This breaks when { automock:true, testEnvironment: "node" }

const admin = require("firebase-admin");

test("hello", () => {
    expect(true).toBe(true);
});

Error:

FAIL  ./testjest.spec.js
  ● Test suite failed to run

    TypeError: Cannot read property 'message' of undefined

      at Error.get (node_modules/firebase-admin/lib/utils/error.js:64:35)
          at Array.forEach (<anonymous>)
          at Array.forEach (<anonymous>)
          at Array.forEach (<anonymous>)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.778 s, estimated 1 s
Ran all test suites matching /testjest.spec.js/i.

Environment Details

Jest Version: v26.6.3
Node Version: v10.20.1
firebase-admin Node Module Version: v9.5.0

Appreciate your time!

I am getting “TypeError: Cannot read property ‘default’ of undefined” from node_module which I expect to be automocked.

 FAIL  src/components/BillingProfile.spec.ts
  ● Test suite failed to run

    TypeError: Cannot read property 'default' of undefined

      15 |           class="text-red"
      16 |           clickable
    > 17 |           @click="devfill()"
         |                                     ^
      18 |         >
      19 |           [DEV] autofill
      20 |         </div>

      at Object.<anonymous> (node_modules/quasar/src/components/form/QForm.js:8:16)
      at src/components/BillingProfile.vue:17:37
      at Object.<anonymous> (src/components/BillingProfile.vue:411:3)
      at Object.<anonymous> (src/components/BillingProfile.spec.ts:2:1)

test

import { shallowMount } from '@vue/test-utils';
import BillingProfile from './BillingProfile.vue';

jest.enableAutomock();
jest.unmock('@vue/test-utils');
jest.unmock('./BillingProfile.vue');

const wrapperFactory = (options = {}) => {
  return shallowMount(BillingProfile, {
    mocks: {
      $route: { path: '/' },
      $store: {},
    },
    ...options,
  });
};

describe('BillingProfile', () => {
  it.only('renders a signup form when user is not present', () => {
    const wrapper = wrapperFactory();

    expect(wrapper.find('.message').text()).toEqual(
      'Welcome to the Vue.js cookbook'
    );
  });
});

jest config

module.exports = {
  // preset reference: https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-plugin-unit-jest/presets/default/jest-preset.js
  preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
  testMatch: ['**/*.spec.ts'],
  moduleNameMapper: {
    '^@/types$': '<rootDir>/src/types/index.d',
    '^@env$': '<rootDir>/src/env/env.dev',
  },
  transformIgnorePatterns: ['node_modules/(?!(quasar|quasar/*|@quasar|@quasar/*))'],
};

I got the similar error as well when I set automock: true in jest.config.json:

Failed to get mock metadata: /Users/deepak/example-app/node_modules/process-nextick-args/index.js

    See: http://facebook.github.io/jest/docs/manual-mocks.html#content

      at Runtime._generateMock (node_modules/jest-runtime/build/index.js:498:15)
      at Object.<anonymous> (node_modules/readable-stream/lib/_stream_readable.js:26:11)
      at Object.<anonymous> (node_modules/readable-stream/readable.js:12:30)

I was trying to use this config to avoid calling jest.mock('../../my-module'); in every test file.