Open LouiseReid opened 4 years ago
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: https://github.com/styled-components/jest-styled-components/commit/8c2ea4a0a8789e11707e7f18e76b811e0d70c4c0#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.
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 https://github.com/styled-components/jest-styled-components/issues/290
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?
I'm having the same problem with enzyme.
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
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
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 }],
];
This is a duplicate of #290
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
This is still broken for me, even with:
const plugins = [
['babel-plugin-styled-components', { ssr: false, displayName: false }],
];
This is also preventing us from upgrading to v7.
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",
@fullstackzach having the same issue here
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)
and other components are not
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?
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?
So... I had similar issue and I have already pointed out the problem in this comment https://github.com/styled-components/jest-styled-components/issues/297#issuecomment-639362675
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.
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' },
],
],
},
},
};
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 }]]
}
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
}
]
]
}
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
I got it working for me with the new
namespace
option ofbabel-plugin-styled-components
, which enables us to pass thesc
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
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.
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.
:x: 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.
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",
I'm receiving an error
No style rules found on passed Component
withtoHaveStyleRule
. It started after updatejest
to 27x, I tried to configure thebabel-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" }],
],
};
};
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' })
})
try with
{ ssr: false, displayName: false, namespace: "sc" }
This worked for me 🥳 Thanks!
None of the recommended solutions are working for me so far
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"
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')};
`};
`;
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",
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 errorNo style rules found on passed Component
.Example test
Tested component
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