Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enzyme Test React.createRef()

I have a commponent where I use the new React.createRef() api, how to test document.activeElement should be equal current ref commponent.

component :

export class Automatic extends Component {
    componentDidMount = () => this.focusContainer()
    componentDidUpdate = () => this.focusContainer()

    container = React.createRef()
    focusContainer = () => this.container.current.focus()

    render = () => {
        return (
            <div
                name='automatic'
                onKeyPress={this.captureInput}
                onBlur={() => setTimeout(() => this.focusContainer(), 0)}
                ref={this.container}
                tabIndex={0}
            >
               ...
            </div>
}

old testing (works):

it('should focus container on mount', () => {
    automatic = mount(<Automatic classes={{}} />, mountContext)

    document.activeElement.should.be.equal(automatic.ref('container'))
})

new one (doesn't work):

it.only('should focus container on mount', () => {
    const container = React.createRef()
    automatic = mount(<Automatic classes={{}} />, mountContext)

    document.activeElement.should.be.equal(automatic.ref(container.current))
})
like image 451
Palaniichuk Dmytro Avatar asked Jun 06 '18 12:06

Palaniichuk Dmytro


People also ask

What does React createRef do?

This method is used to access any DOM element in a component and it returns a mutable ref object which will be persisted as long as the component is placed in the DOM. If we pass a ref object to any DOM element, then the. current property to the corresponding DOM node elements will be added whenever the node changes.

Is React createRef the same as useRef?

useRef: The useRef is a hook that uses the same ref throughout. It saves its value between re-renders in a functional component and doesn't create a new instance of the ref for every re-render. It persists the existing ref between re-renders. createRef: The createRef is a function that creates a new ref every time.

Is it true that refs are created using React createRef () and attached to React elements via the ref attribute?

Refs are created using React. createRef() and attached to React elements via the ref attribute. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the component.


1 Answers

Updated with working examples. Added a styled-components example.

Here's how I solved it with Jest (uses different assertions, but concept is the same):

// setup
const MyComponent = React.forwardRef((props, ref) => (
    <div>
        <span ref={ref}>some element</span>
    </div>
))

// test
it('should contain the forwarded ref in the child span', () => {
    const ref = React.createRef()
    const component = mount(
        <Fragment>
            <MyComponent ref={ref} />
        </Fragment>,
    )

    expect(component.find('span').instance()).toEqual(ref.current)
})
  • The idea is to get the instance of the element that has the ref.
  • It seems to only work when wrapping MyComponent in another element, I used Fragment.

I ran into some trouble when using **Styled-Components. This is because it creates a number of extra elements. Try debugging with console.log(component.debug()). It will show you what enzyme renders.

When debugging you'll see that Styled-Components uses the recommended way to forward props.

You can find the right element using the property selector for forwardedRef:

// setup
const El = styled.div`
    color: red;
`

El.displayName = 'El'

const MyComponentWithStyledChild = React.forwardRef((props, ref) => (
    <El ref={ref}>some element</El>
))

// test
it('should contain the forwarded ref in a rendered styled-component', () => {
    const ref = React.createRef()
    const component = mount(
        <Fragment>
            <MyComponentWithStyledChild ref={ref} />
        </Fragment>,
    )

    // Styled-components sets prop `forwardedRef`
    const target = component
        .find('[forwardedRef]')
        .childAt(0)
        .instance()

    expect(target).toEqual(ref.current)
})
  • You can use the same trick if you created a Higher order Component (HoC) where you need to pass ref
like image 144
publicJorn Avatar answered Sep 21 '22 09:09

publicJorn