Welcome to ZaiZheLe Developer Zone-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
486 views
in Technique[技术] by (71.8m points)

reactjs - Testing React component has updated context

What would be the correct way to test that a component has updated its parent context?

Say from the example below, after MsgSender has been clicked, how can I verify that MsgReader has been updated?

import React from 'react'
import { render, act, fireEvent } from '@testing-library/react'

const MsgReader = React.createContext()
const MsgWriter = React.createContext()

const MsgProvider = ({ init, children }) => {
  const [state, setState] = React.useState(init)
  return (
    <MsgReader.Provider value={state}>
      <MsgWriter.Provider value={setState}>{children}</MsgWriter.Provider>
    </MsgReader.Provider>
  )
}

const MsgSender = ({ value }) => {
  const writer = React.useContext(MsgWriter)
  return (
    <button type="button" onClick={() => writer(value)}>
      Increment
    </button>
  )
}

describe('Test <MsgSender> component', () => {
  it('click updates context', async () => {
    const { getByRole } = render(
      <MsgProvider init={1}>
        <MsgSender value={2} />
      </MsgProvider>,
    )

    const button = getByRole('button')
    await act(async () => fireEvent.click(button))
    
    // -> expect(???).toBe(2)
  })
})

The cleanest way I've managed to come up with is to manually set the *.Providers, but I'm wondering if this is perhaps the wrong way to go about it.

it('click updates context with overrides', async () => {
  let state = 1
  const setState = (value) => {
    state = value
  }

  const { getByRole } = render(
    <MsgReader.Provider value={state}>
      <MsgWriter.Provider value={setState}>
        <MsgSender value={2} />
      </MsgWriter.Provider>
    </MsgReader.Provider>,
  )
  const button = getByRole('button')

  expect(state).toBe(1)
  await act(async () => fireEvent.click(button))
  expect(state).toBe(2)
})

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You need to create a customRender which gives you the ability to assert the state like this:


function customRender(ui, { init, ...options }) {
  const [state, setState] = React.useState(init);

  function wrapper({ children }) {
    return (
      <MsgReader.Provider value={state}>
        <MsgWriter.Provider value={setState}>{children}</MsgWriter.Provider>
      </MsgReader.Provider>
    );
  }

  return {
    ...render(ui, { wrapper, ...options }),
    state,
  };
}

describe("Test <MsgSender> component", () => {
  it("click updates context", async () => {
    const { getByRole, state } = customRender(<MsgSender value={2} />);

    const button = getByRole("button");
    await act(async () => fireEvent.click(button));

    expect(state).toBe(2)
  });
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to ZaiZheLe Developer Zone-Open, Learning and Share
...