styled-components / jest-styled-components

🔧 💅 Jest utilities for Styled Components
MIT License
1.58k stars 145 forks source link

Match snapshot fails with "undefined:3:21: property missing ':'" #97

Closed topicus closed 6 years ago

topicus commented 6 years ago

I have this test:

import 'jest-styled-components';
import React from 'react';
import { truncate } from '../style';
import styled from 'styled-components';
import { shallow } from 'enzyme';

describe('shared/utils/string/isBlank', () => {
  it('should return the css with width', () => {
    const Result = styled.div`
      color: red;
      ${truncate({ width: 100 })};
    `;
    const wrapper = shallow(<Result />);
    expect(wrapper).toMatchSnapshot();
  });
});

And this truncate function

export function truncate({ maxWidth, width }) {
  return `
    ${({ maxWidth }) => maxWidth && `max-width: ${maxWidth}px;`}
    ${({ width }) => width && `width: ${width}px;`}
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  `;
}

However, when I try to match the snapshot I'm getting:

    undefined:3:21: property missing ':'

      at Object.it (src/shared/utils/__tests__/style.js:22:21)
          at Promise (<anonymous>)
      at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
          at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:

Seems like jest-styled-components doesn't like those nested functions because if I remove them it works.

MicheleBertoli commented 6 years ago

Thank you very much @topicus, this looks similar to #93. The code doesn't seem to work in the browser as well, can you please check?

zvictor commented 6 years ago

I am having the same issue. What bothers me is that the stack trace does not help me at all to trace the origin of the problem. In a big project it is hard even to figure out that the issue is being caused by this serialiser.

greypants commented 6 years ago

Also having this issue. What's weird is that the test runs fine locally, but fails in our CI pipeline (Jenkins). So what's the specific issue? Nesting string interpolation?

greypants commented 6 years ago

Solved!

We apparently need to used the css template literal helper

A helper function to generate CSS from a template literal with interpolations. You need to use this if you return a template literal with interpolations inside an interpolation. (This is due to how tagged template literals work)

If you leave off the css your function will be toString()ed and you'll not get the results you expected.

I've determined that using the css helper around nested string interpolation resolves the issue. Not sure why it's only necessary for tests, when it renders fine in the browser. I'd still love to understand why this is.

brycepj commented 6 years ago

@greypants Thanks for that tip. I'll give the css helper a try 👍

marvinkome commented 6 years ago

But due to the poor stack trace, I can't really know where the error is coming from. Is there any easy way to know where the error is coming from?

DevanB commented 6 years ago

I'm running into this exact issue and have narrowed down my problematic code to be background-images. An example:

background-image: url("data:image/svg+xml;utf8, <svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10' height='10' viewBox='0 0 10 7'><polygon points='0 0 5 7 10 0' style='fill: rgb%2839, 34, 84%29' /></svg>");

UPDATE:

My solution was to URL encode the contents in the url() method.

cchampou commented 6 years ago

@DevanB Thank you for the tip ! I'm facing the same issue with a very similar code (svg as background-image), and URL encode solve the parsing issue However the svg did not show up anymore in browser... I'm trying hard getting it to work. If you have any idea, I'd be pleased to hear it.

Source code

const svg = "data:image/svg+xml;utf8, <svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='100' height='100' viewBox='0 0 100 100'><path fill='#fff' d=''/></svg>";
// SVG path was intentionally cut

const ButtonClose = styled.div`
  position: absolute;
  background-image: url("${encodeURIComponent(svg)}");
`

Original non-working scheme

The SVG string was not URL encoded, and the parser failed with

undefined:2:360: property missing ':'

      at error (node_modules/css/lib/parse/index.js:62:15)
      at declaration (node_modules/css/lib/parse/index.js:224:33)
      at declarations (node_modules/css/lib/parse/index.js:253:19)
      at rule (node_modules/css/lib/parse/index.js:561:21)
      at rules (node_modules/css/lib/parse/index.js:118:70)
      at stylesheet (node_modules/css/lib/parse/index.js:81:21)
      at Object.<anonymous>.module.exports [as parse] (node_modules/css/lib/parse/index.js:565:20)
      at getCSS (node_modules/jest-styled-components/src/utils.js:46:26)
      at getStyle (node_modules/jest-styled-components/src/styleSheetSerializer.js:73:15)
      at Object.print (node_modules/jest-styled-components/src/styleSheetSerializer.js:139:19)

What helped but caused the svg not to show up

Just URL encoded the SVG string.

Thanks for your tips, hope we will find out what's wrong.

abejfehr commented 6 years ago

encoding the contents of the url() function is not a solution, the images no longer show up in Firefox or Chrome in that case

VentroArt commented 5 years ago

this issue still exists

export const StyledDiv = styled.div`
    width: 400px;
    height: 100%;
    border-top: 7px solid #e3e7ea;
    border-radius: 5px;
    margin-right: 40px;
    background: #fff;
    display: flex;
    flex-direction: column;
`;

if run only one case - it's okay

it("StyledDiv", () => {
        const component = renderer.create(<StyledDiv />).toJSON();
        expect(component).toMatchSnapshot();
    });

but if run "describe" section it fails with error Error: undefined:2:6176: property missing ':' at error (.../node_modules/css/lib/parse/index.js:62:15)

giovannigiordano commented 5 years ago

Same problem, it happens only with @storybook/addon-storyshots with arg --coverage

kevindantas commented 5 years ago

I'm using jest-dom 6.3.1 and have the same problem with a SVG background image and like @abejfehr said, encoding the image is not gonna work on Chrome or FIrefox.

// MyComponent.js
const MyComponent = styled.span`
    background: url('data:image/svg+xml;utf8,<svg width="9" height="6" xmlns="http://www.w3.org/2000/svg"><path d="M1.28.24a.712.712 0 0 0-1.06 0 .855.855 0 0 0 0 1.144L4.499 6 8.78 1.382a.855.855 0 0 0 0-1.145.712.712 0 0 0-1.06 0L4.499 3.71 1.28.24z" fill="%230E242F" fill-rule="nonzero" fill-opacity=".369"/></svg>');
`

// MyComponent.spec.js
it('should match snapshot', () => {
    const { container } = render(<MyComponent />);
    expect(container).toMatchSnapshot();
});
jaimefps commented 5 years ago

I've dealt with a similar problem for the past week. Unfortunately, the property missing ':' error is so useless that we had to dig around all our code and review each styled component to look for issues.

It was strange that we couldn't get any errors when actually running the app, and that it was only came up during tests. Moreover, the tests were passing before, so some newer version of emotion/jest/jest-emotion/react-emotion was giving us this problem.

Below is a link to our fix.

Root cause: we had a style that sometimes returned a boolean, and sometimes a string. Fix: Had to ensure we always return a string.

https://stackoverflow.com/questions/55641543/react-emotion-and-jest-snapshots-error-property-missing/55656556#55656556

davvidbaker commented 5 years ago

Ran into this same issue today. My problem was some stray text in styled component template literal, like

- const Wrapper = styled.div`
-  color: ${({ theme }) => theme.specialGray};
-  fs
- `;
+ const Wrapper = styled.div`
+  color: ${({ theme }) => theme.specialGray};
+ `; 
phabreeze commented 5 years ago

This worked for me https://css-tricks.com/probably-dont-base64-svg/#article-header-id-2 and https://codepen.io/tigt/post/optimizing-svgs-in-data-uris

UnbearableBear commented 5 years ago

Using base 64 encoding solved the issue for me. None of the above option worked (either the URL encoding or the css utility)

pascualmg commented 4 years ago

image we found this error compiling from TS, this is our solution hope helps someone

fabb commented 4 years ago

I submitted a new issue for the still open svg bug: #293

shravyaRB commented 4 years ago

@jaimefps thanks returning string instead of boolean worked for me

tareqdayya commented 4 years ago

Had the same issue. Was using a variable inside of styled components that returned an object when I was under the impression that it was returning a number. My font size was being set to {}px instead of 16px 😁

jphawk commented 3 years ago

I had the same issue, one variable in styled components was returning an object instead of a number. The error message should really be improved as it took a lot of time to debug 😢