Jest DOM, DOM testing

  1. A simple test example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import React from 'react'
    import {FavoriteNumber} from '../favorite-number'
    import ReactDOM from 'react-dom'

    test('renders a number input with a label "Favorite Number"', () => {
    const div = document.createElement('div')
    ReactDOM.render(<FavoriteNumber />, div)
    console.log(div.innerHTML) //You can use console.log to see the results in the terminal.
    expect(div.querySelector('input').type).toBe('number')
    expect(div.querySelector('label').textContent).toBe('Favorite Number'))
    })

    The result can be seen in the terminal.

    expect(div.querySelector('label').textContent).toBe('Favorite Number')) can be reversed to verify that the false output passes the test. If the result is fail, assertions run normally.


  1. Using Jest DOM to boost assertions

    In the previous method, the error message is not helpful. For example, if the input is wrong in div.querySelector('input'), an error TypeError: Cannot read property 'type' of null will be reported, and it will be marked in div on.

    We use testing-library/jest-dom to solve this problem.

    It has many methods, such as {toHaveAttribute, toHaveTextContent} . To simplify this code, such as expect.extend(jestDom), use import '@testing-library/jest-dom/extend-expect' to import the package. Or you can automatically import this package in jest.setup.js for all files.


    The modified assertion is:

    1
    2
    3
    4
    5
    6
    7
    8
    import '@testing-library/jest-dom/extend-expect'

    test('renders a number input with a label "Favorite Number"', () => {
    const div = document.createElement('div')
    ReactDOM.render(<FavoriteNumber />, div)
    expect(div.querySelector('input')).toHaveAttribute('type','number')
    expect(div.querySelector('label')).toHaveTextContent('Favorite Number')
    })

    At this time, if the input is written incorrectly, the error will become:

    1
    2
    expect(received).toHaveAttribute()
    received value must be an HTMLElement or an SVGElement. Received has value: null

    At this point it is easier to understand and fix.


  2. Use assertions to ensure label and element match exactly

    If there is no match, if the value of htmlFor in label is modified, the test can still pass. But there will be an error when the screen reader reads it. We can use an assertion to get the element corresponding to the label.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import {queries} from '@testing-library/dom' // can be done in the configuration file

    test('renders a number input with a label "Favorite Number"', () => {
    const div = document.createElement('div')
    ReactDOM.render(<FavoriteNumber />, div)
    const input = queries.getByLabelText(div, 'Favorite Number')
    expect(input).toHaveAttribute('type','number') //Simplified because of the previous line
    //The next line is deleted because of duplication
    })

    queries.getByLabelText(div, 'Favorite Number') will cause the DOM testing library to search all children of this div for a label containing this text. At the same time, the previous div.querySelector('label') can also be deleted, because its content is already contained in queries.getByLabelText(div, 'Favorite Number').


    This method is case sensitive. But users of screen reader don’t care about case, so it should be written as:

    1
    2
    3
    4
    5
    6
    test('renders a number input with a label "Favorite Number"', () => {
    const div = document.createElement('div')
    ReactDOM.render(<FavoriteNumber />, div)
    const input = queries.getByLabelText(div, /Favorite Number/i)
    expect(input).toHaveAttribute('type','number')
    })

    This regex ignores case.


  3. Use getQueriesForElement to simplify div fetching

    From getQueriesForElement , we can access many other queries from the DOM testing library to find elements in the render DOM.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import {queries, getQueriesForElement} from '@testing-library/dom'

    test('renders a number input with a label "Favorite Number"', () => {
    const div = document.createElement('div')
    ReactDOM.render(<FavoriteNumber />, div)
    const {getByLabelText} = getQueriesForElement(div)
    const input = getByLabelText(/Favorite Number/i)
    expect(input).toHaveAttribute('type','number')
    })

    What’s done here is that the testing library/DOM module is added, and we pull in getQueriesForElement. We get queries for div. Now, getByLabelText is pre-bound to that div, so we can take the text matching regex as a parameter and get the input. Then we can assert on that input that it has a numeric type.


Share