7

Running React Testing Library to generate snapshots on JSX which uses the Emotion css prop results in no CSS being rendered.

I have tried using the "@emotion/jest/serializer" but still no luck.

Component:

<button
      role="button"
      css={(theme)=> {
        backgroundColor: 'hotpink',
        '&:hover': {
          color: theme('lightgreen'),
        },
      }}
/>

Test:

import React from 'react';
import { render } from '@testing-library/react';
import { createSerializer } from '@emotion/jest';

import { Component } from './component';

expect.addSnapshotSerializer(createSerializer());

describe('IconComponent', () => {
  it('should match the snapshot for the given props', () => {
    const { asFragment } = render(<Component icon="knownIcon" />);
    
    expect(asFragment()).toMatchSnapshot();
  });

Snapshot: (This gets rendered as an anonymous object rather than CSS)

exports[` 1`] = `
<DocumentFragment>
  <button
    css="[object Object]"
    role="button"
  />
</DocumentFragment>
`;
Alex
  • 2,651
  • 2
  • 25
  • 45

2 Answers2

2

I think you are just missing the final step.

https://emotion.sh/docs/css-prop

Set the jsx pragma at the top of your source file that uses the css prop. This option works best for testing out the css prop feature ...... such as Create React App 4 then /** @jsx jsx / pragma might not work and you should use /* @jsxImportSource @emotion/react */ instead.

From the emotion doc, adding /* @jsxImportSource @emotion/react */ on the top of your component file helps css option to render probably in the test.

CustomButton.js

/** @jsxImportSource @emotion/react */

export function CustomButton() {
  return (
    <button
      css={{
        "backgroundColor": "hotpink",
        "&:hover": {
          color: "lightgreen"
        }
      }}
    ></button>
  );
}

Result

exports[`IconComponent should match the snapshot for the given props 1`] = `
<DocumentFragment>
  .emotion-0 {
  background-color: hotpink;
}

.emotion-0:hover {
  color: lightgreen;
}

<button
    class="emotion-0"
  />
</DocumentFragment>
`;

If you are not using create-react-app, use the follow instead:

/** @jsx jsx */
import { jsx } from '@emotion/react'

Here is the repo, you can clone it to test it.


Older Version

For older version of react (< 16.4), you will need to use back "@emotion/core" instead of "@emotion/react" to transpile the file in old way.

package.json

 "@emotion/core": "10.1.1",

Button.js

/** @jsx jsx */
import { jsx } from '@emotion/core' <--- use the @emotion/core to transpile the file in old way. 

import React from "react";

const Button = () => {
  return (
    <button
      css={{
        backgroundColor: "hotpink",
        "&:hover": {
          color: "lightgreen"
        }
      }}
    ></button>
  );
};

export default Button;

Here is the repo for demonstration

Mic Fung
  • 5,404
  • 2
  • 7
  • 17
  • Thanks for your suggestion but this is only for React 16.4.0 upwards. – Alex May 25 '21 at 08:28
  • Which version of react are you using? – Mic Fung May 25 '21 at 08:30
  • updated the answer at the bottom. I think it is better to tell us which version of react and emotion you are dealing with next time. – Mic Fung May 25 '21 at 09:37
  • sure, its hard to know which info is required whilst keeping it as concise as possible. I appreciate the effort and will try out your updated suggestion and give you a shout, thanks – Alex May 25 '21 at 15:07
  • I have checked and since we are using https://emotion.sh/docs/@emotion/babel-preset-css-prop this line is automatically added to the top of each file – Alex May 27 '21 at 13:36
  • It seems like the babel plugin is adding `@emotion/react` instead of `@emotion/core` – Mic Fung May 27 '21 at 13:44
  • check if you are using @emotion/babel-preset-css-prop v11 or v10. If you are using 11, the import will be `@emotion/react`. I read the source code. `v10 will import `@emotion/core` so try `npm install @emotion/babel-preset-css-prop@10.2.1` – Mic Fung May 27 '21 at 13:51
  • just try with pure react and babel with the plugins you mentioned. no problem on generating css class. too much unknown from your side, cross-check your setting with the repo https://github.com/michael-vascue/test-emotion-babel/blob/master/package.json – Mic Fung May 27 '21 at 14:26
  • I agree there is quite a bit of unknown but also no help online whatsoever for serialising Emotion using React Testing Library so was helping to get some concrete info. I will try upgrading as you suggest now, thanks again for your continuing help – Alex May 27 '21 at 15:04
  • We are on "@emotion/babel-preset-css-prop": "11.2.0", – Alex May 27 '21 at 15:05
  • should be 10.2.1 – Mic Fung May 27 '21 at 15:07
  • One difference here, you are using object notation for the css parameter, we use a function as there is a theme hoc. – Alex May 27 '21 at 15:08
  • ok. didn't notice you change the question. will try adding theme – Mic Fung May 27 '21 at 15:13
  • are you using `emotion-theming`? – Mic Fung May 27 '21 at 15:17
  • dont't know which library you are using, the syntax is a bit different from `emotion-theming`. there is a missing `()` to wrap the color and &:hover object for returning and `theme('lightgreen')` is not valid in emotion-theming where theme is not a function – Mic Fung May 27 '21 at 15:24
  • tested with `emotion-theming`, no problem at all. But there is a need to provide ThemeProvider in the test so it can pass the theme params to children. https://github.com/michael-vascue/test-emotion-babel/blob/master/src/Button.test.js – Mic Fung May 27 '21 at 15:52
  • I don't mind if I can earn bounty or not. Able to solve the problem is more important to me. If you cannot make it work, can you make a minimal example for me to work with? like the js file and package.json. – Mic Fung May 27 '21 at 19:12
  • Sure I will try to upload it tomorrow, everything is crazy busy today. – Alex May 27 '21 at 19:27
0

Another solution https://emotion.sh/docs/testing#writing-a-test

import React from 'react'
import renderer from 'react-test-renderer'

const Button = props => (
  <button
    css={{
      color: 'hotpink'
    }}
    {...props}
  />
)

test('Button renders correctly', () => {
  expect(
    renderer.create(<Button>This is hotpink.</Button>).toJSON()
  ).toMatchSnapshot()
})
Marat Zimnurov
  • 1,462
  • 9
  • 15