CSS module #import fails the Jest test suit - javascript

I am using Jest and Enzyme to test my application. I am getting error:
FAIL app/containers/Navbar/NavbarContainer.test.js
● Test suite failed to run
app/components/Navbar/styles.css: Unexpected token (1:0)
> 1 | #import "../../styles/base/_variables";
| ^
2 |
3 | .navbar{
4 | width: $navbar-width;
This is my Jest configuration in package.json:
"jest": {
"verbose": true,
"globals": {
"env": {
"isProd": false,
"isDev": true,
"command": "start"
}
},
"moduleNameMapper": {
"\\.(css)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"js",
"jsx",
"json",
"css"
],
"modulePaths": [
"/app"
],
"moduleDirectories": [
"node_modules"
],
"verbose": true,
"setupFiles": [
"./setupJest.js"
],
"setupTestFrameworkScriptFile": "<rootDir>/setupTests.js"
}
I was following the guides while setting up the application, and I found that identity-obj-proxy will help to mock css-modules functionality, but that's not working in my case. Please let me know what am I missing here.
P.S. this is about not ES6 modules import. The suit failed because there is a #import in css.

UPDATE who use create-react-app from feb 2018.
You cannot override the moduleNameMapper in package.json but in jest.config.js it works, unfortunately i havent found any docs about why it does the trick.
So my jest.config.js look like this:
module.exports = {
...,
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(scss|sass|css)$": "identity-obj-proxy"
}
}
and it skips scss files and #import quite well.
I added to devDependencies identity-obj-proxy
Backing my answer i followed jest webpack

So, I've found the solution to this problem. I was importing CSS without the extension in my components and Jest was confusing that import with JS file. Solution is instead of importing css like:
import * as styles from './styles'
you should import it like:
import * as styles from './styles.css'

One quick gotcha that I found with this. If you have a jest.config.js file, then you need to set your moduleNameWrapper inside of that config file.

I know this post is old but i solved this issue by adding jest-transform-css as a devDependency
npm i --save-dev jest-transform-css
and then adding the following inside jest.config.js
transform: {
'^.+\\.js$': 'babel-jest',
'.+\\.(css|styl|less|sass|scss)$': 'jest-transform-css'
}
you can refer to this github issue for more information

Related

SWC with JavaScript: How to handle CSS imports and how to absolute imports?

TL;DR
How can you tell SWC to compile CSS files imported in React components?
How can you tell SWC to compile absolute imports in tests and in React components?
Here is a minimal reproducible example.
Context
We're migrating from Babel to SWC. (I asked a question a little while ago. I'm improving on that question's answer.)
We're migrated the command from:
"test": "NODE_ENV=test riteway -r #babel/register 'src/**/*.test.js' | tap-nirvana",
to
"test": "SWC_NODE_PROJECT=./jsconfig.json riteway -r #swc-node/register src/**/*.test.js | tap-nirvana",
where the jsconfig.json looks like this:
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "./src",
"jsx": "react-jsx"
}
}
If we write try to compile a test for a self-contained component (no absolute imports, no CSS) it works:
import { describe } from 'riteway';
import render from 'riteway/render-component';
function HomePageComponent({ user: { email } }) {
return <p>{email}</p>;
}
describe('home page component', async assert => {
const user = { email: 'foo' };
const $ = render(<HomePageComponent user={user} />);
assert({
given: 'a user',
should: 'render its email',
actual: $('p').text(),
expected: user.email,
});
});
The test compiles fine.
With Babel we had a .babelrc like this:
{
"env": {
"test": {
"plugins": [
[
"module-resolver",
{
"root": [
"."
],
"alias": {
"components": "./src/components",
"config": "./src/config",
"features": "./src/features",
"hocs": "./src/hocs",
"hooks": "./src/hooks",
"pages": "./src/pages",
"redux": "./src/redux",
"styles": "./src/styles",
"tests": "./src/tests",
"utils": "./src/utils"
}
}
]
]
}
},
"presets": [
[
"next/babel",
{
"ramda": {}
}
]
],
"plugins": [
["styled-components", { "ssr": true }]
]
}
Where the styles where taken care of by styled-components and the absolute imports where defined via the module-resolver plugin. (We switched away from styled-components to CSS modules, which is why we import from .module.css CSS files. Anyways ...)
If we write the test how we wanted to write it with their actual imports like this:
import { describe } from 'riteway';
import render from 'riteway/render-component';
import { createPopulatedUserProfile } from 'user-profile/user-profile-factories';
import HomePageComponent from './home-page-component';
describe('home page component', async assert => {
const user = createPopulatedUserProfile();
const $ = render(<HomePageComponent user={user} />);
assert({
given: 'a user',
should: 'render its email',
actual: $('p').text(),
expected: user.email,
});
});
It fails with:
$ SWC_NODE_PROJECT=./jsconfig.json riteway -r #swc-node/register src/features/home/home-page-component.test.js | tap-nirvana
/Users/janhesters/dev/my-project/src/features/home/home.module.css:1
(function (exports, require, module, __filename, __dirname) { .container {
^
SyntaxError: Unexpected token '.'
when we leave in the CSS import in home-page-component.js, or with:
$ SWC_NODE_PROJECT=./jsconfig.json riteway -r #swc-node/register src/features/home/home-page-component.test.js | tap-nirvana
node:internal/modules/cjs/loader:936
throw err;
^
Error: Cannot find module 'user-profile/user-profile-factories'
Require stack:
- /Users/janhesters/dev/my-project/src/features/home/home-page-component.test.js
- /Users/janhesters/dev/my-project/node_modules/riteway/bin/riteway
respectively, when we get rid of the CSS import.
How can we help SWC understand CSS (or mock CSS modules) and how can we help it understand absolute imports?
We already set the baseUrl in jsconfig.json ...
About absolute path
You already add baseUrl in the jsconfig.json file but didn't add the paths, you should modify your config file like mine:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#screens": ["./screens"],
"#shared": ["./shared"],
"#shared/*": ["./shared/*"]
},
The paths are the alias of module-resolver, and I guess your root shouldn't be ".", it should be exactly like your jsconfig.json file, I mean the baseUrl value.
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"extensions": [".ts", ".tsx", ".js", ".jsx", ".json"],
"alias": {
"#screens": "./src/screens",
"#shared": "./src/shared"
}
}
]
],
If you have Webpack, you should have alias config in your resolve key off Webpack config object, like mine:
const resolve = {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
alias: {
'#screens': path.join(__dirname, 'src/screens/'),
'#shared': path.join(__dirname, 'src/shared/'),
},
modules: ['src', 'node_modules'],
descriptionFiles: ['package.json'],
};
About CSS
Actually, you are using CSS file as CSS-Modules not like recommended NexJS doc, in docs developer should import CSS like import './styles.css' and then use it as string in JSX like <div className="main"
But
You are importing it like a module (CSS-Module):
// you did it
import styles from './styles.css';
<div className={styles.main}
As you know it is built-in support by this doc, it is supported by NextJS, but SWC cannot understand it. I put in hours to find a way for it, but it seems SWC doesn't support CSS-Module yet. you should create your own plugin for SWC to support CSS-Module.
How can we help SWC understand CSS (or mock CSS modules)? - SWC doesn't understand css natively, and neither did Babel. As you noted, when you were using Babel, the plugin styled-components took care of this. You'll need to do the same with SWC. I can't find an existing SWC plugin that does this, but you can roll your own. Obviously this is a pain, but such is the cost of using new tooling.
How can we help SWC understand absolute imports? - The .swrc options for baseUrl and paths should do what you want, but that, too, seems to have some issues.
You may have better luck creating issues directly in the #swc-node GitHub repo, but given the comments there it feels like you might be SOL for a while. Might be faster/easier to rewrite your tests using one of the libraries that Next supports out of the box.
I was able to solve all issues without writing any plugins. I pushed the solution to my example repo from the question.
Firstly, use the official SWC project's register. This means, you have to compile your tests like this:
"test": "riteway -r #swc/register 'src/**/*.test.js' | tap-nirvana",
You can install it by running:
yarn add --dev #swc/core #swc/register
We need this version of register, because it takes into account an .swcrc file, which the other one did not.
Secondly, you need both "path" and "baseUrl" to fix the absolute imports because for some reason SWC doesn't infer all paths with only a "baseUrl" provided. And you need to adapt your .swcrc to handle React.
{
"jsc": {
"baseUrl": "./src",
"paths": {
"*.css": ["utils/identity-object-proxy.js"],
"utils/*": ["utils/*"]
},
"parser": {
"jsx": true,
"syntax": "ecmascript"
},
"transform": {
"react": {
"runtime": "automatic"
}
}
},
"module": {
"type": "commonjs"
}
}
Thirdly, to solve .css you need to remap all imports to .css files to an identity object proxy, which you can see in the .swcrc example above. An identity object proxy is an object that, when you reference any property, returns the stringified key that you're trying to reference. You can create one yourself like this:
const identityObjectProxy = new Proxy(
{},
{
get: function getter(target, key) {
if (key === '__esModule') {
return false;
}
return key;
},
},
);
export default identityObjectProxy;
For the .css remap to go into effect you need to make all your imports to .css files absolute imports. (import styles from './styles.module.css won't work!)

Compiling React projects in MonoRepo failing

I'm trying to setup yarn workspaces with my docker instance. This is my directory structure:
/monorepo/
/node_modules/
#libs/common
#services/common
#services/project-A
...OTHER DEPS...
package.json
/services/
/common/
index.jsx
package.json
/project-A/
webpack.base.config.js
**REACT project with babel, webpack, etc**
/libs/
/tools/
/common/
index.jsx
package.json
To simplify my docker setup I just configured this volume within my docker compose that maps the entire monorepo directory:
volumes:
- '../../../monorepo:/monorepo'
From there in my Project-A I import #libs/common and #services/common. This works fine when the common libraries are exporting simple functions like:
export const Add = (a,b) => a+b
Webpack has no issue resolving this and building Project-A.
However when I try to import a component from one of the common libraries like this:
/libs/tools/common:
import React from 'react'
export MySharedComponent = () => <>HELLLO</>
I get an error in the build process:
Error: Cannot find module '/monorepo/libs/tools/common/webpack.base.config.js'
Require stack:
- /monorepo/node_modules/eslint-import-resolver-webpack/index.js
- /monorepo/node_modules/eslint-module-utils/resolve.js
- /monorepo/node_modules/eslint-plugin-import/lib/rules/no-unresolved.js
- /monorepo/node_modules/eslint-plugin-import/lib/index.js
The eslint file under Project-A:
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true,
"jest": true,
"cypress/globals": true
},
"settings": {
"import/resolver": {
"webpack": {
"config": "webpack.base.config.js"
}
}
}
}
The babel.rc under Project-A
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"#babel/preset-react",
"#babel/preset-flow"
],
"env": {
"test": {
"plugins": [
[
"babel-plugin-webpack-alias",
{
"config": "./webpack.base.config.js"
}
]
]
}
}
}
My Question:
Is the main issue that there's no webpack config set up in the common repositories. Therefore the workspace does not know how to compile my shared resources?
Should there only be 1 webpack build config in my workspace used by all projects within the workspace? Currently I only have 1 config under Project-A?
What happens if I have specific webpack needs per project, does 1 config (if that's the answer) make sense?
1) First, there is a line in your code that you are referring to webpack.base.config.js in both babelrc and eslint,
so if that file does not exist, this error that says module not found makes sense.
2) Second: if you build and use your repositories in the same situation and environment, yes you can have one config for both but you might need environment setup (Development, Production) for your config.
But if you really want to make your dependencies and configs apart, webpack support multiple entries for your project which you can check that out.

SyntaxError: Unexpected token : when running jest test with Aurelia in TypeScript

Just created a new TypeScript Aurelia project using aurelia-cli .
Installed bootstrap and included bootstrap css in the app.ts using import.
import 'bootstrap/dist/css/bootstrap.min.css';
import '../../static/assets/css/app.scss';
import { routes } from './routes';
interface IApp {
message: string;
}
export class App implements IApp{
message = 'Hello World!';
}
Now when I run the test , I get error unexpected token as below
yarn test
# and the output contains
yarn run v1.12.3
$ nps test
nps is executing `test` : nps test.jest
nps is executing `test.jest` : node node_modules/rimraf/bin.js test/coverage-jest && jest
ts-jest[config] (WARN) TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
FAIL test/unit/app.spec.ts
● 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 hav`enter code here`e 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.
SyntaxError: Unexpected token :
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
at Object.<anonymous> (src/home/app.ts:163:1)
I commented the import bootstrap.css line in app.ts and everything runs fine.
Am I missing some configuration for jest to allow me to use css imports in .ts components?
Here is my jest portion from package.json
"jest": {
"verbose": true,
"roots": [
"<rootDir>/test"
],
"modulePaths": [
"<rootDir>/src",
"<rootDir>/node_modules"
],
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"testRegex": "\\.spec\\.(ts|js)$",
"testPathIgnorePatterns": [
"build",
"dist",
"sample"
],
"setupFiles": [
"<rootDir>/test/jest-pretest.ts"
],
"testEnvironment": "node",
"collectCoverage": true,
"collectCoverageFrom": [
"src/**/*.{js,ts}",
"!**/*.spec.{js,ts}",
"!**/node_modules/**",
"!**/test/**"
],
"coverageDirectory": "<rootDir>/test/coverage-jest",
"coverageReporters": [
"json",
"lcov",
"text",
"html",
"clover"
]
},
I was getting the same error. I resolved my issue by changing the module compilerOption in tsconfig.json from "esnext" to "commonjs". Why am I getting “Unexpected token import” on one webpack project but not the other?

Why does Jest try to resolve every component in my index.ts?

So I'm using Jest (with Enzyme) to test a Typescript-React project, and am having an issue with an alias module.
I know the problem per se isn't finding the module, because it finds the module correctly. I think the problem may be the structure of one of my files.
jest.config.js
module.exports = {
"collectCoverage": false,
"collectCoverageFrom": [
"!**/*.d.ts",
"src/**/*.{js,jsx,ts,tsx}"
],
"coverageDirectory": "test",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"testEnvironment": "node",
"testURL": "http://localhost",
"transform": {
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^.+\\.tsx?$": "ts-jest"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$"
],
"resolver": "jest-webpack-resolver",
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^components$": "<rootDir>/src/components",
"^reducers$": "<rootDir>/src/reducers",
"^actions$": "<rootDir>/src/actions",
"^selectors$": "<rootDir>/src/selectors",
"^services$": "<rootDir>/src/services",
"^views$": "<rootDir>/src/views",
"^domains$": "<rootDir>/src/domains"
},
};
Import used in my component being tested:
import { Label } from 'components';
My project structure leads the following way in components:
src
|_ components
|_ // ..various folders with React components
|_ index.ts
And my index.tsx basically looks like this:
export { default as Label } from './Label/Label'
// export other components
What's happening is the following:
When I run Jest, it resolves my 'components' module fine, it's the same in my webpack.alias, but what is breaking the test run is that it starts to 'build' (I'm not sure if it actually builds?) other components, and starts going up the dependency tree for some components I'm not even testing, and eventually breaks because it goes all the way up to my main index.tsx file that runs the entire app.
Is the problem the way I've structured my index.ts to export all my components?
I have the same problem. It seems to be related to jest having it's own module resolver. Maybe this helps: https://jestjs.io/docs/ecmascript-modules

How to configure Jest and babel-jest for specific folder

I'm getting the following error:
import React from 'react';
^^^^^^
SyntaxError: Unexpected token import
The reason is that some module/s are not been compiled when published in npm.
I was wondering, how I can include them in the babel-jest compilation specific node_modules folder?
This is my current configuration in the package.json
"jest": {
"silent": false,
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(scss|css|less)$": "<rootDir>/__mocks__/styleMock.js"
},
"setupFiles": [
"<rootDir>/__mocks__/localStorageMock.js"
],
"transform": {
"^.+\\.jsx$": "babel-jest",
"^.+\\.js$": "babel-jest"
}
I didn't find any solution in the documentation. It would be great if I can do something like this or something similar, adding which folder/s to transform:
"transformPaths": [ "path/to/file.js", "path/to/file.jsx"]
I got some help from the Jest guys,
Here is how to do it

Categories

Resources