jest-dom icon indicating copy to clipboard operation
jest-dom copied to clipboard

haveStyle does not work with linear-gradient

Open Domino987 opened this issue 6 years ago • 19 comments

  • @testing-library/jest-dom version: 4.2
  • npm version: 6.13.1
  • dom-testing-library version: 4.2.4
  • react-testing-library version: 9.3.2

Relevant code or config:

 expect(getByTestId('border')).toHaveStyle('background: linear-gradient(red 0%, red 49%, white 50%);'); // Checks the gradient color of the component.

What you did:

I wanted to test the gradient color applied like this: background: linear-gradient(red 0%, red 49%, white 50%);

What happened:

It always returns true if the expected value is a gradient. If one of them is e.g. a color, it fails as expected. It seems like the gradient string is just parsed into an empty string.

Reproduction:

Here is a sandbox.

If you change the expected value to something else than a gradient, it fails as expected, but lawys true, if it is a gradient.

Problem description:

A gradient in toHaveStyle always returns true.

Suggested solution:

Try to parse the gradient correctly and add a string compare to received and expected gradients.

Domino987 avatar Nov 30 '19 13:11 Domino987

Can you try using the latest version of jest-dom (v4.2.4)? Also, just to be safe, in the assertion, avoid using compound css properties. Try with background-color linear-gradient(...) instead of just background: ....

gnapse avatar Nov 30 '19 15:11 gnapse

I tried it before on my machine, thats why I forgot to update the version.

I updated the sandbox, but the error still persists. It expects - background-color: ; but should expect - background-color: linear-gradient(#96f3f4 0%, #96f3f4 49%, white 50%);

So if the expected and received background-colors are both gradients, they pass no matter the actual gradient.

It seems like that in getStyleDeclaration the normalizing of colors fails because the style is not applied to the copy element created with document.createElement('div');. But only the gradients.

Domino987 avatar Nov 30 '19 18:11 Domino987

Hi all,

I think I hit something similar and it might be helpful or point someone in the right direction before spending some time reproducing it in an isolated scenario.

After playing with different versions, it seems like there's a regression from version 4.1.1 to 4.1.2 (where it starts failing for us)

Test code
    const element = getByTestId('confetti-background-square');

    debug();
    expect(element).toHaveStyle(`
        width: 14px;
        height: 14px;
        top: 30%;
        left: 55%;
        background-color: '#F3F2F0';
        transform: rotateZ(22deg);
    `);
See console output below after running our specs
 FAIL  src/components/ConfettiBackground/ConfettiBackgroundSquare/ConfettiBackgroundSquare.test.tsx
  ● Console

    console.log node_modules/@testing-library/react/dist/pure.js:94
      <body>
        <div>
          <div
            class="confetti-background-square"
            data-testid="confetti-background-square"
            style="width: 14px; height: 14px; background-color: red; top: 30%; left: 55%; transform: rotateZ(22deg);"
          />
        </div>
      </body>

  ● applies the expected styles from required props

    expect(element).toHaveStyle()

    - Expected

    - background-color: ;
      height: 14px;
      left: 55%;
      top: 30%;
      transform: rotateZ(22deg);
      width: 14px;

      16 | 
      17 |     debug();
    > 18 |     expect(element).toHaveStyle(`
         |                     ^
      19 |         width: 14px;
      20 |         height: 14px;
      21 |         top: 30%;

      at Object.<anonymous> (src/components/ConfettiBackground/ConfettiBackgroundSquare/ConfettiBackgroundSquare.test.tsx:18:21)

Fixed it for now by pinning to v4.1.1 - let me know if that's totally unrelated and warrants a separate issue :)

dennisroethig avatar Dec 02 '19 04:12 dennisroethig

@dennisroethig should the background-color value be quoted? In the expect(element).toHaveStyle assertion you have this line:

background-color: '#F3F2F0';

Furthermore, in the output of the debug() call the element seems to have background-color: red, so it's ok that the assertion fails, right? Because the element was expected to have background color '#F3F2F0' but it has red instead.

Let me know if I'm missing something here.

gnapse avatar Dec 02 '19 12:12 gnapse

Adding quotes did not help in my case I am afraid.

Domino987 avatar Dec 02 '19 23:12 Domino987

Adding quotes did not help in my case I am afraid.

I am not advocating for adding quotes around the color name in the css rules, if that's what you mean. I meant that the quotes around the color name look like not valid css.

To be clear, my latest comment was with regards to @dennisroethig's case. I'm still not sure about your case @Domino987. I'm going to give it a look tomorrow.

gnapse avatar Dec 02 '19 23:12 gnapse

Sorry @gnapse, missed the notification and thanks for the quick reply ...

The red was a leftover from my testing, so ignore that 😆

So you're saying the test code should be:

expect(element).toHaveStyle(`
        width: 14px;
        height: 14px;
        top: 30%;
        left: 55%;
        background-color: "#F3F2F0";
        transform: rotateZ(22deg);
`);

I don't think that should make a difference but also confirmed it is doing the same thing. Somehow the test-runner tries to assert

background-color: ;
height: 14px;
left: 55%;
top: 30%;
transform: rotateZ(22deg);
width: 14px;

to

style="width: 14px; height: 14px; background-color: rgb(243, 242, 240); top: 30%; left: 55%; transform: rotateZ(22deg);"

And as I said, pinning to 4.1.1 fixes it. So something must have changed around that time. If it's not clear or you think it's something else on our side I can see if I find some time next week to create a minimal repo to reproduce it, but that will take a bit until I get to it 😆

Thanks again for thinking about it ❤️

dennisroethig avatar Dec 06 '19 00:12 dennisroethig

So you're saying the test code should be:

No, I was saying the opposite, that the color in the background-color line should not have quotes around it.

In the original test assertion you posted here above it had single quotes, and in your previous comment it has double quotes. But I think it shouldn't have any.

gnapse avatar Dec 06 '19 01:12 gnapse

oh wow - thanks so much @gnapse I totally misread the CSS syntax embedded in the JS file and blacked out that it's not valid CSS 🤦‍♂

consider my comment "fixed" 😆

dennisroethig avatar Dec 06 '19 05:12 dennisroethig

consider my comment "fixed" 😆

Do you mean then that this issue is now fixed/can-be-closed?

gnapse avatar Dec 06 '19 12:12 gnapse

No it only addresses @dennisroethig problem. The assertion still fails for a gradient.

Domino987 avatar Dec 06 '19 12:12 Domino987

consider my comment "fixed" 😆

Do you mean then that this issue is now fixed/can-be-closed?

haha - only mine, sorry for hijacking 🙇

dennisroethig avatar Dec 06 '19 12:12 dennisroethig

@Domino987 I'll check up on this early next week and will get back to you.

gnapse avatar Dec 06 '19 12:12 gnapse

This seems to apply for any CSS function, and it doesn't matter what value is asserted.

Here's a sandbox with backgroundImage set to a radial gradient and a url.

I've set the assertion to toHaveStyle("background-color: xxx;"), and it still passes.

jacksteamdev avatar Dec 17 '19 17:12 jacksteamdev

Indeed. Not sure how to deal with this 😕

gnapse avatar Dec 17 '19 17:12 gnapse

@gnapse any news on this?

Domino987 avatar Jan 08 '20 22:01 Domino987

This happens because the style is not correctly applied when applying it to that placeholder element when the property value is not allowed. Eg: .toHaveStyle('background-color: xxx;') Which then returns { 'background-color': '' } for the expected style and if that style is not present on an element it actually is truthy. https://github.com/testing-library/jest-dom/blob/master/src/to-have-style.js#L12

I guess one could error out if copy.style[property] is empty but I dont know if that opens up other weird cases...

Something similiar actually happens for object-styles:

.toHaveStyle({
      borderBottomWidth: '450%',
      backgroundColor: 'blue',
    })

passes as long as element has style backgroundColor: 'blue'. borderBottomWidth just gets ignored as it has an invalid value. https://github.com/testing-library/jest-dom/blob/master/src/utils.js#L195

denniskortsch avatar Jun 18 '20 20:06 denniskortsch

It seems to be an issue with JSDom I would say. https://github.com/jsdom/jsdom/issues/2166

Just setting the style property to a gradient leads to a style property with an empty string as value.

      const div = document.createElement('div');
      const gradient = 'linear-gradient(45deg, #fff, #000)';
      div.style.backgroundColor = gradient;
      expect(div.style.backgroundColor).toEqual(gradient);

I also tried different syntax and -webkit and -moz but no luck. It's just not possible to set this property. Interesting though the css rule parser package used by jsdom (CSSOM) is understanding css rules having linear-gradient. It's only not valid for style properties.

fragsalat avatar Oct 30 '20 10:10 fragsalat

to test gradient have to use toHaveStyleRule. keep in mind it takes two parameter like below

expect(gradient).toHaveStyleRule( 'background-image', ' linear-gradient(45deg, #FFF, #000) ')

issue can be closed now

BitaShamsafar avatar Jan 25 '23 14:01 BitaShamsafar