【问题标题】:How to trigger rerender on test component?如何触发测试组件的重新渲染?
【发布时间】:2019-09-04 19:22:02
【问题描述】:

我正在测试这个连接的组件:

export class ExclusiveSelectboxesFormSectionView extends React.Component<Props> {
  handleSelection = (field: Field, message: string) => {
    this.props.setCard({ message, field });
  };
  cancelSelection = () => this.props.setCard({ message: null, field: null });

  render() {
    return (
      <View>
        {this.props.cancelTitle && (
          <CheckBox
            title={this.props.cancelTitle}
            checked={this.props.card.field == null}
            onPress={this.cancelSelection.bind(this)}
            checkedIcon="dot-circle-o"
            uncheckedIcon="circle-o"
          />
        )}
        {this.props.fields.map((field, i) => {
          const props = {};

          props.isSelected = this.props.card.field == field;
          props.selectionHandler = this.handleSelection.bind(this);

          return <ExclusiveFieldView field={field} key={i} {...props} />;
        })}
      </View>
    );
  }
}

const mapState = ({ currentFormReducer }) => {
  const card = currentFormReducer.card || { message: null, field: null };
  return { card };
};
const mapDispatch = { setCard };

export default connect(mapState, mapDispatch)(ExclusiveSelectboxesFormSectionView);

我正在尝试使用react-native-testing-library 测试未连接的组件。该组件在应用程序中工作,但此测试未能在测试的倒数第二个断言中找到 "Second field option 2"

// non-connected component
import { ExclusiveSelectboxesFormSectionView } from "../../src/components/ExclusiveSelectboxesFormSectionView";

function createWrapper(customProps) {
  let mockCard = { message: null, field: null };
  const props = {
    fields,
    setCard: jest.fn().mockImplementation((card: Types.Card) => {
      mockCard = card;
    }),
    card: mockCard,
    ...customProps
  };
  wrapper = render(
    <Fragment>
      <ExclusiveSelectboxesFormSectionView fields={fields} {...props} />
    </Fragment>
  );
  return wrapper;
}

describe("ExclusiveSelectboxesFormSectionView", () => {
  let checkboxes;
  beforeEach(() => {
    wrapper = createWrapper();
    checkboxes = wrapper.getAllByType(CheckBox);
    expect(checkboxes.length).toBe(3);
  });

  fit("shows the value of the currently selected field", async () => {
    await fireEvent.press(checkboxes[1]); // show options
    await fireEvent.press(wrapper.getByText("Second field option 2")); // select option

    const component = wrapper.getByType(ExclusiveSelectboxesFormSectionView);
    expect(component.props.setCard).toHaveBeenCalled();

    // options should be gone
    expect(wrapper.queryByText("Second field option 1")).toBeNull();
    // selected option should still be on screen
    expect(wrapper.getByText("Second field option 2")).toBeDefined();
    expect(checkboxes[1].props.checked).toBe(true);
  });

});

我已经传入了一个 card 属性和一个 setCard 模拟函数属性,代替了提供这些的 redux。

正在调用模拟setCard 函数,所以我认为问题在于组件没有使用其新道具(以及新设置的card 道具)重新渲染。组件的渲染函数中的日志语句证实了这一点(它只在测试运行时打印一次)。

我想我缺少关于如何渲染组件、包装它、调用它或其他什么的基本知识。

谁能发现我的问题?

【问题讨论】:

    标签: reactjs react-redux jestjs


    【解决方案1】:

    看起来react-native-testing-libraryupdate 函数可以解决问题。但这有点难以弄清楚。

    // refactored from createWrapper
    function getWrapperProps() {
      return {
        fields,
        setCard: jest.fn().mockImplementation((card: Types.Card) => {
          mockCard = card;
        }),
        card: mockCard
      };
    }
    
    function createWrapper(customProps) {
      wrapper = render(
        <Fragment>
          <ExclusiveSelectboxesFormSectionView
            {...getWrapperProps()}
            {...customProps}
          />
        </Fragment>
      );
      return wrapper;
    }
    
    function updateWrapper(customProps) {
      wrapper.update(
        <Fragment>
          <ExclusiveSelectboxesFormSectionView
            {...getWrapperProps()}
            {...customProps}
          />
        </Fragment>
      );
      checkboxes = wrapper.getAllByType(CheckBox);
    }
    
    // call updateWrapper() when you need to get the newly rendered props
      it("shows the value of the currently selected field", async () => {
        await fireEvent.press(checkboxes[1]);
        await fireEvent.press(wrapper.getByText("Second field option 2"));
    
        const component = wrapper.getByType(ExclusiveSelectboxesFormSectionView);
        expect(component.props.setCard).toHaveBeenCalled();
    
        updateWrapper();
    
        // options should be gone
        expect(wrapper.queryByText("Second field option 1")).toBeNull();
        // selected option should still be on screen
        expect(wrapper.getByText("Second field option 2")).toBeDefined();
        expect(checkboxes[1].props.checked).toBe(true);
      });
    

    现在它通过了。

    我很想知道其他选择。虽然早期的实现在组件中使用了state,但我不清楚为什么这一直在使用早期的实现,我敢肯定这基本上是的答案。

    【讨论】:

      猜你喜欢
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-18
      • 2017-03-14
      • 2021-06-20
      • 1970-01-01
      • 2019-04-01
      • 2020-06-02
      相关资源
      最近更新 更多