jestjs / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
44.05k stars 6.44k forks source link

automocking: true is broken #6127

Open CapitanRedBeard opened 6 years ago

CapitanRedBeard commented 6 years ago

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!

CapitanRedBeard commented 6 years ago

I understand that manually mocking each file is a workaround here: https://github.com/kriasoft/react-starter-kit/issues/491 and https://github.com/facebook/jest/issues/678

but I have a massive project and this is not a scalable solution.

jcrben commented 6 years ago

Could you create an actual project that someone can pull down and play with to reproduce the problem?

      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)

Maybe I'm missing something, but can you disclose fooHelper, baz, and bar?

dpkshrma commented 6 years ago

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.

FuzzOli87 commented 6 years ago

When I run jest with automock: true I get some issues as well:

  1. Attempting to mock node-rdkafka fails with the error Cannot read property 'errorCodes' of undefined After some investigation, I see that this is the part of the code where it creates the object from the bindings it has with the underlying C library. It's a bit complex so I fixed it by just creating a manual mock.

However,

Now I get the following error:

received value must be a Promise.
    Received: undefined

When I'm running tests. My module returns a named async function which in fact does return a promise. It works fine without having automock turned on.

DavidLozzi commented 5 years ago

+1

nikoremi97 commented 5 years ago

Had anyone solved this issue? Thanks.

dangreenisrael commented 5 years ago

+1

bhargavshah commented 5 years ago

This is causing a lot of issues for my project. Appreciate if anyone can update here if they find a solution. Cheers! :)

maxammann commented 5 years ago

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 :)

andresattler commented 4 years ago

+1

dimaqq commented 4 years ago

Perhaps under "automock": true it becomes user's responsibility to unmock those modules that are being tested?

luckylooke commented 4 years ago

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/*))'],
};
danielrod02 commented 3 years ago

+1

chhatch commented 3 years ago

Having the same issue. Here is the error:

TypeError: Cannot read property 'default' of undefined

      at Object.<anonymous> (node_modules/zen-observable-ts/src/zenObservable.ts:23:10)
      at Object.<anonymous> (node_modules/zen-observable-ts/src/index.ts:1:1)
govindrai commented 3 years ago

@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!

dddryba commented 3 years ago

@govindrai Do you have a solution for this problem?

john01kpeazu commented 2 years ago

+1

eliw00d commented 2 years ago

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.

edmundsj commented 1 year ago

I am having this issue as well. It happens regardless of whether I set automock: true in jest.config.js, or run jest.enableAutomock() in my files.

Error message for all test suites:

  ● Test suite failed to run

    Failed to get mock metadata: /home/jordan/Documents/axle-mono/frontend/node_modules/lodash/_freeGlobal.js

    See: https://jestjs.io/docs/manual-mocks#content

      at Runtime._generateMock (node_modules/jest-runtime/build/index.js:1901:15)
      at Object.<anonymous> (node_modules/lodash/_root.js:1:100)

I should also not the documentation pointed to by the error message does not work out of the box. I am using TypeScript and jest version 27.5.1 packaged with CRA.

ebrahimGH commented 11 months ago

I got this error when i enable automock:

● Test suite failed to run

TypeError: Cannot read properties of undefined (reading 'initTestEnvironment')

> 1 | import 'jest-preset-angular/setup-jest';
    | ^

  at Object.<anonymous> (node_modules/jest-preset-angular/setup-jest.js:11:13)
  at Object.<anonymous> (setup-jest.ts:1:1)