How can I test swiper with Jest? - jestjs

I'm creating unit testing of Swiper using Jest.
Here is my code:
https://codesandbox.io/s/swiper-default-react-forked-v0dnz?file=/src/App.test.jsx
● Test suite failed to run
Cannot find module 'swiper/react' from 'src/App.jsx'
Require stack:
src/App.jsx
src/App.test.jsx
1 | import React from "react";
2 | // Import Swiper React components
> 3 | import { Swiper, SwiperSlide } from "swiper/react";
| ^
4 |
5 | // Import Swiper styles
6 | import "swiper/css";
at Resolver.resolveModule (node_modules/jest-resolve/build/resolver.js:322:11)
at Object.<anonymous> (src/App.jsx:3:1)
This error has been reported all the time, but the program can run normally. Can anyone help me solve this problem?

I suppose you are having issues with Swiper 7 or newer versions because Jest doesn't support ESM packages yet.
So even if it is not the most optimal solution, you can solve it by downgrading it to Swiper 6
Run these commands:
npm uninstall swiper
npm install swiper#6.8.4
And import it this way:
import { Swiper, SwiperSlide } from 'swiper/react'
import 'swiper/swiper-bundle.min.css'
import 'swiper/swiper.min.css'

This seemed to work for me (Swiper v8):
(in package.json)
"jest": {
"moduleNameMapper": {
"swiper/react": "swiper/react/swiper-react.js",
"swiper/css": "swiper/swiper.min.css"
},
"transform": {
"^.+\\.css$": "jest-transform-css"
}
}
(and maybe also add this to transformIgnorePatterns)
'node_modules/(?!(swiper|ssr-window|dom7)/)'

If you don't care about testing Swiper v8 functionality, but want to test some other features in your components, try to add this line in your jest file:
jest.mock('Swiper', () => class Mocked {});
Worked for nextjs, doesn't complain. Maybe not the best way, but in my case it's more than enough.

I'm using Swiper 8.4.2 and this worked for me while using Swiper in Jest.
TL;DR just give me the Jest config
Here is a configuration that worked for me.
/* eslint-disable */
export default {
displayName: "components",
preset: "../../jest.preset.js",
moduleNameMapper: {
// Jest cannot understand this swiper import so we tell it where this points to
"swiper/css": "swiper/swiper.min.css",
},
transform: {
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "#nrwl/react/plugins/jest",
"^.+\\.[tj]sx?$": ["babel-jest", { presets: ["#nrwl/react/babel"] }],
},
moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
coverageDirectory: "../../coverage/libs/components",
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
transformIgnorePatterns: ["node_modules/(?!swiper|ssr-window|dom7)"],
};
Important things about config
Some of the things can be ignored because they are specific to this NX controlled monorepo, but couple of things are important here. So ignore "nrwl" and "nx" specifics, because I'm expecting this part about transformers to already be configured for your project whether you are using NX or something else.
What errors was I getting?
So running tests first threw errors "Jest encountered an unexpected token" and "SyntaxError: Unexpected token 'export'" for this line in my code:
import { Navigation } from "swiper";
Actual source of the error was this line in Swiper package:
export { default as Swiper, default } from './core/core.js';
Adding swiper|ssr-window|dom7 to transformIgnorePatterns resolved that issue.
Then after adding that I got the same error, but for this line:
import "swiper/css";
One of the answers above managed to help me with this actually because it involved "moduleNameMapper" property.
So adding this into the config solved the issue with this particular import:
moduleNameMapper: {
// Jest cannot understand this swiper import so we tell it where this points to
"swiper/css": "swiper/swiper.min.css",
},
Hopefully this helps someone with resolving their issue and actually understanding what parts of the config resolved specific issues.

Related

"Cannot use import statement outside a module" with Axios

I have a Vue.js application where two files contain:
import axios from "axios"
These files are located in src/lib within the application and include the import statement on their first line.
Running tests on Github causes Axios 1.0.0 to be installed, no matter what the package.json says, and now any test involving these files fails with the above error.
Changing the statement to const axios = require("axios") fails also; node_modules/axios/index.js contains an import statement on line 1 and the exception is thrown there.
A suggestion I've seen quite often for such issues is to add "type": "module" to package.json (which is at the same level as src/). This causes all tests to fail with a demand to rename vue.config.js as vue.config.cjs. Doing that gets me: Error: You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously, which I do not understand.
Can anyone suggest what to do here?
I was able to fix this error by forcing jest to import the commonjs axios build by adding
"jest": {
"moduleNameMapper": {
"axios": "axios/dist/node/axios.cjs"
}
},
to my package.json. Other solutions using transformIgnorePatterns didn't work for me.
The 1.x.x version of axios changed the module type from CommonJS to ECMAScript.
The 0.x.x version of axios index.js file
module.exports = require('./lib/axios');
The 1.x.x version of axiox index.js file
import axios from './lib/axios.js';
export default axios;
Basically, jest runs on Node.js environment, so it uses modules following the CommonJS.
If you want to use axios up to 1.x.x, you have to transpile the JavaScript module from ECMAScript type to CommonJS type.
Jest ignores /node_modules/ directory to transform basically.
https://jestjs.io/docs/27.x/configuration#transformignorepatterns-arraystring
So you have to override transformIgnorePatterns option.
There are two ways to override transformIgnorePatterns option.
jest.config.js
If your vue project uses jest.config.js file, you add this option.
module.exports = {
preset: "#vue/cli-plugin-unit-jest",
transformIgnorePatterns: ["node_modules/(?!axios)"],
...other options
};
package.json
If your vue project uses package.json file for jest, you add this option.
{
...other options
"jest": {
"preset": "#vue/cli-plugin-unit-jest",
"transformIgnorePatterns": ["node_modules\/(?!axios)"]
}
}
This regex can help you to transform axios module and ignore others under node_modules directory.
https://regexper.com/#node_modules%5C%2F%28%3F!axios%29
Updating the version of jest to v29 fixed this in my project. It could be the case that you have an incompatible jest version.
I had the same issues and was able to solve this by using jest-mock-axios library
I experience similar problem but the error is caused by jest.
All the tests trying to import axios fail and throw the same exception:
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:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• 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:
/monorepo/node_modules/axios/index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import axios from './lib/axios.js';
^^^^^^
SyntaxError: Cannot use import statement outside a module
1 | import { describe, expect, it } from '#jest/globals'
> 2 | import axios from 'axios'
The solution is simply tell jest that axios should be transformed with babel:
const esModules = ['lodash-es', 'axios'].join('|')
# add these entries in module.exports
transform: {
[`^(${esModules}).+\\.js$`]: 'babel-jest',
},
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
Note: I'm using Quasar Vue and this is their implementation.
Quick fix
Update the npm run test script from
"test": "react-scripts test",
to
"test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\"",
In my case I had to add the following line to the moduleNameMapper object in the jest config:
axios: '<rootDir>/node_modules/axios/dist/node/axios.cjs',
I had the same issue, it works fine when changing axios to fetch.
axios (Fail)
try {
const response = await axios("api/fruit/all");
return response.data;
} catch (error) {
return error;
}
Fetch (Works fine)
try {
const response = await fetch("api/fruit/all",{method:"GET"});
const data = await response.json();
return data;
} catch (error) {
return error;
}

Jest resolver cannot find a file which path ressembles existing node modules

I have upgraded jest from version 27 to version 29.
Since then, some indirect file resolve do not work anymore.
Here is my config:
module.exports = {
roots: ['app/javascript/__tests__/'],
testMatch: ['**/?(*.)(spec|test).js?(x)'],
testEnvironment: 'jsdom',
testRunner: 'jest-jasmine2',
moduleDirectories: [
'node_modules',
'app/javascript',
'app/javascript/__tests__'
],
transform: {
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^.+\\.(svg)$': '<rootDir>/app/javascript/__tests__/fileMock.js'
},
setupFiles: ['./app/javascript/__tests__/setup.jsx']
}
There is a file in my code base, let's say app/javascript/MyReactComponent.jsx, which is imported as part of my tested component, and that contains the following import line:
// app/javascript/MyReactComponent.jsx
import 'firebase/init'
Expected behavior
Until today, I could run jest, and it was finding all my code as expected, inclluding the above import, which is located here:
app/javascript/firebase/init.js
Error
Instead, running jest throws the following error.
Cannot find module 'firebase/init' from 'app/javascript/MyReactComponent.jsx'
FWIW, I have traced the resolver code up to the default jest resolver, and it seems like it tries to get the file from within the firebase node module, instead of fetching the init.js file in the firebase directory.
Question
Is there a way to adjust my configuration in order for the resolver to find my file?
Have you tried adding an entry for that aliased module in moduleNameMapper?
moduleNameMapper: {
'^.+\\.(svg)$': '<rootDir>/app/javascript/__tests__/fileMock.js',
'^firebase/init': '<rootDir>/app/javascript/firebase/init.js'
}

Vite: Cannot use import statement outside a module

I know little about bundler and I'm using vite to build project, I got a error when import some package to configure dev server :
SyntaxError: Cannot use import statement outside a module
So here is the thing:
import pinyin from 'pinyin/esm/pinyin-web.js'
export const somePlugin = {
name: 'someplugin',
configureServer(server) {
server.middlewares.use('/somepath', (req, res, next) => {
const foo = pinyin('foo')
next()
})
},
}
I don't use the normal way(import pinyin from 'pinyin') , because that need a package nodejieba which need to install unnecessary node-gyp, so I choose the web version that don't need nodejieba.
I've searched the error, some says add "type": "module" to package.json file. but it already exist in my package.json.
however, I make the change:
// import pinyin from 'pinyin/esm/pinyin-web.js'
import pinyin from 'pinyin/lib/pinyin-web.js'
and problem get solved,I was confused because I thought vite prefer ES module.
So,
1> what cause the problem above?
2> why should I import file with extensions ? eg: import pinyin from 'pinyin/lib/pinyin-web.js'
I have to add extensions .js or it will cause error. while in vite.config.ts I needn't add extensions.
3> I tried to add field optimizeDeps in vite.config.ts like this
export default defineConfig({
plugins: [vue(), somePlugin],
optimizeDeps: {
include: ['pinyin'],
},
})
but it seems to be useless, the offical doc says:
"During development, Vite's dev serves all code as native ESM. Therefore, Vite must convert dependencies that are shipped as CommonJS or UMD into ESM first."
did that work for the frontend part and package "pinyin" is for the dev server so whether add the
field optimizeDeps there is no difference.
codesandbox

Jest cannot find module 'got' from node_modules

I'm getting an error from one of my (previously working) tests when I run yarn jest:
Cannot find module 'got' from 'src/rss/queries.ts'
I've added got in package.json:
"devDependencies": {
"got": "^12.0.0",
}
My jest.config.js:
module.exports = {
preset: 'ts-jest',
testMatch: ['**/*.test.ts(|x)'],
collectCoverageFrom: ['**/*.ts', '!.webpack/**/*'],
verbose: true,
}
I'm using got in ./src/rss/queries.ts:
import * as got from 'got'
I've also tried:
import { got, RequestError } from 'got'
In both cases the application works - I can see got making requests via the application logs (and vscode is indicating the correct path to the module in node_modules when I hover over the above). So it's definitely there, and working.
But jest can't find it. Why? It's not an uncommon stackoverflow question, but they all seem to relate to importing custom local modules via relative paths, etc. I'm just trying to use one out of node_modules...
Version 12 of got doesn't work with jest. Best to use version 11 for now. See the details in the release notes at: https://github.com/sindresorhus/got/releases/tag/v12.0.0
Wasn't able to find a reason for, or solution to, this. Ended up swapping got for axios, which is a shame as I liked many got features.

New to React / Babelify; How to fix "Accessing PropTypes" warning

I'm new to both React and Babelify.
I'm using Node to compile a web app. Right now I'm doing this:
browserify({debug: true})
.transform(
babelify.configure({
comments : false,
presets : [
"react",
"babili",
],
})
)
.require('./app.js', {entry: true})
.plugin(collapse)
.bundle()
.on("error", function (err) {
console.log("Error:", err.message);
})
.pipe(fs.createWriteStream(destination));
My app is a VERY trivial "Hello, World!" proof-of-concept at the moment that's about this complex:
class Renderer {
render () {
ReactDOM.render(
<div>Hello, World!</div>
document.querySelector("#react-app")
);
}
}
module.exports = Renderer;
I'm getting this warning:
Warning: Accessing PropTypes via the main React package is deprecated, and
will be removed in React v16.0. Use the latest available v15.* prop-types
package from npm instead. For info on usage, compatibility, migration and more,
see https:/gfb.me/prop-types-docs
Warning: Accessing createClass via the main React package is deprecated,
and will be removed in React v16.0. Use a plain JavaScript class instead. If
you're not yet ready to migrate, create-react-class v15.* is available on npm
as a temporary, drop-in replacement. For more info see
https:/gfb.me/react-create-class
Error: [BABEL] /home/gweb/code/app.js: Unknown option:
/home/gweb/code/node_modules/react/react.js.Children. Check out
http:/gbabeljs.io/docs/usage/options/ for more information about options.
A common cause of this error is the presence of a configuration options
object without the corresponding preset name. Example:
Invalid:
`{ presets: [{option: value}] }`
Valid:
`{ presets: [['presetName', {option: value}]] }`
For more detailed information on preset configuration, please see
http:/gbabeljs.io/docs/plugins/#pluginpresets-options. (While processing
preset: "/home/gweb/code/node_modules/react/react.js") while parsing file:
/home/gweb/code/app.js
I read the recommended stuff, but I'm new enough to both that I can't quite get a handle on it. I also read a bunch of other articles and SO posts, but none of them (that I could find) had this set (browserify, babelify, react).
My goal at the moment is just to get it transpiling with support for the React syntax (which is JSX, from what I understand?), so I can start playing with it and learning both libraries. What's the fastest way to get this implemented (I don't necessarily need most efficient or best; I'd rather have the easiest-to-understand incantation at this stage, so I can have things transparent while I learn).
It is not your setup issue but problem is with your import statements, i'm assuming you are importing react and PropTypes from react
import React, { PropTypes } from 'react';
So, using PropTypes from react library has been deprecated as mentioned in warning and you need to install PropTypes as a standalone library from npm and use that instead.
npm install prop-types --save and then do,
import PropTypes from 'prop-types', for more info https://www.npmjs.com/package/prop-types
this will resolve your first warning, also for second warning you need to install and use https://www.npmjs.com/package/create-react-class.
for the babel error please check if you have both required libraries installed.
https://www.npmjs.com/package/babel-preset-react,
https://www.npmjs.com/package/babel-preset-babili
Do you have an import of the form import * as React from 'react'?
If so, try replacing it with import React from 'react'.
The * imports everything from react, including the deprecated exports, and that's what triggers the warnings.

Resources