malte-wessel/react-textfit

Testing in Jest with JSDom throws Cannot read property 'style' of null

duro opened this issue · 2 comments

duro commented

This does not seem to happen anywhere outside a test environment.

Full stack trace:

TypeError: Cannot read property 'style' of null

      at Window.getComputedStyle (node_modules/jsdom/lib/jsdom/browser/Window.js:371:20)
      at innerWidth (node_modules/react-textfit/lib/utils/innerSize.js:16:24)
      at TextFit.process (node_modules/react-textfit/lib/Textfit.js:136:59)
      at TextFit.componentDidMount (node_modules/react-textfit/lib/Textfit.js:99:18)
      at commitLifeCycles (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:4553:24)
      at commitAllLifeCycles (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5729:9)
      at HTMLUnknownElement.callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1610:14)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
duro commented

Ok, I was able to figure this out, as it had to do with how snapshots work in a React + Jest world.

"refs" in snapshots are by default always null, unless you make use of jest's createNodeMock feature.

I was able to mock the ref node the way that react-textfit wants it (since it relies heavily on DOM specific APIs).

const createNodeMock = el => {
  if (el.type === 'div') {
    const mockEl = document.createElement('div')
    mockEl.style.padding = '0'
    Object.defineProperty(mockEl, 'clientHeight', {
      get() {
        return 100
      },
      enumerable: true,
      configurable: true
    })
    Object.defineProperty(mockEl, 'clientWidth', {
      get() {
        return 300
      },
      enumerable: true,
      configurable: true
    })
    return mockEl
  }
  return null
}

Full usage example:

import Component from './Component'
import renderer from 'react-test-renderer'

const createNodeMock = el => {
  if (el.type === 'div') {
    const mockEl = document.createElement('div')
    mockEl.style.padding = '0'
    Object.defineProperty(mockEl, 'clientHeight', {
      get() {
        return 100
      },
      enumerable: true,
      configurable: true
    })
    Object.defineProperty(mockEl, 'clientWidth', {
      get() {
        return 300
      },
      enumerable: true,
      configurable: true
    })
    return mockEl
  }
  return null
}

describe('CreateNodeMock testing ', () => {
  it('mock node', () => {
    const tree = renderer.create(<Component />, { createNodeMock }).toJSON()
    expect(tree).toMatchSnapshot()
  })
})