jest.mock doesn't mock the module imported in test file - javascript

I'm trying to mock module generating uuid that is used inside the function that I test, and for some reason jest.mock fails to mock it.
file structure
- __test__
-- testFunc.test.ts
- uuidGenerator.ts
- testFunc.ts
./testFunc.ts
import uuidGenerator from "./uuidGenerator";
export const getUUID = () => {
return uuidGenerator().generateUUID();
};
./uuidGenerator.ts
export default function uuidGenerator() {
return { generateUUID: () => "generated-uuid" };
}
./__tests__/testFunc.test.ts
import { getUUID } from "../testFunc";
const testVal = "test-uuid";
jest.mock("../uuidGenerator", () =>
jest.fn(() => ({
generateUUID: () => testVal,
}))
);
describe("test func", function () {
it("should return expected", function () {
expect(getUUID()).toBe(testVal);
});
});
test output:
Error: expect(received).toBe(expected) // Object.is equality
Expected: "test-uuid"
Received: "generated-uuid"
console.log(uuidGenerator) from testFunc.ts returns:
[Function: uuidGenerator]
Edit: I'm using jest 25.5 and here is the configuration file:
module.exports = {
testRegex: "/__tests__/.*(\\.test.js|\\test.jsx|\\.test.ts|\\.test.tsx)$",
testResultsProcessor: "./node_modules/jest-html-reporter",
setupFilesAfterEnv: ["<rootDir>test-setup.js"],
moduleFileExtensions: [
"ts",
"tsx",
"ios.ts",
"android.ts",
"web.ts",
"ios.tsx",
"android.tsx",
"web.tsx",
"js",
"json",
"jsx",
"web.js",
"ios.js",
"android.js",
"ejs",
],
snapshotSerializers: ["enzyme-to-json/serializer"],
modulePaths: ["<rootDir>/packages", "<rootDir>/plugins", "<rootDir>/scripts"],
modulePathIgnorePatterns: ["<rootDir>/xxx/"],
collectCoverageFrom: ["packages/**/*.js", "plugins/**/*.js"],
coveragePathIgnorePatterns: [
"__tests__",
"__mocks__",
"node_modules",
"test_helpers",
"flow-types.js",
],
transformIgnorePatterns: [
"node_modules/(?!(react-native|react-native-webview|react-native-status-bar-height|react-router-native/)"
],
transform: {
"^.+\\.(js|ts|tsx)$": require.resolve("react-native/jest/preprocessor.js"),
"^.+\\.ejs$": "<rootDir>/tools/ejs-transformer.js",
},
testEnvironment: "node",
preset: "react-native",
verbose: true,
watchPlugins: [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname",
],
};
Looks like the module is not getting mocked at all. Can anyone understand why is it happening?

Which version of Yarn are you using ? I just copy-pasted your code and run the test using Jest 26 and everything was working as expected.
Maybe you could try clearing the Jest cache folder : https://jestjs.io/docs/cli#--clearcache

Related

Jest tests started failing with "Cannot use import statement outside a module" after using jail-monkey package in my React Native application

I have a React Native app in which I installed and used jail-monkey to check if the device is rooted. As soon as I added it, some of my Jest tests started failing with the following error:
SyntaxError: Cannot use import statement outside a module
> 3 | import JailMonkey from 'jail-monkey';
After googling I came upon this stack overflow thread which has many answers but neither of which helped me. That being said I imagine this problem has to do with the babel and jest configs - How to resolve "Cannot use import statement outside a module" in jest
My babel.config.js looks like this:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
require.resolve('babel-plugin-module-resolver'),
{
cwd: 'babelrc',
extensions: ['.ts', '.tsx', '.ios.tsx', '.android.tsx', '.js'],
alias: {
'#src': './src',
},
},
],
[
'module:react-native-dotenv',
{
moduleName: 'react-native-dotenv',
},
],
// Reanimated needs to be at the bottom of the list
'react-native-reanimated/plugin',
],
};
And my jest.config.js looks like this:
const { defaults: tsjPreset } = require('ts-jest/presets');
/** #type {import('#jest/types').Config.InitialOptions} */
module.exports = {
...tsjPreset,
preset: 'react-native',
transform: {
'^.+\\.jsx$': 'babel-jest',
},
// Lists all react-native dependencies
// that don't have compiled ES6 code
// and need to be ignored by the transformer
transformIgnorePatterns: [
'node_modules/(?!(react-native' +
'|react-navigation-tabs' +
'|react-native-splash-screen' +
'|react-native-screens' +
'|react-native-reanimated' +
'|#react-native' +
'|react-native-vector-icons' +
'|react-native-webview' +
')/)',
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleNameMapper: {
// Help Jest map the #src's added by babel transform
'^#src(.*)$': '<rootDir>/src$1',
// Allow Jest to mock static asset imports
'\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/assetMock.js',
// Mock SVG Component imports (from React Native SVG)
'\\.svg': '<rootDir>/__mocks__/svgMock.js',
},
setupFiles: ['./jest.setup.js'],
setupFilesAfterEnv: ['#testing-library/jest-native/extend-expect'],
};
I solved this issue by including jail-monkey in my transformIgnorePatterns on jest.config.js and them mocking the jailmonkey.js. In my case I have the file on __mocks__/jail-monkey/index.js with the following content:
export default {
jailBrokenMessage: () => '',
isJailBroken: () => false,
androidRootedDetectionMethods: {
rootBeer: {
detectRootManagementApps: false,
detectPotentiallyDangerousApps: false,
checkForSuBinary: false,
checkForDangerousProps: false,
checkForRWPaths: false,
detectTestKeys: false,
checkSuExists: false,
checkForRootNative: false,
checkForMagiskBinary: false,
},
jailMonkey: false,
},
hookDetected: () => false,
canMockLocation: () => false,
trustFall: () => false,
isOnExternalStorage: () => false,
isDebuggedMode: () => Promise.resolve(false),
isDevelopmentSettingsMode: () => Promise.resolve(false),
AdbEnabled: () => false,
};

Testing React/Typescript components with Jest module errors

I am receiving the error SyntaxError: Cannot use import statement outside a module when running a simple test on a React/Typescript component and not sure the best way of using modules in a React/Typescript project with Babel, webpack, and jest.
Here is my babel.config.js :
const isTest = String(process.env.NODE_ENV) === 'test'
const isProd = String(process.env.NODE_ENV) === 'production'
module.exports = {
presets: [
['#babel/preset-env', { modules: isTest ? 'commonjs' : false }],
'#babel/preset-typescript',
};
jest.config.js
module.exports = {
"roots": [
"<rootDir>/src"
],
"testMatch": [
"**/__tests__/**/*.+(ts|tsx|js)",
"**/?(*.)+(spec|test).+(ts|tsx|js)"
],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"moduleFileExtensions": ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
}
Here is the simple test I am trying to run:
import { render } from '#testing-library/react'
import AppRouter from '../router'
test('it works!', () => {
render(<AppRouter />)
})
Please help!
Solution
Be sure to check your testRegex in your jest.config.js file and the testEnvironment is set correctly with testEnvironment: "jsdom" if you are using ES6 modules for testing.

Jest instantiating empty objects instead of class instances

I'm using ts-jest to test a JS/TS SDK/module. I'm running into a strange issue where a Jest test will run (no compile/import failures) but fail to correctly instantiate an object from the appropriate class.
test("Should build unit", () => {
const builder = new UnitBuilder("TEST_UNIT");
console.log(builder); // prints "{}"
const unit = builder
.addResource(...)
.build();
expect(unit.name).toBe("TEST_UNIT");
});
The test fails with: TypeError: builder.addResource is not a function since the instantiated object is empty. Here's the class in question:
export class UnitBuilder {
constructor(templateId: string) {
this.payload = {
templateId,
parameters: [],
};
}
public addResource = (resource: CreateResourcePayload) => {
// do stuff
};
public build = () => {
// do stuff
};
public payload: CreateUnitPayload;
}
I'm assuming this has something to do with the jest or ts-jest transpilation, e.g. babel, but perhaps it's something to do with the jest configuration as well?
jest.config.ts
import type { Config } from "#jest/types";
const config: Config.InitialOptions = {
preset: "ts-jest",
testEnvironment: "node",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"],
verbose: true,
automock: true,
testMatch: ["**/__tests/*.test.ts"],
roots: ["<rootDir>/src"],
transform: {
"^.+\\.(ts|tsx)$": "ts-jest",
},
};
export default config;
Removing automock: true fixed the problem.

Jest moduleNameMapper not working - error TS2307: Cannot find module '#/[...]'

I have an issue with my Jest test suites not running because they are not importing correctly. I have set up some 'alias' paths in jest.config.js but for whatever reason, I get errors in the form:
Test suite failed to run
src/__tests__/app.test.tsx:3:40 - error TS2307: Cannot find module '#/render/index'.
where I am trying to import like
import { render, fireEvent, act } from '#/render/index';
This should be resolving to /src/testUtils/render/index as per my jest.config.js file:
// jest.config.js
// eslint-disable-next-line #typescript-eslint/no-var-requires
const { defaults } = require('jest-config');
const ignores = [
'[/\\\\]node_modules[/\\\\].+\\.(ts|tsx|js|jsx|mjs)$',
'/__tests__/helpers/',
'__mocks__',
];
module.exports = {
roots: ['<rootDir>/src'],
preset: 'ts-jest',
setupFiles: ['<rootDir>/src/testUtils/globals/index.ts'],
setupFilesAfterEnv: ['<rootDir>/src/testUtils/jest.setup.ts'],
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx'],
moduleDirectories: ['src', 'src/testUtils/render/', 'node_modules', 'src/testUtils/globals/'],
moduleNameMapper: {
// Tell jest to look in the src/testUtils/render/ dir when we use #/
'^#/render/(.*)$': '<rootDir>/src/testUtils/render/$1',
'^#/globals/(.*)$': '<rootDir>/src/testUtils/globals/$1',
},
modulePaths: ['<rootDir>'],
testMatch: ['<rootDir>/**/__tests__/**/*.test.+(ts|tsx)', '<rootDir>/**/*.test.ts'],
testURL: 'http://localhost',
transform: {
'\\.(ts|js)x?$': 'ts-jest',
'^.+\\.css$': '<rootDir>/config/jest/cssTransform.js',
'^(?!.*\\.(mjs|css|json)$)': '<rootDir>/config/jest/fileTransform.js',
},
transformIgnorePatterns: [...ignores],
coverageDirectory: '<rootDir>/src/testUtils/coverage',
collectCoverageFrom: ['<rootDir>/**/*.{ts,tsx,mjs}', '<rootDir>/**/**/*.{ts,tsx,mjs}'],
coveragePathIgnorePatterns: [
...ignores,
'<rootDir>/testUtils/',
'<rootDir>/src/serviceWorker.ts',
],
collectCoverage: false,
coverageThreshold: {
global: {
branches: 40,
functions: 40,
lines: 40,
statements: 40,
},
},
prettierPath: './node_modules/prettier',
timers: 'fake',
verbose: true,
errorOnDeprecated: true,
globals: {
'ts-jest': {
tsConfig: 'tsconfig.extend.json',
diagnostics: true,
},
},
extraGlobals: ['Math'],
notify: true,
watchPathIgnorePatterns: ['<rootDir>/src/serviceWorker.ts'],
snapshotSerializers: ['jest-serializer-html'],
};
I've tried updating Jest to latest, and then to 25.5.4, but nothing has changed anything. This used to work at some point in the past so I don't know what exactly to do to fix it. Would someone have any ideas?
Tried updating ts-jest and jest both to 26.0.0. Still no luck.

How to resolve `require` aliases built with Webpack, for React Unit tests?

question about React unit tests.
I've a ReactJs project and these is the current setup:
based on create-react-app
built with ejected Webpack
lots of Webpack plugins, as sass-extract-loader
based on some aliases built in webpack.config.dev.js
Now, I am installing a Jest environment to write tests both for simple javascript files and also for React components.
Simple javascript unit tests are working properly
But the test configuration is not working properly for unit tests of React components.
What is not working is the resolving of some requires that use aliases -defined in Webpack- within React components.
const motionConfig = require(`scssConfig/shared/motions.scss`)
scssConfig is an alias configured in the webpack.config.dev.js but in the Jest environment, when executing jest --config jest.config.json, an error pops out because the required file is not read / found and when I try to access its content, this is the error displayed coming out of the line const durationConfig = motionConfig.duration
TypeError: Cannot read property 'duration' of undefined
So basically it is failing the setup of the React environment, because the React component unit test is not yet run.
this is my jest.config.json
{
"bail": true,
"setupFilesAfterEnv": ["<rootDir>/jest.setup.js"],
"testMatch": [
"<rootDir>/src/app/**/?(*.)+(spec|test).(js|ts)?(x)"
],
"testPathIgnorePatterns": [
"<rootDir>/build/",
"<rootDir>/generated/",
"<rootDir>/node_modules/",
"<rootDir>/public/"
],
"snapshotSerializers": ["enzyme-to-json/serializer"],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}"
],
"testEnvironment": "node",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.(css|scss)$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
"^.+\\.module\\.(css|scss)$"
],
"moduleDirectories": [
"node_modules",
"<rootDir>/../library"
],
"moduleNameMapper": {
"\\.(css|scss)$": "identity-obj-proxy",
"#company/library/(.*)": "<rootDir>/../library/$1"
},
"resolver": null,
"moduleFileExtensions": [
"js",
"jsx",
"ts",
"tsx",
"scss",
"css"
]
}
and this is jest.setup.js
import Adapter from 'enzyme-adapter-react-16'
import { shallow, mount, configure } from 'enzyme'
import { format } from 'util'
import React from 'react'
import dotenv from 'dotenv'
import registerRequireContextHook from 'babel-plugin-require-context-hook/register'
dotenv.config({ path: __dirname + '/../.env' })
registerRequireContextHook()
configure({ adapter: new Adapter() })
let global
global.React = React
global.shallow = shallow
global.mount = mount
class ConsoleError extends Error {}
if (global.console) {
const throws = jest.fn((message, ...rest) => {
if (!(message instanceof ConsoleError)) {
const err = new ConsoleError(format(message, ...rest))
Error.captureStackTrace(err, throws)
throw err
}
})
global.console = {
...global.console,
error: throws,
warn: throws,
exception: throws
}
}
and this is .babelrc.js
const commonPlugins = [
[
require.resolve('babel-plugin-module-resolver'),
{
root: ['./src/app/'],
alias: {
'scssConfig': '../path/to/scssConfig',
}
}
]
]
module.exports = {
plugins: [...commonPlugins]
}
I think the json configuration is properly done but there is something missing.... what? any tips to make it working properly? thanks a lot
Fixed it like that
the require got replaced by the import
import motionScss from 'scssConfig/shared/gl-config-motion.scss'
in the jest.config.json I did this update
"\\.(scss)$": "<rootDir>/src/app/mocks/tests/scss.js",
"\\.(css)$": "identity-obj-proxy",
and this is the src/app/mocks/tests/scss.js
module.exports = { global: { '$motion': { duration: {}, ease: {} }}};

Categories

Resources