Skip to content

Unable to use jest.mock with Wallaby #872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
narthollis opened this issue Nov 17, 2016 · 20 comments
Closed

Unable to use jest.mock with Wallaby #872

narthollis opened this issue Nov 17, 2016 · 20 comments

Comments

@narthollis
Copy link

Issue description or question

When running tests in wallaby, modules mocked using jest.mock are imported rather than the requested mocked version.

A minimal reproduction can be found at https://github.com/narthollis/minimal_jest_mock

Output from npm run -s test (jest --no-cache --config jest.config.json)

E:\temp\minimal_jest_mock>npm run -s test
 PASS  src\items\example.test.js
  example
    √ should return the current unix time stamp (4ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.812s
Ran all test suites.

Output from Wallaby console

1 failing tests, 0 passing

src/items/example.test.js example should return the current unix time stamp [3 ms]

	TypeError: _dateProvider2.default.now.mockImplementationOnce is not a function
		at Object.<anonymous> src/items/example.test.js:15
		at Object.e.length.arguments.(anonymous function) test/setup-before-after.js:34

Wallaby.js configuration file

process.env.NODE_ENV = 'test';

// eslint-disable-next-line func-names
module.exports = function (wallaby) {
    return {
        files: [
            { pattern: 'node_modules/react/dist/react-with-addons.js', instrument: false },
            'defaultData/**/*.json',
            'src/**/*.js*',
            '!src/**/*.test.js*',
            '!src/**/*.fixture.js',

            { pattern: 'test/*.js', instrument: false },
        ],

        tests: [
            'src/**/*.test.js',
            'src/**/*.test.jsx',
        ],

        compilers: {
            '**/*.js': wallaby.compilers.babel(),
            '**/*.jsx': wallaby.compilers.babel(),
        },

        env: {
            type: 'node',
            runner: 'node',
            params: {
                runner: '--harmony',
            },
        },

        testFramework: 'jest',

        setup: (w) => {
            w.testFramework.configure({
                setupTestFrameworkScriptFile: '<rootDir>/test/setup-before-after.js',
                moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
                moduleNameMapper: {
                    '^.+\\.(css|scss|sass)$': '<rootDir>/test/styleMock.js',
                    '^.+\\.(gif|ttf|eot|svg)$': '<rootDir>/test/fileMock.js',
                },
                // testRegex: '/__tests__/.*|\\.(test|spec)\\.(js|jsx)$',
            });
        },
    };
};

Code editor or IDE name and version

WebStorm 2016.3

OS name and version

Windows 7

A Min

@ArtemGovorov
Copy link
Member

Interesting, if you change

import * as example from './example';
import DateProvider from '../module/dateProvider';
jest.mock('../module/dateProvider');

to

jest.mock('../module/dateProvider');
const example = require('./example')
const DateProvider = require('../module/dateProvider').default;

then it starts working. Looks like jest is doing some magic internally to call jest.mock before imports and the magic is not called when jest is used by wallaby. I'm investigating it now.

@narthollis
Copy link
Author

In the Jest documentation, it mentions:

Note: When using babel-jest, calls to mock will automatically be hoisted to the top of the code block. Use doMock if you want to explicitly avoid this behavior.

https://facebook.github.io/jest/docs/api.html#jestmockmodulename-factory-options

Could this be related?

@ArtemGovorov
Copy link
Member

Yes, it looks like the case. Wallaby instrumentation is probably breaking the hoisting behaviour. I'm looking into the ways to fix it.

@ArtemGovorov
Copy link
Member

ArtemGovorov commented Nov 17, 2016

Ok, so I have investigated what exactly is going on. jest is sneakily using babel-preset-jest to hoist calls to mock. But because it's implementation is not wallaby instrumentation friendly, it doesn't work. Actually anything other than simple usage breaks it, so for example following examples will not work with plain jest/npm run test:

import * as example from './example';
import DateProvider from '../module/dateProvider';
{
  jest.mock('../module/dateProvider');
}

or

import * as example from './example';
import DateProvider from '../module/dateProvider';
1, jest.mock('../module/dateProvider');

To make it work, the preset has to be applied during wallaby babel compilation. There're a few options to make it work.

  1. It can be specified in your .babelrc:
{
  "presets": [
    ["es2015", {"loose": false, "modules": false}],
    "react",
    "stage-1"
  ],
  "env": {
    "test": {
      "presets": [
        "babel-preset-jest", // <---
        ["es2015", {"loose": false, "modules": "commonjs"}],
        "react",
        "stage-1"
      ]
    }
  }
}
  1. Alternatively you can have a separate section:
{
  "presets": [
    ["es2015", {"loose": false, "modules": false}],
    "react",
    "stage-1"
  ],
  "env": {
    "test": {
      "presets": [
        ["es2015", {"loose": false, "modules": "commonjs"}],
        "react",
        "stage-1"
      ]
    }
    "wallaby": { // <---
      "presets": [
        "babel-preset-jest", // <---
        ["es2015", {"loose": false, "modules": "commonjs"}],
        "react",
        "stage-1"
      ]
    }
  }
}

plus

process.env.NODE_ENV = 'wallaby';

in your wallaby config.

  1. Alternatively, it can be added to babel configuration in your wallaby config:
process.env.NODE_ENV = 'test';

const babelConfig = JSON.parse(require('fs').readFileSync(require('path').join(__dirname, '.babelrc'))).env.test;
babelConfig.presets.push('babel-preset-jest');

// eslint-disable-next-line func-names
module.exports = function (wallaby) {
    return {
        ...
        compilers: {
            '**/*.js*': wallaby.compilers.babel(babelConfig)
        },
        ...
    };
};

Whatever way you choose, it should only affect wallaby, npm run test should still work the same way as it does now.

@narthollis
Copy link
Author

Excellent. Thanks very much for looking into this and getting back to me
quickly.

On 17 Nov. 2016 15:19, "Artem Govorov" [email protected] wrote:

Ok, so I have investigated what exactly is going on. jest is sneakily
using babel-preset-jest to hoist calls to mock. But because it's
implementation is not wallaby instrumentation friendly, it doesn't work.
Actually anything other than simple usage breaks it, so for example
following examples will not work with plain jest/npm run test:

import * as example from './example';import DateProvider from '../module/dateProvider';
{
jest.mock('../module/dateProvider');
}

or

import * as example from './example';import DateProvider from '../module/dateProvider';1, jest.mock('../module/dateProvider');

To make it work, the preset has to be applied during wallaby babel
compilation. There're a few options to make it work.

  1. It can be specified in your .babelrc:

{
"presets": [
["es2015", {"loose": false, "modules": false}],
"react",
"stage-1"
],
"env": {
"test": {
"presets": [
"babel-preset-jest", // <---
["es2015", {"loose": false, "modules": "commonjs"}],
"react",
"stage-1"
]
}
}
}

  1. Alternatively you can have a separate section:

{
"presets": [
["es2015", {"loose": false, "modules": false}],
"react",
"stage-1"
],
"env": {
"test": {
"presets": [
["es2015", {"loose": false, "modules": "commonjs"}],
"react",
"stage-1"
]
}
"wallaby": { // <---
"presets": [
"babel-preset-jest", // <---
["es2015", {"loose": false, "modules": "commonjs"}],
"react",
"stage-1"
]
}
}
}

plus

process.env.NODE_ENV = 'wallaby';

in your wallaby config.

  1. Added to babel configuration in your wallaby config:

process.env.NODE_ENV = 'test';
const babelConfig = JSON.parse(require('fs').readFileSync(require('path').join(__dirname, '.babelrc'))).env.test;babelConfig.presets.push('babel-preset-jest');
// eslint-disable-next-line func-namesmodule.exports = function (wallaby) {
return {
...
compilers: {
'/.js': wallaby.compilers.babel(babelConfig)
},
...
};
};

Whatever way you choose, it should only affect wallaby, npm run test
should still work the same way as it does now.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#872 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEIlMPYB4eV100Vj-K2XO8GZfTxkz4Eks5q-9zFgaJpZM4K0zGN
.

@ArtemGovorov
Copy link
Member

Forgot to mention one more way, probably the easiest one, with the only one change to wallaby config:

        ...
        compilers: {
            '**/*.js*': wallaby.compilers.babel({babelrc: true, presets: ['babel-preset-jest']})
        },

@gregorskii
Copy link

gregorskii commented Oct 9, 2018

When I add babel-preset-jest to my project I get:

Failed to run compilers on src/App.js, Error: Plugin/Preset files are not allowed to export objects, only functions.

Wallaby.js:

const babelConf = require('./babel.config.js');

module.exports = (wallaby) => {
  return {
    files: [
      {
        pattern: 'babel.config.js',
        instrument: false
      },
      {
        pattern: '.babelrc',
        instrument: false
      },
      'src/**/*.js?(x)',
      '__tests__/**/*.js',
      '__mocks__/**/*.js',
      'src/**/*.snap',
      '!src/**/*.test.js?(x)'
    ],

    tests: ['src/**/*.test.js?(x)'],

    env: {
      type: 'node',
      runner: 'node'
    },

    compilers: {
      'src/**/*.js?(x)': wallaby.compilers.babel(babelConf)
    },

    testFramework: 'jest',

    debug: true
  };
};

I have an issue I am trying to track down where the mocks in __mocks__ of jest are not working.

I am also using Babel 7.

Edit:

Issue may be jestjs/jest#6126

@ArtemGovorov
Copy link
Member

@gregorskii This doesn't look like Wallaby specific issue. Looks like it is Babel version mismatch and may indeed be related to the issue you've referenced. If Jest CLI is working for you, but Wallaby doesn't for the same project, please create a sample repo demonstrating the issue, we are happy to take a look and help.

@gregorskii
Copy link

@ArtemGovorov yep jest CLI does work.

It was related to this babel-preset-jest I found that using babel-plugin-jest-hoist is more compatible with Babel 7. The issue I am having now is the __mocks__ is still not working.

I can try to put together a simpler repo to demonstrate, this project is a client's project.

Let me try a few more things and then Ill create the repo.

Have you seen any issues with using the jest __mocks__ folder before?

Seems like jest.mock mocks are working.

@gregorskii
Copy link

gregorskii commented Oct 10, 2018

@ArtemGovorov here is a smaller fork of my project:

https://github.com/gregorskii/wallaby-native-test

When running wallaby I see a lot of issues with long execution:

Some long running code has been detected: one of your files is taking more than 5000ms to execute.
Execution of the following files has started but has not finished:
- src/App.js
- src/App.test.js
- src/navigation/AppNavigator.js
Try commenting out the test or excluding the test file from the `tests` list in your wallaby config,
and restarting wallaby to make sure that it is this test/file causing the issue and not something else.
Pinging test runner sandbox...
The sandbox is not responsive. Check for possibly recently introduced infinite loops.

At the end of it env variables that should be set by react-native-config are not set. These values are mocked in the __mocks__ folder.

console.log: PASS src/App.test.js (18.6s)

console.log:   ● Console

    console.log ../../../wallaby/server.js:19
      undefined
    console.log ../../../wallaby/server.js:19
      undefined

Running yarn test results in the correct behavior:

 PASS  src/components/StyledText.test.js
 PASS  src/App.test.js
  ● Console

    console.log src/App.js:12
      WALLABY@!
    console.log src/App.js:12
      WALLABY@!


Test Suites: 2 passed, 2 total
Tests:       3 passed, 3 total
Snapshots:   3 passed, 3 total
Time:        2.223s
Ran all test suites.

The value Config.TEST is set, which is defined in the .env.

The details of how react-native-config work is not the issue I have (that package was picked for this project by a previous team. My issue is that it appears that the __mocks__ and the mock in __tests__/setupJest.js do not appear to be running.

On my actual project one of the things being supplied by the Config is the API URL. This results in the tests waiting a LOOONG time to timeout before completing. I will get to mocking this API so that the tests are not trying to call the API, but I have not gotten there yet. I need the tests to run in the same state across jest CLI and wallaby.

Thank you.

@ArtemGovorov
Copy link
Member

@gregorskii

Thanks for providing the repo.

When running wallaby I see a lot of issues with long execution:

This is expected (Jest initialising react-native). If you run Jest cold start (without cache, for example by cloning your sample repo from the scratch), you'd get similar timings, even longer. However, once Wallaby.js has started, editing the same tests should be fast.

The value Config.TEST is set, which is defined in the .env.

All you need to do is to add the .env file to the files list, and it should work for you the same way as in Jest CLI. I have sent you the pull request with the change.

@gregorskii
Copy link

gregorskii commented Oct 11, 2018

Ah yes. That makes perfect sense. Will add the .env and instruct the team the delay in starting is expected (makes sense it would be).

I was initiated thinking the delay was due to the missing env variable, but it does make sense it has to mount a lot to run react native code.

Thank you!

@just-jeb
Copy link

How am I supposed to workaround it with yoshi 3.0.0? The only line in wallaby.js is module.exports = require('yoshi/config/wallaby-jest');

@ArtemGovorov
Copy link
Member

@meltedspark Since different questions had been raised/answered in this issue, could you please provide some more details about the issue that you have? Perhaps even create a separate issue - we are happy to help.

@just-jeb
Copy link

The issue is exactly the same - when running with wallaby.js the jest.mocks are not hoisted. I can open a separate issue but not sure it's necessary because it will be the same.

@ArtemGovorov
Copy link
Member

@meltedspark Could you please share some more details about your project:

  • is it TypeScript or JavaScript?
  • please share your package.json devDependencies section (so I get an idea what Babel/TS versions are in use).

@just-jeb
Copy link

Sure, here you go:

  • Typescript
  • package.json devDependencies:
      "devDependencies": {
      "@types/enzyme": "^3.9.0",
      "@types/i18next": "~8.4.0",
      "@types/jest": "^23.3.9",
      "@types/node": "^8.0.0",
      "@types/prop-types": "~15.5.0",
      "@types/react": "~16.4.7",
      "@types/react-dom": "~16.0.10",
      "@types/react-i18next": "~4.6.0",
      "@types/react-redux": "^7.0.1",
      "@wix/business-manager": "latest",
      "@wix/business-manager-api": "latest",
      "@wix/dealer-lightbox": "^1.0.94",
      "@wix/wix-eventually": "^1.0.454",
      "enzyme": "^3.7.0",
      "enzyme-adapter-react-16": "^1.5.0",
      "get-port": "^4.0.0",
      "husky": "~0.14.0",
      "jest-localstorage-mock": "^2.4.0",
      "jest-yoshi-preset": "^3.20.0",
      "lint-staged": "^7.2.2",
      "prop-types": "~15.5.0",
      "puppeteer": "^1.10.0",
      "react": "^16.6.3",
      "react-dom": "^16.6.3",
      "react-module-container": "~1.0.0",
      "react-test-renderer": "16.6.3",
      "typescript": "~3.0.1",
      "yoshi": "^3.0.0",
      "yoshi-style-dependencies": "^3.0.0"
    },
    

@just-jeb
Copy link

Here is the project, here is the branch, here is the sample code.

@ArtemGovorov
Copy link
Member

@meltedspark Thanks. I can not access the repo that you've listed (looks like it's private Wix repo), but your devDependencies is enough to see the issue.

Wallaby with Jest and Typescript needs the following preprocessor to make Jest hoisting work:

module.exports = wallaby => {
  const config = require('yoshi/config/wallaby-jest')(wallaby);
  config.workers = {recycle: false};
  config.preprocessors = {
    '**/*.js?(x)': file =>
      require('babel-core').transform(file.content, {
        sourceMap: true,
        filename: file.path,
        presets: ['babel-preset-jest']
      })
  };
  return config;
};

I have also set workers.recycle to false, it makes Wallaby much faster - not sure why it's set to true in yoshi, I will create a pull request to revert it.

@just-jeb
Copy link

just-jeb commented Mar 12, 2019

Oops, I just noticed that I posted in the wrong issue ))) I meant to post in in yoshi's repository, there is an issue with the exact same title. facepalm.
Thank you so much for helping despite of missing context!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants