Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.toHaveStyle() does not get font-size w/ css variable #322

Open
KOREAN139 opened this issue Dec 30, 2020 · 8 comments
Open

.toHaveStyle() does not get font-size w/ css variable #322

KOREAN139 opened this issue Dec 30, 2020 · 8 comments
Labels
bug Something isn't working

Comments

@KOREAN139
Copy link

  • @testing-library/jest-dom version: 5.11.6
  • node version: v14.15.1
  • npm (or yarn) version: 1.22.10
  • svelte-testing-library version: 3.0.0

Relevant code or config:

  :root {
    --font-size-xlarge: 64px;
    --font-weight-bold: 700;
  }

  .title {
    font-size: var(--font-size-xlarge);
    font-weight: var(--font-weight-bold);
    margin: auto 0;
  }
    <div data-testid="title" class="title">Title</div>
    const search = getByTestId('search');
    expect(title).toHaveStyle({
      'font-size': 'var(--font-size-xlarge)',
      'font-weight': 'var(--font-weight-bold)',
    });

What you did:

Test font style w/ @testing-library/jest-dom and @testing-library/svelete-testing-library

What happened:

Test should fail if i set font-size not as var(--font-size-xlarge), but test still passes.
But works charm about font-weight.

    expect(element).toHaveStyle()

    - Expected

    - font-size: ;
    - font-weight: var(--font-weight-light);
    + font-weight: var(--font-weight-bold);

      33 |     const settings = getByTestId('settings');
      34 | 
    > 35 |     expect(title).toHaveStyle({
         |                   ^
      36 |       'font-size': 'var(--font-size-xlarge)',
      37 |       'font-weight': 'var(--font-weight-light)',
      38 |     });

Reproduction:

from this commit,
install w/ yarn then run test w/ yarn test

Problem description:

Seems like cannot recognize font-size with css variable, as we can see the result of getComputedStyle(title) below

      CSSStyleDeclaration {
        '0': 'display',
        '1': 'font-weight',
        '2': 'margin',
        '3': 'visibility',
        _values: {
          display: 'block',
          'font-weight': 'var(--font-weight-bold)',
          margin: 'auto 0px',
          'margin-top': 'auto',
          'margin-right': '0px',
          'margin-bottom': 'auto',
          'margin-left': '0px',
          visibility: 'visible'
        },
        _importants: {
          display: '',
          'font-size': '',
          'font-weight': '',
          margin: '',
          visibility: undefined
        },
        _length: 4,
        _onChange: [Function (anonymous)]
      }
@gnapse
Copy link
Member

gnapse commented Dec 30, 2020

Hi, thanks for taking the time to report this.

I am having no luck reproducing it though. I just added the following test to the test module for toHaveStyle and it passes:

  it('handles CSS custom properties', () => {
    const {container, queryByTestId} = render(`
      <div data-testid="title" class="title">Title</div>
    `)

    const style = document.createElement('style')
    style.innerHTML = `
      :root {
        --font-size-xlarge: 64px;
        --font-weight-bold: 700;
      }
      .title {
        font-size: var(--font-size-xlarge);
        font-weight: var(--font-weight-bold);
        margin: auto 0;
      }
    `
    document.body.appendChild(style)
    document.body.appendChild(container)

    const title = queryByTestId('title')
    expect(title).toHaveStyle({
      'font-size': 'var(--font-size-xlarge)',
      'font-weight': 'var(--font-weight-bold)',
    })
  })

Any ideas on what I may be missing? Maybe if you can provide a minimal repo where the issue can be reproduced, that'd be great.

@yjcyun
Copy link

yjcyun commented Jul 2, 2021

Hi, I'm also having a similiar problem with toHaveStyle.

"@nrwl/jest": "^12.0.6"
"@testing-library/jest-dom": "^5.11.10"
"@testing-library/react": "^11.2.6"
"@nrwl/node": "^12.0.6"
"styled-components": "^5.2.3",
"jest": "^26.6.3"

In my case, the test always passes when css variable is used within Styled Components. I've created a code sandbox here.

The following test should fail because the color is actually set to var(--clr-blue) and also because var(--clr-red) doesn't exist. Am I using toHaveStyle correctly? Is there an alternative for testing the style using jest-dom?

  expect(getByTestId("message-cont")).toHaveStyle(`
    color: var(--clr-red)
  `);

Any help would be greatly appreciated. Thanks.

@gnapse
Copy link
Member

gnapse commented Jul 5, 2021

As mentioned before, a minimal repository where this can be reproduced would go a long way towards figuring this out.

@nickmccurdy nickmccurdy added the bug Something isn't working label Jul 11, 2021
@solimant
Copy link

solimant commented Jul 31, 2021

Any ideas on what I may be missing? Maybe if you can provide a minimal repo where the issue can be reproduced, that'd be great.

@gnapse - have you tried changing your test to something like this?

expect(title).toHaveStyle({
  'font-size': 'var(--font-size-small)', // this should cause a failure, but it doesn't
  'font-weight': 'var(--font-weight-bold)',
})

The reported issue is that the test still passes.

@gregmalcolm
Copy link

I just encountered the kind of problem (false positive on a toHaveStyle() assertion) when I was selecting through screen.findByText. Applying a console.log to the returned element told me I was getting a HTMLDivElement which I think was from a wrapper, not the desired component (a <td />). Switching to a more cell specific selector (getByRole('cell', text: /something/) allowed me to use .toHaveStyle() successfully:

 expect(element).toHaveStyle()

    - Expected

    - height: ;
    + height: 56px;

I would guess from all this that toHaveStyle gives surprising false successes if the wrong root element is accidentally selected (in my case the div height was probably inherited).

Note: I know the original complaint was for a getByTestID() selection, but I'm guessing a wrapped selection could still be happening that way

@jeongnaehyeok
Copy link

jeongnaehyeok commented Oct 29, 2021

Hey guys, Did you import CSS variable and use it?. I encountered the same problem and realized that the Css variable was not defined. And I tried to use variable using css file at css-in-js.

@hughes-ch
Copy link

hughes-ch commented Nov 25, 2021

Just ran into this problem today. Seems like it's related to the jsdom dependency. Based on what I found, it's either due to a bug parsing the :root selector or due to how cascaded property values are implemented. See here.

I'll continue to investigate because this seems like a feature that's needed.

Edit Nov-29-2021:
After some more investigation, I don't think there's a workaround, but there seems to be a fix in the pipeline. In the original comment in this thread, the reason for the false positive is that --font-size-xlarge evaluates to the empty string, which means that

expect(title).toHaveStyle({
      'font-size': 'var(--font-size-xlarge)',
      'font-weight': 'var(--font-weight-bold)',
    });

really evaluates to:

expect(title).toHaveStyle({
      'font-size': '', // Not valid - CSS parser will remove this rule
      'font-weight': 'var(--font-weight-bold)',
    });

This particular issue is not actually a problem with jest-dom, but with its JSDOM dependency. It looks like the problem will be fixed with this pull request.

I've included my original suggestion for a workaround below (not sure if it's valid though):

Since it seems to be related to the CSS selectors instead of the variables, a (really ugly) workaround is to put the variables directly in the most specific selector for the unit test:

  it('handles CSS custom properties', () => {
    const {container, queryByTestId} = render(`
      <div data-testid="title" class="title">Title</div>
    `)

    const style = document.createElement('style')
    style.innerHTML = `
      .title {
        --font-size-xlarge: 64px;
        --font-weight-bold: 700;
        font-size: var(--font-size-xlarge);
        font-weight: var(--font-weight-bold);
        margin: auto 0;
      }
    `
    document.body.appendChild(style)
    document.body.appendChild(container)

    const title = queryByTestId('title')
    expect(title).toHaveStyle({
      'font-size': 'var(--font-size-xlarge)',
      'font-weight': 'var(--font-weight-bold)',
    })
  })

Since you are just testing that the correct variables are being loaded by your components, it still meets the spirit of the test, though it's not quite DRY...

@hughes-ch
Copy link

I've submitted two pull requests for the JSDOM project to get this feature working:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants