Jest encountered an unexpected token + react markdown - reactjs

I'm getting an error when trying to run my test file (I'm using react typescript)
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
• 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/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
export {uriTransformer} from './lib/uri-transformer.js'
^^^^^^
SyntaxError: Unexpected token 'export'
5 | const Markdown = ({ text, classStyle }: ITextMedia) => (
6 | <div className={`${classes.mediaParagraph} ${classStyle ?? ''}`}>
> 7 | <ReactMarkdown>{text}</ReactMarkdown>
| ^
8 | </div>
9 | );
10 | export default Markdown;
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
at Object.<anonymous> (components/media/markdown/index.tsx:7:45)
I already tried adding the React markdown to the transform ignore patterns, but it still doesn't work
here's my jest.config
{
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
'next/router': '<rootDir>/__mocks__/next/router.js',
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
'^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$': '<rootDir>/__mocks__/file-mock.js',
},
transform: {
'^.+\\.(js|jsx)$': 'babel-jest'
},
transformIgnorePatterns: [
'node_modules/(?!react-markdown/)'
]
}
my babel config:
{
"presets": [
"next/babel",
"#babel/preset-env"
],
"plugins": []
}
I'm new to jest, so I'm not sure if I'm doing something wrong

In the jest.config file, you need to add the following to the moduleNameMapper attribute:
"react-markdown": "<rootDir>/node_modules/react-markdown/react-markdown.min.js"
So effectively, your moduleNameMapper should really look like this:
...
moduleNameMapper: {
'next/router': '<rootDir>/__mocks__/next/router.js',
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
'^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$': '<rootDir>/__mocks__/file-mock.js',
'react-markdown': '<rootDir>/node_modules/react-markdown/react-markdown.min.js',
},
...
Good luck!

Related

After updating the query-string library, test:ci now fails

The development environment uses next.js 13.
After updating the query-string library to 8.1, test:ci now fails.
It fails at the following point.
before "query-string": "^7.1.0",
after "query-string": "^8.1.0",
error
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as queryString from './base.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Changed part.
before
import { stringifyUrl } from 'query-string';
.
. omission
.
stringifyUrl({url})
after
import queryString from 'query-string';
.
. omission
.
queryString.stringifyUrl({ url })
I am very troubled.
If anyone knows how to solve this problem, please let me know.
added
module.exports = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!**/*.d.ts'],
moduleDirectories: ['node_modules', 'src'],
moduleNameMapper: {
// Handle CSS imports (with CSS modules)
// https://jestjs.io/docs/webpack#mocking-css-modules
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// Handle CSS imports (without CSS modules)
'^.+\\.(css|sass|scss)$': '<rootDir>/src/__mocks__/styleMock.ts',
// Handle image imports
// https://jestjs.io/docs/webpack#handling-static-assets
'^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/src/__mocks__/fileMock.ts`,
// Handle ESM packages
'^react-markdown$': '<rootDir>/src/__mocks__/react-markdown.tsx',
},
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jest-environment-jsdom',
transform: {
// Use babel-jest to transpile tests with the next/babel preset
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
};
The issue is query-string version 8 introduced a breaking to consuming applications because their dependencies upgraded to ESM. See their release notes here:
v8.0.0
Breaking
Require Node.js 14
This package is now pure ESM. Please read this.
Add "module": "node16", "moduleResolution": "node16" to your
tsconfig.json.
(Example)
And more!!!
It appears Jest in trying to use import but it's not configured to do so. Jest also provides some guidance for how to deal with this: https://jestjs.io/docs/ecmascript-modules
Since you're using Next.js, those steps don't really apply.
I'm reproducing and testing in a sandbox... Will update shorty.
For React apps:
Try setting "type": "module" inside package.json.
You should also update your package.json test script to:
"test": "node --experimental-vm-modules ./node_modules/.bin/jest"
Now inside jest.config.js you'll want to export transform: {}:
export default {
transform: {}
}
After all those steps, you should no longer have this issue.

React with TypeScript using tsyringe for dependency injection

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>
}

Babel Standalone Invalid plugin #babel/plugin-proposal-decorators

I am trying to use babel standalone inside a react app to transpile Angular TypeScript.
The short version:
How can I use #babel/plugin-proposal-decorators and #babel/plugin-proposal-class-properties with babel standalone?
The long version:
This tutorial https://medium.com/#hubert.zub/using-babel-7-and-preset-typescript-to-compile-angular-6-app-448eb1880f2c says that "apparently #babel/plugin-syntax-decorators doesn’t do the work and causes transform errors.". He recommends using the following config in a babelrc file:
{
"presets": [
"#babel/preset-env",
"#babel/preset-typescript"
],
"plugins": [
[
"#babel/plugin-proposal-decorators",
{
"legacy": true,
}
],
"#babel/plugin-proposal-class-properties"
]
}
using syntax-decorators does "work" for me but then I get another error that it does not recognise a selector for an imported component.
Since I am using babel standalone I need to use Babel.transform like this:
const TS_OPTIONS = {
presets: [
'typescript',
['es2017', { 'modules': false }],
],
plugins: [
// the following two options "work" but with another error
// 'syntax-decorators',
// 'syntax-class-properties',
// none of these options work
["#babel/plugin-proposal-decorators"],
["#babel/plugin-proposal-class-properties"],
//['plugin-proposal-decorators', { 'legacy': true }],
//['plugin-proposal-class-properties', { 'loose': true }],
// 'plugin-proposal-decorators',
// 'plugin-proposal-class-properties',
// ['syntax-decorators', { 'legacy': true }],
'transform-es2015-modules-commonjs',
],
};
my transpile function (greatly simplified):
export default function transpile(myCode) {
const { code } = Babel.transform(myCode, TS_OPTIONS);
return myCode;
}
No matter how I write the plugins it does not work. I keep getting an error along the lines of
Error: Invalid plugin specified in Babel options: "proposal-decorators"
using the syntax-decorators plugin will transpile the code but I get the following error when importing a component and trying to use the components selector:
Uncaught Error: Template parse errors:
'search-bar' is not a known element:
1. If 'search-bar' is an Angular component, then verify that it is part of this module.
2. If 'search-bar' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component to suppress this message.
I solved this by upgrading the version of Babel I was using which gave me access to more available plugins. I posted another question that I thought was a different issue but it turns out they were related. I will reference that question here if anyone is interested: Angular Uncaught Error: Template parse errors: is not a known element
with babel-standalone .babelrc wont work .you might need to use transform to apply plugins .i am wondering why you exactly need to use standalone babel ?. if its react or angular you can just use babel only and don't need to use transform

Test suits failed with "SyntaxError: Unexpected token 'export" ' react typescript using jest

i setup jest and enzyme in my react-typescript project. In this project i'm not using babel.
i tried to run basic component and its working well.
After that i added another component,and added our custom react-typescript based lib in this component(cc-react-common-lib).
when i include cc-react-common-lib, jest throws following error
SyntaxError: Unexpected token 'export'
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:
• 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:
/home/convertcart/projects/intelli-blocks/node_modules/cc-react-common-lib/lib/index.js:1
export { default as TableSpaced } from './general/table-spaced';
^^^^^^
SyntaxError: Unexpected token 'export'
1 | /* eslint-disable jsx-a11y/control-has-associated-label */
2 | import React, { useState, useEffect } from 'react';
> 3 | import {
| ^
4 | TextField,
5 | useAjaxForm,
6 | Spacer,
I try to solve this error past1 week, but i can't find any solution
jest.config.js:
module.exports = {
// The root of your source code, typically /src
// `<rootDir>` is a token Jest substitutes
roots: ['<rootDir>'],
// Jest transformations -- this adds support for TypeScript
// using ts-jest
// transform: {
// "^.+\\.tsx?$": "ts-jest"
// },
preset: 'ts-jest',
// maxConcurrency:30,
// Runs special logic, such as cleaning up components
// when using React Testing Library and adds special
// extended assertions to Jest
// setupFilesAfterEnv: [
// "#testing-library/react/cleanup-after-each",
// "#testing-library/jest-dom/extend-expect"
// ],
// Test spec file resolution pattern
// Matches parent folder `__tests__` and filename
// should contain `test` or `spec`.
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
// Module file extensions for importing
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
snapshotSerializers: ['enzyme-to-json/serializer'],
setupFilesAfterEnv: ['<rootDir>/setupEnzyme.ts'],
};
setupEnzyme.js:
/* eslint-disable import/no-extraneous-dependencies */
import Enzyme from 'enzyme';
import ReactSixteenAdapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new ReactSixteenAdapter() });
Update: when i add following lines in jest.confi.js file
transform: {
'^.+\\.tsx?$': 'babel-jest',
},
following Error message coming:
● Test suite failed to run
SyntaxError: /home/convertcart/projects/intelli-blocks/client/__tests__/editblock.test.tsx: Support for the experimental syntax 'jsx' isn't currently enabled (8:29):
6 | console.log("Edit block test");
7 | it('Renders and Simulates Click Event ', () => {
> 8 | const Wrapper = shallow(<EditBlock />);
| ^
9 | const checkbox = () => Wrapper.find({ type: 'checkbox' });
10 | expect(checkbox().props().checked).toBe(false);
11 | checkbox().simulate('change', { target: { checked: true } });
Add #babel/preset-react (https://git.io/JfeDR) to the 'presets' section of your Babel config to enable transformation.
If you want to leave it as-is, add #babel/plugin-syntax-jsx (https://git.io/vb4yA) to the 'plugins' section to enable parsing.
at Parser._raise (../node_modules/#babel/parser/src/parser/error.js:60:45)
at Parser.raiseWithData
if you are running the test via a code editor plugin, try configuring the plugin test command within the editor to ensure the plugin executes the right command.
for e.g. i am using vscode, jestrunner plugin, and yarn package manager. so i included the following line inside my workspace settings.json file:
{
"jestrunner.jestCommand": "yarn react-scripts test"
}
the same error got resolved. hope it works for you :)

How to use jest with webpack?

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

Resources