Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test methods inside functional component using enzyme as instance() returns null for shallow wrapper?

Let's say I have a simple component like this.

import React, { useState } from "react";

const Counter = () => {
  const [counter, setCounter] = useState(0);
  const incCounter = () => {
    setCounter(counter + 1);
  };
  return (
    <>
      <p>Counter value is: {counter}</p>
      <button className="increment" onClick={incCounter}>
        Up
      </button>
    </>
  );
};
export default Counter;

I want to write test cases using jest and enzyme. But counter.instance() always returns null. Any help will be greatly appreciated.

import React from "react";
import Counter from "../components/Counter";
import {
  mount,
  shallow
} from "./enzyme";

describe("Counter", () => {
  let counter;
  beforeEach(() => {
    counter = shallow( < Counter / > );
  })

  it("calls incCounter function when button is clicked", () => {
    console.log(counter)
    counter.instance().incCounter = jest.fn();
    const incButton = counter.find("button");
    incButton.simulate("click");
    expect(counter.incCounter).toBeCalled();

  })

});
like image 487
Deepak Kumar Padhy Avatar asked Dec 25 '19 06:12

Deepak Kumar Padhy


People also ask

Can we use render () inside functional component?

There is no render method used in functional components. With functional components there are fewer lines of code another positive to this is that the fewer lines of code a developer has to read and write, the faster and easier their code is to comprehend.

What is wrapper instance ()?

instance() => ReactComponent. Returns the single-node wrapper's node's underlying class instance; this in its methods. It must be a single-node wrapper. NOTE: With React 16 and above, instance() returns null for stateless functional components.

Can I use lifecycle hooks in functional components?

Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don't work inside classes — they let you use React without classes. (We don't recommend rewriting your existing components overnight but you can start using Hooks in the new ones if you'd like.)

How do you test for enzyme useState?

Testing the useState Hook with Enzyme js file with the following: import React from "react"; const App= () => { const [name, setName] = React. useState(""); return ( <form> <div className="row"> <div className="col-md-6"> <input type="text" placeholder="Enter your name" className="input" onChange={(e) => { setName(e.

What does the enzyme wrapper do?

I recently learned about the enzyme wrapper.instance() method, which returns the component instance inside of the wrapper. Getting access to this instance allows you to directly invoke component methods, instead of resorting to event simulation to indirectly trigger them.

What is the difference between enzyme and instance in react 16?

Before React 16, Enzyme was used to test class based react components and the instance method was used to access the component class’ methods and test it. But with the latest react 16 adaptor, while testing functional components, the instance object is returned as null.

Should I use Wrapper instance() or wrapper State() for testing components?

I personally think that using wrapper.instance () or wrapper.state () indicates that the test tests the component's implementation rather than its behavior, which is usually not desired. I completely agree with this. I'm actually in the process of writing a new post that will clarify this point.

How to test functional components in react?

Generally, functional components in React aren't meant to be tested in that way. The React team are suggesting that you use the approach of React Testing Library which is more focused on the actual user interface scenarios. Instead of testing React component instances, you're testing DOM nodes.


1 Answers

From this docs: https://airbnb.io/enzyme/docs/api/ShallowWrapper/instance.html

NOTE: can only be called on a wrapper instance that is also the root instance. With React 16 and above, instance() returns null for stateless functional components.

Test component behavior, not implementation details.

E.g.

index.jsx:

import React, { useState } from 'react';

const Counter = () => {
  const [counter, setCounter] = useState(0);
  const incCounter = () => {
    setCounter(counter + 1);
  };
  return (
    <>
      <p>Counter value is: {counter}</p>
      <button className="increment" onClick={incCounter}>
        Up
      </button>
    </>
  );
};
export default Counter;

index.spec.jsx:

import React from 'react';
import Counter from './';
import { shallow } from 'enzyme';

describe('Counter', () => {
  let counter;
  beforeEach(() => {
    counter = shallow(<Counter />);
  });

  it('calls incCounter function when button is clicked', () => {
    expect(counter.find('p').text()).toBe('Counter value is: 0');
    const incButton = counter.find('button');
    incButton.simulate('click');
    expect(counter.find('p').text()).toBe('Counter value is: 1');
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/59475724/index.spec.jsx (10.045s)
  Counter
    ✓ calls incCounter function when button is clicked (17ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |      100 |      100 |      100 |      100 |                   |
 index.jsx |      100 |      100 |      100 |      100 |                   |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.697s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59475724

like image 91
slideshowp2 Avatar answered Oct 08 '22 19:10

slideshowp2