Skip to content
This repository has been archived by the owner on Jun 15, 2022. It is now read-only.

Unable to get input value of wrapped component in <TypedController /> on Jest #19

Open
redshoga opened this issue Sep 24, 2020 · 1 comment

Comments

@redshoga
Copy link

redshoga commented Sep 24, 2020

Unable to get input value of wrapped component in <TypedController /> on Jest.

Both codes work correctly in the browser. (Chrome 85.0.4183.102)

use <TypedController /> sample test code

Only the last test will not pass.

import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { useTypedController } from '@hookform/strictly-typed';

const FORM_ID = 'test-textarea-id';
const SUBMIT_ID = 'test-submit-id';

type CustomeTextareaProps = {
  testId: string;
  name: string;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>;
const CustomeTextarea: React.FC<CustomeTextareaProps> = (props: CustomeTextareaProps) => {
  const { testId, ...textAreaProps } = props;

  return (
    <div>
      <textarea data-testid={testId} {...textAreaProps} />
    </div>
  );
};

type SampleFormValue = {
  sample: string;
};
type SampleFormProps = {
  onSubmit: (value: SampleFormValue) => void;
};
const SampleForm: React.FC<SampleFormProps> = (props: SampleFormProps) => {
  const { handleSubmit, control } = useForm<SampleFormValue>({
    criteriaMode: 'all',
  });
  const TypedController = useTypedController<SampleFormValue>({ control });
  const onSubmit: SubmitHandler<SampleFormValue> = (data) => {
    props.onSubmit(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <TypedController
        name={'sample'}
        render={(formProps) => <CustomeTextarea testId={FORM_ID} name={'sample'} {...formProps} />}
      />
      <input type="submit" data-testid={SUBMIT_ID} />
    </form>
  );
};

describe('SampleForm', () => {
  test('Input value should be equal to the form value', async () => {
    const mockOnSubmit = jest.fn();
    await act(async () => {
      const renderResult = render(<SampleForm onSubmit={mockOnSubmit} />);
      const input = renderResult.getByTestId(FORM_ID) as HTMLTextAreaElement;
      fireEvent.change(input, { target: { value: 'test-value' } });
      expect(input.value).toBe('test-value'); // No Error
    });
  });

  test('Submitted data should be equal to the input data', async () => {
    const mockOnSubmit = jest.fn();
    await act(async () => {
      const renderResult = render(<SampleForm onSubmit={mockOnSubmit} />);
      const input = renderResult.getByTestId(FORM_ID) as HTMLTextAreaElement;
      fireEvent.change(input, { target: { value: 'test-value' } });
      expect(input.value).toBe('test-value');
      fireEvent.submit(renderResult.getByTestId(SUBMIT_ID));
    });
    expect(mockOnSubmit).toBeCalled(); // No Error
    expect(mockOnSubmit).toBeCalledWith({}); // No Error
    expect(mockOnSubmit).toBeCalledWith({ sample: 'test-value' }); // -> Error
  });
});

Error log

SampleForm
    √ Input value should be equal to the form value (122 ms)
    × Submitted data should be equal to the input data (89 ms)

  ● SampleForm › Submitted data should be equal to the input data

    expect(jest.fn()).toBeCalledWith(...expected)

    - Expected
    + Received

    - Object {
    -   "sample": "test-value",
    - }
    + Object {},

    Number of calls: 1

      71 |     expect(mockOnSubmit).toBeCalled(); // No Error
      72 |     expect(mockOnSubmit).toBeCalledWith({}); // No Error
    > 73 |     expect(mockOnSubmit).toBeCalledWith({ sample: 'test-value' }); // -> Error
         |                          ^
      74 |   });
      75 | });
      76 | 

without <TypedController /> sample test code

All tests pass.

import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { useTypedController } from '@hookform/strictly-typed';

const FORM_ID = 'test-textarea-id';
const SUBMIT_ID = 'test-submit-id';

type CustomeTextareaProps = {
  testId: string;
  name: string;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>;

const CustomeTextarea = React.forwardRef<HTMLTextAreaElement, CustomeTextareaProps>(
  (props: CustomeTextareaProps, ref) => {
    const { testId, ...textAreaProps } = props;
    return (
      <div>
        <textarea data-testid={testId} ref={ref} {...textAreaProps} />
      </div>
    );
  }
);

type SampleFormValue = {
  sample: string;
};
type SampleFormProps = {
  onSubmit: (value: SampleFormValue) => void;
};
const SampleForm: React.FC<SampleFormProps> = (props: SampleFormProps) => {
  const { handleSubmit, register } = useForm<SampleFormValue>({
    criteriaMode: 'all',
  });
  const onSubmit: SubmitHandler<SampleFormValue> = (data) => {
    props.onSubmit(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <CustomeTextarea testId={FORM_ID} name={'sample'} ref={register()} />
      <input type="submit" data-testid={SUBMIT_ID} />
    </form>
  );
};

describe('SampleForm', () => {
  test('Input value should be equal to the form value', async () => {
    const mockOnSubmit = jest.fn();
    await act(async () => {
      const renderResult = render(<SampleForm onSubmit={mockOnSubmit} />);
      const input = renderResult.getByTestId(FORM_ID) as HTMLTextAreaElement;
      fireEvent.change(input, { target: { value: 'test-value' } });
      expect(input.value).toBe('test-value'); // -> No Error
    });
  });

  test('Submitted data should be equal to the input data', async () => {
    const mockOnSubmit = jest.fn();
    await act(async () => {
      const renderResult = render(<SampleForm onSubmit={mockOnSubmit} />);
      const input = renderResult.getByTestId(FORM_ID) as HTMLTextAreaElement;
      fireEvent.change(input, { target: { value: 'test-value' } });
      expect(input.value).toBe('test-value'); // -> No Error
      fireEvent.submit(renderResult.getByTestId(SUBMIT_ID));
    });
    expect(mockOnSubmit).toBeCalled(); // -> No Error
    expect(mockOnSubmit).toBeCalledWith({ sample: 'test-value' }); // -> No Error
  });
});

dependencies (package.json)

{
  ...
  "dependencies": {
    "@aspida/axios": "^0.9.4",
    "@emotion/core": "^10.0.28",
    "@hookform/resolvers": "^0.1.0",
    "@hookform/strictly-typed": "^0.0.4",
    "axios": "^0.19.2",
    "css-element-queries": "^1.2.3",
    "dayjs": "^1.8.36",
    "next": "^9.4.4",
    "next-images": "^1.4.0",
    "nprogress": "^0.2.0",
    "qrcode.react": "^1.0.0",
    "query-string": "^6.13.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-hook-form": "^6.0.2",
    "react-loading-skeleton": "^2.1.1",
    "react-modal": "^3.11.2",
    "react-toastify": "^6.0.8",
    "react-tooltip": "^4.2.8",
    "swr": "^0.3.0",
    "ts-node": "^8.10.2",
    "vanilla-lazyload": "^17.1.0"
  },
  "devDependencies": {
    "@babel/core": "^7.10.4",
    "@next/bundle-analyzer": "^9.4.4",
    "@stoplight/prism-cli": "^3.3.7",
    "@storybook/addon-a11y": "^5.3.19",
    "@storybook/addon-actions": "^5.3.19",
    "@storybook/addon-backgrounds": "^5.3.19",
    "@storybook/addon-docs": "^5.3.19",
    "@storybook/addon-knobs": "^5.3.19",
    "@storybook/react": "^5.3.19",
    "@testing-library/jest-dom": "^5.11.0",
    "@testing-library/react": "^10.4.4",
    "@testing-library/react-hooks": "^3.4.1",
    "@types/jest": "^26.0.4",
    "@types/node": "^14.0.14",
    "@types/nprogress": "^0.2.0",
    "@types/qrcode.react": "^1.0.1",
    "@types/react": "^16.9.41",
    "@types/react-modal": "^3.10.6",
    "@types/react-tooltip": "^4.2.4",
    "@types/testing-library__jest-dom": "^5.9.1",
    "@typescript-eslint/eslint-plugin": "^3.5.0",
    "@typescript-eslint/parser": "^3.5.0",
    "babel-loader": "^8.1.0",
    "babel-preset-react-app": "^9.1.2",
    "cross-env": "^7.0.2",
    "eslint": "^7.4.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-react": "^7.20.3",
    "husky": "^4.2.5",
    "jest": "^26.1.0",
    "openapi2aspida": "^0.9.0",
    "prettier": "^2.0.5",
    "react-is": "^16.13.1",
    "react-test-renderer": "16.9.0",
    "stylelint": "^13.6.1",
    "stylelint-config-prettier": "^8.0.2",
    "stylelint-config-standard": "^20.0.0",
    "ts-jest": "^26.1.1",
    "typescript": "3.8.3"
  }
}

@kotarella1110
Copy link
Member

kotarella1110 commented Sep 28, 2020

@redshoga Thanks for your feedback!
I haven't tried it, but it looks like fireEvent.change doesn't fire an onChange event and an onChange callback passed by TypedController is not being executed. Can you verify this? 🙏

You may also be able to resolve using userEvent.type instead of fireEvent.change.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants