From b6566784928d0cfa8310dd3429bd7ba5a3289396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=8E=E4=BC=9F=E6=9D=B0?= <674416404@qq.com> Date: Tue, 29 Sep 2026 22:13:44 +0800 Subject: [PATCH] test: fix React act(...) warnings in unit tests --- .../__tests__/ActionSheetMethod.test.tsx | 90 +++++++++++-------- src/collapse/__tests__/collapse.test.tsx | 10 ++- src/dialog/__tests__/dialog.test.tsx | 22 ++--- src/form/__tests__/form.test.tsx | 10 ++- src/guide/__tests__/guide.test.tsx | 42 ++++++--- src/message/__tests__/message.test.tsx | 8 +- .../__tests__/pull-down-refresh.test.tsx | 6 +- src/qrcode/__tests__/qrcode.test.tsx | 6 +- 8 files changed, 124 insertions(+), 70 deletions(-) diff --git a/src/action-sheet/__tests__/ActionSheetMethod.test.tsx b/src/action-sheet/__tests__/ActionSheetMethod.test.tsx index ac8804cea..bd5440ac3 100644 --- a/src/action-sheet/__tests__/ActionSheetMethod.test.tsx +++ b/src/action-sheet/__tests__/ActionSheetMethod.test.tsx @@ -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', () => { @@ -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(); + }); }); }); }); diff --git a/src/collapse/__tests__/collapse.test.tsx b/src/collapse/__tests__/collapse.test.tsx index 3affc7df6..b18a47ee9 100644 --- a/src/collapse/__tests__/collapse.test.tsx +++ b/src/collapse/__tests__/collapse.test.tsx @@ -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', () => { @@ -426,7 +426,9 @@ describe('Collapse', () => { fireEvent.click(panels[1]); // 此时应该有一次debounced调用 - vi.advanceTimersByTime(150); + act(() => { + vi.advanceTimersByTime(150); + }); // 验证最终状态 expect(onChange).toHaveBeenCalled(); @@ -452,7 +454,9 @@ describe('Collapse', () => { fireEvent.click(panels[0]); // 等待debounce - vi.advanceTimersByTime(150); + act(() => { + vi.advanceTimersByTime(150); + }); // 验证行为 expect(onChange).toHaveBeenCalled(); diff --git a/src/dialog/__tests__/dialog.test.tsx b/src/dialog/__tests__/dialog.test.tsx index 1d6d5225f..509ad7aa0 100644 --- a/src/dialog/__tests__/dialog.test.tsx +++ b/src/dialog/__tests__/dialog.test.tsx @@ -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 () => { @@ -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 () => { diff --git a/src/form/__tests__/form.test.tsx b/src/form/__tests__/form.test.tsx index 52c17ac63..a89d7f1df 100644 --- a/src/form/__tests__/form.test.tsx +++ b/src/form/__tests__/form.test.tsx @@ -1690,7 +1690,7 @@ describe('Form 组件测试', () => { expect(() => requestSubmit({} as any)).toThrow('target must be HTMLFormElement'); }); - it('HTMLFormElement 正常工作', () => { + it('HTMLFormElement 正常工作', async () => { const { container } = render(
, ); - expect(() => requestSubmit(container.querySelector('form') as HTMLFormElement)).not.toThrow(); + await act(async () => { + expect(() => requestSubmit(container.querySelector('form') as HTMLFormElement)).not.toThrow(); + }); }); }); @@ -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(); @@ -1832,6 +1834,7 @@ describe('Form 组件测试', () => { }; render(