Vite / Jest / React-Testing - javascript

I am trying to test in React application with Jest; my application uses Vite as a module bundler. The issue is, every time I run tests I get the following error:
> react-test#0.0.0 test
> jest
FAIL src/test/App.test.jsx
● 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:
SyntaxError: C:\Users\Tomas\Desktop\react-test\src\test\App.test.jsx: Support for the experimental syntax 'jsx' isn't currently enabled (8:30):
6 |
7 | test("renders content", ()=>{
> 8 | const component = render(<App></App>)
| ^
9 | console.log(component)
10 | })
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:150:45)
at Parser.raiseWithData (node_modules/#babel/parser/src/parser/error.js:145:17)
at Parser.expectOnePlugin (node_modules/#babel/parser/src/parser/util.js:214:18)
at Parser.parseExprAtom (node_modules/#babel/parser/src/parser/expression.js:1238:16)
at Parser.parseExprSubscripts (node_modules/#babel/parser/src/parser/expression.js:682:23)
at Parser.parseUpdate (node_modules/#babel/parser/src/parser/expression.js:662:21)
at Parser.parseMaybeUnary (node_modules/#babel/parser/src/parser/expression.js:633:23)
at Parser.parseMaybeUnaryOrPrivate (node_modules/#babel/parser/src/parser/expression.js:388:14)
at Parser.parseExprOps (node_modules/#babel/parser/src/parser/expression.js:398:23)
at Parser.parseMaybeConditional (node_modules/#babel/parser/src/parser/expression.js:356:23)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 1.379 s
Ran all test suites.
Package.json
{
"name": "react-test",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "jest"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"jest": {
"verbose": true,
"testEnvironment": "jsdom",
"transform": {
"^.+\\.(js|jsx)$": "babel-jest"
},
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleNameMapper": {
"\\.(gif|ttf|eot|svg|png)$": "<rootDir>/test/__mocks__/fileMock.js",
"\\.(css|less|sass|scss)$": "identity-obj-proxy"
}
},
"devDependencies": {
"#babel/plugin-syntax-jsx": "^7.16.7",
"#testing-library/jest-dom": "^5.16.2",
"#testing-library/react": "^12.1.3",
"#types/jest": "^27.4.1",
"#vitejs/plugin-react": "^1.0.7",
"jest": "^27.5.1",
"vite": "^2.8.0"
}
}
App.test.jsx
import React from "react";
import "#testing-library/jest-dom/extend-expect"
import { render } from "#testing-library/react";
import App from "../App.jsx";
test("renders content", ()=>{
const component = render(<App></App>)
console.log(component)
})

The error output is correct, Jest runs on your local node binary and requires that your jsx files be transformed into a syntax it can understand.
Vite does not so this transformation by default. It was designed to transpile and bundle your code into some bundle.js that is appropriate for the browser (it can do other types of output, like libraries. You'd need to tweak your vite.config.js).
Luckily, other folks have solved this problem for you. I'd recommend using vitest, since you wouldn't need to download another transformer or invest a lot of time into setting up tricky build scripts.
Here's a guide on how to quickly set it up:
https://www.eternaldev.com/blog/testing-a-react-application-with-vitest/
And a migration guide:
https://vitest.dev/guide/migration.html

Related

How to import js module when Typescript declaration file is located in a separate directory?

Question:
When I run npm run build with the configuration below, rollup.js is unable to resolve the dependency (import) and displays the following message below. Is there any way to make rollup happy while also referencing the Typescript declaration file?
Message from rollup:
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
pdfjs-dist/types/web/ui_utils (imported by index.ts)
Here is my index.ts:
import { RendererType } from 'pdfjs-dist/types/web/ui_utils'
const renderType = RendererType.CANVAS;
My package.json:
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rollup --config"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#rollup/plugin-node-resolve": "^13.2.1",
"#rollup/plugin-typescript": "^8.3.2",
"pdfjs-dist": "^2.13.216",
"rollup": "^2.70.2",
"typescript": "^4.6.4"
}
}
My rollup.config.js:
import typescript from '#rollup/plugin-typescript';
import { nodeResolve } from '#rollup/plugin-node-resolve';
export default [
{
input: 'index.ts',
output: {
format: 'es',
file: 'index.js'
},
plugins: [
typescript(),
nodeResolve({ browser: true })
]
}
]
Here are the exact steps to reproduce the error above:
Create an empty folder and then run npm -y init
Run the following command:
npm install typescript pdfjs-dist rollup #rollup/plugin-node-resolve #rollup/plugin-typescript --save-dev
Add "build": "rollup --config" to your package.json
Create the rollup.config.js file shown above
Run npm run build in the terminal
More background:
Now, I should point out that the file pdfjs-dist/types/web/ui_utils is a typescript declaration file (ui_utils.d.ts). The actual js file is in pdfjs-dist/lib/web.
If I copy the typescript declaration file so that it is located in the same directory as the js file, dependency resolution works. However, since I will be writing a wrapper around pdf js, I would have to do this for every typescript declaration file which is very tedious and upgrading would also become an issue.
So another way to word the question would be how to resolve a module *.d.ts when the js file is located in another directory?
I came up with the following solution to the problem.
Create a d.ts with the following and name it the same as the module name (ui_utils.d.ts in my case)
declare module 'pdfjs-dist/lib/web/ui_utils' {
export * from 'pdfjs-dist/types/web/ui_utils'
}
Using the above, now I can reference the actual location of the module and Typescript will pick up the declarations as well.
import { RendererType } from 'pdfjs-dist/lib/web/ui_utils'
Side note: When using rollup, you may also need to use #rollup/plugin-commonjs to be able to resolve dependencies.

Making NPM package available to ES6 and ECMAScript

I'm making an NPM package in TypeScript, and wanted to know how I can make it available for ES and Node modules.
I've set it up with Rollup and a few configs:
rollup.config.js
export default {
input: 'build/kimp.js', // built from TS
output: [
{
file: 'dist/main/kimp.js',
format: 'es',
strict: false,
name: 'module',
banner: `#! /usr/bin/env node - Copyright 2020 Herbie Vine - Updated: ${new Date()}`
},
{
file: 'dist/module/kimp.js',
format: 'umd',
strict: false,
name: 'common',
banner: `#! /usr/bin/env node - Copyright 2020 Herbie Vine - Updated: ${new Date()}`
}
],
plugins: [
terser(),
resolve(),
json(),
commonjs({
include: 'node_modules/**'
})
],
external: [
'crypto'
]
};
package.json
{
"name": "kimp",
"version": "1.0.0",
"description": "Lightweight ID generator",
"sideEffects": false,
"main": "dist/main/kimp.js", // import() - es6
"module": "dist/module/kimp.js", // require() - node
"scripts": {
"build": "tsc -p ./src/tsconfig.json",
"rollup": "rollup -c"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com/"
},
"keywords": [...],
"repository": {...},
"author": "Herbie Vine",
"license": "MIT",
"bugs": {...},
"homepage": "https://github.com/herbievine/kimp#readme",
"devDependencies": {...}
}
I tried using it in an express app, but I get an error:
const { kimp } = require('kimp');
console.log(kimp)
------
C:\Users\**\kimp-ts\dist\main\kimp.js:3484
export { kimp };
^^^^^^
This is coming from the built version for es modules
basic gist on github
Am I wrong to believe that when node requires a package, it looks at the module key in package.json. Anyways I've been at it for hours, any help would mean a lot cheers 👍
Using rollup you have compiled in to ESModules as you have specified format: 'es' in your rollup.config.js. Nodejs uses commonjs modules and require is supposed to import the commonjs module which it couldn't find there and hence you are getting error. Nodejs started shipping experimental support for ES modules starting node version 10.
If you have greater than version node 10 you can just update your express server start script in package.json to allow the experimental modules support for instance: "start": "node --experimental-modules server.js".
Other approaches that can work depending on your liking or requirements:
Use the third party #std/esm to compile and use es modules as commonjs modules
Compile your library in commonjs modules via this rollup plugin
Edit: It seems the above code in question had issue in config and which fixed the issue, main and module entries in package.json were declared other way around and had to swap the entries to set them up correctly. Main should actually point to umd and module should point to es modules.

Jest encountered an unexpected token when testing a Vue single file component

I have a vue application with single file components and i want to add unit tests to test the components. I'm trying to use jest like described here but i keep getting the error "Jest encountered an unexpected token" with the following details:
/some_path/MyRecipe.vue:1
<template>
^
SyntaxError: Unexpected token <
1 | import { shallowMount } from "#vue/test-utils"
> 2 | import MyRecipe from "../src/components/MyRecipe.vue"
| ^
3 |
4 | describe('MyRecipe', () => {
5 | test('is a Vue instance', () => {
at Runtime._execModule (node_modules/jest-runtime/build/index.js:1166:56)
at Object.<anonymous> (__tests__/MyRecipe.test.js:2:1)
After some research (e.g. from here) I gather that this is probably due to jest expecting a .js file, but the .vue single file components have html, javascript and css in them, usually dealt with by webpack and vue-loader. I've tried to follow jest configurations from various tutorials to make jest use vue-jest to transform .vue files, but the error persists. This is my package.json file (unnecessary parts removed):
{
"name": "all-recipes ",
"version": "0.1.0",
"private": true,
"scripts": {
// ...
"test": "jest"
},
"dependencies": {
// ...
"core-js": "^3.4.3",
"vue": "^2.6.10"
// ...
},
"devDependencies": {
"#vue/cli-plugin-babel": "^4.1.0",
"#vue/cli-plugin-eslint": "^4.1.0",
"#vue/cli-service": "^4.1.0",
"#vue/test-utils": "^1.0.3",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.3",
"babel-jest": "^26.0.1",
// ...
"jest": "^26.0.1",
"jest-serializer-vue": "^2.0.2",
"vue-jest": "^3.0.5",
"vue-template-compiler": "^2.6.10",
"vue-test-utils": "^1.0.0-beta.11"
},
// ...
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
".*\\.,(vue)$": "vue-jest",
"^.+\\.js$": "babel-jest"
},
"snapshotSerializers": [
"jest-serializer-vue"
]
}
}
Any idea what might be wrong, or some tips on how to debug this?
EDIT: I have looked into this question and I don't believe the answer there would solve my problem since what I am trying to import is a .vue file and not an .html file.
EDIT 2: I have a feeling that jest is somehow just not picking up the transforms, because removing them from package.json doesn't change anything.
EDIT 3: No, jest is correctly using vue-jest for transforming. If I uninstall vue-jest and try running the test again, jest complains that vue-jest is missing.
The solution to my problem turns out to be a bit anti-climatic.
The problem was that my regexp string to recognize .vue files was wrong and didn't pick up my MyRecipe.vue file. Therefore, vue-jest wasn't used to transform it for jest to interpret, hence the trouble understanding that the file in question started with a very non-js line; <template>. The regexp that works is ^[^.]+.vue$, so the transform section of my package.json file becomes
{
// ...
"jest": {
// ...
"transform": {
"^[^.]+.vue$": "vue-jest",
"^.+\\.js$": "babel-jest"
},
// ...
}
}
Met same issuesome time ago. What i found.
The problem was in the short note of template v-slot
template(v-slot:body)
It works to compile, but Jest throws an error
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.
There was two ways i fount to solve this:
Edit my jest.config.js, like this
globals: {
'vue-jest': {
pug: {
doctype: 'html',
},
},
},
Write a full note like this
template(v-slot:body="")
What worked for me was changing the transform of the vue-jest to what is shown in the documentation.
https://github.com/vuejs/vue-jest
so try using "^.+\\.vue$": "vue-jest" instead of "^[^.]+.vue$": "vue-jest"
full config might look like this
{
"jest": {
"moduleFileExtensions": ["js", "json", "vue"],
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.vue$": "vue-jest"
}
}
}
I faced same issues tried many solution but none of them work ..below is following workaround in my case
Check package json has following dev dependency entries and jest configurations
"devDependencies": {
"babel-jest": "^23.6.0",
"#vue/cli-plugin-babel": "~4.5.0",
"#vue/cli-plugin-eslint": "~4.5.0",
"#vue/cli-plugin-unit-jest": "~4.5.0",
"#vue/cli-service": "~4.5.0",
"#vue/eslint-config-airbnb": "^5.0.2",
"#vue/test-utils": "^1.0.3",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-vue": "^6.2.2",
},
"jest": {
"moduleFileExtensions": [
"js",
"jsx",
"json",
"vue"
],
"transform": {
"^.+\\.vue$": "vue-jest"
},
"moduleNameMapper": {
"^#/(.*)$": "<rootDir>/src/$1"
},
"snapshotSerializers": [
"jest-serializer-vue"
],
"testMatch": [
"**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.
(js|jsx|ts|tsx)"
],
"testURL": "http://localhost/"
}
Check babel.config.js
module.exports = {
presets: [
'#vue/cli-plugin-babel/preset',
],
};
check jest.config.js
module.exports = {
preset: '#vue/cli-plugin-unit-jest',
};
You need to install vue-jest (https://github.com/vuejs/vue-jest) with
npm install -D #vue/vue3-jest
Here are the available versions and their corresponding vue and jest versions
Vue version
Jest Version
Package
Vue 2
Jest <= 26
vue-jest#4
Vue 3
Jest <= 26
vue-jest#5
Vue 2
Jest 27
#vue/vue2-jest
Vue 3
Jest 27
#vue/vue3-jest
Then, you'll just have to update your jest configuration (in jest.config.ts for example) and add a transform section
"transform": {
"^.+\\.vue$": "#vue/vue3-jest"
}
Warning: be sure to update the npm install and the jest.config.ts with the vue-jest package that match your need!

jest says cannot import outside a module

I'm attempting make a few functions using the Test Driven Development (TDD)
I am writing in javascript.
checkTransparency(urlString)
maketransparent(urlString)
are two functions of mine I'm trying to test and develop which is located in a file called transcript.js.
These uses the inkscape and graphicsmagick npm. I checked checkTransparent works in some other project of mine, but I'm trying to make sure I can just copy paste this transparent.js into another project and use it elsewhere as well.
My folder structure of the project are the following :
+ node_modules
+ src
--- transparent.js
+ test
--- transparent.spec.js
+ package.json
+ package-lock.json
+ jest.config.js
I am using jest as my test framework.
The problem is when I run jest (or npm test)
I get the following:
FAIL test/transparent.spec.js
● 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:
\\..............\transparent\test\transparent.spec.js:4 <FEW DETAILS OMITTED HERE DELIBERATELY>
import { checkTransparency, makeTransparent } from "../src/transparent"; // const transparent = require("../src/transparent");
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime._execModule (C:/Users/Kjeong/AppData/Local/Yarn/Data/global/node_modules/jest-runtime/build/index.js:988:58)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.862s
Ran all test suites.
my jest.config.js:
module.exports = {
testEnvironment: "node",
moduleDirectories: ["node_modules", "src", "transparent"],
moduleFileExtensions: [
"js",
"json",
"jsx",
"ts",
"tsx",
"node"
],
clearMocks: true,
}
I've tried the following exports to get this thing working:
export function checkTransparency(urlString) { ... }
export function makeTransparent(urlString) {... }
module.exports = {
checkTransparency: checkTransparency,
makeTransparent: makeTransparent,
};
In your package.json, using configuration like following could solve your problem:
{
"name": "<blah blah>",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"start": "node server.js",
"test": "node --experimental-vm-modules node_modules/.bin/jest"
},
}
If you really want to use import keyword then you probably need to follow these explanations. Otherwise why not just require ?
const { checkTransparency, makeTransparent } = require('../src/transparent')
Hope this helps :)

Gulp throws error 'Must use import to load ES Module'

We're converting our gulpfile.js in node v13.8.0 to ES6 as following:
import { src, dest, series, parallel, watch } from 'gulp'
import nodemon from 'gulp-nodemon' // normal nodemon does not display an error on app crash
import env from 'gulp-env'
import browser from 'browser-sync'
import sass from 'gulp-sass'
// Tasks
export default {
cssTranspile: cssTranspile,
jsTranspile: jsTranspile,
server: series(startNodemon, startBrowserSync),
default: series(
parallel(
cssTranspile,
jsTranspile
),
startNodemon,
startBrowserSync,
function () {
watch('public/scss/*.scss', cssTranspile)
}
)
}
The error reported, when simply running gulp, is:
internal/modules/cjs/loader.js:1160
throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: T:\Node\ICP\gulpfile.js
require() of ES modules is not supported.
I must be doing something wrong. Anyone an idea on what it might be?
CLI version: 2.2.0
Local version: 4.0.2
The flag "type": "module", is set in package.json as described in the note docs. The issue is very much similar to this issue in the geolib library.
And when we rename gulpfile.js to gulpfile.babel.js as described here we get the same error.
The package.json contain these packages:
"devDependencies": {
"#babel/core": "^7.8.4",
"#babel/preset-env": "^7.8.4",
"#babel/register": "^7.8.3",
"exports-loader": "^0.7.0",
"gulp": "^4.0.2",
"gulp-env": "^0.4.0",
"gulp-nodemon": "^2.4.2",
"gulp-sass": "^4.0.2",
"nodemon": "^2.0.2"
},
"type": "module",
"babel": {
"presets": [
"#babel/env"
]
In an answer to my own question, when the flag "type": "module" is set in package.json you can't use gulp. More info can be found here.
This seems to be fixed now: https://github.com/gulpjs/gulp-cli/pull/214. Be sure to install the latest version of gulp-cli (2.3.0 as of June 2020).
If your package.json specifies "type": "module" you can name your ES module with Gulp tasks gulpfile.js, otherwise name it gulpfile.mjs. No need to use any transpilers or preloaders like esm, Babel or TypeScript.

Categories

Resources