npm i -D jest typescript ts-jest @types/jest react-test-rendererjest.config.js with following content:module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
};
tsconfig.json with the following content:{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"exclude": [
"node_modules"
],
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
]
}
NOTE: this is the default generated by next.js when it determines you're using typescript
__tests__/index.test.tsx with the following contents:import React from 'react';
import TestRenderer from 'react-test-renderer';
import Index from '../pages/index';
describe('Index', () => {
it('should render without throwing an error', () => {
const testRenderer = TestRenderer.create(<Index />);
expect(testRenderer.toJSON()).toMatchSnapshot();
});
});
package.json --> "test": "jest"npm run testAt this point you should see the following error:
● 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:
• 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/mar/NodeJSProjects/lawn-box/__tests__/index.test.tsx:11
var testRenderer = react_test_renderer_1.default.create(<index_1.default />);
^
SyntaxError: Unexpected token <
You expect the test to be transformed and pass.
This issue is caused because jsx is not being transformed and jest doesn't know how to parse it. The fix is very simple, in your tsconfig.json you need to set the "jsx" key to "react" rather than "preserve". Unfortunately next's build expects it to be "preserve" and automatically changes it back in tsconfig.json :( The way I got around this was to create a seperate tsconfig.jest.json. Here are the steps:
tsconfig.jest.json with the following contents:{
"extends": "./tsconfig.json",
"compilerOptions": {
"jsx": "react"
}
}
NOTE: here we are extending the base tsconfig so most of our settings are getting applied, and simply overriding the "jsx" key.
jest.config.js to use our new tsconfig.jest.json:module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
globals: {
// we must specify a custom tsconfig for tests because we need the typescript transform
// to transform jsx into js rather than leaving it jsx such as the next build requires. you
// can see this setting in tsconfig.jest.json -> "jsx": "react"
"ts-jest": {
tsConfig: "tsconfig.jest.json"
}
}
};
npm run testNote to the maintainers: Feel free to close this issue, hoping it will help others who may run into this.
Maybe it should be (part of) one of the examples?
Yes it should be documented. I spent some time to figure that out myself
Can we assure that the result is always same?
if jsx field is preserve as you know, it passes the role of parsing jsx to next parser weather typescript parse the jsx when jsx field is react.
@codemilli I'm guessing here but I think next's parser is just wrapping the typescript compiler when it finds that you have a tsconfig.json. So if you set up ts-jest to use the same config you should be alright.
I'm guessing here but I think next's parser is just wrapping the typescript compiler when it finds that you have a tsconfig.json
We use @babel/preset-typescript to compile the code and don't actually need a tsconfig.json, however for consistency and integration with code editors like vscode we force the tsconfig to have the exact same settings as the way that we compile. We also do type checking in parallel which does use tsc but that is only for type checking and not compiling the code.
I also don't think you need ts-jest in particular if babel is ran against the test code correctly
@codemilli there's your answer as to how nextjs is compiling typescript ^. They're using babel with a typescript preset vs. tsc so you're not likely going to get the exact same result. I would hope that @babel/preset-typescript is transpiling to near the same output however.
As far as not using ts-jest, we would need some way to tell jest to plug in to the babel config then, and transpile with babel prior to attempting to run tests. Is there any documentation for how to do that?
You should be able to simply add a .babelrc like this example.
If you add the .babelrc and jest.config.js and jest.setup.js like the example, you simply need jest, @types/jest and then renderer of your choice (enzyme or react-test-renderer).
Running jest just works at that point.
We just landed a new Jest example.
We just landed a new Jest example.
Link?
I think Jest Test Environment would be jsdom instead of node.
testEnvironment: "jsdom",
I encounter the following error if I don't import React in both page.tsx and page.spec.tsx:
'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.
Any ideas?
@mehmetnyarar , I'm not 100% sure if that problem is related to this issue, but if you're having trouble using Nextjs with Jest, you can try out the boilerplate that I've made: https://github.com/Prottoy2938/nextjs-typescript-eslint-jest-template.git
Its a boilerplate where it has the basic configuration for Nextjs with TypeScript, ESLint and Jest
@mehmetnyarar I am getting the same error as you did. Did you find a workaround? I have a year-old Next.js app and have never specifically imported React but it seems with jest I have to do it... Seems like there must be a way around this.
Most helpful comment
Maybe it should be (part of) one of the examples?