I am making an exercise with ES2015, Jest, React and I get this error:
TypeError: Property description must be an object: undefined
at defineProperties (native)
at Object.eval (<PROJECT>/node_modules/event-emitter/index.js:127:8)
After digging into it, I think it is related to the import of the nodeModule EventEmitter or by extending the class by it.
This is the code of the script file:
import EventEmitter from 'event-emitter';
import AppDispatcher from '../dispatcher/app-dispatcher';
import {
ACTION_CURSOR_POSITION_CHANGED,
ACTION_IS_DRAGGING_CHANGED
} from '../constants/actions';
let _draggingStoreInstance = null;
/**
* DraggingStore class
*/
export default class DraggingStore extends EventEmitter
{
/**
* Constructor
*/
constructor () {
// ...
The source code of the test file looks like this:
import '../unmock/dragging-store.unmock.js';
import DraggingStore from '../../src/stores/dragging-store';
describe('Dragging Store', () => {
let draggingStoreInstance = null;
beforeEach(() => {
draggingStoreInstance = DraggingStore.getInstance();
});
it('should be defined', () => {
expect(DraggingStore).toBeDefined();
expect(draggingStoreInstance).toBeDefined();
});
});
I made an extra file for excluding mocks:
jest.dontMock('../../src/stores/dragging-store.js');
jest.dontMock('../../src/dispatcher/app-dispatcher.js');
jest.dontMock('../../src/constants/actions.js');
The code itself runs smoothly in the browser after compiling, but the test engine gives the error.
I added this in my package.json:
"scripts": {
"test": "jest"
},
"jest": {
"scriptPreprocessor": "./node_modules/babel-jest",
"unmockedModulePathPatterns": [
"./node_modules/react"
],
"collectCoverage": true,
"testDirectoryName": "spec",
"moduleFileExtensions": [
"js"
],
"collectCoverageOnlyFrom": {
// All files to test
}
}
Does anyone have a clue how to get around the problem?
Thanks in advance...
Update: full source code can be found here: https://github.com/dejakob/unlease-chess
I realize this is very late, but, a lot has changed in the time you have posted this question. With Jest v19+, and assuming you are using the latest version of Babel as well, you can follow the instructions here:
http://facebook.github.io/jest/docs/webpack.html#using-with-webpack-2
since you are using modules, you will need to tell Babel to transpile them to commonjs requires so that they can be run in the node environment, which is how Jest works.
Related
I encountered the module resolving issue in my testcafe(1.17.1) test.
I have a test
//test.e2e.ts in <root>/tests folder
import {MyComponent} from '../src/MyComponent';
...
...
fixture('Custom domain tests');
test('test 1', async () => {
...
...
});
the <root>/src/MyComponent.tsx looks like this
//MyComponent.tsx in <root>/src folder
import React, { FunctionComponent } from 'react';
import styles from '../scss/MyComponent.module.scss';
export const MyComponent: FunctionComponent = () => {
...
...
}
When I run testcafe ./tests/test.e2e.ts, I always got the error
Error: TypeScript compilation failed. Cannot find module '../scss/MyComponent.module.scss' or its corresponding type declarations.
My testcafe tsconfig specified the path config, the <root>/scss-module-for-tests.ts just exports a empty string
// .testcaferc.json in <root>/
{
"compilerOptions": {
"typescript": {
"options": {
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"../scss/MyComponent.module.scss": ["scss-module-for-tests.ts"],
"*.scss": ["scss-module-for-tests.ts"]
}
}
}
}
}
However, seems typescript path config doesn't resolve relative path nor accept a regex, but My project has a lot of those ../scss/*module.scss imports. Is there anyway to resolve the scss file directly for testcafe?
Thanks in advance!
Update on 12/02/2021
I tried add compiler for testcafe according to this doc , I put a .testcaferc.json at the root folder
//.testcaferc.json at <root>
{
"compilerOptions": {
"typescript": {
"options": {
"esModuleInterop": "true"
}
}
}
}
But seems the esModuleInterop=true config didn't reach to testcafe.
Update 12/13/2021:
Not easy to configure it correctly, I removed the *.scss file reference in the test code. Problem solved.
It looks like your TestCafe tests' code references your testing application code. However, TestCafe tests do not require testing application code. In fact, the code of the TestCafe tests and the application can be divided into two separate projects. Please try to separate your web application code and your TestCafe tests' code.
I am currently having trouble with my React TypeScript project.
I created my project with npx create-react-app my-app --template typescript.
I recently added tsyringe for dependency injection and was trying to implement it for an apiService. After following the readme(https://github.com/microsoft/tsyringe#injecting-primitive-values-named-injection) for adding primitive values I have hit a block. I already add experimentalDecorators and emitDecoratorMetadata to my tsconfig.json file with no success.
The error actual error I am encountering is:
./src/ts/utils/NetworkService.ts 9:14
Module parse failed: Unexpected character '#' (9:14)
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|
| let NetworkService = (_dec = singleton(), _dec(_class = (_temp = class NetworkService {
> constructor(#inject('SpecialString')
| value) {
| this.str = void 0;
I am fairly sure this problem is caused by Babel, however I created this with npm create react-app --template typescript and do not seem to have access to the Babel configuration.
NetworkService.ts
#singleton()
export default class NetworkService
{
private str: string;
constructor(#inject('SpecialString') value: string) {
this.str = value;
}
}
Invocation method
bob()
{
const inst = container.resolve(NetworkService);
}
Registering Class in index.ts
container.register('SpecialString', {useValue: 'https://myme.test'});
#registry([
{ token: NetworkService, useClass: NetworkService },
])
class RegisterService{}
React-Scripts manages many of the configs related to the project. For many cases, this is fine and actually a nice feature. However, because React-Scripts uses Babel for it's development environment and does not expose the config.
You have to run npm run eject to expose the configurations.
Please note, this is a one-way operation and can not be undone.
Personally, I prefer more control with my configuration.
After this you can edit the webpack.config.js in the newly created config folder.
Find the section related to the babel-loader in the dev-environment and add 'babel-plugin-transform-typescript-metadata' to the plugins array.
Expanding on Jordan Schnur's reply, here are some more pitfalls I encountered when adding TSyringe to my CRA app:
Use import type with #inject
If you get this error "TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled." replace import with import type for the offending imports. You will encounter this when working with #inject
E.g. replace import { IConfig } from "iconfig" with import type { IConfig } from "iconfig"
Fixing Jest
Your Jest tests will also break with TSyringe, especially when using #inject. I got the error "Jest encountered an unexpected token" with details constructor(#((0, _tsyringe.inject)("")) ("#" marked as the offending token). I took the following steps to fix that in CRA:
Add the line import "reflect-metadata"; to the top of the file src/setupTests.ts
In config/jest/babelTransform.js replace line 18 and following:
From
module.exports = babelJest.createTransformer({
presets: [
[
require.resolve('babel-preset-react-app'),
{
runtime: hasJsxRuntime ? 'automatic' : 'classic',
},
],
],
babelrc: false,
configFile: false,
});
to:
module.exports = babelJest.createTransformer({
presets: [
[
require.resolve('babel-preset-react-app'),
{
runtime: hasJsxRuntime ? 'automatic' : 'classic',
},
],
],
plugins: [
require.resolve('babel-plugin-transform-typescript-metadata')
],
babelrc: false,
configFile: false,
});
Instead of eject, you may use a lib that "overrides" some of your params.
I used craco : https://www.npmjs.com/package/#craco/craco
I've created an simpler DI library that doesn't need decorators or polyfill. Works with CRA like a charm and has cool React bindings
iti
import { useContainer } from "./_containers/main-app"
function Profile() {
const [auth, authErr] = useContainer().auth
if (authErr) return <div>failed to load</div>
if (!auth) return <div>loading...</div>
return <div>hello {auth.profile.name}!</div>
}
I have the following line that executes correctly in browser
eval(Babel.transform(template, { presets: ['react'] }).code);
but when I run jest tests I am getting ReferenceError: React is not defined
What am I missing?
More info:
in the test file I have the following:
const wrapper = shallow(<MyComponent/>);
const instance = wrapper.instance();
instance.componentFunction(...)
and then the componentFunction has the eval(Babel.transform(template, { presets: ['react'] }).code); line where template is something it gets from the test file and can be something like <span>...</span>
Please let me know if more details are needed
#babel/preset already has support for what you need. According to the react 17 documentation I only had to set the runtime to automatic in my babel.config.json.
{
"presets": [
["#babel/preset-react", {
"runtime": "automatic"
}]
]
}
If you are using #babel/plugin-transform-react-jsx the config should be
{
"plugins": [
["#babel/plugin-transform-react-jsx", {
"runtime": "automatic"
}]
]
}
The latter is usually not needed since #babel/preset-react includes #babel/plugin-transform-react-jsx.
Why you shouldn't use import React from 'react';
The documentation states:
There are some performance improvements and simplifications that React.createElement does not allow.
There is also a technical RFC that explains how the new transformation works.
If you want to upgrade. React also provides an automated script that removes unnecessarry imports from your code.
If you are using JSX in your jest test files, you will need to add the following import line to the top of the file:
import React from 'react';
The reason for this is that Babel transforms the JSX syntax into a series of React.createElement() calls, and if you fail to import React, those will fail.
The best solution for Next.js (where jsx: 'preserve' specifically is:
Configuring your babel config in the way that next already does: (no need to install another babel plugin):
babel.config.js:
module.exports = {
presets: ['next/babel']
};
Alternatively, if anyone experienced this bug had the problem wherein import React from 'react' is not necessary, because it is already included globally and doesn't need to be included in every file, then this solution may work for you.
I simply configured React to be globally defined in jest.
My jest.config.js:
module.exports = {
moduleDirectories: ['./node_modules', 'src'],
// other important stuff
setupFilesAfterEnv: ['<rootDir>/src/jest-setup.ts']
}
import '#testing-library/jest-dom';
import React from 'react';
global.React = React; // this also works for other globally available libraries
Now I don't need to worry about each file importing React (even though eslint knows that's unnecessary with Next.js)
This happened to me after react-native and jest and other node_modules related to unit test were upgraded.
Here is my working config:
jest.config.js
module.exports = {
preset: 'react-native',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleDirectories: ['./node_modules', 'src'],
cacheDirectory: '.jest/cache',
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!#react-native|react-native)',
],
moduleNameMapper: {
'^[./a-zA-Z0-9$_-]+\\.svg$': '<rootDir>/tests/SvgStub.js'
},
setupFiles: ['./jest-setup.js'],
modulePathIgnorePatterns: ['<rootDir>/packages/'],
watchPathIgnorePatterns: ['<rootDir>/node_modules'],
}
For setup file I had to use project specific one ./jest-setup.js but for a general use './node_modules/react-native-gesture-handler/jestSetup.js' should work too.
babel.config
{
presets: ['module:metro-react-native-babel-preset'],
plugins: [
'react-native-reanimated/plugin'
]
};
Sources: https://github.com/facebook/jest/issues/11591#issuecomment-899508417
More info about the dependencies here: https://stackoverflow.com/a/74278326/1979861
If you are storing test data in separate test data files that contain JSX, you will also need to import react, as your file contains JSX and so results in a ReferenceError: React is not defined in jest tests error.
const testData = {
"userName": "Jane Bloggs",
"userId": 101,
"userDetailsLink": Jane Bloggs
};
importing react, as below, resolves the error.
import React from "react";
const testData = {
"userName": "Jane Bloggs",
"userId": 101,
"userDetailsLink": Jane Bloggs
};
In my Angular/Typescript/Webpack project, I was rewriting unit tests after code modifications.
The symptom of the issue was an error when running a very basic component test: "Error: Unexpected value 'undefined' declared by the module 'DynamicTestModule'"
In order to debug the issue, I wound up stripping out all dependencies from the constructor of the component and essentially all code. The component did nothing and yet I still got the error. It couldn't be a circular dependency because there were no dependencies.
The folder files were:
--profile
----profile.component.ts
----profile.component.spec.ts
----profile.component.html
----index.ts (barrel)
The component (with most meaningful code removed in order to figure out problem) is:
import { Component } from '#angular/core';
#Component({
selector: 'profile',
template: `<h1></h1>`
})
export class ProfileComponent {
title = 'Test Tour of Heroes';
constructor(){}
}
And the spec is:
import { NO_ERRORS_SCHEMA, DebugElement } from '#angular/core';
import { ComponentFixture, TestBed }
from '#angular/core/testing';
import { ProfileComponent } from './profile.component';
console.log(ProfileComponent);
fdescribe('Component: Jasmine Spy Test', () => {
console.log(ProfileComponent);
let fixture: ComponentFixture<ProfileComponent>;
let component: ProfileComponent;
let fixture2: ComponentFixture<ProfileComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ProfileComponent]
}).compileComponents();
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
});
it(`should create instance of objects`, () => {
expect(1).toBe(1);
});
});
Versions:
"#angular/core": "^4.0.0",
"karma": "~1.4.1"
"webpack": "^2.3.3"
There are lots of other packages but I don't think that was the issue.
I was using VisualCode 1.14.0 (1.14.0).
The Real Issue VisualCode identified that ProfileComponent was in ./profile.component but the console.log lines printing that out said 'undefined' and no compile/transpile error was thrown.
Notice that there is a separate .html file in the folder but the code doesn't reference it.
ProfileComponent began to have value (no longer undefined) when I renamed the profile.component.html file -- must have been something about the webpack build.
I don't know what is wrong with this particular set of files because there any many folders with this exact same naming convention/setup in this project that do run the tests correctly.
I'm leaving this here in case someone runs across this error.
I also faced this issue. The component I was testing was not declared in any module. I had commented out the code in the module, after removing the comments, the error was fixed.
I use webpack to develop a React component. Here is a simple version of it:
'use strict';
require('./MyComponent.less');
var React = require('react');
var MyComponent = React.createClass({
render() {
return (
<div className="my-component">
Hello World
</div>
);
}
});
module.exports = MyComponent;
Now, I would like to test this component using jest. Here is the relevant bit from my package.json:
"scripts": {
"test": "jest"
},
"jest": {
"rootDir": ".",
"testDirectoryName": "tests",
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"unmockedModulePathPatterns": [
"react"
]
}
When running npm test, I get the following error:
SyntaxError: /Users/mishamoroshko/react-component/src/tests/MyComponent.js: /Users/mishamoroshko/react-component/src/MyComponent.js: /Users/mishamoroshko/react-component/src/MyComponent.less: Unexpected token ILLEGAL
Looks like webpack needs to process require('./MyComponent.less') before jest can run the test.
I wonder if I need to use something like jest-webpack. If yes, is there a way to specify multiple scriptPreprocessors? (note that I already use babel-jest)
The cleanest solution I found for ignoring a required module is to use the moduleNameMapper config (works on the latest version 0.9.2)
The documentation is hard to follow. I hope the following will help.
Add moduleNameMapper key to your packages.json config. The key for an item should be a regex of the required string. Example with '.less' files:
"moduleNameMapper": { "^.*[.](less|LESS)$": "EmptyModule" },
Add a EmptyModule.js to your root folder:
/**
* #providesModule EmptyModule
*/
module.exports = '';
The comment is important since the moduleNameMapper use EmptyModule as alias to this module (read more about providesModule).
Now each require reference that matches the regex will be replaced with an empty string.
If you use the moduleFileExtensions configuration with a 'js' file, then make sure you also add the EmptyModule to your 'unmockedModulePathPatterns'.
Here is the jest configuration I ended up with:
"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"moduleFileExtensions": ["js", "json","jsx" ],
"moduleNameMapper": {
"^.*[.](jpg|JPG|gif|GIF|png|PNG|less|LESS|css|CSS)$": "EmptyModule"
},
"preprocessorIgnorePatterns": [ "/node_modules/" ],
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react",
"<rootDir>/node_modules/react-dom",
"<rootDir>/node_modules/react-addons-test-utils",
"<rootDir>/EmptyModule.js"
]
}
I ended up with the following hack:
// package.json
"jest": {
"scriptPreprocessor": "<rootDir>/jest-script-preprocessor",
...
}
// jest-script-preprocessor.js
var babelJest = require("babel-jest");
module.exports = {
process: function(src, filename) {
return babelJest.process(src, filename)
.replace(/^require.*\.less.*;$/gm, '');
}
};
But, I'm still wondering what is the right solution to this problem.
I just found that it's even simpler with Jest's moduleNameMapper configuration.
// package.json
"jest": {
"moduleNameMapper": {
"^.+\\.scss$": "<rootDir>/scripts/mocks/style-mock.js"
}
}
// style-mock.js
module.exports = {};
More detail at Jest's tutorial page.
I recently released Jestpack which might help. It first builds your test files with Webpack so any custom module resolution/loaders/plugins etc. just work and you end up with JavaScript. It then provides a custom module loader for Jest which understands the Webpack module runtime.
From Jest docs:
// in terminal, add new dependency: identity-obj-proxy
npm install --save-dev identity-obj-proxy
// package.json (for CSS Modules)
{
"jest": {
"moduleNameMapper": {
"\\.(css|less)$": "identity-obj-proxy"
}
}
}
The snippet above will route all .less files to the new dependency identity-obj-proxy, which will return a string with the classname when invoked, e.g. 'styleName' for styles.styleName.
I think a less hacky solution would be to wrap your preprocessor in a conditional on the filename matching a javascript file:
if (filename.match(/\.jsx?$/)) {
return babelJest.process(src, filename);
} else {
return '';
}
This works even if you don't explicitly set the extension in the require line and doesn't require a regex substitution on the source.
I have experienced similar issue with such pattern
import React, { PropTypes, Component } from 'react';
import styles from './ContactPage.css';
import withStyles from '../../decorators/withStyles';
#withStyles(styles)
class ContactPage extends Component {
see example at https://github.com/kriasoft/react-starter-kit/blob/9204f2661ebee15dcb0b2feed4ae1d2137a8d213/src/components/ContactPage/ContactPage.js#L4-L7
For running Jest I has 2 problems:
import of .css
applying decorator #withStyles (TypeError: <...> (0 , _appDecoratorsWithStyles2.default)(...) is not a function)
First one was solved by mocking .css itself in script preprocessor.
Second one was solved by excluding decorators from automocking using unmockedModulePathPatterns
module.exports = {
process: function (src, filename) {
...
if (filename.match(/\.css$/)) src = '';
...
babel.transform(src, ...
}
}
example based on https://github.com/babel/babel-jest/blob/77a24a71ae2291af64f51a237b2a9146fa38b136/index.js
Note also: when you working with jest preprocessor you should clean cache:
$ rm node_modules/jest-cli/.haste_cache -r
Taking inspiration from Misha's response, I created an NPM package that solves this problem while also handling a few more scenarios I came across:
webpack-babel-jest
Hopefully this can save the next person a few hours.
If you're using babel, you can strip unwanted imports during the babel transform using something like https://github.com/Shyp/babel-plugin-import-noop and configuring your .babelrc test env to use the plugin, like so:
{
"env": {
"development": {
...
},
"test": {
"presets": [ ... ],
"plugins": [
["import-noop", {
"extensions": ["scss", "css"]
}]
]
}
}
}
We had a similar problem with CSS files. As you mentioned before jest-webpack solves this problem fine. You won't have to mock or use any module mappers either. For us we replaced our npm test command from jest to jest-webpack and it just worked.
Webpack is a great tool, but I don't need to test it's behavior with my Jest unit tests, and adding a webpack build prior to running unit tests is only going to slow down the process. The text-book answer is to mock non-code dependencies using the "moduleNameMapper" option
https://facebook.github.io/jest/docs/webpack.html#handling-static-assets