**How to check for the dynamic state changes in a parent component and write the test case using the react testing library if the props passed to the child component are based on the state changes which are happening dynamically in the parent component. Can someone help me with this?
App.js
import React, { Component } from 'react';
import './App.css';
import TextArea from './components/TextArea/TextArea';
class App extends Component {
constructor() {
super();
this.state = {
textAreaParams: {},
};
}
componentDidMount() {
this.setDefaultTextAreaMessage();
}
setDefaultTextAreaMessage = () => {
this.setState({
textAreaParams: { message: 'Hello' },
});
};
render() {
const { textAreaParams } = this.state;
return (
<div className="App">
{Object.keys(textAreaParams).length > 0 ? (
<TextArea params={textAreaParams} />
) : null}
</div>
);
}
}
export default App;
TextArea.js
import { Component } from 'react';
class TextArea extends Component {
constructor(props) {
super(props);
this.state = {
message: this.props.params.message,
};
}
render() {
return (
<div>
<textarea
rows="4"
cols="50"
value={this.state.message ? this.state.message : ''}
placeholder="test"
onChange={() => {}}
>
{this.state.message}
</textarea>
</div>
);
}
}
export default TextArea;
App.test.js
import App from './App';
import { cleanup, render } from '@testing-library/react';
describe('Rendering the App component and passing props to text area', () => {
afterEach(cleanup);
it('render the App component and check for the TextArea component', async () => {
const props = { textAreaParams: { message: 'save' } };
const { getByPlaceholderText } = render(<App {...props} />);
const textAreaParams = getByPlaceholderText('test');
expect(textAreaParams).toHaveTextContent('save');
});
});
We need to pass onChange
handler prop from the App component to TextArea and then TextArea will component will call that handler when there is a change in the text area.
updateTextAreaMessage = (messageInTextArea) => {
this.setState({
textAreaParams: { message: messageInTextArea}
})
}
In the above code, messageInTextArea
is a string value when we change the text in TextArea and when updateTextAreaMessage
is called in the TextArea component with the same string value as a parameter, it will update the state in the App component.
Full Implementation:
App.js:
import React, { Component } from "react";
import './App.css';
import TextArea from './components/TextArea/TextArea';
class Main extends Component {
constructor() {
super();
this.state = {
textAreaParams: { message: "hello" } // we can provide default value here
};
}
updateTextAreaMessage = (messageInTextArea) => {
this.setState({
textAreaParams: { message: messageInTextArea }
});
};
render() {
const { textAreaParams } = this.state;
return (
<div className="App">
{Object.keys(textAreaParams).length > 0 ? (
<TextArea
params={textAreaParams}
onUpdate={this.updateTextAreaMessage}
/>
) : null}
<p aria-label="text area message">{textAreaParams.message}</p>
</div>
);
}
}
export default Main;
TextArea.js:
import { Component } from "react";
class TextArea extends Component {
render() {
return (
<div>
<textarea
rows="4"
cols="50"
value={this.props.params.message ? this.props.params.message : ""}
placeholder="test"
onChange={(event) => this.props.onUpdate(event.target.value)}
>
{this.props.params.message}
</textarea>
</div>
);
}
}
export default TextArea;
import { render } from "@testing-library/react";
import App from "./App";
import TextArea from './components/TextArea/TextArea';
describe("Rendering the App component and passing props to text area", () => {
it("should render the App component with default message in TextArea", () => {
const { getByPlaceholderText } = render(<Main />);
const textAreaParams = getByPlaceholderText("test");
expect(textAreaParams).toHaveTextContent(/hello/i);
});
it("should update the text area when we type something", () => {
const { getByPlaceholderText, getByLabelText } = render(<Main />);
userEvent.type(getByPlaceholderText("test"), "Anything");
expect(getByLabelText(/text area message/i)).toHaveTextContent(/anything/i);
});
});
describe("Rendering the Text Area component", () => {
it("should render the TextArea component and calls onChange handlers when we type something", () => {
const mockOnChangeHandler = jest.fn();
const mockParams = { message: "save" };
const { getByPlaceholderText } = render(
<TextArea params={mockParams} onUpdate={mockOnChangeHandler} />
);
const inputTextArea = getByPlaceholderText("test");
expect(inputTextArea).toHaveTextContent(/save/i);
userEvent.type(inputTextArea, "Anything");
expect(mockOnChangeHandler).toHaveBeenCalled();
});
});