Why Does This Happen?
When running Jest tests with tsx
(or jsx
) React components, you might encounter the "SyntaxError: Unexpected token '<'
" error like the following:
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: /path/to/__tests__/MyComponent.test.tsx:27 (0, react_2.render)(<client_1.MyComponent foo="bar"> ^ SyntaxError: Unexpected token '<' at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)
This error indicates that Jest is unable to parse the file due to non-standard JavaScript syntax or inadequate configuration. The "'<'
" in the error message suggests that Jest is not able to transpile code in a tsx
(or jsx
) file because it might not be configured to do so.
How to Fix the Issue?
To fix this issue you need to make sure Jest is configured to transpile the code in a tsx
(or jsx
) file. You can do so by checking for the following configurations:
- You're Using the Right Transformer;
- You're Using the Right Jest Testing Environment;
- You're Using the Right "
jsx
" Mode intsconfig.json
.
Choosing the Right Transformer
You can use babel-jest
or ts-jest
as a transformer:
Using babel-jest
as the Transformer
You should use babel-jest
as a transformer in the following cases:
- When you have
jsx
files, or; - When you have
tsx
files, but do not want to type-check your tests as they are run.
To set it up, you need to first install the following packages:
npm install --save-dev babel-jest @babel/core @babel/preset-typescript @babel/preset-env
After that, you must create a babel.config.js
file (or .babelrc
) with a minimum configuration like the following:
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};
@babel/preset-typescript
is only required for transpiling TypeScript code (tsx
files). For jsx
files, you can exclude it.
Based on the Babel configuration, Jest will automatically transpile tsx
(or jsx
) files. However, if you wish, you can explicitly define babel-jest
as a transformer for these files in your jest.config.js
:
// jest.config.js
module.exports = {
// ...
testEnvironment: 'jsdom',
transform: {
'^.+\\.tsx?$': 'babel-jest',
},
// ...
}
Using ts-jest
as the Transformer
You should use ts-jest
as a transformer when you have tsx
files and want to type-check your tests as they are run.
Although, by default ts-jest
performs type-checking, it is possible to disable it by passing isolatedModules: true
as an option.
To set it up, you need to first install the following packages:
npm install --save-dev ts-jest @types/jest
After that, you need to add the following settings to your jest.config.js
file:
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
};
If this setting does not work for you, as an alternative, you can try explicitly setting ts-jest
as the transformer for tsx
files:
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
};
Ensuring the Right Jest Test Environment
By default, jest uses the "node
" as the test environment, making tests meant for a browser environment invalid. Therefore, you must set testEnvironment
to jsdom
in your jest.config.js
file, like so:
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
// ...
};
This ensures a browser-like environment for tests that are meant for a browser environment.
Make sure you have the jest-environment-jsdom
package installed for this to work.
Ensuring the Right "jsx
" Mode in tsconfig.json
In your tsconfig.json
file, you must ensure that you're using the right value for the "compilerOptions
" "jsx
" property, i.e. one of the following:
jsx Mode |
Description | Use When |
---|---|---|
"jsx": "preserve" |
This will preserve the tsx (or jsx ) code so that it can be transpiled later by another transformer (such as Babel). The output will have a .jsx extension.
|
Use this when you're using babel-jest to transpile your tsx (or jsx ) files. |
"jsx": "react-native" |
Same as the "preserve " option, but the output will have a .js extension.
|
|
"jsx": "react" |
This will emit React.createElement() and serve .js files. It does not need to go through any further transpiling later.
|
Use this when you're using ts-jest to transpile your tsx (or jsx ) files. |
"jsx": "react-jsx" |
Same as the "react " option, but relevant for React 17+. It helps you avoid the necessity of importing React in every jsx file.
|
|
"jsx": "react-jsxdev" |
Same as the "react-jsx " option, but uses "react/jsx-dev-runtime " in the transformed code (instead of "react/jsx-runtime ") to add debugging information.
|
You must specify one of these "jsx
" options in the "compilerOptions
" in your tsconfig
file, like so:
// tsconfig.json
{
"compilerOptions": {
"jsx": "react",
// ...
This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.