Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shallow HOC with Enzyme and TypeScript

I have a HOC to test, during shallow mount I should to call some class methods:

it('Should not call dispatch', () => {
        const dispatch = jest.fn()
        const WrappedComponent = someHoc(DummyComponent)
        const instance = shallow(
          <WrappedComponent
            dispatch={dispatch}
          />,
        ).instance() as WrappedComponent
        instance.someMethod()
        expect(dispatch).toHaveBeenCalledTimes(0)
})

test works fine but TS compiler throws an error

 Cannot find name 'WrappedComponent'.

And it is right because WrappedComponent is not a type or class, but if I remove the

 as WrappedComponent

line, TS throws an error

Property 'someMethod' does not exist on type 'Component<{}, {}, any>'.

Also, it does not compile if I change that line as

as typeof WrappedComponent

someHoc description:

import ...

interface State {
  /*state*/
}

interface Props {
  dispatch: Dispatch<Action>
  /*props*/
}

export someHoc = <T extends {}>(
  ChildComponent: React.ComponentClass<T>,
) => {
  class Wrapper extends React.PureComponent<T & Props, State> {

    someMethod = () => {
       /*do smth*/
    }

    render() {
      return (
        <div>
          <ChildComponent {...this.props} />
        </div>
      )
    }
  }

  return Wrapper
}

How can I type the HOC instance? Thanks.

like image 856
Alex Borodin Avatar asked Oct 16 '18 19:10

Alex Borodin


People also ask

What is shallow rendering in Enzyme?

Shallow rendering lets you render a component “one level deep” and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered.

Does Enzyme shallow call componentDidMount?

As of Enzyme v3, the shallow API does call React lifecycle methods such as componentDidMount and componentDidUpdate . You can read more about this in the version 3 migration guide.

What is the difference between shallow and mount in Enzyme?

The difference between shallow() and mount() is that shallow() tests components in isolation from the child components they render while mount()goes deeper and tests a component's children.


1 Answers

It is expected that functions that have variable return value types that can be parametrized are generics. shallow is a generic:

export function shallow<C extends Component, P = C['props'], S = C['state']>(node: ReactElement<P>, options?: ShallowRendererProps): ShallowWrapper<P, S, C>;
export function shallow<P>(node: ReactElement<P>, options?: ShallowRendererProps): ShallowWrapper<P, any>;
export function shallow<P, S>(node: ReactElement<P>, options?: ShallowRendererProps): ShallowWrapper<P, S>;

It likely should be used as:

const instance = shallow<typeof WrappedComponent>(
  <WrappedComponent
    dispatch={dispatch}
  />,
).instance();

There currently seem to be problems in Enzyme typings with using generic parameters to infer component type in ShallowWrapper.

A workaround that secures type safety down the test is to assert the type:

const instance = shallow(
  <WrappedComponent
    dispatch={dispatch}
  />,
)
.instance() as any as InstanceType<typeof WrappedComponent>;
like image 55
Estus Flask Avatar answered Oct 17 '22 15:10

Estus Flask