Blog

Tests en React: setProps en un elemento que requiere history

Tests en React: setProps en un elemento que requiere history

Tenemos un componente que requiere history:

export const RuleImplementationsFromRuleLoader = ({
  clearRuleImplementations,
  deletionQuery,
  fetchRuleImplementations,
  ruleImplementationsLoading,
  ruleImplementations,
}) => {

  const history = useHistory();

  useEffect(() => {
    if (id) {
      fetchRuleImplementations({ id, deleted: deletionQuery.deleted });
    }
  }, [clearRuleImplementations, deletionQuery, fetchRuleImplementations, id]);

  useEffect(() => {
    return history.listen((location) => {
      const value = [RULE, RULE_IMPLEMENTATIONS, RULE_EVENTS].some(
        (tabRoute) => (
          return matchPath(location.pathname, tabRoute)?.isExact
        )
      )
      value || clearRuleImplementations();
    });
  }, [clearRuleImplementations, history]);

  return ruleImplementationsLoading ? (
    <Dimmer active={ruleImplementationsLoading} inverted>
      <Loader size="massive" inverted />
    </Dimmer>
  ) : null;
};

Si intentamos hacer un test así:

it("calls fetchRuleImplementations when component updates", () => {
  const history = createMemoryHistory();
  const existingProps = ...

  const wrapper = mount(
    <Router history={history}>
      <RuleImplementationsFromRuleLoader {...existingProps} />
    </Router>
  );

  expect(fetchRuleImplementations).toHaveBeenCalledTimes(1);
  wrapper.setProps({ deletionQuery: { deleted: true } });
  expect(fetchRuleImplementations).toHaveBeenCalledTimes(2);
  expect(fetchRuleImplementations).toHaveBeenCalledWith({
    id: 1,
    deleted: true,
  });
});

Saltará el error ReactWrapper::setProps() can only be called on the root (línea wrapper.setProps...) Para evitarlo, podemos envolver todo en otro componente creado con React.createElement, que recibe las propiedades y las pasa al componente contenido. Visto en este enlace:

it("calls fetchRuleImplementations when component updates", () => {
  const history = createMemoryHistory();
  const existingProps = ...

  const wrapper = mount(
    React.createElement(
      (props) => (
        <Router history={history}>
          <RuleImplementationsFromRuleLoader {...existingProps} />
        </Router>
      ),
      props
    )
  );

  expect(fetchRuleImplementations).toHaveBeenCalledTimes(1);
  wrapper.setProps({ deletionQuery: { deleted: true } });
  expect(fetchRuleImplementations).toHaveBeenCalledTimes(2);
  expect(fetchRuleImplementations).toHaveBeenCalledWith({
    id: 1,
    deleted: true,
  });
});