Skip to content

Commit

Permalink
Fixed an issue with Enzyme snapshots for components using an array as…
Browse files Browse the repository at this point in the history
… the `css` prop (#2233)

* test: create failing test case for #2139

* fix(@emotion/jest): internal props are serialized when child component has css prop

(cherry picked from commit 2c32d546ad206a2ab255ef93f7bdf2e2a136dcf7)

* fix(@emotion/jest): css array should work with serializer

(cherry picked from commit 2a1a68424e8eb9a7c38b637f2a639024c667401b)

* chore: add changeset

(cherry picked from commit 2460754)
(cherry picked from commit 7d3eb7942f798621c2e374fc9fa0fae8b555dd16)

* test: update titles for tests

* Update .changeset/two-laws-provide.md

* Update snapshots

Co-authored-by: Andrew Stephens <astephens@cainc.com>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
  • Loading branch information
3 people authored Feb 8, 2021
1 parent c9b57f3 commit 0c31ed0
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/two-laws-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@emotion/jest': minor
---

Fixed an issue with Enzyme snapshots for components using an array as the `css` prop - those should be printed OK now.
39 changes: 34 additions & 5 deletions packages/jest/src/create-serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,34 @@ function filterEmotionProps(props = {}) {
return rest
}

function isShallowEnzymeElement(element: any, classNames: string[]) {
function getLabelsFromCss(css) {
const getLabel = style => {
const styleString = style.styles || style
const matches = styleString.match(/.*;label:([^;]+);/)
return matches && matches[1]
}
return (Array.isArray(css) ? css.map(getLabel) : [getLabel(css)]).filter(
Boolean
)
}

function isShallowEnzymeElement(
element: any,
keys: string[],
labels: string[]
) {
const delimiter = ' '
const childClassNames = flatMap(element.children || [], ({ props = {} }) =>
(props.className || '').split(delimiter)
).filter(Boolean)
return !hasIntersection(classNames, childClassNames)
return !childClassNames.some(className => {
const [childKey, hash, ...childLabels] = className.split('-')
return (
keys.includes(childKey) &&
childLabels.length &&
childLabels.every(childLabel => labels.includes(childLabel))
)
})
}

const createConvertEmotionElements = (keys: string[], printer: *) => (
Expand All @@ -104,13 +126,20 @@ const createConvertEmotionElements = (keys: string[], printer: *) => (
return node
}
if (isEmotionCssPropEnzymeElement(node)) {
const cssClassNames = (node.props.css.name || '').split(' ')
const labels = getLabelsFromCss(node.props.css)
const cssName = Array.isArray(node.props.css)
? node.props.css
.map(({ name }) => name)
.filter(Boolean)
.join(' ')
: node.props.css.name
const cssClassNames = (cssName || '').split(' ')
const expectedClassNames = flatMap(cssClassNames, cssClassName =>
keys.map(key => `${key}-${cssClassName}`)
)
// if this is a shallow element, we need to manufacture the className
// since the underlying component is not rendered.
if (isShallowEnzymeElement(node, expectedClassNames)) {
if (isShallowEnzymeElement(node, keys, labels)) {
const className = [node.props.className]
.concat(expectedClassNames)
.filter(Boolean)
Expand All @@ -128,7 +157,7 @@ const createConvertEmotionElements = (keys: string[], printer: *) => (
type
}
} else {
return node.children
return node.children[0]
}
}
if (isEmotionCssPropElementType(node)) {
Expand Down
61 changes: 52 additions & 9 deletions packages/jest/test/__snapshots__/react-enzyme.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ exports[`enzyme mount theming 1`] = `
</div>
`;

exports[`enzyme mount with array of styles as css prop 1`] = `
.emotion-0 {
background-color: black;
color: white;
}
<div
className="emotion-0"
>
Test content
</div>
`;

exports[`enzyme mount with prop containing css element 1`] = `
.emotion-0 {
background-color: blue;
Expand Down Expand Up @@ -251,17 +264,34 @@ exports[`enzyme mount with styles on top level 1`] = `
background-color: red;
}
Array [
<Greeting
<Greeting
className="emotion-0"
>
<div
className="emotion-0"
>
<div
className="emotion-0"
>
Hello
</div>
</Greeting>,
]
Hello
</div>
</Greeting>
`;

exports[`enzyme parent and child using css property 1`] = `
.emotion-0 {
background-color: black;
}
.emotion-1 {
color: white;
}
<div
className="emotion-0"
>
Test content
<div
className="emotion-1"
/>
</div>
`;

exports[`enzyme shallow basic 1`] = `
Expand Down Expand Up @@ -343,6 +373,19 @@ exports[`enzyme shallow theming 1`] = `
</div>
`;

exports[`enzyme shallow with array of styles as css prop 1`] = `
.emotion-0 {
background-color: black;
color: white;
}
<div
className="emotion-0"
>
Test content
</div>
`;

exports[`enzyme shallow with prop containing css element 1`] = `
.emotion-0 {
background-color: blue;
Expand Down
34 changes: 33 additions & 1 deletion packages/jest/test/react-enzyme.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'test-utils/enzyme-env'

import jestInCase from 'jest-in-case'
import * as enzyme from 'enzyme'
import { jsx, ThemeProvider } from '@emotion/react'
import { css, jsx, ThemeProvider } from '@emotion/react'
import styled from '@emotion/styled'
import React from 'react'
import toJson from 'enzyme-to-json'
Expand Down Expand Up @@ -143,6 +143,19 @@ const cases = {
)
}
},
'with array of styles as css prop': {
render() {
const style1 = css`
background-color: black;
`

const style2 = css`
color: white;
`

return <div css={[style1, style2]}>Test content</div>
}
},
theming: {
render() {
const Button = styled.button`
Expand Down Expand Up @@ -191,6 +204,25 @@ describe('enzyme', () => {
cases
)

test('parent and child using css property', () => {
const parentStyle = css`
background-color: black;
`

const childStyle = css`
color: white;
`

const wrapper = enzyme.mount(
<div css={parentStyle}>
Test content
<div css={childStyle} />
</div>
)

expect(wrapper).toMatchSnapshot()
})

test('with prop containing css element in fragment', () => {
const FragmentComponent = () => (
<React.Fragment>
Expand Down

0 comments on commit 0c31ed0

Please sign in to comment.