reactjs - Hvordan mocke formik useFormikContext hook når man skriver enhetstester med jest


Jeg har en enkel komponent se nedenfor, som i utgangspunktet prøver å hente noen data fra Formik FormContext ved å bruke useFormikContext-hooken.

Men når jeg prøver å skrive enhetstester for denne komponenten, vil den at jeg skal mocke hooken, noe som er greit, men å mocke hooken med TypeScript betyr å returnere godt over 20 egenskaper, hvorav de fleste er en rekke metoder og funksjoner.

Har noen funnet en bedre måte å gjøre dette på? Det virker bare litt irriterende selv om jeg får det til å fungere, siden jeg bare trenger ett felt fra kroken.

Komponent

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>
    </>
  );
};

Enhetstest (Ufullstendig, dette var bare et raskt forsøk på å mocke alle returverdiene for hooken)

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,
    });
  }
}

Svar #1

Jeg løste dette problemet, er ikke 100 % sikker på at det er den beste løsningen, men har lagt det ut her i tilfelle det hjelper noen med et lignende problem.

Jeg overskrev i praksis FormikType slik at jeg kunne ignorere alle feltene og metodene jeg ikke brukte, det har tydeligvis noen ulemper siden det fjerner typesikkerheten, men jeg tenkte at siden det bare var i enhetstesten, er det greit på en måte.

Importer

import * as Formik from 'formik';

Testoppsett

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

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

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

Hjelpemetode

export const getFieldMetaMock = (name: string) => {
  return ({
    value: 'testValue',
    initialTouched: true,
    touched: false,
  });
};

Svar #2

Du kan også lage en mock av Formik-biblioteket og dets ønskede funksjoner på denne måten:

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

Bare legg denne koden øverst i unit-testfilen din, utenfor describe-området.

Relaterte artikler