Skip to content

Commit

Permalink
🐛 fix: fix form input in provider (lobehub#5571)
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx authored Jan 24, 2025
1 parent 2734cf3 commit 07e2396
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@
"@semantic-release/exec": "^6.0.3",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.6.1",
"@types/chroma-js": "^3.1.0",
"@types/crypto-js": "^4.2.2",
"@types/debug": "^4.1.12",
Expand Down
70 changes: 70 additions & 0 deletions src/components/FormInput/FormInput.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { beforeEach, describe, expect, test, vi } from 'vitest';

import FormInput from './FormInput';

describe('FormInput', () => {
const user = userEvent.setup();
const onChangeMock = vi.fn();

beforeEach(() => {
onChangeMock.mockClear();
});

test('正确渲染初始值', () => {
render(<FormInput value="initial value" />);
const input = screen.getByRole('textbox');
expect(input).toHaveValue('initial value');
});

test('输入值并在失焦时触发 onChange', async () => {
render(<FormInput onChange={onChangeMock} />);
const input = screen.getByRole('textbox');

await user.type(input, 'new value');
expect(input).toHaveValue('new value');
expect(onChangeMock).not.toHaveBeenCalled();

fireEvent.blur(input);
expect(onChangeMock).toHaveBeenCalledWith('new value');
});

test('按下 Enter 触发 onChange', async () => {
render(<FormInput onChange={onChangeMock} />);
const input = screen.getByRole('textbox');

await user.type(input, 'test{enter}');
expect(onChangeMock).toHaveBeenCalledWith('test');
});

test('中文输入时按下 Enter 不触发 onChange', async () => {
render(<FormInput onChange={onChangeMock} />);
const input = screen.getByRole('textbox');

// 模拟中文输入法开始
fireEvent.compositionStart(input);
await user.type(input, 'nihao');
await user.type(input, '{enter}');

// 中文输入法结束前按 Enter 不应触发
expect(onChangeMock).not.toHaveBeenCalled();

// 结束中文输入
fireEvent.compositionEnd(input);
await user.type(input, '{enter}');
expect(onChangeMock).toHaveBeenCalledWith('nihao');
});

test('defaultValue 更新时同步显示新值', async () => {
const { rerender } = render(<FormInput value="old value" />);

// 初始值
const input = screen.getByRole('textbox');
expect(input).toHaveValue('old value');

// 更新值并重新渲染
rerender(<FormInput value="new value" />);
expect(input).toHaveValue('new value');
});
});
6 changes: 5 additions & 1 deletion src/components/FormInput/FormInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Input } from 'antd';
import { InputRef, InputProps as Props } from 'antd/es/input/Input';
import { memo, useRef, useState } from 'react';
import { memo, useEffect, useRef, useState } from 'react';

interface FormInputProps extends Omit<Props, 'onChange'> {
onChange?: (value: string) => void;
Expand All @@ -12,6 +12,10 @@ const FormInput = memo<FormInputProps>(({ onChange, value: defaultValue, ...prop

const [value, setValue] = useState(defaultValue as string);

useEffect(() => {
setValue(defaultValue as string);
}, [defaultValue]);

return (
<Input
onBlur={() => {
Expand Down
6 changes: 5 additions & 1 deletion src/components/FormInput/FormPassword.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Input } from 'antd';
import { InputRef, InputProps as Props } from 'antd/es/input/Input';
import { memo, useRef, useState } from 'react';
import { memo, useEffect, useRef, useState } from 'react';

interface FormPasswordProps extends Omit<Props, 'onChange'> {
onChange?: (value: string) => void;
Expand All @@ -12,6 +12,10 @@ const FormPassword = memo<FormPasswordProps>(({ onChange, value: defaultValue, .

const [value, setValue] = useState(defaultValue as string);

useEffect(() => {
setValue(defaultValue as string);
}, [defaultValue]);

return (
<Input.Password
onBlur={() => {
Expand Down

0 comments on commit 07e2396

Please sign in to comment.