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

v7.0.0 No Styles found on passed Component #294

Open
LouiseReid opened this issue Jan 15, 2020 · 31 comments
Open

v7.0.0 No Styles found on passed Component #294

LouiseReid opened this issue Jan 15, 2020 · 31 comments

Comments

@LouiseReid
Copy link

LouiseReid commented Jan 15, 2020

I've just updated styled components to v5 and jest-styled-components to v7 and now any test that calls on toHaveStyleRule fails with the error No style rules found on passed Component.

Example test

  test("it renders correctly when disabled", () => {
    const { container } = render(<ControlButton disabled />);
    const button = container.querySelector("button");
    expect(button).toHaveStyleRule("opacity", "0.5");
  });

Tested component

const ControlButton = styled.button`
  background-color: white;
  border: none;
  font-size: 0;
  height: 20px;
  line-height: 0;
  margin: 0;
  padding: 0;
  user-select: none;
  width: 20px;

  ${props =>
    props.disabled &&
    css`
      opacity: 0.5;
      pointer-events: none;
    `}
`

This test passed using styled components v4.3.2 and jest-styled-components v6.3.3.

This is being tested with @testing-library/react v9.1.4

@benbryant0
Copy link

benbryant0 commented Jan 15, 2020

I'm not very familiar with the inner workings of SC or this package, but I think I may have tracked the issue down to here: 8c2ea4a#diff-4eed74593d3d8efde6a0959c9c35119bR71

In my case the static classes have names of the format "Component-sc-hashstuff", but the filter expects them to start with 'sc-', so none are found. Then due to the way the some() calls are nested, hasClassNames returns false when I don't think it should.

@visoft
Copy link

visoft commented Jan 15, 2020

My issue with this boiled down to 'babel-plugin-styled-components' being used. That plugin modifies the class names to include the component, removing that fixed the issue. See #290

@ryanirilli
Copy link

We need the babel-plugin-styled-components plugin for server side rendering to have consistent hashing of classnames. Unless this is no longer needed in v5?

@BatuhanW
Copy link

I'm having the same problem with enzyme.

@Undistraction
Copy link

Undistraction commented Jan 21, 2020

I'm seeing the same issue even with displayName set to false during tests:

[
  `babel-plugin-styled-components`,
  { ssr: false, displayName: false },
]

Test:

describe(`example`, () => {
  const Example = styled.div`
    color: red;
  `

  it(`has style rule`, () => {
    const tree = renderer.create(<Example />).toJSON()
    expect(tree).toHaveStyleRule(`color`, `red`)
  })
})

Tree:

type: 'div',
props: { className: 'sc-AykKC kWTpbh' },
children: null

Message:

No Styles found on passed Component

  • react: 16.12.0
  • react-test-renderer: 16.12.0
  • styled-components: 5.0.0
  • jest-styled-components: 7.0.0

@tcodes0
Copy link

tcodes0 commented Jan 25, 2020

I'm having this same issue styled 4.4.1, and 6.3.4 of this lib, not sure. For now I'm rolling with a local patch-package that seems to fix things. Hoping the update to 7 here and styled 5 fixes.

I'll following this repo and lmk if I can help in any way. :D

@WayneEllery
Copy link

We are having the same issue with styled-components 5.0.0 and jest-styled-components 7. To fix it we are currently using:

const plugins = [
  ['babel-plugin-styled-components', { ssr: !isTest, displayName: !isTest }],
];

@stefee
Copy link
Member

stefee commented Jan 28, 2020

This is a duplicate of #290

@sombreroEnPuntas
Copy link

sombreroEnPuntas commented Feb 21, 2020

Having a similar issue when using:

    "jest": "^25.1.0",
    "jest-styled-components": "^7.0.0",
    "@testing-library/jest-dom": "^4.0.0",
    "@testing-library/react": "^9.1.1",
    "babel-plugin-styled-components": "^1.10.7",
    "styled-components": "^5.0.1",

And configuring babelrc:

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "styled-components",
      {
        "ssr": true,
        "preprocess": false,
        "displayName": true
      }
    ],
  ]
}

Test is:

    it('should be visible', () => {
      const { getByTestId } = render(
        ...
      );

      const cta = getByTestId('cta-id');
      fireEvent.click(cta);

      expect(getByTestId('content')).toMatchSnapshot();
      expect(getByTestId('content')).toHaveStyleRule('visibility', 'visible');
    });

The snapshot clearly shows that styles are there:

.c0 {
  -webkit-transform: translateY(0px);
  -ms-transform: translateY(0px);
  transform: translateY(0px);
  -webkit-transition: all 200ms cubic-bezier(0.175,0.885,0.32,1.275);
  transition: all 200ms cubic-bezier(0.175,0.885,0.32,1.275);
}

.c1 {
  background-color: #FFFFFF;
  border-radius: 0 0 4px 4px;
  box-shadow: 0 3px 7px 0 rgba(126,87,194,0.2);
  top: calc(100% + 0.5rem);
  position: absolute;
  padding: 0.5rem;
  min-width: 300px;
  right: 0;
  visibility: visible;
}

<div
  class="c0 c1"
  data-testid="content"
  y="0"
>
  Content Test
</div>
`;

But assertion says:
No style rules found on passed Component

@Undistraction
Copy link

Undistraction commented Feb 24, 2020

This is still broken for me, even with:

const plugins = [
  ['babel-plugin-styled-components', { ssr: false, displayName: false }],
];

@fullstackzach
Copy link

This is also preventing us from upgrading to v7.

quantizor pushed a commit that referenced this issue Apr 9, 2020
* Fix support classes with displayName prefix

Closes #290 #294

* simplify regexp on get classname

* add unit test for custom prefix/display name
@fullstackzach
Copy link

fullstackzach commented Apr 13, 2020

I saw that 7.0.2 was released, I'm still having trouble getting it to work with Styled components v5.1.0 and react-testing-library. I think it does have something to do with the class name used and the regex code in jest-styled-components to parse it. It looks like the regex is looking for "sc-" but my component is outputting a different pattern. TextField__StyledLabel-ramey7-1

Here's the test:

const rendered = render(<TextField />)
...
const label = rendered.getByTestId('field-label')
expect(label).toMatchSnapshot()
expect(label).toHaveStyleRule('width', '(100% / 0.75)')

here is a debug() output of the component:

  console.log node_modules/@testing-library/react/dist/pure.js:94
    <span
      class="TextField__StyledLabel-ramey7-1 jQMSNG"
      data-test-id="field-label"
    />

When I output the snapshot I see the style rule does exist.

exports[`TextField removes active state on blur 1`] = `
.c0 {
  padding: 0.5rem 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
  position: absolute;
  top: 1rem;
  -webkit-transform-origin: 0 0;
  -ms-transform-origin: 0 0;
  transform-origin: 0 0;
  -webkit-transition: color 0.4s cubic-bezier(0.25,0.8,0.25,1),-webkit-transform 0.4s cubic-bezier(0.25,0.8,0.25,1);
  -webkit-transition: color 0.4s cubic-bezier(0.25,0.8,0.25,1),transform 0.4s cubic-bezier(0.25,0.8,0.25,1);
  transition: color 0.4s cubic-bezier(0.25,0.8,0.25,1),transform 0.4s cubic-bezier(0.25,0.8,0.25,1);
  width: 100%;
  -webkit-transform: translateY(-50%) scale(0.75);
  -ms-transform: translateY(-50%) scale(0.75);
  transform: translateY(-50%) scale(0.75);    
  width: (100% / 0.75);  <-- style testing for
}

Test output shows:

● TextField › removes active state on blur

    No style rules found on passed Component

      159 |     // input has focus
    > 161 |     expect(label).toHaveStyleRule('width', '(100% / 0.75)')
          |                   ^

Dependencies:

    "@testing-library/jest-dom": "5.5.0",
    "@testing-library/react": "10.0.2",
    "babel-plugin-styled-components": "1.10.7",
    "jest-styled-components": "7.0.2",
    "styled-components": "5.1.0",

@hyeunny
Copy link

hyeunny commented Apr 13, 2020

@fullstackzach having the same issue here

@keubs
Copy link

keubs commented May 11, 2020

Adding to this: I'm seeing the same issue on the toHaveStyleRule() assertion. A little debugging appears to show some components loading the stylesheet via the getHTML() function via this function in utils.js (https://github.com/styled-components/jest-styled-components/blob/master/src/utils.js#L17)
image

and other components are not
image

masterSheet is a module imported via __PRIVATE__ (https://github.com/styled-components/jest-styled-components/blob/master/src/utils.js#L2) when styled-components is imported. I can't wrap my head around how these modules are constructed in styled-components, so this is where my trail goes cold. Should I reach out to the styled components team about this?

wenche added a commit to equinor/design-system that referenced this issue Jun 10, 2020
* Upgrade fix and feature in storybook

* Remove core-js as dependency as it doesn't seems to be used directly, but rather by other packages

* Use @storybook/source-loader instead of  @storybook/addon-storysource/loader because of deprecation warning

* ⬆️ Upgrade styled-components from 4 to 5.1.1

* Upgrade fix and feat. Upgrade github-markdown-css to 4.0.0

* ⬆️ Upgrade Prettier from 1.19.1 to 2.0.5. We already use the new defaults for trailingComma, arrowParens and endOfLine

* ⬆️ Upgrade react-helmet from 5.x.x to 6.0.0. Missing title almost everywhere, but that's not caused by this upgrade

* ⬆️ Upgrade gatsby-plugin-matomo from 0.7.2 to 0.8.3

* ⬆️ Upgrade fix and feature

* ⬆️ Upgrade prettier from 1.19.1 to 2.0.5

* :arrow_up; Upgrade ramda from 0.26.1 to 0.27.0. No upgrade guide, so assuming it's safe even if there is no real semver

* ⬆️ Upgrade fix and feature. Upgrade prettier from 1.19.1 to 2.0.5

* Replace deprecated rollup-plugin-babel with @rollup/plugin-babel

* Replace deprecated rollup-plugin-json with @rollup/plugin-json

* ⬆️ Upgrade rollup from 1.32.1 to 2.15.0

* Replace rollup-plugin-node-resolve and rollup-plugin-commonjs with corresponding @rollup/plugin-x

* ⬆️ Upgrade ætesting-library/jest-dom from 4.2.4 to 5.9.0

* Update test to work

* Downgrade styled-components og jest-styled-components because of a bug styled-components/jest-styled-components#294

* Upgrade prettier. Fix eslint errors. Support for optional chaining with eslint

* ⬆️ Upgrade fix and features

* Remove eslint-config-airbnb, use eslint:recommended as defaults instead

* Upgrade eslint from 6.8.0 to 7.2.0. Remove duplicate eslint settings in core to avoid errors

* Add some more eslint rules

* Add missing semi

* Add missing semi

* Merge

* Add missing displayName

* Add node engine greater than 10

* Add hard space back in

* ⬆️ Upgrade rollup and @rollup/plugin-node-resolve

* ⬆️ Upgrade rollup and @rollup/plugin-node-resolve
@solimant
Copy link

Probably similar?

Bug.test.tsx

import styled from "styled-components";
import React from "react";
import {mount} from "enzyme";

import 'jest-styled-components';

const Foo = () => (
  <div>Bar</div>
);

const StyledFoo = styled(Foo)`
  color: mediumspringgreen;
`;

describe('StyledFoo', () => {
  it('has a mediumspringgreen color', () => {
    const styledFoo = mount(<StyledFoo />);
    expect(styledFoo).toHaveStyleRule('color', 'mediumspringgreen');
  });
});

Snapshot:

exports[`StyledFoo has a mediumspringgreen color 1`] = `
.c0 {
  color: mediumspringgreen;
}

<Styled(Foo)>
  <Foo
    className="c0"    <<<<  it's there
  >
    <div>
      Bar
    </div>
  </Foo>
</Styled(Foo)>
`;

But I get No style rules found on passed Component.

However, if I introduce className, it works:

const Foo = ({className}: {className?: string}) => (
  <div className={className}>Bar</div>
);

Snapshot:

exports[`StyledFoo has a mediumspringgreen color 1`] = `
.c0 {
  color: mediumspringgreen;
}

<Styled(Foo)>
  <Foo
    className="c0"
  >
    <div
      className="c0"
    >
      Bar
    </div>
  </Foo>
</Styled(Foo)>
`;

Is this expected?

@Tokimon
Copy link

Tokimon commented Jun 24, 2020

So... I had similar issue and I have already pointed out the problem in this comment
#297 (comment)

In short the algorithm is built so that you HAVE TO have the sc- prefix when testing (ssr: true), but in my case (for some strange unknown reason) not all my components class names get the prefix, even with ssr: true, so I am stuck with upgrading until this is fixed.

I have already proposed to fix it, but as I am not sure how the procedure work I won't start any correction before I get a green light to do so.

@tobilen
Copy link

tobilen commented Oct 15, 2020

I got it working for me with the new namespace option of babel-plugin-styled-components, which enables us to pass the sc prefix by hand now. This is my babel config now:

module.exports = {
  // ...
  env: {
    test: {
      plugins: [
        [
          'babel-plugin-styled-components',
          { ssr: false, displayName: false, namespace: 'sc' },
        ],
      ],
    },
  },
};

@oguzgelal
Copy link

oguzgelal commented Oct 31, 2020

Simply adding the package react-test-renderer as a dependency fixed this issue for me:

yarn add react-test-renderer --dev
npm install react-test-renderer --save-dev

# for ts projects
yarn add @types/react-test-renderer --dev
npm install @types/react-test-renderer --save-dev

Also, here's my babel config:

{
  "presets": ["next/babel"],
  "plugins": [["styled-components", { "ssr": true }]]
}

@Fi1osof
Copy link

Fi1osof commented Nov 10, 2020

Simply adding the package react-test-renderer as a dependency fixed this issue for me:

@oguzgelal , react-test-renderer installed, but problem still exists.

jest-styled-components checking is hardcoded.

const isStyledClass = className =>
  /^(\w+(-|_))?sc-/.test(className);

styles should masker with "sc-".

Snapshot from another my project with working:

<div
  class="indextest__DivStyled-sc-1wt13as-0 hViIRb"
>
  Text 
</div>

"sc-" in classname exists.

But on broken project not exists:

<div
  class="indextest__DivStyled-p00oe-0 jAwXaO"
>
  Text 
</div>

To fix i have to add namespace to babel config.

{
  "presets": ["next/babel"],
  "plugins": [
    [
      "styled-components",
      {
        // In some projects missed namespace for styled-components
        // По какой-то причине в styled пустой неймспейс и в тестах не проходит маска
        // /^(\w+(-|_))?sc-/.test(className)
        "namespace": "sc-",
        "ssr": true
      }
    ]
  ]
}

@nielswijers
Copy link

i got the same problem. i saw that there where multiple versions of styled components included (v5.1 and v5.2).

removing v5.2 did the trick for me

@tiagomnferreira-zz
Copy link

I got it working for me with the new namespace option of babel-plugin-styled-components, which enables us to pass the sc prefix by hand now. This is my babel config now:

module.exports = {
  // ...
  env: {
    test: {
      plugins: [
        [
          'babel-plugin-styled-components',
          { ssr: false, displayName: false, namespace: 'sc' },
        ],
      ],
    },
  },
};

This worked for me! Using nx.dev

@stonebk
Copy link

stonebk commented Mar 25, 2021

Using Jest testEnvironment "node" seemed to be one of the issues for me. When I change it back to the default "jsdom", the issue went away.

@kylorhall
Copy link

kylorhall commented Jun 24, 2021

Maybe another slight piece to someone's puzzle. I've had to solve this a half dozen times and this is yet another scenario for me.

Both specificity and the modifier option are very key. Regardless of babel-plugin-styled-components configuration, you can still easily encounter this error for a lot of other reasons.

❌ Broken No style rules found on passed Component:

import styled from 'styled-components';
import { mount } from 'enzyme';

const Checkbox = styled.input`
  input[type='checkbox']& {
    height: 20px;
  }
`;

test('fails', () => {
  expect(mount(<Checkbox />)).toHaveStyleRule('height', '20px');
});

test('fails w/ modifier', () => {
  expect(mount(<Checkbox />)).toHaveStyleRule('height', '20px', {
    modifier: "input[type='checkbox']",   // no combination of this worked here like it does in other tests…
  });
});

🎉 I got it passing by changing the component itself, adding &, to the specificity. This would be breaking in other places, but in here it works 🤞…

import styled from 'styled-components';
import { mount } from 'enzyme';

const Checkbox = styled.input`
  &,
  input[type='checkbox']& {
    height: 20px;
  }
`;

test('passes', () => {
  expect(mount(<Checkbox />)).toHaveStyleRule('height', '20px');
});

I hope no one's really using this specific pattern scenario, but it might highlight specificity issues to people debugging.

norentkhy added a commit to norentkhy/mindmap that referenced this issue Aug 2, 2021
Previously
```js
  expect(Element).toHaveStyleRule('some', 'args')
```
had problems rendering, similar to problems mentioned here:
styled-components/jest-styled-components#294

the prefix of sc in babel-styled-components did not work.
I tried to debug the jest-styled-components matcher, but alas.
@lucasiori
Copy link

I'm receiving an error No style rules found on passed Component with toHaveStyleRule. It started after update jest to 27x, I tried to configure the babel-plugin-styled-components with { ssr: false } but it doesn't work. Any idea to fix it?

Setup:

"jest": "^27.0.6"
"jest-styled-components": "^7.0.5",
"styled-components": "^5.3.1",

@tobilen
Copy link

tobilen commented Aug 27, 2021

I'm receiving an error No style rules found on passed Component with toHaveStyleRule. It started after update jest to 27x, I tried to configure the babel-plugin-styled-components with { ssr: false } but it doesn't work. Any idea to fix it?

Setup:

"jest": "^27.0.6"
"jest-styled-components": "^7.0.5",
"styled-components": "^5.3.1",

try with { ssr: false, displayName: false, namespace: "sc" }.

our babel config:

const defaultConfig = {
  presets: ["next/babel"],
  plugins: [],
};

module.exports = ({ env }) => {
  if (env("test")) {
    return {
      ...defaultConfig,
      plugins: [
        ...defaultConfig.plugins,
        [
          "babel-plugin-styled-components",
          { ssr: false, displayName: false, namespace: "sc" },
        ],
      ],
    };
  }

  return {
    ...defaultConfig,
    plugins: [
      ...defaultConfig.plugins,
      ["babel-plugin-styled-components", { ssr: true, namespace: "sc" }],
    ],
  };
};

@moatorres
Copy link

moatorres commented Nov 5, 2021

Just a heads-up: none of the above seems to work for me, either with enzyme's mount function or react-test-renderer's renderer.create.

By "none of the above" I mean any { ssr: false, displayName: false, namespace: "sc" } suggested solutions.

Versions:

"jest-styled-components": "7.0.5",
"styled-components": "5.3.3"
"react-test-renderer": "17.0.2"
"enzyme": "3.11.0",
"babel-plugin-styled-components": "1.13.3",

My current workaround (this gist):

test-helpers.ts

import renderer, { ReactTestRendererJSON } from 'react-test-renderer'

export function render(component: React.ReactElement) {
  return (
    renderer
      .create(component)
      .toJSON() as ReactTestRendererJSON
  )
}

export function renderClasses(component: React.ReactElement): string[] {
  const {
    props: { className },
  } = render(component)
  return className ? className.trim().split(' ') : []
}

type ComputedStyles = Record<string, string | Record<string, string>>

export function getComputedStyles(className: string) {
  const div = document.createElement('div')
  div.className = className

  const computed: ComputedStyles = {}

  for (const sheet of document.styleSheets) {
    for (const rule of sheet.cssRules) {
      if (rule instanceof CSSMediaRule) readMedia(rule)
      else if (rule instanceof CSSStyleRule) readRule(rule, computed)
    }
  }

  return computed

  function matchesSafe(node: HTMLDivElement, selector: string) {
    if (!selector) return false

    try {
      return node.matches(selector)
    } catch (error) {
      return false
    }
  }

  function readRule(rule: CSSStyleRule, dest: ComputedStyles) {
    if (matchesSafe(div, rule.selectorText)) {
      const { style } = rule
      for (let i = 0; i < style.length; i++) {
        const prop = style[i]
        dest[prop] = style.getPropertyValue(prop)
      }
    }
  }

  function readMedia(mediaRule: CSSMediaRule) {
    const key = `@media ${mediaRule.media[0]}`
    const dest = {}
    for (const rule of mediaRule.cssRules) {
      if (rule instanceof CSSStyleRule) readRule(rule, dest)
    }

    if (Object.keys(dest).length > 0) computed[key] = dest
  }
}

/* Return styles from all classes applied merged into a single object. */
export function getStyles(comp: React.ReactElement) {
  return renderClasses(comp)
    .filter(c => !c.includes('sc'))
    .map(getComputedStyles)
    .reduce((result, current) => Object.assign(result, current), {})
}

Then we can use the getStyles function to check our styles directly with jest, like so:

import { getStyles } from './test-helpers'

test('extended components keep their styles', () => {
  const Box = styled.div`
    margin: 16px;
  `
  const Card = styled(Box)`
    color: tomato;
  `

  const styles = getStyles(<Card />)
  expect(styles).toEqual({ margin: '16px', color: 'tomato' })
})

@mryechkin
Copy link

try with { ssr: false, displayName: false, namespace: "sc" }

This worked for me 🥳 Thanks!

@tenshiemi
Copy link

None of the recommended solutions are working for me so far

@nickjohngray
Copy link

nickjohngray commented Mar 2, 2022

Adding the line below in babel.config.js fixed it for me:
['babel-plugin-styled-components', { ssr: process.env.NODE_ENV === 'test' }]

// our project originally had ssr as false , process.env.NODE_ENV === 'test' sets it as true when running tests.

when using:

"react-test-renderer": "^17.0.2"
"jest-styled-components": "^7.0.8"
"styled-components": "^5.1.1"

@athammer
Copy link

athammer commented Jul 6, 2022

Seems to happen to me when switching from commonjs to esnext for me. None of the solutions worked above. Been to pretty much every GitHub/Stackoverflow thread related to this and nothing worked.

I'm guessing something is breaking due to the switch? No clue what package or how to fix it though

I'm using

    "@testing-library/react": "^12.1.2",
    "babel-plugin-styled-components": "^2.0.7",
    "jest-styled-components": "^7.0.4",
    "styled-components": "^5.3.3",

Reverting to the versions below fixes it even without reverting back to commonjs. This is super frustrating :(

    "jest-styled-components": "^6.3.4",
    "styled-components": "^4.4.1",

Code example

// Test File
expect(screen.getByTestId('payment-date-name')).toHaveStyleRule('color', '#aa2e23');

// Code
const $PaymentDateName = styled.div<{ isOverdue: boolean }>`
  color: ${fromTheme('clrGrey')};
  ${({ isOverdue }) =>
    isOverdue &&
    css`
      /* In Chrome only, without setting flex-start the item will stretch to fill up its container */
      align-items: flex-start;
      background-color: ${fromTheme('clrWarningLight')};
      color: ${fromTheme('clrWarning')};
      padding: 0 ${fromTheme('spacing8')};
    `};
`;

@kolesker
Copy link

kolesker commented Mar 2, 2023

To me none of the above fixes worked and I found why it was working for me in some test files but not in others:

I was creating the renderer INSIDE the DESCRIBE and it was like 'jest-styled-components' was not being applied to those test files. I moved the renderer creation to every single test (test/it) and worked:

// BEFORE
describe('Label', () => {
  const tree = renderer.create(<Label />).toJSON();
  it('should match snapshot', () => {
    expect(tree).toHaveStyleRule('display', 'block');
  });
});

// AFTER
describe('Label', () => {
  it('should match snapshot', () => {
    const tree = renderer.create(<Label />).toJSON();
    expect(tree).toHaveStyleRule('display', 'block');
  });
});

"styled-components": "^5.3.6",
"jest-styled-components": "^7.1.1",
"babel-plugin-styled-components": "^2.0.7",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests