artooras
artooras

Reputation: 6805

toHaveFocus behaviour in jest-dom

I'm having trouble understanding how toHaveFocus() works exactly. Here's my setup:

MyComponent.js

import React from 'react'
import styled from 'styled-components'

import TextArea from './TextArea'


const Container = styled.div`
  flex: 1;
  height: 100%;
  padding: ${props => props.theme.size};
`

const Title = styled(TextArea)`
  font-weight: bold;
  font-size: ${props => props.theme.sizeLarger};
  margin-left: ${props => props.theme.sizeSmall};
`

class MyComponent extends React.Component {

  handleTitleChange = e => {
    this.props.onTitleChange(e.target.value)
  }

  handleTitleLostFocus = () => {
    this.props.onChangeComplete()
  }

  render () {
    return (
      <Container>
        <Title 
          value={this.props.item.title || ''}
          onChange={this.handleTitleChange}
          onBlur={this.handleTitleLostFocus}
        />
      </Container>
    )
  }
}

export default MyComponent

MyComponent.test.js

import React from 'react'
import {render, fireEvent, prettyDOM} from 'react-testing-library'

import MyComponent from '../MyComponent'


describe('MyComponent', () => {
  it('handles title changes', () => {
    const title = 'title'
    const handleTitleChangeMock = jest.fn()
    const {getByText} = render(
      <MyComponent
        item={{
          title: title
        }}
        onTitleChange={handleTitleChangeMock}
        onChangeComplete={() => {}}
      />
    )
    const titleInput = getByText(title)
    console.log(prettyDOM(titleInput))
    fireEvent.click(getByText(title))
    expect(getByText(title)).toHaveFocus()
    fireEvent.change(getByText(title), {target: {value: title.slice(0, -1)}})
    expect(handleTitleChangeMock).toHaveBeenCalledTimes(1)
    expect(handleTitleChangeMock).toHaveBeenCalledWith(title.slice(0, -1))
  })
})

When I do this:

const titleInput = getByText(title)
console.log(prettyDOM(titleInput))

The console logs the following:

<textarea
    class="sc-htoDjs dLjZCT sc-bxivhb jdLTBU"
    style="height: 0px;"
  >
    title
  </textarea>

That textarea element is the one I am targeting. But then, when I do this:

fireEvent.click(titleInput)
expect(titleInput).toHaveFocus()

I get this error:

Received:
  <body><textarea style="min-height: 0 !important; max-height: none !important; height: 0px !important; visibility: hidden !important; overflow: hidden !important; position: absolute !important; z-index: -1000 !important; top: 0px !important; right: 0px;" /><div><div class="sc-bZQynM ePHCfO"><textarea class="sc-htoDjs dLjZCT sc-bxivhb jdLTBU" style="height: 0px;">title</textarea></div></div></body>

  at Object.it (src/__tests__/MyComponent.test.js:84:30)
      at new Promise (<anonymous>)
  at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
      at <anonymous>
  at process._tickCallback (internal/process/next_tick.js:188:7)

I don't quite understand why when I'm trying to assert a textarea element toHaveFocus(), I'm receiving an error that references the entire DOM tree under body...

Upvotes: 1

Views: 3983

Answers (1)

Gio Polvara
Gio Polvara

Reputation: 27018

If you give focus using titleInput.focus() it works. I'm not sure why fireEvent.focus doesn't work.

You can see it working here https://codesandbox.io/s/y020r74rjj

Upvotes: 2

Related Questions