Import jest object when not using jest runner - jestjs

What do I need to import/require in order to access the magic jest object that contains jest.fn when not running my code with jest?

Jest now exports the jest-mock package seperately (https://github.com/facebook/jest/tree/master/packages/jest-mock).
import jestMock from 'jest-mock';
const mockFunction = jestMock.fn();

Related

nestjs testing - how to start a server with jest mocked modules

I already have e2e backend tests running using jest and some mocked modules using fastify and now that when I use app.listen it will be able to receive calls.
My problem:
I would like to start the nestjs server with the mocked jest modules to be able to call it from outside without the jest scope e.g. for vulnerability scanning of the api endpoints. I have some external dependencies that I want to exclude - this is why I would like to use my jest mocked nestjs modules.
if I try to used ts-node an error will be thrown in those mocked modules
command:
npx ts-node run.ts
file: run.ts
import { initializeApplication } from './app';
(async () => {
const app = await initializeApplication();
app.listen(3005, '0.0.0.0');
})();
error:
jest.fn(
^
ReferenceError: jest is not defined
I would like to be able to start the nestjs backend with jest mocked nestjs modules to make external api calls against the backend using fake dependencies.

create-react-app and jest - Cannot use import statement outside a module

I am using create-react-app. Running jest from the CLI causes this error (though in VS Code it shows in my test file that my test passes):
(base) ➜ component-library git:(setup) ✗ jest
FAIL src/App.test.js
● Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
/Users/Me/go/src/gitlab.com/tensile-payments/component-library/src/setupTests.js:5
import '#testing-library/jest-dom';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
My setupTests.js file looks like this:
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '#testing-library/jest-dom';
import Enzyme from 'enzyme';
import Adapter from '#wojtekmaj/enzyme-adapter-react-17';
Enzyme.configure({ adapter: new Adapter() });
I understand from another question's answer that Jest Babel-transforms files before running tests, which should get rid of these import statements. I haven't ejected and so haven't changed the babel config. Other people had the issue that node modules weren't being transformed because the default config excludes them, but this error isn't coming from a node module. How can I fix this?
I fixed it by running tests with npm run test instead of jest, as well as removing
"jest": {
"setupFilesAfterEnv": [
"<rootDir>src/setupTests.js"
]
}
from my package.json (though Enzyme instructs to include it when using Jest).

When should I use setupFiles rather than setupFilesAfterEnv?

I see that there are two config options in jest for having some code running before each tests : setupFiles and setupFilesAfterEnv. It seems to me that setupFilesAfterEnv gives more flexibility (I can use jest, beforeEach and so on ...), so I don't understand in what context setupFiles would be more useful. Can someone provide an example where you need to use setupFiles rather than setupFilesAfterEnv ?
Documentation : https://jestjs.io/docs/en/configuration#setupfiles-array
We can see what different between setupFiles and setupFilesAfterEnv from the documentation.
The most important difference will probably be when it is run.
setupFiles will be executed
before the test framework is installed in the environment.
setupFilesAfterEnv will be executed
after the test framework has been installed in the environment.
That's why the name has AfterEnv.
I actually use both of them in my actual project.
In my case, I use the setupFiles to set up fro .env values and use the setupFilesAfterEnv to set up jest configuration like jest.setTimeout(70000)
>> In my case >>>>>>>>>>>>>>>>>>>>>>>
jest.config.js
setupFiles: ['<rootDir>/tests/settings/env-setup.ts'],
setupFilesAfterEnv: ['<rootDir>/testSetupFile.js'],
env-setup.ts
import dotenv from 'dotenv';
import path from 'path';
console.log(`============ env-setup Loaded ===========`);
dotenv.config({ path: path.resolve(process.cwd(), 'tests', 'settings', '.test.env') });
testSetupFile.ts
// Some of the `jest` tests are very slow and cause
// timeouts on bitbucket pipeline
console.log(`============ testSetupFile Loaded ===========`);
jest.setTimeout(70000);

how to use node module with es6 import syntax in typescript

I have a typescript project which has uses one of our node modules which normally runs in our front-end. We are now looking to use this module in node on our server.
The module uses es6 import syntax import { props } from 'module/file'
When I include a ref in typescript using either of the following methods
import { props } from 'module/file';
var props = require('module/file');
I get the following error from typescript
unexpected token 'import'
(function (exports, require, module, __filename, __dirname) { import
It's a big job to re-write the module, and I've tried using babel with babel-plugin-dynamic-import-node, as well as SystemJS.
The problem with these systems is that they are all asynchronous, so I can't import the module in the standard fashion, so I would need to do a whole bunch of re-write when we get to the point that I can use import natively in node.js.
I can't be the first person to have this issue, but I can't seem to find a working solution.
--------------- update with set-up -------------
In response to #DanielKhoroshko's response. The original module I am trying to import is normally packaged by webpack in order to use on the front-end. I am now trying to use this same module both server-side and in the front-end (via webpack on the front-end) without re-writing the imports to use require and without running webpack to bundle the js to use on the server.
To be clear, the original module is written in JS, our service which is trying to use this module is written in typescript and transpiled. When the typescript tries to require the old module which uses import, it is at this point that we are running into the issue.
------------------ some progress ---------------------------
I've made some progress by creating a file in my imported module which uses babel in node.js to transpile the es6 code into commonJS modules.
I've done this via
var babel = require("babel-core")
var store = babel.transformFileSync(__dirname + '/store.js', {
plugins: ["transform-es2015-modules-commonjs"]
});
module.exports = {
store: store.code
}
I can now get the store in my new node.js project. However, the submodules within the store.js file are not included in the export.
So where in my module, it says
import activities from './reducers/activities';
I now get an error
Cannot find module './reducers/activities'
How can I get babel to do a deep traversal to include the sub-directories?
unexpected token 'import' means you are running es-modules code in environment that doesn't support import/export commands. If you are writing you code in TypeScript it's important to transpile it first before building for the browser or use ts-node to run it server-side.
If you are using webpack there are loaders ts-loader and awesome-typescript-loader
What is your setup?
To describe the module you would need to create an activities.d.ts file in the same folder where the js-version (I understood it is called activities.js and containers a reducer) resides with the following (approx.):
import { Reducer } from 'redux';
export const activities: Reducer<any>;
#Daniel Khoroshko was right in many ways, I ended up finding #std/esm which lets you import es6 modules and worked find for fetching the included imports as well.
var babel = require('babel-register')({
presets: ["env"]
});
require = require('#std/esm')(module);
var store = require('ayvri-viewer/src/store');
exports.default = {
store: store
}
I had to run babel to get a consistent build from es6 to node compatible es5

mock module which does not exist?

When i run my mocha tests in my meteor app by:
node_modules/.bin/mocha --compilers js:babel-core/register //..opts
i get a problem when my module under test wants to import:
import { Meteor } from 'meteor/meteor';
So i tried to mock it with mockery:
mockery.enable();
moduleUnderTest = '../moduleUnderTest';
mockery.registerAllowable(moduleUnderTest);
meteorMock = {};
mockery.registerMock('Meteor', meteorMock);
Unfortunately the module cannot be found
Error: Cannot find module 'meteor/meteor'
So the mocking of Meteor cannot be done.
Is there a way how i can fake the location meteor/meteor?
(Alternate Solution: If i can get access to the Meteor Environment in my mocha test)
If you look at the documentation, you'll see that .registerAllowable takes a string, not a module. You also need to give the exact module name that you are mocking, and provide a fake module with the values you want.
So:
var mockery = require("mockery");
mockery.enable();
mockery.registerAllowable("./moduleUnderTest");
// We want Meteor to have the value "foo". You probably want something
// different.
var meteorMock = { Meteor: "foo" };
// We mock 'meteor/meteor' because that's what's imported.
mockery.registerMock('meteor/meteor', meteorMock);
If you think about it, what you were doing cannot work. You were requiring the module before Mockery is configured for mocking 'Meteor', so Node loads your module, and then tries to load Meteor before the mock is available, and you get a failure.
Moreover, Meteor mocks modules so when you register a mock, you have to give a module name, not the name of a variable.

Resources