29

I have a component like that:

<Parent>
  <Child/>
</Parent>

and <Child/> component have a method foo. I want test the foo method but I don't know how to access it. I tried:

mount(<Parent><Child/></Parent>).props().children.foo

or

mount(<Parent><Child/></Parent>).children().foo

but both them are undefined. I can't use .instance() because it's not root. I can't mount <Child/> only because the <Parent> add something (react-router's context.router) on context and I need them when init <Child/>. Any idea with this?

Vikas Yadav
  • 2,812
  • 1
  • 20
  • 20
Fomahaut
  • 1,204
  • 1
  • 11
  • 18
  • 1
    It's seems this is still not possible or at least complicated: https://github.com/airbnb/enzyme/issues/361 – Leonardo Apr 13 '17 at 14:29
  • Test the react components lower down in the tree before working your way up. Also export an unwrapped version of your component for tests in order to remove the dependency of the component on react router. – therewillbecode Sep 16 '17 at 18:37
  • 1
    +1 most annoying thing about writing react specs, I don't understand how you could write a spec framework for react and not have an easy way to access instances of child components. dumb. – dezman Apr 18 '18 at 20:54

11 Answers11

6

This worked for me:

mount(<Parent><Child/></Parent>).find(Child).instance().foo
jackocnr
  • 16,344
  • 9
  • 52
  • 62
4

I would consider writing tests for only your parent class, and then a separate test file to only test your child.

Once you have mounted you component using:

const component = mount(<Child>); 

you then have access to it's methods using:

component.instance().methodname

You can then do stuff like override it with jest.fn() and test appropriately.

rnmalone
  • 840
  • 10
  • 23
4

I prefer shallow mount over full mount from enzyme.

In conjunction with proxyquire to resolve child component (which you want to test) I do

wrapper.find('Child1').props().propName

And test it.

Or I use shallow

mount wrapper.dive()
DaFois
  • 2,166
  • 8
  • 22
  • 38
2

I think your problem is way different from how to test child components.

My first question is: Why are you checking if a child component has a specific method in the parent's component tests?

IMHO you need to have a test specific for this component and, then, in this test you check if the method exists.

Just to not leave without the answer, did you tried .find(Child).instance().foo ?

Arthur Almeida
  • 548
  • 2
  • 8
2

I had a similar problem when trying to mock a function on an inner component within a MemoryRouter:

cont wrapper = mount(<MemoryRouter><AvailabilityButtonWithRouter.WrappedComponent vetId={ vetId  } appointment={ availability } /></MemoryRouter>);     

I ended up being able to mock the function like so:

const mockFn = jest.fn();    
wrapper.children(0).children(0).instance().reloadCurrentPage = mockFn;
pmaher
  • 21
  • 1
  • Good, it helped me find a function in 3 level nested Item child component that rendered multiple times. Don't need the `0` argument, like `.children(0)`, but just `children()`. And when ready to find it, just `.first().getElement()` and props. My Example : `wrapper.find('Item').children().first().getElement()` – KeitelDOG Mar 05 '21 at 20:00
2

I was able to get a handle on child function like the following, i was looking for the first child to call the function on -

const component = shallow(<Component />);
component.find(Child).first().getNode().props.someChildFunction()
andy mccullough
  • 8,070
  • 6
  • 28
  • 44
0

I faced a similar problem and I went through mount API by logging. In my use case, my child component(CommonStoresReactions) is wrapped with mobx inject.

const jsx = (
    <Provider {...stores}>
      <CommonStoresReactions>
        <div />
      </CommonStoresReactions>
    </Provider>
)
const wrapper = mount(jsx)

I want to test clearStores method in CommonStoresReactions. Below snippet worked for me.

wrapper
      .find(CommonStoresReactions)
      .instance()
      .wrappedInstance.clearStores()
Anesh
  • 194
  • 2
  • 9
0

Enzyme has an option for the mount API called wrappingComponent (and wrappingComponentProps) to wrap the mounted object inside another component for providing context, etc.

See https://github.com/airbnb/enzyme/blob/master/docs/api/mount.md#mountnode-options--reactwrapper

Chris
  • 1,904
  • 24
  • 36
0

I managed to solve this by using dive

wrapper.dive().props().propName
klugjo
  • 16,697
  • 7
  • 46
  • 64
0

With enzyme:

mount(<Parent><Child/></Parent>).childAt(0).instance().foo

There are valid reasons to access the child and call a method. If the parent is superficial and children have a consistent interface you can call methods without knowing which child it is, testing that all children have the correct interface, signature etc.

0

The best way I find out is using shallow wrapper's dive method. Here is the doc: enzyme dive doc

Remember if ur parent component use the fully rendering like mount, then the react wrapper itself doesnt have the dive method so u have to use shallow render.

Here is one example:

let instance, child, diveChild;
describe('Test Parent child Child component', () => {
  beforeEach(() => {
    wrapper = shallow(<Parent {...props} />);
    child = wrapper.find('Child');
    diveChild = child.dive();
    console.log(diveChild.instance());
  });

  test('Child get mounted', () => {
    expect(child.exists()).toBeTruthy();
    expect(child.debug()).toMatchSnapshot();
  });
});
qmkiwi
  • 105
  • 5