Тестирование реагирующего компонента обновило контекст

#reactjs #react-testing-library

#reactjs #react-testing-library

Вопрос:

Каков был бы правильный способ проверить, что компонент обновил свой родительский контекст?

Скажем, из приведенного ниже примера, после MsgSender нажатия, как я могу проверить, что MsgReader он был обновлен?

 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)
  })
})
 

Самый чистый способ, который мне удалось придумать, — это вручную установить *.Providers , но мне интересно, возможно, это неправильный способ сделать это.

 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)
})
 

Комментарии:

1. если ответ был полезным, попробуйте принять ответ

Ответ №1:

Вам нужно создать customRender , который дает вам возможность утверждать state подобное:

 
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)
  });
});
 

Комментарии:

1. Спасибо вам за это, однако ваш пример выдает Invalid hook call. Hooks can only be called inside of the body of a function component. ошибку, когда я пытаюсь его запустить.

2. @kgreen да, ты прав, я об этом не подумал