mui-datatables icon indicating copy to clipboard operation
mui-datatables copied to clipboard

Jest & ReactTestingLibrary - Could not parse CSS stylesheet

Open liamlows opened this issue 3 years ago • 14 comments

Hey y'all,

So we have been going through and adding more tests to some of the components we are using in our app and for some reason every component/page that uses muidatatables throws an error during testing. It does not fail the test but simply spits out the error. It goes as follows:

console.error
  Error: Could not parse CSS stylesheet
      at exports.createStylesheet (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:34:21)
      at HTMLStyleElementImpl._updateAStyleBlock (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:68:5)
      at HTMLStyleElementImpl._childTextContentChangeSteps (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:36:12)
      at HTMLStyleElementImpl._insert (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:832:14)
      at HTMLStyleElementImpl._preInsert (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:768:10)
      at HTMLStyleElementImpl._append (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:868:17)
      at HTMLStyleElementImpl.appendChild (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:610:17)
      at HTMLStyleElement.appendChild (<MY_USER_PATH>/.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/generated/Node.js:395:60)
      at StyleSheet.insert (<MY_USER_PATH>/.yarn/cache/@emotion-sheet-npm-1.1.0-40e9c90e06-a4b74e16a8.zip/node_modules/@emotion/sheet/dist/emotion-sheet.cjs.dev.js:135:11)
      at Array.finalizingPlugins (<MY_USER_PATH>/.yarn/cache/@emotion-cache-npm-11.7.1-82b45442ee-cf7aa8fe3b.zip/node_modules/@emotion/cache/dist/emotion-cache.cjs.dev.js:296:24) .tss-swqr74-MUIDataTable-@global{@media print{.datatables-noprint{display:none;}}}

  at VirtualConsole.<anonymous> (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
  at exports.createStylesheet (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js:38:63)
  at HTMLStyleElementImpl._updateAStyleBlock (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:68:5)
  at HTMLStyleElementImpl._childTextContentChangeSteps (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js:36:12)
  at HTMLStyleElementImpl._insert (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:832:14)
  at HTMLStyleElementImpl._preInsert (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:768:10)
  at HTMLStyleElementImpl._append (.yarn/__virtual__/jsdom-virtual-f91bf4c0c4/0/cache/jsdom-npm-16.7.0-216c5c4bf9-454b833718.zip/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js:868:17)

we have tried a plethora of solutions to try and fix this issue and none work. Could this be due to Next 12 using the rust compiler as opposed to babel in the past? we have tried manually mocking stylesheets, manually transforming stylesheets and media files, using identity-obj-proxy, and a few other random attempts at fixing.

Here is a sample test we have tried, CacheProvider is an emotion cache provider, DarkThemeProvider provides a theme for muidatatable to use, and assume the correct props are provided to the table to render:

it('should render a table with default content', () => {
    render(
      <CacheProvider value={emotionCache}>
        <DarkThemeProvider>
          <MUIDataTable title={tableTitle} data={data} columns={columns} options={options} />
        </DarkThemeProvider>
      </CacheProvider>,
    );
    expect(screen.getByText('row 1 col 1')).toBeInTheDocument();
    expect(screen.getByText('row 1 col 2')).toBeInTheDocument();
});

Expected Behavior

Does not throw could not parse stylesheet error during testing.

Current Behavior

Throws could not parse stylesheet error during testing, despite what seems to be correct testing configuration.

Steps to Reproduce (for bugs)

  1. Using next.js, jest, ts-jest, and react testing library (set up as directed https://nextjs.org/docs/testing) create a test using a muidatatable.
  2. Run the testing library and observe the error.

Your Environment

Tech Version
Material-UI 5.4.3
MUI-datatables 4.1.2
React 17.0.2
Next 12.1,0
Jest 27.5.1
ts-jest 27.1.3
@testing-library/react 12.1.3
@testing-library/jest-dom 5.16.2

liamlows avatar Mar 08 '22 16:03 liamlows

Also getting this issue suddenly.

nickraphael avatar Apr 14 '22 01:04 nickraphael

Getting the same error, but without using Next.js. I am using emotion though because of the MUI v5, and since the error is coming from @emotion/cache, I'm guessing that's the issue here.

Looking at the stack trace, the error originates node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js when trying to do sheet = cssom.parse(sheetText);. Seems like there could be issues in cssom related to @media print: https://github.com/NV/CSSOM/issues/110, as this is where the error fails based on the stacktrace: .tss-swqr74-MUIDataTable-@global{@media print{.datatables-noprint{display:none;}}} (@global in the selector kind of looks suspicious to me as well)

The issue happens to me when trying to update from v4.0.0 to 4.1.0. To me it looks like the biggest change was switching to tss-react, so maybe the styles that it outputs are different and cssom cannot handle it.

Don't really know how this should be dealt with, but maybe this would help with investigating 🙂

aaneitchik avatar Apr 20 '22 12:04 aaneitchik

To follow up with a bit more investigation: I decided to try and see how the CSS that cssom is trying to parse looks like with both versions (the original styles are here), and here's what I got: [email protected] (no tss-react):

.MUIDataTable-paperResponsiveScrollFullHeightFullWidth-42 {
  position: absolute;
}
.MUIDataTable-tableRoot-43 {
  outline: none;
}
.MUIDataTable-responsiveBase-44 {
  overflow: auto;
}
@media print {
  .MUIDataTable-responsiveBase-44 {
    height: auto !important;
  }
}
.MUIDataTable-responsiveScroll-45 {
  height: 100%;
  overflow: auto;
}
.MUIDataTable-responsiveScrollMaxHeight-46 {
  height: 100%;
  overflow: auto;
}
.MUIDataTable-responsiveScrollFullHeight-47 {
  height: 100%;
}
.MUIDataTable-responsiveStacked-48 {
  overflow: auto;
}
@media (max-width:899.95px) {
  .MUIDataTable-responsiveStacked-48 {
    overflow: hidden;
  }
}
.MUIDataTable-caption-50 {
  left: -3000px;
  position: absolute;
}
.MUIDataTable-liveAnnounce-51 {
  clip: rect(0 0 0 0);
  width: 1px;
  border: 0;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  position: absolute;
}
@media print {
  .datatables-noprint {
    display: none;
  }
}

Notice how the last @media rule, which in the original is defined under @global key, is just in the stylesheet, there's no class name generated for it

vs.

[email protected] (with tss-react):

.tss-swqr74-MUIDataTable-@global{@media print{.datatables-noprint{display:none;}}}

Not sure why the stylesheet contains only one rule, but I assume it doesn't really matter.

What I assume matters here is that a class name is created with @global in it, which doesn't look correct, but I may be lacking some context of course.

aaneitchik avatar Apr 20 '22 18:04 aaneitchik

Any ideas for a work around? I tried downgrading to [email protected], which helped some but that seemed to cause other issues.

EDIT: Poked around a little more and it seems like an out of date jsdom version may be to blame?

x3igh7 avatar May 17 '22 06:05 x3igh7

Hi @aaneitchik, I am the maintainer of tss-react, let me know if there is something I can do on my end to smooth things up.

garronej avatar Jun 06 '22 04:06 garronej

Hi @garronej , thank you for reaching out! I made a PR that should fix the issue for mui-datatables. Since the problem seems to be in @global style, I rewrote the styles to remove it.

I don't know if @global is a "special" style that should be supported and handled separately by tss-react (like for example how @media queries are), since it doesn't seem to be one of CSS at-rules. To me it looks like it shouldn't, so nothing to do on tss-react's side, but in case I'm wrong then I guess supporting @global would also solve it.

aaneitchik avatar Jun 13 '22 12:06 aaneitchik

I am having the same issue and I am not using Next.js I have done this as temp work around.

jest.spyOn(console, 'error').mockImplementation(() => {});

cagosto avatar Jul 20 '22 13:07 cagosto

I encountered this issue as well on 4.2.2. Here is the (typescript eslint ready) workaround I put together:

jest.mock('tss-react/mui', () => {
    const real: typeof import('tss-react/mui') = jest.requireActual('tss-react/mui')

    return {
        ...real,
        withStyles: (...args: unknown[]) => {
            /** Making sure we are not targeting the wrong rule */
            if (
                args.length !== 3 ||
                typeof args[1] !== 'function' ||
                args[1].name !== 'defaultTableStyles' ||
                !args[2] ||
                typeof args[2] !== 'object' ||
                !('name' in args[2]) ||
                (args[2] as Record<string, unknown>).name !== 'MUIDataTable'
            ) {
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                return real.withStyles(...args)
            }

            const [component, styleGenerator, config] = args

            return real.withStyles(
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                component,
                (...args: unknown[]) => {
                    const styles: unknown = styleGenerator(...args)

                    /** Making sure we are deleting the right styles */
                    if (styles && typeof styles === 'object' && '@global' in styles) {
                        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                        // @ts-ignore
                        delete styles['@global']
                    }

                    return styles
                },
                config
            )
        }
    }
})

Put it before your tests that involve this library and the bad styles complaints should go away. This could have other side effects but its good enough for my usecase and brittle on purpose.

filipomar avatar Jul 27 '22 13:07 filipomar

Hi @aaneitchik,

Sorry your answer went under my radar for some reason.

I don't know if @global is a "special" style that should be supported and handled separately by tss-react (like for example how @media queries are)

You are correct, thank for clearing this out for me, I add to my backlog to support @media. I wasn't aware the legacy API supported that.

@filipomar thanks for sharing a workaround.

Best,

garronej avatar Jul 27 '22 14:07 garronej

Still experiencing this in "mui-datatables": "^4.2.2" any idea if this will get resolved?

Npervic avatar Sep 22 '22 12:09 Npervic

@Npervic, I've open an issue about it.
But the mainteainer of mui-datatables don't review PRs very often and I'm not mainteaner.
I'll do what I can but I encourage you to try to find a fix on your end.

Best

garronej avatar Sep 22 '22 12:09 garronej

@wdh2100 anyway we could get these PRs merged in? looks like they are GTG.

liamlows avatar Sep 23 '22 19:09 liamlows

@wdh2100 Any way we can get the above mentioned pr merged?

Npervic avatar Nov 10 '22 13:11 Npervic