enzyme icon indicating copy to clipboard operation
enzyme copied to clipboard

Why is `.wrap()` not included in the documentation?

Open jpenna opened this issue 6 years ago • 15 comments

Sorry for not following the template, but it is a simple request.

Why is .wrap() not included in the documentation?

As you can see here #919 at least more 6 people found this method useful. Just for completion it should be in the docs. Even if a note is included against the use of it and a suggestion of how to better write the component.

The author suggested to write the PR, I put myself available to do the same.

My use case

My use case is a HOC <Flow> that receives the content component <Step> as a prop. The component <Container>, which renders this HOC, renders the <Step> conditionally based on the current step of a specific flow. I'm using useMemo() to render this component inside the <Container> and that's why I need .wrap() to wrap the <Step> passed as a prop to <Flow>.

I could use a separate function to conditionally render and return <Step>, but this would obscure the code and have the same behavior: this function would be wrapped in a useMemo() and passed as a prop to <Flow>.

jpenna avatar Oct 01 '19 04:10 jpenna

Indeed, see https://github.com/airbnb/enzyme/issues/919#issuecomment-297756797 and #920.

It is intentionally undocumented.

I’m not clear tho on why you need wrap. Can you share some code?

ljharb avatar Oct 01 '19 04:10 ljharb

This is a simplified version of the code, but the structure is the basically the same.

I used the same names as the example I gave above, so you can follow that to understand what is going on below if needed.

import React, { useState, useMemo } from 'react';
import Flow from 'components/Flow';
import FlowData from 'components/FlowData';
import { statuses } from 'lib/ducks/meta';

import ChoosePathStep from './steps/ChoosePathStep';
import IssuesStep from './steps/IssuesStep';
import UploadingStep from './steps/UploadingStep';

const Container = ({ uploadStatus }) => {
  const [step, setStep] = useState(() => ChoosePathStep);

  let Step = step;
  if (uploadStatus === statuses.LOADING) {
    Step = UploadingStep;
  } else if (uploadStatus === statuses.FAILURE) {
    Step = IssuesStep;
  }

  const MountedStep = useMemo(() => (
    <Step
      me={me}
      setStep={setStep}
    />
  ), [me, setStep]);

  return (
    <>
      <FlowData
        collapseContentGutter
        rounderBorders
        editable
      />
      <Flow
        blankContent={MountedStep}
      />
    </>
  );
};

export default Container;

jpenna avatar Oct 01 '19 06:10 jpenna

sorry, i meant #920 :-)

ljharb avatar Oct 01 '19 12:10 ljharb

Can you also share your test code that uses wrap (or doesn't, and doesn't work)?

ljharb avatar Oct 01 '19 12:10 ljharb

This is working (simplified/mocked version)

import { shallow } from 'enzyme';
import Flow from 'components/Flow';
import Container from './Container';

import ChoosePathStep from './steps/ChoosePathStep';

describe('Flow', () => {
  it('Renders initial step', () => {
    const wrapper = shallow(<Container />);
    const step = wrapper.wrap(wrapper.find(Flow).prop('blankContent'));
    expect(step.is(ChoosePathStep)).toBe(true);
  });
});

If I change wrapper.wrap() for shallow(), it doesn't work, I don't know why...

jpenna avatar Oct 01 '19 15:10 jpenna

const Step = () => wrapper.find(Flow).prop('blankContent');
const step = shallow(<Step />);

ljharb avatar Oct 01 '19 15:10 ljharb

Nice, it works! I should have tried with a function...

Why would you say this way is preferable instead of using .wrap()?

jpenna avatar Oct 01 '19 15:10 jpenna

Mainly because wrap isn't intended to be used externally.

A better future enzyme addition would be something like wrapProp('blankContent') that did this for you.

ljharb avatar Oct 01 '19 17:10 ljharb

Right. Yes, that would be good, make it clear how to deal with this scenario.

I took a look into the code, this is quick piece I wrote. I can dive deeper to include this method if it sounds interesting to you.

  wrapProp(prop) {
    if (!prop || typeof prop !== 'string') {
      throw new TypeError('ReactWrapper::wrapProp() expects a string as first argument');
    }
    return this.wrap(this.prop(prop));
  }

jpenna avatar Oct 01 '19 18:10 jpenna

@jpenna sure, why not :-) can you make a PR to add that (with docs and tests) to both shallow and mount? Please also look to renderProp and invoke for the prop name validations I'd expect.

ljharb avatar Oct 01 '19 18:10 ljharb

Cool! I'll work on this this weekend then!

jpenna avatar Oct 01 '19 19:10 jpenna

@ljharb Man, I'm getting a lot of lint errors on the Master branch when I run npm test with React 16. React 15 went fine.

npm run react 16
npm run build
npm test

Just a sample below:

react/destructuring-assignment
  3483:26  warning  Must use destructuring state assignment                                                                                                                                                                                                                                                                      react/destructuring-assignment
  3513:38  warning  Must use destructuring state assignment                                                                                                                                                                                                                                                                      react/destructuring-assignment
  3513:38  warning  Use callback in setState when referencing the previous state    

.../enzyme/packages/enzyme-test-suite/test/shared/methods/setProps.jsx
  260:9   error  componentWillReceiveProps is deprecated since React 16.9.0, use UNSAFE_componentWillReceiveProps instead, see https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops. Use https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles to automatically update your components  react/no-deprecated

jpenna avatar Oct 05 '19 03:10 jpenna

Go ahead and ignore those for your PR; any failures on master, I’ll take care of :-)

ljharb avatar Oct 05 '19 04:10 ljharb

@ljharb Hey man! Did you see the PR?

jpenna avatar Oct 10 '19 15:10 jpenna

any updates on wrapProp?

gaplyk avatar Feb 19 '21 21:02 gaplyk