7

I'm trying to test a react component and use expect(elm).not.toBeVisible() without success.

Update 3

I have cut down the code into this simpler form:

// ./TestItem.js
import React from 'react'
import './TestItem.css'

export default ({ hide }) => {
  return <div className={hide ? 'shouldHide' : ''}>Text</div>
}

// ./__tests__/TestItem.test.js
import React from 'react'
import { render } from 'react-testing-library'
import TestItem from '../TestItem'
import 'jest-dom/extend-expect'
import 'react-testing-library/cleanup-after-each'


test.only('TestItem should render correctly', async () => {
  const { getByText, debug } = render(<TestItem hide={true} />)
  const itemNode = getByText('Text')
  debug()
  expect(itemNode).not.toBeVisible()
})

// ./TestItem.css
.shouldHide {
  display: none;
}

Test result:

 TestItem should render correctly

    expect(element).not.toBeVisible()

    Received element is visible:
      <div class="shouldHide" />

       7 |   const itemNode = getByText('Text')
       8 |   debug()
    >  9 |   expect(itemNode).not.toBeVisible()
         |                        ^
      10 | })
      11 |

debug() log:

console.log node_modules/react-testing-library/dist/index.js:58
    <body>
      <div>
        <div
          class="shouldHide"
        >
          Text
        </div>
      </div>
    </body>

Update 2:

Okay it's getting pretty weird because I got the test to pass on codesanbox but still find no luck on my local machine.


My original question:

I use React, semantic-ui-react and react-testing-library.

Here is the code:

// ComboItem.test.js    
import React from 'react'
import ComboItem from '../ComboItem'
import { render } from 'react-testing-library'
import comboXoi from '../images/combo-xoi.jpg'
import 'path/to/semantic/semantic.min.css'

describe('ComboItem', () => {
  test('should render', async () => {
    const { getByText, debug } = render(
      <ComboItem image={comboXoi} outOfStock={false} />
    )
    const outOfStockNotice = getByText('Out of stock')
    debug()
    expect(outOfStockNotice).not.toBeVisible()
  })
})

// ComboItem.js
import React from 'react'
import { Card, Image } from 'semantic-ui-react'

export default ({ image, outOfStock = false }) => {
  return (
    <Card>
      <Image
        src={image}
        dimmer={{
          active: outOfStock,
          inverted: true,
          'data-testid': 'combo-item-dimmer',
          content: (
            <span style={{ marginTop: 'auto', color: 'black' }}>
               Out of stock
            </span>
          ),
        }}
      />
    </Card>
  )
}

What i get is the result here:

ComboItem › should render

    expect(element).not.toBeVisible()

    Received element is visible:
      <span style="margin-top: auto; color: black;" />

      at Object.test (src/app/screens/App/screens/SaleEntries/screens/CreateSaleEntry/screens/StickyRiceComboSelect/__tests__/ComboItem.test.js:14:34)
      at process._tickCallback (internal/process/next_tick.js:68:7)

I have tried to see the component render result on the browser and the node outOfStockNotice in the test code is actually hidden because its parent, which is a div with class dimmer has style display: none.

According to jest-dom doc (which is used by testing-react-library:

toBeVisible

An element is visible if all the following conditions are met:

  • it does not have its css property display set to none
  • it does not have its css property visibility set to either hidden or collapse
  • it does not have its css property opacity set to 0
  • its parent element is also visible (and so on up to the top of the DOM tree)

Please help. I really don't know what could go wrong here.

Update:

I include the result of debug() here:

console.log node_modules/react-testing-library/dist/index.js:58
      <body>
        <div>
          <div
            class="ui card"
          >
            <div
              class="ui image"
            >
              <div
                class="ui inverted dimmer"
                data-testid="combo-item-dimmer"
              >
                <div
                  class="content"
                >
                  <span
                    style="margin-top: auto; color: black;"
                  >
                    Out of stock
                  </span>
                </div>
              </div>
              <img
                src="combo-xoi.jpg"
              />
            </div>
          </div>
        </div>
      </body>
skyboyer
  • 15,149
  • 4
  • 41
  • 56
Wormie
  • 201
  • 2
  • 10
  • I don't think you should do `await getByText`. I think it's a synchronous function. Can you paste the result of `debug()` too, please? – Giorgio Polvara - Gpx Oct 15 '18 at 09:32
  • @Gpx I dont think its really matter is sync. He using await and it works for async and sync same way – Eduard Jacko Oct 15 '18 at 10:52
  • @Gpx Hello there, I have updated my question to include the `debug()` result. Yes you are right, I must have mistaken its usage. But after removing `await` I still get the same error. Please check my updated question. Thanks. – Wormie Oct 15 '18 at 10:52
  • dimmer is definitely not active. Is missing an 'active' class. My guess the testing-react-library has render out of sync from semantic-ui. try wait for element to be not visible if its possible https://github.com/kentcdodds/react-testing-library#wait – Eduard Jacko Oct 15 '18 at 11:11
  • @EduardJacko thanks for your comment Eduard! I tried `await wait(() => expect(outOfStockNotice).not.toBeVisible())` but the result is the same. I have updated the question with codesanbox example. It works on codesandbox but does not work on my machine. Any ideas why or how to resolve this problem? – Wormie Oct 15 '18 at 11:20
  • make sure you have same all version of dependencies as in codesandbox. After that delete node_module folder. install everything again. Thats the start. – Eduard Jacko Oct 15 '18 at 11:22
  • one more thing. Are you sure you are injecting semantic.css? maybe stupid question – Eduard Jacko Oct 15 '18 at 11:26
  • @EduardJacko Hi I have remove node_modules and reinstall all packages. Even upgrade the `create-react-app` to v2 but I'm still getting the same result. – Wormie Oct 15 '18 at 12:00
  • @EduardJacko Yes I injected the `semantic.css` by `import 'semantic-ui-css/semantic.min.css'` – Wormie Oct 15 '18 at 12:01
  • @EduardJacko Maybe the `toBeVisible` of `jest-dom` doesn't work for `display:none` defined in a css file. But I can't find the info anywhere. – Wormie Oct 15 '18 at 12:03
  • @Wormie I tried to download codesandbox version and run it locally. It fail. Somehow codesandbox is messig with test. I dig for you the answer so if you happy with it, please accept it as answer. Took me a while to find it with some trial and errors. Thanks – Eduard Jacko Oct 15 '18 at 13:01
  • You have a point about the stylesheet display:none. – Eduard Jacko Oct 15 '18 at 13:45

1 Answers1

12

Here is the answer according to the author of react-testing-library himself:

Probably a JSDOM limitation (in codesandbox it runs in the real browser). Actually, the problem is that the css isn't actually loaded into the document in JSDOM. If it were, then that would work. If you can come up with a custom jest transform that could insert the css file into the document during tests, then you'd be set.

So this would work if you were using CSS-in-JS.

So basically the import './TestItem.css' part in the test will not works because JSDOM doesn't load it, therefore jest-dom could not understand the class shouldHide means display: none.

Update:

According to this Stack Overflow thread, you can insert css into jsdom:

import React from 'react'
import { render } from 'react-testing-library'
import TestItem from '../TestItem'

import fs from 'fs'
import path from 'path'

test.only('TestItem should render correctly', async () => {
  const cssFile = fs.readFileSync(
    path.resolve(__dirname, '../TestItem.css'),
    'utf8'
  )
  const { container, getByText, debug } = render(<TestItem hide={true} />)

  const style = document.createElement('style')
  style.type = 'text/css'
  style.innerHTML = cssFile
  container.append(style)

  const itemNode = getByText('Text')
  debug()
  expect(itemNode).not.toBeVisible()
})

And then the test should pass.

Community
  • 1
  • 1
Wormie
  • 201
  • 2
  • 10