Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 52 additions & 38 deletions src/action-sheet/__tests__/ActionSheetMethod.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { describe, it, expect, afterEach } from '@test/utils';
import { describe, it, expect, afterEach, act } from '@test/utils';
import { show, close } from '../ActionSheetMethod';

describe('ActionSheetMethod', () => {
afterEach(() => {
afterEach(async () => {
// 清理每次测试后可能残留的 ActionSheet
close();
await act(async () => {
close();
});
});

describe('module exports', () => {
Expand All @@ -13,51 +15,63 @@ describe('ActionSheetMethod', () => {
expect(typeof close).toBe('function');
});

it('should be able to call show function', () => {
expect(() => {
show({
items: ['Item 1', 'Item 2'],
});
}).not.toThrow();
it('should be able to call show function', async () => {
await act(async () => {
expect(() => {
show({
items: ['Item 1', 'Item 2'],
});
}).not.toThrow();
});
});

it('should be able to call close function', () => {
expect(() => {
close();
}).not.toThrow();
it('should be able to call close function', async () => {
await act(async () => {
expect(() => {
close();
}).not.toThrow();
});
});

it('should handle show with empty config', () => {
expect(() => {
show({});
}).not.toThrow();
it('should handle show with empty config', async () => {
await act(async () => {
expect(() => {
show({});
}).not.toThrow();
});
});

it('should handle show with various config options', () => {
expect(() => {
show({
items: ['Test Item'],
theme: 'grid',
description: 'Test Description',
visible: true,
});
}).not.toThrow();
it('should handle show with various config options', async () => {
await act(async () => {
expect(() => {
show({
items: ['Test Item'],
theme: 'grid',
description: 'Test Description',
visible: true,
});
}).not.toThrow();
});
});

it('should handle multiple show calls', () => {
expect(() => {
show({ items: ['Item 1'] });
show({ items: ['Item 2'] });
}).not.toThrow();
it('should handle multiple show calls', async () => {
await act(async () => {
expect(() => {
show({ items: ['Item 1'] });
show({ items: ['Item 2'] });
}).not.toThrow();
});
});

it('should handle show and close sequence', () => {
expect(() => {
show({ items: ['Item 1'] });
close();
show({ items: ['Item 2'] });
close();
}).not.toThrow();
it('should handle show and close sequence', async () => {
await act(async () => {
expect(() => {
show({ items: ['Item 1'] });
close();
show({ items: ['Item 2'] });
close();
}).not.toThrow();
});
});
});
});
10 changes: 7 additions & 3 deletions src/collapse/__tests__/collapse.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { describe, expect, it, render, fireEvent, vi, beforeEach, afterEach, waitFor } from '@test/utils';
import { describe, expect, it, render, fireEvent, vi, beforeEach, afterEach, waitFor, act } from '@test/utils';
import { Collapse, CollapsePanel } from 'tdesign-mobile-react';

describe('Collapse', () => {
Expand Down Expand Up @@ -426,7 +426,9 @@ describe('Collapse', () => {
fireEvent.click(panels[1]);

// 此时应该有一次debounced调用
vi.advanceTimersByTime(150);
act(() => {
vi.advanceTimersByTime(150);
});

// 验证最终状态
expect(onChange).toHaveBeenCalled();
Expand All @@ -452,7 +454,9 @@ describe('Collapse', () => {
fireEvent.click(panels[0]);

// 等待debounce
vi.advanceTimersByTime(150);
act(() => {
vi.advanceTimersByTime(150);
});

// 验证行为
expect(onChange).toHaveBeenCalled();
Expand Down
22 changes: 12 additions & 10 deletions src/dialog/__tests__/dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,14 @@ describe('Dialog', () => {
onClosed,
});
});
instance.hide();

setTimeout(() => {
expect(document.querySelector(name)).toBeFalsy();
expect(onClosed).toHaveBeenCalled();
}, 1000);
await act(async () => {
instance.hide();
});
await act(async () => {
vi.advanceTimersByTime(1000);
});
expect(document.querySelector(name)).toBeFalsy();
expect(onClosed).toHaveBeenCalled();
});

it(': update', async () => {
Expand All @@ -218,10 +220,10 @@ describe('Dialog', () => {
onCancel: vi.fn(),
});
});
instance.update({ title: '新标题' });
setInterval(() => {
expect(document.querySelector(`${name}__header`).textContent).toBe('新标题');
}, 1000);
await act(async () => {
instance.update({ title: '新标题' });
});
expect(document.querySelector(`${name}__header`).textContent).toBe('新标题');
});

it(': destroy', async () => {
Expand Down
10 changes: 7 additions & 3 deletions src/form/__tests__/form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1690,15 +1690,17 @@ describe('Form 组件测试', () => {
expect(() => requestSubmit({} as any)).toThrow('target must be HTMLFormElement');
});

it('HTMLFormElement 正常工作', () => {
it('HTMLFormElement 正常工作', async () => {
const { container } = render(
<Form>
<FormItem name="test">
<Input />
</FormItem>
</Form>,
);
expect(() => requestSubmit(container.querySelector('form') as HTMLFormElement)).not.toThrow();
await act(async () => {
expect(() => requestSubmit(container.querySelector('form') as HTMLFormElement)).not.toThrow();
});
});
});

Expand Down Expand Up @@ -1804,7 +1806,7 @@ describe('Form 组件测试', () => {
expect((getByPlaceholderText('name') as HTMLInputElement).value).toBe('delayed');
});

it('taskQueue 延迟执行 - setFields/submit/reset/clearValidate/setValidateMessage', () => {
it('taskQueue 延迟执行 - setFields/submit/reset/clearValidate/setValidateMessage', async () => {
const submitFn = vi.fn();
const TestForm = () => {
const [form] = Form.useForm();
Expand Down Expand Up @@ -1832,6 +1834,7 @@ describe('Form 组件测试', () => {
};
render(<TestForm />);
// taskQueue 方法在 flashQueue 时执行,不崩溃即可
await mockDelay();
});
});

Expand Down Expand Up @@ -2490,6 +2493,7 @@ describe('Form 组件测试', () => {
);
// 无 onSubmit 时不崩溃
expect(() => fireEvent.click(getByText('submit'))).not.toThrow();
await mockDelay();
});

it('onReset 不传时 reset 正常工作', async () => {
Expand Down
42 changes: 31 additions & 11 deletions src/guide/__tests__/guide.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import Guide from '../Guide';
Expand Down Expand Up @@ -850,7 +850,9 @@ describe('Guide Component', () => {
render(<Guide steps={mockSteps} current={0} />);

// 快进定时器
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

const portal = document.querySelector('.t-portal-wrapper');
expect(portal).toBeInTheDocument();
Expand All @@ -863,11 +865,15 @@ describe('Guide Component', () => {

// 超时后应可见
vi.useFakeTimers();
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// 更改 current 触发可见性变化
rerender(<Guide steps={mockSteps} current={1} />);
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

const portal = document.querySelector('.t-portal-wrapper');
expect(portal).toBeInTheDocument();
Expand All @@ -889,7 +895,9 @@ describe('Guide Component', () => {
render(<Guide steps={stepsDialog} current={0} />);

// 快进定时器以触发 showDialogGuide(内部调用 scrollToParentVisibleArea)
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// 应调用 scrollToParentVisibleArea
const portal = document.querySelector('.t-portal-wrapper');
Expand All @@ -907,7 +915,9 @@ describe('Guide Component', () => {
expect(portal).toBeInTheDocument();

// 快进定时器触发 showGuide 内的 setTimeout
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// 超时后设置为可见
portal = document.querySelector('.t-portal-wrapper');
Expand All @@ -930,7 +940,9 @@ describe('Guide Component', () => {
render(<Guide steps={stepsWithCenter} current={0} />);

// 快进定时器以触发 setReferenceFullW(可能存在空元素)
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// setReferenceFullW 应优雅处理空元素
const portal = document.querySelector('.t-portal-wrapper');
Expand Down Expand Up @@ -1152,7 +1164,9 @@ describe('Guide Component', () => {
render(<Guide steps={stepsWithCustomHighlight} current={0} />);

// 快进定时器以触发 showPopoverGuide(其以 isReference=true 调用 setHighlightLayerPosition)
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// 组件应渲染自定义高亮
expect(screen.getByTestId('custom-highlight-ref')).toBeInTheDocument();
Expand Down Expand Up @@ -1204,7 +1218,9 @@ describe('Guide Component', () => {
render(<Guide steps={stepsWithCenter} current={0} />);

// 快进定时器以触发 showPopoverGuide
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// 气泡模式下居中应调用 setReferenceFullW
const portal = document.querySelector('.t-portal-wrapper');
Expand All @@ -1227,7 +1243,9 @@ describe('Guide Component', () => {
render(<Guide steps={stepsDialog} current={0} />);

// 快进定时器以触发 showDialogGuide
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// showDialogGuide 应无错执行
const portal = document.querySelector('.t-portal-wrapper');
Expand All @@ -1245,7 +1263,9 @@ describe('Guide Component', () => {
expect(portal).toBeInTheDocument();

// 快进定时器触发 setPopoverVisible(true)
vi.advanceTimersByTime(100);
act(() => {
vi.advanceTimersByTime(100);
});

// 现在气泡应可见
portal = document.querySelector('.t-portal-wrapper');
Expand Down
8 changes: 6 additions & 2 deletions src/message/__tests__/message.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,9 @@ describe('Message', () => {
expect(textEl).toMatchSnapshot();

// Fire transitionend -> snapshot reset state
textEl.dispatchEvent(new Event('transitionend'));
act(() => {
textEl.dispatchEvent(new Event('transitionend'));
});
expect(textEl).toMatchSnapshot();

// Next play after delay (playedCount > 0): snapshot styles applied
Expand All @@ -290,7 +292,9 @@ describe('Message', () => {
expect(textEl).toMatchSnapshot();

// Fire transitionend -> snapshot reset state
textEl.dispatchEvent(new Event('transitionend'));
act(() => {
textEl.dispatchEvent(new Event('transitionend'));
});
expect(textEl).toMatchSnapshot();

// Next play after delay (playedCount > 0): snapshot styles applied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ describe('PullDownRefresh', () => {
expect(container.querySelector(name)).toBeTruthy();
});

it(': maxBarHeight with string', () => {
it(': maxBarHeight with string', async () => {
const { container } = render(
<PullDownRefresh maxBarHeight="10rem">
<div>content</div>
Expand All @@ -177,6 +177,8 @@ describe('PullDownRefresh', () => {
const track = container.querySelector(`${name}__track`) as HTMLElement;

mockPullDown(track!, 60, 2, 0);
// 等待 doRefresh 内的异步状态更新在 act 中完成
await act(async () => {});

expect(track).toHaveStyle({ transform: 'translate3d(0, 50px, 0)' });
});
Expand Down Expand Up @@ -366,6 +368,8 @@ describe('PullDownRefresh', () => {

// absX = 0, absY = 60
mockPullDown(track!, 80, 4, 0);
// 等待 doRefresh 内的异步状态更新在 act 中完成
await act(async () => {});

expect(mockRefresh).toHaveBeenCalled();
});
Expand Down
Loading
Loading