I followed a JavaScript unit testing tutorial at acadamind.com in that tutorial instructor used Vitest for demonstrations and the reason they mentioned using Vitest instead of Jest was Jest needed some extra configuration to work with the latest JavaScript syntax.
After doing my own research about unit testing I realized industry demand unit testing skills with the Jest. So I followed another tutorial for learning unit testing with Jest and React Testing Library (RTL).
I created a brand new TypeScript project with Create React App (CRA) and followed the instructions in that tutorial and everything went well. The instructor mentioned that Jest and RTL are supported out of the box with CRA.
After studying unit testing I tried to apply that knowledge and write some tests with my application, which was created some time back, and recently we updated it to React Scripts 5. In that application, I check node_modules folder, and Jest is there as a dependency. But I have noticed that the following packages are not listed in the package.json file in my project, so I installed them:
#testing-library/jest-dom": "^5.16.5",
#testing-library/react": "^13.4.0",
#testing-library/user-event": "^14.4.3",
#types/jest": "^29.4.0",
After that, I noticed my new project has this file in the src folder so I have copy pasted this file as well.
setupTest.ts
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '#testing-library/jest-dom';
When I tried to run when I tried to write my first unit test I noticed that VS Code doesn't recognize this test function as a global function and indicates an error and then I try to run the test script and I am getting this error
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:
/home/pathum/Documents/tagd/node_modules/axios/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import axios from './lib/axios.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
> 1 | import axios from 'axios';
| ^
2 | // config
3 | import { HOST_API } from '../config';
4 |
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
at Object.<anonymous> (src/utils/axios.ts:1:1)
at Object.<anonymous> (src/hooks/useRefresh.tsx:2:1)
at Object.<anonymous> (src/hooks/useAxiosPrivate.tsx:3:1)
at Object.<anonymous> (src/pages/contracts/contract-form/new-contact-person.tsx:12:1)
at Object.<anonymous> (src/pages/contracts/contract-form/parties.tsx:15:1)
at Object.<anonymous> (src/pages/contracts/contract-form/contract-form.tsx:9:1)
at Object.<anonymous> (src/pages/contracts/contract-form/contract-form.test.tsx:2:1)
at TestScheduler.scheduleTests (node_modules/#jest/core/build/TestScheduler.js:333:13)
at runJest (node_modules/#jest/core/build/runJest.js:404:19)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 2.398 s
Ran all test suites related to changed files.
Watch Usage: Press w to show more.
Seems I need to do some configurations for Jest to work properly in the application. How do I fix this?
Install the necessary dependencies: npm install --save-dev #babel/preset-typescript and npm install --save-dev jest-cli typescript
Create a new file in the root of your project called jest.config.js and add the following content to it:
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
};
Add a new property called "jest" to the "scripts" section of your package.json file and set it to the following: "jest --config jest.config.js --coverage". This will tell Jest to use the configuration file you just created and also generate a coverage report.
Create a new file in the root of your project called tsconfig.test.json and add the following content to it:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./test-dist"
},
"include": [
"src/**/*.test.ts"
]
}
Finally, you can run your tests with npm run jest.
You also need to make sure that you are using import statement correctly in your tests. You should use import statement to import functions, classes, and variables from other modules, but you should use require statement to import modules that are not written in TypeScript.
Related
I have used JavaScript to created a simple web application to measure how much time I spend on different projects.
I want to test the code with Jest and this works fine until I try to test a function that contains the JQuery object ($).
This is the error message I get:
ReferenceError: $ is not defined
The answers I have found online tells me that I need to add a jQuery dependency in my global object, which I have done. Below is my package.json file:
"jest": {
"setupFiles": ["PathToSetupFile/setup-jest.js"],
"type": "module"
and my setup-jest.js:
import $ from 'jquery';
global.$ = global.jQuery = $;
I am now met with a new error message:
SyntaxError: Cannot use import statement outside a module
I cannot find any further information on how to fix this. A few resources tell me I need to update my jest.config.js file but this file does not exist anywhere in my node modules.
I thought it would be helpful to start completely from the beginning and therefore address a much wider scope but never the less provide the exact answer to your problem at the end of my response here.
In PowerShell CD to your project folder
Install the jest node modules locally into your project folder using
npm install --save-dev jest
Install jest globally so you can use it as a CLI command
npm install jest -g
This installs Jest globally i.e. to your user profile %APPDATA%\npm location
Ensure %APPDATA%\npm is in your user profile environment PATH variable (in Windows settings, "Edit Environment variables for your account")
Check in your PowerShell console that it is in your path using $Env:PATH. (If your %APPDATA%\npm path still isn't showing then restart the PowerShell window, if the terminal is inside VSCode then you will have to restart VSCode so that the terminal inherits the new environment)
In order to import jquery you will need to a) install jquery and b) define a setup file for jest which is referenced in jest.config.js created using jest --init in your project folder.
Install jquery -
npm install --save-dev jquery
Generate jest.config.js -
jest --init
The following questions will help Jest to create a suitable configuration for your project
√ Would you like to use Typescript for the configuration file? ... no
√ Choose the test environment that will be used for testing » jsdom (browser-like)
√ Do you want Jest to add coverage reports? ... yes
√ Which provider should be used to instrument code for coverage? » v8
√ Automatically clear mock calls, instances, contexts and results before every test? ... yes
✏️ Modified your\project\folder\package.json
📝 Configuration file created at jest.config.js
If you don't specify the jsdom (browser-like) test environment then running code under test that uses jquery will yield an error of "jQuery requires a window with a document"
But this means the 'jest-environment-jsdom' must now be installed
(As of Jest 28 "jest-environment-jsdom" is no longer shipped by default, make sure to install it separately.) -
npm install --save-dev jest-environment-jsdom
Edit jest.config.js
Change
// setupFiles: [],
To
setupFiles: [ './jest.setup.js' ],
N.B. the "./" prefix is required otherwise jest will state it cannot find the jest.setup.js file.
The create jest.setup.js in your project folder and add the following -
const $ = require('jquery');
global.$ = global.jQuery = $;
Node uses the CommonJS module system (https://nodejs.org/en/knowledge/getting-started/what-is-require/)
so the above syntax is required to work with Node.js
I'm new to unit test in JavaScript, and I'm trying to write a unit test to a Next JS project, but I got this error in response:
Code:
import {isBase64} from '../../service/base64-service'
test('should return false for a invalid base64 string', () => {
expect(
isBase64('YWJj')
)
.toBe(false);
}
)
Error:
● 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
I found out what I needed to do, the answer was on the documentation 😅:
#1: add this dependence:
yarn add --dev #babel/plugin-transform-modules-commonjs
#2: Edit the .babelrc file:
if you don't have it, create it at the root folder
{
"presets": ["next/babel"],
"env": {
"test": {
"plugins": ["#babel/plugin-transform-modules-commonjs"]
}
},
"plugins": []
}
And now your unit test is going to work with import statements as well 🥰
I'm trying to migrate an NX monorepo from Angular 12 to Angular 13. As part of this migration, Jest is also updated to version 27.2.3. the project is also using a custom editor build of CKEditor5.
When CKEditor was first integrated (back when the project was using Angular 9 I believe) we had a lot of issues getting it to work with Jest and whenever the unit tests were ran, any component that included CKEditor was giving the error message:
SyntaxError: Cannot use import statement outside a module
We managed to fix the issue by adding the following configuration to the global jest.preset.js file in the root of the project:
transform: {
'node_modules[\\\\/]#ckeditor.+.(js)$': 'babel-jest',
'^.+.(ts|html)$': 'ts-jest',
},
transformIgnorePatterns: ['/node_modules/(?!#ckeditor|lodash).+.(js|jsx|ts|tsx|svg)$'],
However, now that we are migrating from Angular 12 to 13, the above error message has returned and it seems the above config is now ignored.
As part of the migration, NX has automatically created new project.json files in all of the libs in the monorepo. This file contains some Jest configuration so I have tried moving the config above from the jest.preset.js file to the individual project.json files in any lib using CKEditor, but this has not fixed the issue. The new project.json files also read some Jest config from a project-specific jest.config.js so I have tried adding the config there as well, and that has also not fixed the issue.
I have also tried updating the testEnviroment config in package.json from "node" to "jsdom" and this has not helped either. I also tried moving the whole transform/transformIgnorePatterns config to Jest section of package.json and that also did not help.
I assume my previously working config just need to move to a different file, it is just not clear which file it needs to move to.
My environment is as follows:
Windows 10
Node 16.13.2
NPM 8.1.2
NX 13.4.5
Jest 27.2.3
Angular 13.1.2
This was fixed by adding the following config to the Jest preset file, and removing same config from individual apps/libs configs:
transform: {
'node_modules[\\\\/]#ckeditor.+\\.(js)$': 'babel-jest',
'^.+\\.(ts|js|mjs|html|svg)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*.mjs$|#ckeditor)'],
Problem was related to having multiple strinfs inside transformIgnorePatterns - it supports only one item despite being an array
I'm trying to export a Vue component as a package, and using vue cli to build the dist. I intend to publish it on npm, but I'm currently using a symbolic link for testing purpose. However even with a simple hello-world project I can't make a valid package.
I created a project:
vue create hello-world
Then I modified the package.json:
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build --target lib --name vue-hello-world ./src/components/HelloWorld.vue",
"lint": "vue-cli-service lint"
},
"main": "./dist/vue-hello-world.common.js",
Then I call
npm run build
and it compiles without error.
Then I make an import in a vue component in another project (I used a symbolic link in node_modules):
import HelloWorld from "hello-world";
On page render I get the following error:
[Vue warn]: Failed to resolve async component: function MediaViewerPdf() {
return Promise.all(/*! import() */[__webpack_require__.e(62), __webpack_require__.e(46)]).then(__webpack_require__.bind(null, /*! ./viewers/MediaViewerPdf.vue */ "./vuejs/components/mediaViewer/viewers/MediaViewerPdf.vue"));
}
Reason: ReferenceError: require is not defined
Any idea what's happening?
Remarks:
using vue inspect, I checked that in webpack config that:
target: "web"
I already set resolve.symlinks at false on the importing project.
EDIT: I have confirmed that it doesn't come from the symbolic link, I have exactly the same error with package directly on node_modules.
Repo with whole code: https://github.com/louis-sanna/vue-hello-world
So I asked the question on the vue-cli repo and I got the solution! https://github.com/vuejs/vue-cli/issues/4245
Turns out NODE_ENV was already set at development in my shell, so it was the mode used to make the build.
Just need to set the mode explicitly and it works:
vue-cli-service build --target lib --name vue-hello-world ./src/components/HelloWorld.vue --mode production
You may need to add it to vue.config.js:
config
.mode("production")
This happens due to the fact that Vue CLI Webpack setup by default does not import commonjs modules, as described in your "main" field in package.json. So the problem is with the project that attempts import, not with the project that exports the component.
There are two ways to attempt to solve this problem.
From the importing project side
You can remedy this by installing babel plugins for the project that imports your components and setting babel.config.js
module.exports = {
presets: [
'#vue/app'
],
plugins: [
'#babel/plugin-transform-modules-commonjs', // leave to import .common.js files
'#babel/plugin-transform-modules-umd' // leave to import .umd.js files
]
}
But doing this alone will not be sufficient: you also will need to import CSS that is generated with the library by adding this in your entry file
import 'hello-world/dist/vue-hello-world.css';
Note that I have only tested this using yarn link, but I have confidence that this will work with an imported separate npm module just fine.
From the library side
The intent (I suppose) of the original question - how do I bundle a library so my users don't have to do this little dance each time they want to use it?
Option 1: don't bundle it - provide .vue files and sources. Just include everything in 'src' directory of your module, write a readme with explanation and be done with it. Let the importing project figure the compilation and bundling out.
Option 2: use rollup with Vue plugin to roll components into bundle. There is an example on how to do that. In that example you can see that your project will be able to import .esm build
https://github.com/vuejs/rollup-plugin-vue/tree/master/cookbook/library
Not sure how you are creating the symbolic link, but you should use npm link for that. If you are still having problems (like I did myself) I would suggest you try npm-link-better:
npm install -g npm-link-better
cd vue-hello-world
npm link
cd ../hello-world
nlc -w vue-hello-world
For building component libraries, I suggest you have a look at vue-cli-plugin-component. This plugin already sets up the vue-cli project pretty well.
I'm trying to follow the official Angular docs to set up testing for an Angular project - https://angular.io/guide/testing#service-tests
I've downloaded the sample Angular project from the page above, using the first (top) link. I've done an npm install and when I run ng serve it builds fine.
When I run ng test using the CLI, I get the message:
ERROR in Entry module not found: Error: Cant' resolve 'C:Code\testing\src\test.ts' in 'C:\Code\testing'
ERROR in error TS6053: File 'C:Code\testing\src\test.ts' not found.
I looked at this question - How to resolve test.ts when running ng test?, but in that case the file actually exists, but in the Angular example project it doesn't exist at all.
(When I first ran ng test I originally got a message about Jasmine Marbles being missing, which I resolved using:)
npm install jasmine-marbles --save
The documentation says:
You can fine-tune many options by editing the karma.conf.js and the
test.ts files in the src/ folder.
So I know the test.cs is some kind of configuration file, but how do I generate it? It doesn't exist in the Angular 'live example' project either. And how do I know that a test.cs I generate will work reliably with this project?
I used #joshbaeha's suggestion to ng new a new Angular 5 project and copied the test.ts file, which appears to be completely generic and not reliant on project structure or anything else. Everything is now working. Here it is:
test.ts
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '#angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '#angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
I don't know whether you can generate just the test.ts file or not, but as far as i know this file is automatically generated when you create a new angular project using angular-cli. So you can just create a new project using angular-cli then copy the src/test.ts file from that new project