jest-styled-components icon indicating copy to clipboard operation
jest-styled-components copied to clipboard

jest-styled-components is breaking with new 5.0.0 styled-components

Open santaclauze opened this issue 5 years ago • 36 comments

We just udpated to styled-components 5.0.0 and our snapshot tests are breaking:

    > 3 | import 'jest-styled-components';

Could neither find styled-components secret internals nor styled-components/lib/models/StyleSheet.js

I can see that you had the pre 5.0.0 your package.json.

Is this expected?

santaclauze avatar Jan 17 '20 01:01 santaclauze

That error you see has been resolved when you update jest-styled-components to 7.0.0

ARXChrono avatar Jan 17 '20 03:01 ARXChrono

However theres a few other errors occurring for me after upgrading, would be nice to see the changelog to 7.0.0

ARXChrono avatar Jan 17 '20 03:01 ARXChrono

I have upgraded to 7.0.0 and are experiencing the exact samt problem.

pgsandstrom avatar Jan 17 '20 08:01 pgsandstrom

toHaveStyleRule expectations are failing after upgrading styled components to 5 and jest-styled-components to 7.

BatuhanW avatar Jan 17 '20 12:01 BatuhanW

@BatuhanW do the failing expects happen to contain modifiers with single quotes, i.e. is it the same issue as #296 ?

SoontirFell avatar Jan 17 '20 19:01 SoontirFell

yup, styled-components 5.0 + jest-styled-components 7.0 + Typescript also not happy:

error TS2339: Property 'toHaveStyleRule' does not exist on type 'JestMatchersShape<Matchers<void, HTMLElement>, Matchers<Promise<void>, HTMLElement>>'

moarwick avatar Jan 18 '20 00:01 moarwick

Having the same issues, sadly

hutber avatar Jan 21 '20 08:01 hutber

@BatuhanW do the failing expects happen to contain modifiers with single quotes, i.e. is it the same issue as #296 ?

I don't think. Because we have singleQuote set to false on prettierrc.

BatuhanW avatar Jan 21 '20 12:01 BatuhanW

I'm also experiencing issues for tests that used to work on v4.4... places where toHaveStyleRule is used are generating: Error: No style rules found on passed Component

related to this issue

hamatoyogi avatar Jan 22 '20 14:01 hamatoyogi

Can confirm latest is broken with styled-components 4.4.1. Does a version rollback fix?

edit: can confirm version v6.3.4 works with styled-components 4.4.1

tcodes0 avatar Jan 25 '20 16:01 tcodes0

@Thomazella yes we dropped support for v4 with the v7 release. The internals changed a lot between v4 and v5 and the library needed incompatible updates.

quantizor avatar Jan 25 '20 20:01 quantizor

Thanks. I tried jest-styled-components v6 is working fine with styled-components v4.

Duncan00 avatar Jan 26 '20 00:01 Duncan00

Not working with react-native v0.61.5 and styled-components v5 / jest-styled-components v7. Get TypeError: global.beforeEach is not a function

lucianomlima avatar Jan 31 '20 05:01 lucianomlima

@lucianomlima are you using global installation approach?

Note the deprecation warning here: https://jestjs.io/docs/en/configuration#setupfilesafterenv-array

When importing from a file referenced via jest.setupFilesAfterEnv its working for me with v5/v7.

mircoservices avatar Feb 06 '20 12:02 mircoservices

@lucianomlima are you using global installation approach?

Note the deprecation warning here: https://jestjs.io/docs/en/configuration#setupfilesafterenv-array

When importing from a file referenced via jest.setupFilesAfterEnv its working for me with v5/v7.

No, i'm not using global installation and I use jest.setupFilesAfterEnv too. I'm try it again and maybe create a repro repo.

lucianomlima avatar Feb 07 '20 04:02 lucianomlima

@mirco312312 Thanks! I got working now!

lucianomlima avatar Feb 08 '20 02:02 lucianomlima

thanks @mirco312312 - since it took me more than a few minutes to solve, here was the diff in my package.json that worked:

replaced: "setupFiles": ["./spec/setupTests.js"], with: "setupFilesAfterEnv": ["<rootDir>/spec/setupTests.js"],

raurir avatar Feb 20 '20 01:02 raurir

@raurir thanks! that solved the TypeError: global.beforeEach is not a function for me 👍

stazrad avatar Mar 18 '20 15:03 stazrad

after two months, the problem is still existing. I have to use styled-components v4.4.1 and jest-styled-components 6.3.3 due to this problem.

Soul244 avatar Mar 31 '20 07:03 Soul244

import 'jest-styled-components';

Could neither find styled-components secret internals

styled-components - 4.4.1 and jest-styled-components - 7.0.2

Can anyone help me to solve this error

PravallikaVinod avatar Apr 16 '20 11:04 PravallikaVinod

I can confirm that for me it is working with this config:

  • "styled-components": "^4.3.2"
  • "jest-styled-components": "^6.3.4",

...🤔 @PravallikaVinod , try these versions or those combinations mentioned at comments above

wdonet avatar Apr 22 '20 21:04 wdonet

Its happend to me, when i use import 'jest-styled-components/native';, any update about it ?

sebas-bytelion avatar Apr 30 '20 05:04 sebas-bytelion

Temporary? workaround for "styled-components": "^5.1.0" and "jest-styled-components": "^7.0.2" is to render the component inside the test.

  • reference https://styled-components.com/docs/tooling#tohavestylerule
  • I used react-test-renderer but I tested it for enzyme

failing test

import React from 'react';
import renderer from 'react-test-renderer'
import 'jest-styled-components';

import styled from 'styled-components'

const Button = styled.button`
  color: red;
`

describe('Button', () => {
    const app = renderer.create(<Button />).toJSON()
    it('Button has red color', () => {
        expect(app).toHaveStyleRule('color', 'red');
    });

});

image

workable test

import React from 'react';
import renderer from 'react-test-renderer'
import 'jest-styled-components';

import styled from 'styled-components'

const Button = styled.button`
  color: red;
`

describe('Button', () => {
    it('Button has red color', () => {
        const app = renderer.create(<Button />).toJSON()
        expect(app).toHaveStyleRule('color', 'red');
    });
});

image

kdalkafoukis avatar May 21 '20 17:05 kdalkafoukis

I also have this problem as well using react-test-renderer and the latest versions:

"jest-styled-components": "^7.0.2",
"react-test-renderer": "16.13.1",
"styled-components": "^5.1.1",

I have tried the various suggested solutions above, but nothing have helped so far. Any news on any official solution?

Tokimon avatar Jun 05 '20 08:06 Tokimon

So I had a look under the hood and I found out why the test were breaking.

TL;DR - The solution for now

Configure your babel-plugin-styled-components to use static class names by activating ssr: true, like so:

[
  'babel-plugin-styled-components',
  { ssr: true }
]

The analysis

The culprit is that you are directly reliant on having static class names witch are determined by a filtering on the classNames:

const staticClassNames = classNames.filter(x => /^(\w+(-|_))?sc-/.test(x));

So the this filter extracts any static class names (hence the name) like: something-sc-xxx or something_sc-xxx or sc-xxx

However if you don't use static class names, the whole check fails since the getModifiedClassName will never be called.

return classNames.some(className =>
    staticClassNames.some(staticClassName =>
      selectors.includes(
        getModifiedClassName(
          className,
          staticClassName,
          options.modifier
        ).replace(/['"]/g, '"')
      )
    )
  );

In my configuration none of my styled-components class names have this prefix, since my ssr: false in my babel-plugin-styled-components options:

[ 'Tab__TabElement-gNeteQ', 'fjgULR', 'Tab', '', 'active' ]

and with ssr: true, we see I now have the correct class name (the first one):

[ 'Tab__TabElement-sc-16mr2vi-1', 'cQclop', 'Tab', '', 'active' ]

I don't think that this direct dependency on the static class names are intentional as that would break the very nature of ssr being optional. And any mention of having to have ssr activated is missing from the documentation.

So... This seems like a bug and the check has to be redone somehow to not be directly reliant on the static class names.

If you want I can try and look into doing a fix. Let me know.

Update

Even with ssr: true I still have some components that does not have the sc- prefix and as such cannot be tested with toHaveStyleRule. A class name list like so:

[ 'Image__Img-k1inrs-0', 'gNQhls', 'Image', '', 'img' ]

Tokimon avatar Jun 05 '20 09:06 Tokimon

this was fixed on https://github.com/styled-components/jest-styled-components/pull/302 (v7.0.2) https://github.com/styled-components/jest-styled-components/pull/313 (master)

ghost avatar Jun 24 '20 17:06 ghost

#302 does not fix the issue. jest-styled-components looks for the presence of "sc-" anywhere in the component id. babel-plugin-styled-components does not guarantee that the component id will contain the "sc-" substring.

The issue is that babel-plugin-styled-components only applies the "sc-" prefix if it detects the component ID has an invalid css classname, specifically whether it is prefixed by a digit.

Temporarily fixed in my project via patch-package and the following patch for version 1.10.7 which modifies the getComponentId function to ensure it contains "sc-":

diff --git a/node_modules/babel-plugin-styled-components/lib/visitors/displayNameAndId.js b/node_modules/babel-plugin-styled-components/lib/visitors/displayNameAndId.js
index b67a1c8..2b41702 100644
--- a/node_modules/babel-plugin-styled-components/lib/visitors/displayNameAndId.js
+++ b/node_modules/babel-plugin-styled-components/lib/visitors/displayNameAndId.js
@@ -127,7 +127,8 @@ var getNextId = function getNextId(state) {
 
 var getComponentId = function getComponentId(state) {
   // Prefix the identifier with a character because CSS classes cannot start with a number
-  return `${(0, _prefixDigit.default)(getFileHash(state))}-${getNextId(state)}`;
+  var componentId = `${(0, _prefixDigit.default)(getFileHash(state))}-${getNextId(state)}`;
+  return componentId.indexOf('sc-') >= 0 ? componentId : `sc-${componentId}`;
 };
 
 var _default = function _default(t) {

noahnu avatar Jun 27 '20 18:06 noahnu

This does seem to stem from an issue in babel-plugin-styled-components for us - removing it does fix the issue. To achieve this while preserving prod behaviour we've split the .babelrc file into envs, not running babel-plugin-styled-components in test mode.

See https://github.com/babel/babel-preset-env/issues/189#issuecomment-284466362 for a reference of how to split babelrc files into envs.

markwoodward23 avatar Jul 01 '20 21:07 markwoodward23

I concur with @noahnu that the problem resides in the fact that not all class names are being prefixed by sc- (I did not make the link with the digit in the class name so thank you for the clarification).

And I also agree that a correction has to be done in babel-plugin-styled-component since it is a bit inconsistent right now.

But the questions is if it is logical that for jest-style-components to find any class names any styled-component class name HAVE to contain sc-? I guess it makes it easier to determine styled-components class names, and as such improve performance, but it makes it less flexible. And (at least what I have seen) the documentation does not clearly state that ssr has to be activated for it to work.

Tokimon avatar Jul 02 '20 15:07 Tokimon

On that note, is it better to just remove the class name filtering entirely?

noahnu avatar Jul 02 '20 20:07 noahnu