console.error Error: Could not parse CSS stylesheet
Asked Answered
C

6

19

I'm having the follow error when running my tests with jest.

  console.error
    Error: Could not parse CSS stylesheet
        at exports.createStylesheet ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:34:21)
        at HTMLStyleElementImpl._updateAStyleBlock ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:68:5)
        at HTMLStyleElementImpl._childTextContentChangeSteps ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:36:12)
        at HTMLStyleElementImpl._insert ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:832:14)
        at HTMLStyleElementImpl._preInsert ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:768:10)
        at HTMLStyleElementImpl._append ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:868:17)
        at HTMLStyleElementImpl.appendChild ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:610:17)
        at HTMLStyleElement.appendChild ([PERSONAL_PATH]/node_modules/jsdom/lib/jsdom/living/generated/Node.js:395:60)
        at StyleSheet.insert ([PERSONAL_PATH]/node_modules/@emotion/sheet/dist/sheet.cjs.dev.js:121:11)
        at Object.insert ([PERSONAL_PATH]/node_modules/@emotion/cache/dist/cache.cjs.dev.js:168:19) {width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ[BLOB]== */

      at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
      at exports.createStylesheet (node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:38:63)
      at HTMLStyleElementImpl._updateAStyleBlock (node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:68:5)
      at HTMLStyleElementImpl._childTextContentChangeSteps (node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:36:12)
      at HTMLStyleElementImpl._insert (node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:832:14)
      at HTMLStyleElementImpl._preInsert (node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:768:10)

I've tried to set a jsdom version on my packages.json, also tried to update jest packages. Didn't changed the error. It's not actually causing the tests to fail, but it is polluting the jest output.

If need to more details please ask in comments than I edit this question.

Edit

Here is the sass file to the tested component:

$spacing-medium: 2.4rem
$spacing-small: 1.6rem
$color-green: #3aa537
$color-white: #ffffff
$color-super-pale-gray: #f0f0f0
$color-pale-gray: #e6e6e6
$color-border-pale-gray: #b3b3b3
$tundora: #4d4d4d
$boulder: #757575
$electric-blue: #2251ff
$font-size-large: 1.6rem
$font-family-regular: "Arial", sans-serif
$font-family-bold: "Arial Bold", sans-serif
$[PRIVATE]-sans-regular-font-family: '[PRIVATE] Sans Regular', $font-family-regular
$[PRIVATE]-sans-medium-font-family: '[PRIVATE] Sans Medium', $font-family-bold
$font-size-medium: 1.4rem

@font-face
  font-family: [PRIVATE] Sans Medium
  src: url('https://cdn.[PRIVATE].com/assets/fonts/web/[PRIVATE]Sans-Medium.woff2') format('woff2')

@font-face
  font-family: [PRIVATE] Sans Regular
  src: url('https://cdn.[PRIVATE].com/assets/fonts/web/[PRIVATE]Sans-Regular.woff2') format('woff2')

.margin-cell
  margin-left: -12px

.active
  color: $color-green
  font-family: $[PRIVATE]-sans-medium-font-family
  margin-left: -12px

section
  margin: 1rem 0

  nav.sub-navigation
    background-color: $color-white
    padding: $spacing-medium

    a.sub-navigation-active
      display: inline-flex
      color: $electric-blue
      font-size: $font-size-large
      font-family: $[PRIVATE]-sans-medium-font-family
      text-decoration: none
      border-bottom: 4px solid $electric-blue
      padding-bottom: 1rem

  div.grid-container
    padding: $spacing-small 0 $spacing-small 0
    font-size: $font-size-medium
    background-color: $color-white
    display: grid

    .group-key
      font-family: $[PRIVATE]-sans-medium-font-family
      color: $tundora
      margin-bottom: 10px

    .input-style
      width: 100%
      font-family: $[PRIVATE]-sans-regular-font-family
      height: 30px
      padding: 0 $spacing-small
      color: $tundora
      font-size: $font-size-medium

    .group-divider
      padding: $spacing-small 10px $spacing-small 10px

    .advanced-configurations-container
      width: 100%
      font-size: $font-size-medium

    .advanced-configurations-header
      font-size: $font-size-medium
      color: $electric-blue
      width: unset

  div.info-group
    padding: 0 0 $spacing-small $spacing-medium
    font-size: 1.4rem
    background-color: $color-white
    border-top: 2px solid $color-super-pale-gray
    display: grid
    grid-template-columns: 1fr 1fr

    div.group-subsection
      display: grid
      padding: 0.8rem 0
      margin: 10px 25px 10px 0
      height: 50px
      &.variable-height
        height: unset
        min-height: 50px

    .group-key
      font-family: $[PRIVATE]-sans-medium-font-family
      color: $tundora
      margin-bottom: 10px

    .info-group-internal
      display: grid
      grid-template-columns: 1fr 1fr

  .icons-holder
    display: flex
    justify-content: center
    gap: 26px

.tab
  margin-top: $spacing-medium

.filter-wrapper
  padding: $spacing-small $spacing-medium $spacing-small $spacing-medium
  background-color: $color-white
  border-top: 1px solid $color-pale-gray

.search-input
  width: 300px
  height: 32px

.modal-form

  .form-row
    display: flex
    margin: $spacing-medium 0
    gap: $spacing-medium

    > .form-column
      flex: 1

      .input-wrapper
        height: 32px

        textarea
          //border: $color-pale-gray solid 1px
          color: $tundora
          height: 24px
          min-height: 9rem
          overflow: hidden
          padding: 10px
          resize: none

    .question-label
      color: $tundora
      font-family: $[PRIVATE]-sans-medium-font-family
      display: block
      font-weight: bold
      margin-bottom: 10px
      font-size: 1.4rem

Here is my jest.config.js:

module.exports = {
  clearMocks: true,
  collectCoverageFrom: ['src/**/*.{ts,tsx,js,jsx}'],
  coverageDirectory: 'coverage',
  coveragePathIgnorePatterns: [
    '/node_modules/',
    'src/index.tsx',
    'src/temp/',
    'src/types/',
    'src/helpers/testHelper.ts',
    'src/helpers/constants.ts',
    'src/pages/Errors/*',
  ],
  coverageThreshold: {
    global: {
      branches: 90,
      functions: 90,
      lines: 90,
      statements: 90,
    },
  },
  moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx'],
  moduleNameMapper: {
    '\\.(css|scss|sass)$': 'identity-obj-proxy',
    '\\.svg$': '<rootDir>/__mocks__/genericMock.js',
    '^@src/(.*)$': '<rootDir>/src/$1',
    '^@helpers/(.*)$': '<rootDir>/src/helpers/$1',
    '^@appConfig(.*)$': '<rootDir>/config/application/appConfigTypes.ts',
  },
  preset: 'ts-jest',
  setupFilesAfterEnv: ['./src/helpers/jestHelper.ts'],
  testEnvironment: 'jsdom',
  testMatch: ['**/*.(test|spec).(ts|tsx)'],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  transformIgnorePatterns: ['node_modules/(?!(react-native|[PRIVATE]|lodash)/)'],
};

Update

I've begun to isolate the things from the component that I was testing, got to the point of having just a single component in it. So I've found a date-picker from a third-party library was causing the problem. I did clone it, run their tests, notice that they were using another library to render the component in the tests. Found out that they also had testing-library/react, created another test using it to render, but had no success to reproduce the error. Does anyone have any suggestions about what I may try next? I'm running out of ideas.

Corgi answered 9/11, 2021 at 23:3 Comment(6)
"Could not parse CSS stylesheet" usually means you have some kind of error in your CSS. Without that CSS, we couldn't tell you what the issue is.Fungible
I've compiled the stylesheets that the tested component uses using npx sass <StyleFile.sass> It outputs with no errors.Corgi
@Fungible Just add the main sass file. Thank you for trying to help.Corgi
Just tried to delete the file content from both sass files. Same error with clean files.Corgi
@Corgi did you ever end up solving this?Desex
@Corgi Did you find a solution to this? Could you please be a hero and answer your question if so?Autotype
C
12

There was an issue open for it here: https://github.com/jsdom/jsdom/issues/2230, saying you should change your jsdom configuration to:

const jsdom = require('jsdom');
const { JSDOM } = jsdom;
const virtualConsole = new jsdom.VirtualConsole();
virtualConsole.on("error", () => {
  // No-op to skip console errors.
});
const dom = new JSDOM(``, { virtualConsole });

(copied directly from that git issue).

That same answer is also available here: JSDOM: Could not parse CSS stylesheet.

There's also another issue mentioned here, https://github.com/styled-components/styled-components/issues/1931, where it seems that changing the multiline comments to single line comments fixed the issue for some people.

I believe jsdom doesn't have that great CSS support or it seems like it's breaking on weird things trying to parse CSS.

However I don't believe that the solution is to parse the CSS anyways, you should be using jest transformations or moduleNameMapper to mock the css and import an empty object, no reason to test the styles.

According to the jest documentation, https://jestjs.io/docs/webpack#mocking-css-modules, you can use moduleNameMapper:

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

Then inside the fileMock.js you can just export an empty object.

You can also use transform:

"transform": {
  "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.js"
}

Then in that fileTransformer.js file you can also just export an empty object.

Campaign answered 13/11, 2021 at 23:12 Comment(3)
Hi there, thanks for trying to help. I've checked the modulesNameMapper I already have this config '\\.(css|scss|sass)$': 'identity-obj-proxy'. About the jsdom config, where should I place it?The only string with jsdom that I have is in jest.config.js the follow testEnvironment: 'jsdom'.Corgi
Remove identity-obj-project and just uninstall that, all you need is an empty mock.js file and all it has to do is module.exports = {}, then use that file in your moduleNameMapper, i.e. \\.css$: <rootDir>/tests/mock.js, so that you map any css imports to an empty object import instead.Campaign
How can I inject virtualConsole via Jest configuration? ``` module.exports = { verbose: true, preset: 'ts-jest', testEnvironment: 'jsdom', ... ``` moduleNameMapper doesn't work because some of the css comes from 3rd party library which is already a js file from node_modulesCircumscribe
G
11

The error message pops up...

due to the stylesheet using (legitimate) features that [the jsdom] CSS parser does not support. source comment on GitHub issue

In the same thread there is a solution which worked for me. I modified it slightly:

// in setupTests.js
const originalConsoleError = console.error;
console.error = function (...data) {
  if (
    typeof data[0]?.toString === 'function' && 
    data[0].toString().includes('Error: Could not parse CSS stylesheet')
  ) return;
  originalConsoleError(...data);
};
Gauntlett answered 16/3, 2023 at 13:38 Comment(1)
I like this. I think the original question is when your component depends on another 3rd party component which includes css file in JS file, this way, I'm afraid the top answer can't help. I will take this solution until I saw a better one.Circumscribe
G
1

Use identity-obj-proxy in Jest to transform your scss for the tests only: npm install identity-obj-proxy.

npm i -D identity-obj-proxy.

Also see this answer: https://mcmap.net/q/666975/-jest-unable-to-resolve-alias-used-in-sass-file-in-react-project.

Girl answered 9/11, 2021 at 23:37 Comment(1)
Already have it in my jest.config.js I've add it into my question.Corgi
D
1

I use vitest and had the same issue with PrimeVue.

The answer from stackoverflow helped me.

import { useConfirm } from 'primevue/useconfirm';
import PrimeVue from 'primevue/config';
import ConfirmationService from 'primevue/confirmationservice';

const wrapper = shallowMount(MyComponent, {
  props: { aProp },
  global: {
    components: { useConfirm },
    plugins: [PrimeVue, ConfirmationService],
  },
});
Decaliter answered 22/11, 2023 at 19:48 Comment(0)
L
1

Had similar error in angular project. Turned out to be a wrong declaration of component with styles: string instead of styles: string[], which did not cause compilation / typescript / eslint error for some reason.

Langham answered 18/1 at 7:38 Comment(0)
D
1

put this in setup-jest.ts This should fix the issue

let consoleSpy: jest.SpyInstance;
beforeAll(() => {
    consoleSpy = jest.spyOn(global.console, 'error').mockImplementation((message) => {
        if (!message?.message?.includes('Could not parse CSS stylesheet')) {
            global.console.warn(message);
        }
    })
});

afterAll(() => consoleSpy.mockRestore());
Derayne answered 22/5 at 16:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.