Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jest doesn't works with JSX which imports CSS #3094

Closed
svipas opened this issue Mar 7, 2017 · 30 comments
Closed

Jest doesn't works with JSX which imports CSS #3094

svipas opened this issue Mar 7, 2017 · 30 comments

Comments

@svipas
Copy link

svipas commented Mar 7, 2017

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
If app.jsx have import './app.css'; it's impossible to run test, I got this error:

yarn run:test v0.21.3
$ NODE_ENV=client jest -u
 FAIL  src/__tests__/app.test.js
  ● Test suite failed to run

    /home/svipben/Documents/react-boilerplate/src/client/app/app.css:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){body {
                                                                                                  ^
    SyntaxError: Unexpected token {

      at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:320:12)
      at Object.<anonymous> (src/client/app/app.jsx:7:1)
      at Object.<anonymous> (src/__tests__/app.test.js:2:12)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.693s
Ran all test suites.
error Command failed with exit code 1.

What is the expected behavior?
To run tests without error...

Please provide your exact Jest configuration and mention your Jest, node, yarn/npm version and operating system.

OS: Linux Ubuntu 16.04
Jest: Latest
Yarn: Latest
Node: Latest
babel-jest: Latest

.babelrc:

        "client": {
            "presets": [
                "latest", // All you need to compile what's in ES2015+
                "flow", // Flow support
                "react", // Strip flow types and transform JSX
                "stage-2" // Experimental syntax extensions
            ],
            "sourceMaps": true // Compile with Source Maps
        },

jest: NODE_ENV=client jest -u

P.S. Everything runs well if I comment/remove import './app.css';

@maximderbin
Copy link
Contributor

@svipben https://facebook.github.io/jest/docs/webpack.html#mocking-css-modules

@svipas
Copy link
Author

svipas commented Mar 7, 2017

@maximderbin Thanks!

@cpojer cpojer closed this as completed Mar 7, 2017
@simonxl
Copy link

simonxl commented Mar 1, 2018

@maximderbin Thank you! It resolves my issue by adding moduleNameMapper

@sarahmarciano
Copy link

@svipben @maximderbin @simonxl where do I have to add this moduleNameMapper?
I see in the doc that we shall add it in the packag.json but which one?
tnx

@thymikee
Copy link
Collaborator

@sarahmarciano moduleNameMapper is a part of your configuration. By default, you can set the config in package.json (the one which features jest in dependencies) under "jest" key, like this:

{
  "dependencies": {...}
  "jest": {
    "moduleNameMapper": {...}
  }
}

@dennisja
Copy link

dennisja commented Apr 28, 2018

I solved this by using the moduleNameMapper key in the jest configurations in the package.json file

{
   "jest":{
        "moduleNameMapper":{
             "\\.(css|less|sass|scss)$": "<rootDir>/__mocks__/styleMock.js",
             "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js"
        }
   }
}

After this you will need to create the two files as described below

  • __mocks__/styleMock.js
module.exports = {};
  • __mocks__/fileMock.js
module.exports = 'test-file-stub';

If you are using CSS Modules then it's better to mock a proxy to enable className lookups.
hence your configurations will change to:

{
  "jest":{
     "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
      "\\.(css|less|scss|sass)$": "identity-obj-proxy"
    },
  }
}

But you will need to install identity-obj-proxy package as a dev dependancy i.e.

yarn add identity-obj-proxy -D

For more information. You can refer to the jest docs

@matthew-dean
Copy link

Note that the approaches recommended here will not work if your CSS modules export values which your JSX files depend on. Most guides assume you're only using CSS modules to export class names. I wish there was a guide for properly mocking CSS modules.

@SimenB
Copy link
Member

SimenB commented Sep 15, 2018

@matthew-dean what do you mean "properly mocking CSS modules"? Can you describe your use case a bit more? I have great experience using identity-obj-proxy

@matthew-dean
Copy link

:export {
  sizeMobile: $size-mobile / 1px;
  sizePhablet: $size-phablet / 1px;
  sizeSmallTablet: $size-small-tablet / 1px;
  sizeTablet: $size-tablet / 1px;
  sizeDesktop: $size-desktop / 1px;
  sizeLargeDesktop: $size-large-desktop / 1px;
}
import styles from './variables.scss'

const tileSize = parseFloat(styles.sizeTablet) / 3
//...
render() {
  return <Tile style={{width: tileSize}} />
}

This is a contrived example, just demonstrating that you can share constants (values) between CSS modules and JS, and that conditional rendering or dynamic props can be assigned based on values.

But with identity-obj-proxy, these values can't be cast to integers, let alone the actual values that are present. So if you have JSX code that relies on constants defined in your CSS modules, then you can't test this without properly mocking the CSS module (having an object returned that has the values as testable integers). identity-obj-proxy only assumes that your CSS modules contain an object with nothing more than scoped CSS classnames; it does not support the other aspect of CSS modules which is the ability to export values / constants that in turn get used in JS operations.

@matthew-dean
Copy link

matthew-dean commented Sep 18, 2018

@SimenB

Incidentally, I WAS able to mock the CSS module successfully like this:

const styles = require('styles/variables.scss')

jest.mock('styles/variables.scss', () => {
  return {
    sizePhablet: 500,
    sizeSmallTablet: 768,
    sizeTablet: 1024,
    sizeDesktop: 1440,
    sizeLargeDesktop: 1920
  }
})

Hopefully that's useful for someone else who is using all the features of CSS modules and, like me, was tearing their hair out at all the default "just use identity-obj-proxy" advice.

@krajasekhar
Copy link

krajasekhar commented Oct 20, 2018

I solved this problem by using 'jest-transform-css'.
After installing, added the below in the jest config.

"transform": {
      "^.+\\.js$": "babel-jest",
      ".+\\.(css|styl|less|sass|scss)$": "jest-transform-css"
    }

Now css files will get transpiled just like js files did.

@gustavo-tailrecursive
Copy link

@matthew-dean where did you write the mock the CSS module and how do you reference it to jest?

@CeamKrier
Copy link

CeamKrier commented Feb 14, 2019

I'm using an external package and it imports its own files to a single file by using the following:
@import "progress-tracker/progress-tracker-variables.scss";

Whenever I run the Jest for to start testing
image
the error above shows up. I already have specified css mockup inside the package.json
image

Im looking forward to get some help about that issue. Any tricks, suggestions?

Edit: I have tried both babel-jest and identity-obj-proxy packages and none of those worked. The problem still persists.

Edit 2: Also I have tried the config below according to solutions that I have come across with on the web.
image

@bengrunfeld
Copy link

I'm using Babel 7, babel-jest ^24.5.0, Jest ^24.1.0.

After following the above advice, I'm still getting this error when I try to import a function or object into a Jest test file (e.g. Post.test.js) when the target file (e.g. Post.js) imports a CSS file - e.g. ./postStyles.css.

Jest encountered an unexpected token

SyntaxError: Unexpected token .

Details:

    /Users/ben/Desktop/Work/code/bengrunfeld/src/front-end/components/Post/postStyles.css:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){.post h1, .post h2, .post h3 {

      3 |
      4 | import { PostText } from './styles'
    > 5 | import './postStyles.css'

As per the article linked above, this is in my package.json:

"jest": {
    "moduleFileExtensions": ["js", "jsx"],
    "moduleDirectories": ["node_modules", "bower_components", "shared"],

    "moduleNameMapper": {
      "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
      "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js",

      "^react(.*)$": "<rootDir>/vendor/react-master$1",
      "^config$": "<rootDir>/configs/app-config.js"
    }
  },

and in the root directory, I have __mocks__/styleMock.js which has the following code:

module.exports = {};

Lastly, my jest.config.js:

module.exports = {
  setupFiles: ['<rootDir>/src/test/setup.js']
}

Which in turn configures Enzyme:

import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new Adapter() })

@fthomas82
Copy link

fthomas82 commented Apr 29, 2019

import Error
I am struggling to solve almost same issue where my scss file contain @import statements. Test fails telling SyntaxError: Invalid or unexpected token. Can somebody help me please?

I followed solutions given above but none of them seems to be working for me

@FJKhan
Copy link

FJKhan commented May 12, 2019

I was able to resolve this by adding @babel/polyfill as a dev dependency

@yanlee26
Copy link

same here @fthomas82

@joseigor
Copy link

I solved this by using the moduleNameMapper key in the jest configurations in the package.json file

{
   "jest":{
        "moduleNameMapper":{
             "\\.(css|less|sass|scss)$": "<rootDir>/__mocks__/styleMock.js",
             "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js"
        }
   }
}

After this you will need to create the two files as described below

  • __mocks__/styleMock.js
module.exports = {};
  • __mocks__/fileMock.js
module.exports = 'test-file-stub';

If you are using CSS Modules then it's better to mock a proxy to enable className lookups.
hence your configurations will change to:

{
  "jest":{
     "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
      "\\.(css|less|scss|sass)$": "identity-obj-proxy"
    },
  }
}

But you will need to install identity-obj-proxy package as a dev dependancy i.e.

yarn add identity-obj-proxy -D

For more information. You can refer to the jest docs

It worked for me. Thanks!!!

@idindrakusuma
Copy link

I solved this problem by using 'jest-transform-css'.
After installing, added the below in the jest config.

"transform": {
      "^.+\\.js$": "babel-jest",
      ".+\\.(css|styl|less|sass|scss)$": "jest-transform-css"
    }

Now css files will get transpiled just like js files did.

Thanks, bro @krajasekhar
It works for me 👍

@ShadOoW
Copy link

ShadOoW commented Jul 23, 2019

I added suggested config to packages.json, without success, then I realized I had a jest.config.js in my project root directory, Jest uses that config file over packages.json.

For reference here is my jest.config.js file:

module.exports = {
  setupFilesAfterEnv: ['<rootDir>/.setup-tests.js'],
  testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
  transform: {
    '^.+\\.js$': 'babel-jest',
    '.+\\.(css|styl|less|sass|scss)$': 'jest-transform-css',
  },
};

@neginqantas
Copy link

I have to import a raw css in my code

import "./cloud.css?raw"

I also modified jest config
"jest":{ "moduleNameMapper": { "\\.(css|less|scss|sass|css?raw)$": "identity-obj-proxy" },

still, I am getting test error on the import line. Any idea how to mock raw import?

@jahnaviv
Copy link

jahnaviv commented Jan 16, 2020

Solution of @import Unexpected token=:)

Install package:
npm i --save-dev identity-obj-proxy

Add in jest.config.js

module.exports = {
  "moduleNameMapper": {
    "\\.(css|less|scss)$": "identity-obj-proxy"
  }
}

@rafinskipg
Copy link

If somebody arrives here:
This module is the most updated I have seen: https://www.npmjs.com/package/jest-css-modules-transform

transform: {
    '^.+\\.(js|jsx|ts|tsx)$': '<rootDir>/node_modules/babel-jest',
    ".+\\.(css|styl|less|sass|scss)$": "jest-css-modules-transform"
  },
  transformIgnorePatterns: [
    '/node_modules/',
    '^.+\\.module\\.(css|sass|scss)$',
  ],
  moduleNameMapper: {
    '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy'
  },

@danielrsantana
Copy link

danielrsantana commented Oct 8, 2020

I added suggested config to packages.json, without success, then I realized I had a jest.config.js in my project root directory, Jest uses that config file over packages.json.

For reference here is my jest.config.js file:

module.exports = {
  setupFilesAfterEnv: ['<rootDir>/.setup-tests.js'],
  testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
  transform: {
    '^.+\\.js$': 'babel-jest',
    '.+\\.(css|styl|less|sass|scss)$': 'jest-transform-css',
  },
};

Thanks to everybody who presented a solution and specially to you @ShadOoW! It was a kind of logic thing but I was missing that ... config file will be used over settings in package.json

In short, for new comers, what worked to me was an union of multiple solutions presented by our community dream team:

  1. create a jest.config.json file

touch jest.config.json open jest.config.json

  1. Install jest-transform-css:

yarn add jest-transform-css -D

  1. This is how your jest config file should look like:
module.exports = {
  preset: 'ts-jest/presets/js-with-babel',
  moduleNameMapper: {
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)$': './jest.mock.js',
  },
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/assets/'],
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
    '\\.(css|less|scss|sass)$': 'jest-transform-css',
  },
};
  1. Update your package.json (first, transfer all your JEST configurations, if you have some there, to the new jest config file), then the magic goes here:

"test": "jest --config ./jest.config.js"

Tks Everyone !

@Mano534
Copy link

Mano534 commented Dec 24, 2020

it worked for me when I add the moduleNameMapper in the jest.config.ts, not the package.json

@olignyf
Copy link

olignyf commented Apr 1, 2021

If you are using Jest for images snapshots there is not much choice to parse SCSS into CSS and inject it in the tests. I tried "sass-jest" and "sass-jest-transform" and they didn't work. I'm wondering if I will have to write my own?

@luiznasciment0
Copy link

luiznasciment0 commented Apr 12, 2021

Hey! I'm still having this error after trying all the options. If I remove the "?type=global" it works, but then I run out of styles...
Screen Shot 2021-04-12 at 17 46 38

My jest.config.js:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'jsdom', // https://jestjs.io/docs/en/configuration#testenvironment-string
  roots: ['<rootDir>'],
  testPathIgnorePatterns: ['<rootDir>[/\\\\](node_modules|.next)[/\\\\]'],
  transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$'],

  automock: false,
  restoreMocks: true,

  // Runs special logic, such as cleaning up components
  // when using React Testing Library and adds special
  // extended assertions to Jest
  setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],

  // Module file extensions for importing
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node', 'css'],

  // tsconfig.json `paths` aliases
  moduleNameMapper: {
    '^@maria/api(.*)$': '<rootDir>/main/core/api/$1',
    '^@maria/bifrost(.*)$': '<rootDir>/main/core/bifrost/$1',
    '^@maria/request(.*)$': '<rootDir>/main/core/request/$1',
    '^@maria/metrics(.*)$': '<rootDir>/main/core/metrics/$1',
    '^@maria/utils(.*)?': '<rootDir>/main/core/utils',
    '^@maria/models(.*)$': '<rootDir>/main/app/models/$1',
    '^@maria/components(.*)$': '<rootDir>/main/app/components/$1',
    '^@maria/hooks(.*)$': '<rootDir>/main/app/hooks/$1',
    '^@maria/hocs(.*)$': '<rootDir>/main/app/hocs/$1',
    '^@maria/layout(.*)$': '<rootDir>/main/app/layout/$1',
    '^@maria/providers(.*)$': '<rootDir>/main/app/providers/$1',
    '^@maria/assets(.*)$': '<rootDir>/main/app/assets/$1',
    '^@maria/selectors(.*)$': '<rootDir>/main/app/selectors/$1',
    '^@maria/screens(.*)$': '<rootDir>/main/app/screens/$1',
    '^@maria/containers(.*)$': '<rootDir>/main/app/containers/$1',
    '^@maria/validators(.*)$': '<rootDir>/main/app/validators/$1',
    '^@maria/server(.*)$': '<rootDir>/server/$1',
    '^@maria/test(.*)$': '<rootDir>main/app/test/$1',
    '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
      '<rootDir>/__mocks__/fileMock.js',
    '\\.(css|less|sass|scss|css?type=global)$': '<rootDir>/__mocks__/styleMock.js',
  },

  // Jest transformations -- this adds support for TypeScript and styled-jsx
  transform: {
    '^.+\\.(ts|tsx)?$': 'babel-jest',
    '.+\\.css$': 'jest-styled-jsx-transformer',
  },
}

@sam-621
Copy link

sam-621 commented Apr 17, 2021

I move my config from jest.config.js to my package.json and worked

@darekkay
Copy link

I came across this issue when importing CSS files from node_modules:

import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";

This was my configuration:

transform: {
  "^.+\\.(css|scss)$": here("./jest/transforms/css-transform"),
};

While it works fine with local CSS files, It didn't for the imports above. The reason is that transformIgnorePatterns includes node_modules by default, hence the CSS transform will be skipped for those files. This change was necessary:

transformIgnorePatterns: [
  "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
],

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests