React.js: How to get all props component expects?

Viewed 4187

I'm starting to unit test a React.js application and one of the challenge I'm facing is to determine all the props a component needs to mount it properly. Is there any utility to check what all is needed to mount the component successfully? Additionally the data type of those props to initialize them appropriately for component rendering.

Like one of my component is getting props from parent using spread {...props} operator. And the parent is also getting these using spread operator and then adds some additional props and passes it to child. Which makes it very difficult for me to get all props a components expects. Is there any legit way to get the list of props?

3 Answers

An Interesting task.

I start with:

import React from "react";
import * as PropTypes from "prop-types";

function Hello(props) {
  const { boo, foo } = props;
  return (
    <div>
      <h1>{boo}</h1>
      <h2>{foo}</h2>
    </div>
  );
}

Hello.propTypes = {
  boo: PropTypes.string,
  foo: PropTypes.number
};

export default Hello;

I found this article https://blog.jim-nielsen.com/2020/proptypes-outside-of-react-in-template-literal-components/ with function:

/**
 * Anytime you want to check prop types, wrap in this
 * @param {function} Component
 * @param {Object} propTypes
 * @return {string} result of calling the component
 */
function withPropTypeChecks(Component) {
  return props => {
    if (Component.propTypes) {
      Object.keys(props).forEach(key => {
        PropTypes.checkPropTypes(
          Component.propTypes,
          props,
          key,
          Component.name
        );
      });
    }
    return Component(props);
  };
}

Then I wrote another one:

const getPropsInfo = (component) => {
  const result = {};
  const mock = Object.keys(component.propTypes).reduce(
    (acc, p) => ({ ...acc, [p]: Symbol() }),
    {}
  );
  const catching = (arg) => {
    const [, , prop, type] = `${arg}`.match(
      /Warning: Failed (.*) type: Invalid .* `(.*)` of type `symbol` supplied to.*, expected `(.*)`./
    );
    result[prop] = type;
  };
  const oldConsoleError = console.error.bind(console.error);
  console.error = (...arg) => catching(arg);
  withPropTypeChecks(component)(mock);
  console.error = oldConsoleError;
  return result;
};

I chose Symbol as the less expected type.

And called it:

const propsInfo = getPropsInfo(Hello);
console.log(propsInfo);

As result I got: {boo: "string", foo: "number"}

P.S.: I have not tested this on other types. Just for fun! :)

Related