【问题标题】:How to mock a parent component which passes props to child component using react testing library如何使用反应测试库模拟将道具传递给子组件的父组件
【发布时间】:2021-10-01 14:24:53
【问题描述】:

**如果传递给子组件的道具基于父组件中动态发生的状态更改,如何检查父组件中的动态状态更改并使用反应测试库编写测试用例。有人可以帮我解决这个问题吗?

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

【问题讨论】:

  • 为什么需要模拟任何东西?如果您的测试是针对应用程序的,那么您绝对不应该将其模拟出来(那么您只是在测试模拟),如果您想单独测试 TextArea,您已经可以这样做,您的测试实际上成为了父项。跨度>
  • 嗨@jhonrsharpe 感谢您的快速回复,但我想问的问题是如果您有一个子组件,这取决于您从父级传递的值如何测试它。我刚刚给出了一个 app(父)和 textarea(子)的小例子
  • 您的测试不起作用,因为 App 没有使用任何道具,但您还是尝试通过一些道具。目前尚不清楚您为什么希望这样做。同样,您可以单独测试 TextArea,您可以直接将 props 传递给它,或者在 App 的上下文中,在这种情况下,它将始终传递该组件中硬编码的内容。
  • 你认为下面的方法是一种理想的方法
  • it('检查文本区域参数', () => { const params = { message: 'h1' }; const { getByPlaceholderText } = render( ); const textAreaParams = getByPlaceholderText('test'); expect(textAreaParams).toHaveTextContent('h1'); });`

标签: reactjs react-testing-library react-testing


【解决方案1】:

我们需要将 App 组件中的 onChange handler 属性传递给 TextArea,然后 TextArea 组件会在文本区域发生变化时调用该处理程序。

updateTextAreaMessage = (messageInTextArea) => {
  this.setState({
    textAreaParams: { message: messageInTextArea}
  })
}

在上面的代码中,messageInTextArea是一个字符串值,当我们改变TextArea中的文本时,当在TextArea组件中调用updateTextAreaMessage时,使用相同的字符串值作为参数,它会更新App中的状态组件。

全面实施

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;

现在,我们将为 App.js 添加测试。但问题是在这里测试什么?答案是我们将在 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();
  });
});

【讨论】:

  • 您好@Subrato Patnaik 感谢您的回复,这里我们使用的是 render() 所以我们还需要导入 TextArea 组件?
  • 如果您的问题已解决,请接受此答案。这就是我们接受答案的方式。 stackoverflow.com/help/someone-answers
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多