0
votes

I have a simple form with just one text field. I have used react material ui library along with formik for validations and verification. I'm unable to get the textfield within the form by using shallow method of enzyme. Not sure what I'm doing wrong.

declarationForm.js

import React, { useState, useEffect } from 'react';
import * as Yup from 'yup';
import { Formik } from 'formik';
import { useNavigate, Prompt } from "react-router-dom";
import { Box, Button, Card, CardContent, CardHeader, Divider, Grid, TextField } from '@material-ui/core';
import { get_declarations_details, put_declarations_details } from './../../utils/service';

const DeclarationsForm = () => {

  const [ initialData, setInitialData ] = useState({ declarations:'' });

  useEffect(()=>{
    get_data();
  },[]);

  let navigate = useNavigate();

  const get_data = async() =>{
    try {
      const result = await get_declarations_details();
      if(result){
        setInitialData({
          ...initialData,
          ...result,
        });
      }
    } catch (error) {
      console.log(error);
    }
  }

  const put_data = async(data) =>{
    try {
      const result = await put_declarations_details(data);
      if(result){
        setInitialData({
          ...initialData,
          ...result,
        });
      } 
    } catch (error) {
      console.log(error);
    }
  }

  return (
    <Formik
      initialValues={initialData}
      enableReinitialize={true}
      validationSchema={
      Yup.object().shape({
        declarations: Yup.string().max(255).required('Declarations is required'),
        })
      }
      onSubmit={(values) => {
        if(JSON.stringify(initialData) !== JSON.stringify(values)){
          put_data(values);
        }
        navigate(`/summary`, { replace: true })
      }}
    >
    {({
      errors,
      handleBlur,
      handleChange,
      handleSubmit,
      isSubmitting,
      touched,
      isValid,
      values
      }) => (
      <form onSubmit={handleSubmit}>
      <Card>
        <Prompt
          when={!isValid}
          message="Are you sure you want to proceed without saving?"
        />
        <CardHeader
          subheader="The information can be edited"
          title="Declarations"
        />
        <Divider />
        <CardContent>
          <Grid
            container
            spacing={3}
          >
            <Grid
              item
              md={6}
              xs={12}
            >
              <TextField
                fullWidth
                error={Boolean(touched.declarations && errors.declarations)}
                helperText={touched.declarations && errors.declarations}
                label="Declarations"
                name="declarations"
                handleBlur={handleBlur}
                onChange={handleChange}
                required
                value={values.declarations}
                variant="outlined"
              />
            </Grid>
          </Grid>
        </CardContent>
        <Divider />
        <Box
          display="flex"
          justifyContent="flex-end"
          p={2}
        >
          <Button
            color="primary"
            variant="contained"
            disabled={isSubmitting}
            onClick={handleSubmit}
          >
            Continue
          </Button>
        </Box>
      </Card>
      </form>
      )}
    </Formik>
  );
};

export default DeclarationsForm;

My test file is as below

declarationForm.test.js

import { createShallow } from '@material-ui/core/test-utils';
import React from 'react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import DeclarationsForm from './declarationsForm';
import { ThemeProvider as MuiThemeProvider } from '@material-ui/core/styles';
import { TextField } from '@material-ui/core';

configure({ adapter: new Adapter() });

describe('<DeclarationsForm />', () => {
  let shallow, wrapper;

  beforeAll(() => {  // This is Mocha; in Jest, use beforeAll
    shallow = createShallow();
  });

  beforeEach(() => {
    wrapper = shallow(<MuiThemeProvider><DeclarationsForm /></MuiThemeProvider>);
  });
  it('should work', () => {
    
    console.log(wrapper.find(TextField).debug());
    expect(wrapper.find(TextField)).toHaveLength(1);
  });
});

When I run the test below is the result

 FAIL  src/views/declarations/declarationsForm.test.js
  ● Console

    console.error node_modules/prop-types/checkPropTypes.js:20
      Warning: Failed prop type: The prop `theme` is marked as required in `ThemeProvider`, but its value is `undefined`.
          in ThemeProvider (at declarationsForm.test.js:19)
    console.log src/views/declarations/declarationsForm.test.js:23
      

  ● <DeclarationsForm /> › should work

    expect(received).toHaveLength(expected)

    Expected length: 1
    Received length: 0
    Received object: {}

      22 |     
      23 |     console.log(wrapper.find(TextField).debug());
    > 24 |     expect(wrapper.find(TextField)).toHaveLength(1);
         |                                     ^
      25 |   });
      26 | });

      at Object.<anonymous> (src/views/declarations/declarationsForm.test.js:24:37)

wrapper is unable to find text field or form. 

How to debug this? What is the right approach to write test when we have also used useNavigate method within the component?
1
Looks like you may need to pass a theme prop to MuiThemeProvider in your test. I ditched Enzyme a long time ago, but perhaps if you did a full mount versus shallow, I think the shallow mounting treats children components differently and doesn't fully render them.Drew Reese

1 Answers

0
votes

Just like Drew's above, you need to pass in a theme prop to resolve the Failed prop type error.

shallow(<MuiThemeProvider theme={{}}><DeclarationsForm /></MuiThemeProvider>);

Also, wrapper cannot find TextField cos you're using shallow. Use dive() to expand the nested form

console.log(wrapper.find(Formik).dive().find(TextField).debug());