From 5f69470ebf966a781b43520c66980d092cf5c66b Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:05:15 +0800 Subject: [PATCH] test: try fix test, clear test log in CI (#31912) --- .../create/common-modal.spec.tsx | 3 ++ .../components/update-dsl-modal.spec.tsx | 54 ++++++++++++++----- web/package.json | 5 +- web/pnpm-lock.yaml | 26 +++++++++ web/vitest.config.ts | 2 +- web/vitest.setup.ts | 1 + 6 files changed, 75 insertions(+), 16 deletions(-) diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.spec.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.spec.tsx index b7e4f01f58..0c1b5efc29 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.spec.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.spec.tsx @@ -2031,6 +2031,9 @@ describe('CommonCreateModal', () => { expect(mockCreateBuilder).toHaveBeenCalled() }) + // Flush pending state updates from createBuilder promise resolution + await act(async () => {}) + const input = screen.getByTestId('form-field-webhook_url') fireEvent.change(input, { target: { value: 'test' } }) diff --git a/web/app/components/rag-pipeline/components/update-dsl-modal.spec.tsx b/web/app/components/rag-pipeline/components/update-dsl-modal.spec.tsx index f57bd80d7b..45eb1cafe1 100644 --- a/web/app/components/rag-pipeline/components/update-dsl-modal.spec.tsx +++ b/web/app/components/rag-pipeline/components/update-dsl-modal.spec.tsx @@ -613,6 +613,11 @@ describe('UpdateDSLModal', () => { expect(importButton).not.toBeDisabled() }) + // Flush the FileReader microtask to ensure fileContent is set + await act(async () => { + await new Promise(resolve => queueMicrotask(resolve)) + }) + const importButton = screen.getByText('common.overwriteAndImport') fireEvent.click(importButton) @@ -761,6 +766,8 @@ describe('UpdateDSLModal', () => { }) it('should call importDSLConfirm when confirm button is clicked in error modal', async () => { + vi.useFakeTimers({ shouldAdvanceTime: true }) + mockImportDSL.mockResolvedValue({ id: 'import-id', status: DSLImportStatus.PENDING, @@ -778,20 +785,27 @@ describe('UpdateDSLModal', () => { const fileInput = screen.getByTestId('file-input') const file = new File(['test content'], 'test.pipeline', { type: 'text/yaml' }) - fireEvent.change(fileInput, { target: { files: [file] } }) - await waitFor(() => { - const importButton = screen.getByText('common.overwriteAndImport') - expect(importButton).not.toBeDisabled() + await act(async () => { + fireEvent.change(fileInput, { target: { files: [file] } }) + // Flush microtasks scheduled by the FileReader mock (which uses queueMicrotask) + await new Promise(resolve => queueMicrotask(resolve)) }) const importButton = screen.getByText('common.overwriteAndImport') - fireEvent.click(importButton) + expect(importButton).not.toBeDisabled() + + await act(async () => { + fireEvent.click(importButton) + // Flush the promise resolution from mockImportDSL + await Promise.resolve() + // Advance past the 300ms setTimeout in the component + await vi.advanceTimersByTimeAsync(350) + }) - // Wait for error modal await waitFor(() => { expect(screen.getByText('newApp.appCreateDSLErrorTitle')).toBeInTheDocument() - }, { timeout: 500 }) + }) // Click confirm button const confirmButton = screen.getByText('newApp.Confirm') @@ -800,6 +814,8 @@ describe('UpdateDSLModal', () => { await waitFor(() => { expect(mockImportDSLConfirm).toHaveBeenCalledWith('import-id') }) + + vi.useRealTimers() }) it('should show success notification after confirm completes', async () => { @@ -1008,6 +1024,8 @@ describe('UpdateDSLModal', () => { }) it('should call handleCheckPluginDependencies after confirm', async () => { + vi.useFakeTimers({ shouldAdvanceTime: true }) + mockImportDSL.mockResolvedValue({ id: 'import-id', status: DSLImportStatus.PENDING, @@ -1025,19 +1043,27 @@ describe('UpdateDSLModal', () => { const fileInput = screen.getByTestId('file-input') const file = new File(['test content'], 'test.pipeline', { type: 'text/yaml' }) - fireEvent.change(fileInput, { target: { files: [file] } }) - await waitFor(() => { - const importButton = screen.getByText('common.overwriteAndImport') - expect(importButton).not.toBeDisabled() + await act(async () => { + fireEvent.change(fileInput, { target: { files: [file] } }) + // Flush microtasks scheduled by the FileReader mock (which uses queueMicrotask) + await new Promise(resolve => queueMicrotask(resolve)) }) const importButton = screen.getByText('common.overwriteAndImport') - fireEvent.click(importButton) + expect(importButton).not.toBeDisabled() + + await act(async () => { + fireEvent.click(importButton) + // Flush the promise resolution from mockImportDSL + await Promise.resolve() + // Advance past the 300ms setTimeout in the component + await vi.advanceTimersByTimeAsync(350) + }) await waitFor(() => { expect(screen.getByText('newApp.appCreateDSLErrorTitle')).toBeInTheDocument() - }, { timeout: 500 }) + }) const confirmButton = screen.getByText('newApp.Confirm') fireEvent.click(confirmButton) @@ -1045,6 +1071,8 @@ describe('UpdateDSLModal', () => { await waitFor(() => { expect(mockHandleCheckPluginDependencies).toHaveBeenCalledWith('test-pipeline-id', true) }) + + vi.useRealTimers() }) it('should handle undefined imported_dsl_version and current_dsl_version', async () => { diff --git a/web/package.json b/web/package.json index 7b2e570554..494a9f0848 100644 --- a/web/package.json +++ b/web/package.json @@ -46,7 +46,7 @@ "uglify-embed": "node ./bin/uglify-embed", "i18n:check": "tsx ./scripts/check-i18n.js", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage": "vitest run --coverage --reporter=dot --silent=passed-only", "test:watch": "vitest --watch", "analyze-component": "node ./scripts/analyze-component.js", "refactor-component": "node ./scripts/refactor-component.js", @@ -233,7 +233,8 @@ "uglify-js": "3.19.3", "vite": "7.3.1", "vite-tsconfig-paths": "6.0.4", - "vitest": "4.0.17" + "vitest": "4.0.17", + "vitest-canvas-mock": "1.1.3" }, "pnpm": { "overrides": { diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index abf3a444a2..9119d2554a 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -579,6 +579,9 @@ importers: vitest: specifier: 4.0.17 version: 4.0.17(@types/node@18.15.0)(@vitest/browser-playwright@4.0.17)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.1))(sass@1.93.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest-canvas-mock: + specifier: 1.1.3 + version: 1.1.3(vitest@4.0.17) packages: @@ -4002,6 +4005,9 @@ packages: engines: {node: '>=4'} hasBin: true + cssfontparser@1.2.1: + resolution: {integrity: sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==} + cssstyle@5.3.7: resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} engines: {node: '>=20'} @@ -5751,6 +5757,9 @@ packages: monaco-editor@0.55.1: resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + moo-color@1.0.3: + resolution: {integrity: sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -7216,6 +7225,11 @@ packages: yaml: optional: true + vitest-canvas-mock@1.1.3: + resolution: {integrity: sha512-zlKJR776Qgd+bcACPh0Pq5MG3xWq+CdkACKY/wX4Jyija0BSz8LH3aCCgwFKYFwtm565+050YFEGG9Ki0gE/Hw==} + peerDependencies: + vitest: ^3.0.0 || ^4.0.0 + vitest@4.0.17: resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -11274,6 +11288,8 @@ snapshots: cssesc@3.0.0: {} + cssfontparser@1.2.1: {} + cssstyle@5.3.7: dependencies: '@asamuzakjp/css-color': 4.1.1 @@ -13573,6 +13589,10 @@ snapshots: dompurify: 3.2.7 marked: 14.0.0 + moo-color@1.0.3: + dependencies: + color-name: 1.1.4 + mri@1.2.0: {} mrmime@2.0.1: {} @@ -15202,6 +15222,12 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 + vitest-canvas-mock@1.1.3(vitest@4.0.17): + dependencies: + cssfontparser: 1.2.1 + moo-color: 1.0.3 + vitest: 4.0.17(@types/node@18.15.0)(@vitest/browser-playwright@4.0.17)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.1))(sass@1.93.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest@4.0.17(@types/node@18.15.0)(@vitest/browser-playwright@4.0.17)(jiti@1.21.7)(jsdom@27.3.0(canvas@3.2.1))(sass@1.93.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.17 diff --git a/web/vitest.config.ts b/web/vitest.config.ts index c58a92f217..370bc74904 100644 --- a/web/vitest.config.ts +++ b/web/vitest.config.ts @@ -8,7 +8,7 @@ export default mergeConfig(viteConfig, defineConfig({ setupFiles: ['./vitest.setup.ts'], coverage: { provider: 'v8', - reporter: ['text', 'json', 'json-summary'], + reporter: ['json', 'json-summary'], }, }, })) diff --git a/web/vitest.setup.ts b/web/vitest.setup.ts index 0e1d9e6d10..9e54b80492 100644 --- a/web/vitest.setup.ts +++ b/web/vitest.setup.ts @@ -1,6 +1,7 @@ import { act, cleanup } from '@testing-library/react' import { mockAnimationsApi, mockResizeObserver } from 'jsdom-testing-mocks' import '@testing-library/jest-dom/vitest' +import 'vitest-canvas-mock' mockResizeObserver()