测试用打字稿编写的自定义反应钩子

发布于 2025-01-10 23:15:29 字数 1616 浏览 0 评论 0 原文

我有一个用 TS 编写的自定义钩子 useForm ,它工作得很好。使用@testing-library/react-hooks 进行测试。测试通过。但是打字稿在一个特定的地方抱怨 - 见下文:

这是自定义挂钩:

import { useState } from 'react';

export function useForm<T>(initialValues: T) {
  const [values, setValues] = useState(initialValues);

  return {
    values: values,
    handleChange: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
      setValues({
        ...values,
        [e.target.name]: e.target.value,
      });
    },
    reset: () => setValues(initialValues),
  };
}

这是测试:

import { renderHook, act } from '@testing-library/react-hooks';

import { useForm } from './useForm';

test('should render useForm hook', () => {
  const { result } = renderHook(() =>
    useForm({
      text: 'Note One',
    }),
  );

  expect(result.current).toBeDefined();
  expect(result.current.values.text).toBe('Note One');

  act(() => {
    result.current.handleChange({
      target: { //complains here - Type '{ name: string; value: string; }' is not assignable to type 'EventTarget & (HTMLTextAreaElement | HTMLInputElement)'.
        name: 'text',
        value: 'Note Two',
      },
    });
  });

  expect(result.current.values.text).toBe('Note Two');

  act(() => {
    result.current.reset();
  });
  expect(result.current.values.text).toBe('Note One');
});

这是一个工作代码沙箱:https://codesandbox.io/s/flamboyant-curie-6i5moy?file=/src/useForm.test.tsx

I have a custom hook useForm written in TS and it works just fine. Testing it with @testing-library/react-hooks. The tests pass. But typescript is complaining in a one specific place - see below:

Here is the custom hooks:

import { useState } from 'react';

export function useForm<T>(initialValues: T) {
  const [values, setValues] = useState(initialValues);

  return {
    values: values,
    handleChange: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
      setValues({
        ...values,
        [e.target.name]: e.target.value,
      });
    },
    reset: () => setValues(initialValues),
  };
}

Here is the test:

import { renderHook, act } from '@testing-library/react-hooks';

import { useForm } from './useForm';

test('should render useForm hook', () => {
  const { result } = renderHook(() =>
    useForm({
      text: 'Note One',
    }),
  );

  expect(result.current).toBeDefined();
  expect(result.current.values.text).toBe('Note One');

  act(() => {
    result.current.handleChange({
      target: { //complains here - Type '{ name: string; value: string; }' is not assignable to type 'EventTarget & (HTMLTextAreaElement | HTMLInputElement)'.
        name: 'text',
        value: 'Note Two',
      },
    });
  });

  expect(result.current.values.text).toBe('Note Two');

  act(() => {
    result.current.reset();
  });
  expect(result.current.values.text).toBe('Note One');
});

Here is a working code sandbox: https://codesandbox.io/s/flamboyant-curie-6i5moy?file=/src/useForm.test.tsx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

伤痕我心 2025-01-17 23:15:29

我将使用 change 事件>Event() 构造函数。并使用 Object.defineProperty(event, 'target', {value: {}, writable: false}) 设置此事件的事件目标,另请参阅此 答案。然后使用类型转换事件作为未知作为React.ChangeEvent转换事件。

例如

import "@testing-library/react-hooks/lib/dom/pure";
import { renderHook, act } from "@testing-library/react-hooks";

import { useForm } from "./useForm";

test("should render useForm hook", () => {
  const { result } = renderHook(() =>
    useForm({
      text: "Note One"
    })
  );

  expect(result.current).toBeDefined();
  expect(result.current.values.text).toBe("Note One");

  const event = new Event("change");
  Object.defineProperty(event, "target", {
    value: {
      name: "text",
      value: "Note Two"
    },
    writable: false
  });

  act(() => {
    result.current.handleChange(event as unknown as React.ChangeEvent<HTMLInputElement>);
  });

  expect(result.current.values.text).toBe("Note Two");

  act(() => {
    result.current.reset();
  });
  expect(result.current.values.text).toBe("Note One");
});

I will create a change event by using Event() constructor. And set the event target for this event by using Object.defineProperty(event, 'target', {value: {}, writable: false}), also see this answer. Then use type casting event as unknown as React.ChangeEvent<HTMLInputElement> cast the event.

E.g.

import "@testing-library/react-hooks/lib/dom/pure";
import { renderHook, act } from "@testing-library/react-hooks";

import { useForm } from "./useForm";

test("should render useForm hook", () => {
  const { result } = renderHook(() =>
    useForm({
      text: "Note One"
    })
  );

  expect(result.current).toBeDefined();
  expect(result.current.values.text).toBe("Note One");

  const event = new Event("change");
  Object.defineProperty(event, "target", {
    value: {
      name: "text",
      value: "Note Two"
    },
    writable: false
  });

  act(() => {
    result.current.handleChange(event as unknown as React.ChangeEvent<HTMLInputElement>);
  });

  expect(result.current.values.text).toBe("Note Two");

  act(() => {
    result.current.reset();
  });
  expect(result.current.values.text).toBe("Note One");
});
活雷疯 2025-01-17 23:15:29

你可以简单地投射它:

 act(() => {
   result.current.handleChange({
     target: {
       name: 'text',
       value: 'Note Two',
     },
   }) as React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>;
 });

You can simply cast it:

 act(() => {
   result.current.handleChange({
     target: {
       name: 'text',
       value: 'Note Two',
     },
   }) as React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>;
 });
阳光①夏 2025-01-17 23:15:29

我遇到了同样的问题,这就是解决方法。

// Create a mock type for the changeEvent
type MockFormEvent = ChangeEvent<HTMLInputElement | HTMLTextAreaElement>

  act(() => { result.current.handleChange({
  target: { 
    name: 'text',
    value: 'Note Two',
  }
 } as MockFormEvent);
});

这为我解决了这个问题。

I got into this same problem this was the fix.

// Create a mock type for the changeEvent
type MockFormEvent = ChangeEvent<HTMLInputElement | HTMLTextAreaElement>

  act(() => { result.current.handleChange({
  target: { 
    name: 'text',
    value: 'Note Two',
  }
 } as MockFormEvent);
});

This fixed it for me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文