0

I have a component in my React codebase and I am trying to create some snapshot tests for it, but unfortunately there is some weird error going on. Jest implies that I'm doing some destructuring on non-iterable instance and logs shows something that however much I tried to think about it, it would work perfectly, but I don't know what is wrong with this snippet of code shown in image below:

1

Also please note that I did a mock for formik in my component like below:

jest.mock('formik', () => ({
  useField: jest.fn(),
  useFormikContext: jest.fn(),
}));

and every other question related to the topic either is not for Jest or answer is not working and not even accepted!

Here is my test file:

import React from 'react';
import renderer from 'react-test-renderer';

import MyComponent from '../MyComponent';

jest.mock('../MyComponentManager');
jest.mock('formik', () => ({
  useField: jest.fn(),
  useFormikContext: jest.fn().mockReturnValue({ isValidating: false, setFieldValue: () => {} }),
}));

describe('MyComponent', () => {
  test('should render component properly', () => {
    const component = renderer.create(<MyComponent />);
    const tree = component.toJSON();
    expect(tree).toMatchSnapshot();
  });
});

And here is the minor version of the component that is being testing:


const MyComponent = () => {

  <SomeWrapperComponent>
    ...some jsx
    <NumberField {...props} />
  </SomeWrapperComponent>

}

and the error happens in side the <NumberField /> component.

2 Answers 2

1

I believe your problem is setting useFormikContext: jest.fn(). jest.fn() by default returns a function that returns undefined as mentioned in jest docs. and by that you try to deconstruct undefined.

you need to mock the return value of useFormikContext function:

jest.mock('formik', () => ({
  useField: jest.fn(),
  useFormikContext: jest.fn().mockReturnValue({ isValidating: false, setFieldValue: () => {} }),
}));

If that doesnt help, please add full and simple runnable example that's not working, so I can take a deeper look. (i.e. test file and code file)


Edit

I see you only mocked useField useFormikContext functions of formik module, although you probably use more from formik module, like Formik tag and such, but they're now overriden.

jest.mock overrides the whole module, and not suitable for your use case, because you only want to mock only useField & useFormikContext.

I like to use jest.spyOn which can be used to mock only specific functions of a module. see jest docs on jest.spyOn.

Here's full working small example mocking formik in jest react testing.

  1. example.js - react component that's being tested.
  2. example.spec.js - simple jest test

example.js:

import React from 'react';
import { useFormikContext, Formik, Form, Field } from 'formik';

export const OtherComponent = () => {
  // Grab values and submitForm from context
  const { isValidating, setFieldValue } = useFormikContext();

  return (
    <div>
      <div>{isValidating ? 'validating...' : 'validated!'}</div>
      <button type="submit" disabled={isValidating}>
        submit
      </button>
      <button
        type="button"
        disabled={isValidating}
        onClick={() => {
          setFieldValue('token', '123456');
        }}
      >
        return to default
      </button>
    </div>
  );
};

export const ExmpleComponent = () => {
  return (
    <div>
      <h1>Example</h1>
      <Formik
        initialValues={{ token: '' }}
        validate={(values) => {
          return new Promise((resolve, _reject) => setTimeout(resolve, 3000)).then(() => {
            // wait 3 seconds
            const errors = {}; // no errors
            return errors;
          });
        }}
        onSubmit={(_values, _actions) => {
          console.log('submitted!');
        }}
      >
        <Form>
          <Field name="token" type="tel" />
          <OtherComponent />
        </Form>
      </Formik>
    </div>
  );
};

example.spec.js:

import React from 'react';

import renderer from 'react-test-renderer';
import * as formik from 'formik';
import { ExmpleComponent } from '../src/example.js';

// jest.mock('formik', () => ({
//   useField: jest.fn(),
//   useFormikContext: jest.fn().mockReturnValue({ isValidating: false, setFieldValue: () => {} }),
// }));

describe('MyComponent', () => {
  test('should render component properly', () => {
    const useFieldSpy = jest.spyOn(formik, 'useField');
    const useFormikContextSpy = jest.spyOn(formik, 'useFormikContext');

    useFieldSpy.mockReturnValue(undefined);
    useFormikContextSpy.mockReturnValue({ isValidating: true, setFieldValue: () => {} });

    const component = renderer.create(<ExmpleComponent />);
    const tree = component.toJSON();
    expect(tree.children[1].children[1].children[0].children[0]).toBe('validating...');

    useFieldSpy.mockRestore();
    useFormikContextSpy.mockRestore();
  });
});

If that still doesnt work, please add full & simple example that I can run to test by myself to see what's wrong in your code. You added full example of the test file, but not the code you're testing.

Sign up to request clarification or add additional context in comments.

4 Comments

i did that this way in my code sample jest.mock('formik', () => ({ useField: jest.fn(), useFormikContext: () => jest.fn().mockReturnValue({ isValidating: false, setFIeldValue: () => {} }), })); it does not worked
you need to set useFormikContext to just jest.fn().mockReturnValue({ isValidating: false, setFIeldValue: () => {} }), not a function that returns jest.fn(). if that still doesnt work, please also add the full code example (that's being tested) as well, and remove unnecessary code to make it simple. I've edited my answer to show what i wrote here.
i did that and it did not work, i really appreciate your effort trying to help me, and i updated the code, i use some component inside of <MyComponent> and it calles the <NumberField /> component an i use useFormikContext logic inside of that component
Alright. I've tried and made an example. see my edit.
0

For contribute, I solved similar issue using this code:

jest.mock('formik', () => ({
  useField: jest.fn(),
  useFormikContext: jest.fn().mockReturnValue({ 
    setFieldValue: () => {}, 
    handleChange: () => {},
    initialValues: {} as AddDoctorInfoFormValues, 
    errors: {} as FormikErrors<AddDoctorInfoFormValues>,
    values: {} as AddDoctorInfoFormValues, 
  }),
}));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.