简体   繁体   中英

How to mock the formik useFormikContext hook when writing unit tests with jest

I have a simple component see below, that basically attempts to grab some data from the formik FormContext using the useFormikContext hook.

However when attempting to write unit tests for this component it wants me to mock the hook which is fine, however, mocking the hook with typescript means returning well over 20 properties most of which are a variety of methods and functions.

Has anyone found a better way of doing this? Just seems a bit annoying even if I get it to work as I only need 1 field from the hook.

Component

const AphControlInput: React.FC<IAphControlInput> = ({ name, value, label, type, small, disabled, vertical = true, className = '', ...attributeOptions }) => {
  const form = useFormikContext();

  return (
    <>
      <div className={
        `aph-control-input ${className}` +
        `${small ? ' aph-control-input--small' : ''}` +
        `${vertical ? ' aph-control-input--block' : ''}` +
        `${form.getFieldMeta(name).error ? ' aph-control-input--invalid' : ''}`
      }
      >
        <Field
          className='aph-control-input__input'
          name={name}
          id={value ? value?.toString() : name}
          type={type}
          value={value ? value : undefined}
          disabled={disabled}
          {...attributeOptions}
        />
        <label className='aph-control-input__text' htmlFor={value ? value?.toString() : name}>
          {label}
        </label>
      </div>
    </>
  );
};

Unit test (Incomplete this was just a quick attempt at mocking all the returns for the hook)

describe('AphInputLabel UnitTests', () => {
  let wrapper: any;
  const useFormikContextMock = jest.spyOn(formik, 'useFormikContext');

  beforeEach(() => {
    useFormikContextMock.mockReturnValue({
      values: { testName: 'testValue' },
      getFieldMeta: getFieldMetaMock,
      touched: true,
      isSubmitting: false,
      isValidating: false,
      errors: false,
      submitCount: 0,
      setStatus: (status?: any) => { return null },
      setErrors: (errors?: FormikErrors<any>) => { return null },
      setSubmitting: (isSubmitting: boolean) => { return null },
      setTouched: (touched: FormikTouched<any>, shouldValidate?: boolean) => { return null },
      setValues: (values: React.SetStateAction<any>, shouldValidate?: boolean) => { return null },
      setFieldValue: (field: string, value: any, shouldValidate?: boolean) => { return null },
      setFieldError: (field: string, message: string | undefined) => { return null },
      setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => { return null },
      resetForm: (nextState?: Partial<FormikState<any>>) => { return null },
      validateField: (field: string) => { return null },
      setFormikState: (f: FormikState<any> | ((prevState: FormikState<any>) => FormikState<any>), cb?: () => void) => null,
      validateForm: (values?: any) => { return new Promise<FormikErrors<unknown>>((resolve, reject) => {
        const formikErrors: FormikErrors<any> = {
          'testName': ''
        }
          return formikErrors;
        });
      },
      submitForm: () => new Promise<void>(() => null),
      handleSubmit: (e?: React.FormEvent<HTMLFormElement> | undefined) => null,
      handleReset: (e?: React.SyntheticEvent<any>) => null,
    });
  }
}

I resolved this issue not 100% sure it is the best solution but have posted here in case it helps anyone with a similar issue.

I basically overwrote the FormikType allowing me to ignore all of the fields and methods I wasn't using, it clearly has some drawbacks as it is removing the type-safety, but I figured since it was only inside the unit test it is somewhat okay.

  beforeEach(() => {
    useFormikContextMock.mockReturnValue({
      getFieldMeta: getFieldMetaMock
    } as unknown as any);

    wrapper = shallow(
      < AphInputLabel {...baseComponentProps} />
    );
  });

How would you test here just setFieldValue? I have kind of the same issue here, I am mocking useFormikContext as above here, all works, but I cannot test the setFieldValue, I mean I don't really get what should go here in the test part, sorry if the question is dumb, but just started learning/writing test.

I cant share all the code, but all my tests pass, I just don't know how to go about testing if the components children sets the value correctly or not

 const PasswordMeter: FC<PasswordMeterProp> = ({ password }) => { const { setFieldValue } = useFormikContext(); return ( <> <PasswordStrengthBar className={'strength-bar-meter'} password={password} minLength={4} onChangeScore={(score, feedback) => { setFieldValue('complexityField', score); }} shortScoreWord="" barColors={['#D9D9D9', '#FF0000', '#FFAA00', '#40FF7A', '#40FF7A']} /> <Textbox name="complexityField" id="complexityField" type="text" hidden="true" /> </> ); }; const useFormikContextMock = jest.spyOn(Formik, 'useFormikContext'); const setFieldValueMock = () => { return { value: 3, field: 'complexityField', }; }; beforeEach(() => { useFormikContextMock.mockReturnValue({ setFieldValue: setFieldValueMock, } as unknown as any); });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM