diff --git a/web/__tests__/develop/develop-page-flow.test.tsx b/web/__tests__/develop/develop-page-flow.test.tsx
index 703f7362f1..5fe78fb3a6 100644
--- a/web/__tests__/develop/develop-page-flow.test.tsx
+++ b/web/__tests__/develop/develop-page-flow.test.tsx
@@ -6,27 +6,12 @@
*
* Uses real DevelopMain, ApiServer, and Doc components with minimal mocks.
*/
-import { act, render, screen, waitFor } from '@testing-library/react'
+import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { beforeEach, describe, expect, it, vi } from 'vitest'
import DevelopMain from '@/app/components/develop'
import { AppModeEnum, Theme } from '@/types/app'
-beforeEach(() => {
- vi.useFakeTimers({ shouldAdvanceTime: true })
-})
-
-afterEach(() => {
- vi.runOnlyPendingTimers()
- vi.useRealTimers()
-})
-
-async function flushUI() {
- await act(async () => {
- vi.runAllTimers()
- })
-}
-
let storeAppDetail: unknown
vi.mock('@/app/components/app/store', () => ({
@@ -85,6 +70,10 @@ vi.mock('@/service/knowledge/use-dataset', () => ({
useInvalidateDatasetApiKeys: () => vi.fn(),
}))
+vi.mock('@/app/components/develop/secret-key/secret-key-modal', () => ({
+ default: ({ isShow }: { isShow: boolean }) => (isShow ?
: null),
+}))
+
// ---------- tests ----------
describe('DevelopMain page flow', () => {
@@ -159,7 +148,7 @@ describe('DevelopMain page flow', () => {
})
it('should open API key modal from the page', async () => {
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime })
+ const user = userEvent.setup()
storeAppDetail = {
id: 'app-1',
@@ -171,14 +160,11 @@ describe('DevelopMain page flow', () => {
render()
// Click API Key button in the header
- await act(async () => {
- await user.click(screen.getByText('appApi.apiKey'))
- })
- await flushUI()
+ await user.click(screen.getByText('appApi.apiKey'))
// SecretKeyModal should open
await waitFor(() => {
- expect(screen.getByText('appApi.apiKeyModal.apiSecretKey')).toBeInTheDocument()
+ expect(screen.getByRole('dialog', { name: 'Secret key modal' })).toBeInTheDocument()
})
})
diff --git a/web/__tests__/explore/explore-app-list-flow.test.tsx b/web/__tests__/explore/explore-app-list-flow.test.tsx
index 40f2156c06..accdb6014c 100644
--- a/web/__tests__/explore/explore-app-list-flow.test.tsx
+++ b/web/__tests__/explore/explore-app-list-flow.test.tsx
@@ -62,6 +62,15 @@ vi.mock('@/context/app-context', () => ({
useAppContext: vi.fn(),
}))
+vi.mock('@/context/global-public-context', () => ({
+ useGlobalPublicStore: () => ({
+ systemFeatures: {
+ enable_explore_banner: false,
+ enable_trial_app: false,
+ },
+ }),
+}))
+
vi.mock('@/service/use-common', () => ({
useMembers: vi.fn(),
}))
@@ -108,6 +117,10 @@ vi.mock('@/app/components/app/create-from-dsl-modal/dsl-confirm-modal', () => ({
),
}))
+vi.mock('@/app/components/explore/try-app', () => ({
+ default: () => null,
+}))
+
const createApp = (overrides: Partial = {}): App => ({
app: {
id: overrides.app?.id ?? 'app-id',
diff --git a/web/vite.config.ts b/web/vite.config.ts
index de74154651..12eca33cda 100644
--- a/web/vite.config.ts
+++ b/web/vite.config.ts
@@ -84,6 +84,7 @@ export default defineConfig(({ mode }) => {
// Vitest config
test: {
+ detectAsyncLeaks: true,
environment: 'jsdom',
globals: true,
setupFiles: ['./vitest.setup.ts'],
diff --git a/web/vitest.setup.ts b/web/vitest.setup.ts
index e63ea2b54e..46ec7e5b4b 100644
--- a/web/vitest.setup.ts
+++ b/web/vitest.setup.ts
@@ -98,6 +98,10 @@ afterEach(async () => {
await act(async () => {
cleanup()
})
+
+ // Give Headless UI transition scheduler tasks one event-loop turn to settle
+ // so detectAsyncLeaks does not report teardown false positives.
+ await new Promise(resolve => setTimeout(resolve, 0))
})
// mock foxact/use-clipboard - not available in test environment