#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 да, ты прав, я об этом не подумал