test: enable vitest async leak detection

Co-authored-by: hyoban <38493346+hyoban@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-18 09:36:56 +00:00
parent 7dac2f0d82
commit 3a64db3d60
4 changed files with 27 additions and 23 deletions

View File

@ -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 ? <div aria-label="Secret key modal" role="dialog" /> : 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(<DevelopMain appId="app-1" />)
// 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()
})
})

View File

@ -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 => ({
app: {
id: overrides.app?.id ?? 'app-id',

View File

@ -84,6 +84,7 @@ export default defineConfig(({ mode }) => {
// Vitest config
test: {
detectAsyncLeaks: true,
environment: 'jsdom',
globals: true,
setupFiles: ['./vitest.setup.ts'],

View File

@ -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<void>(resolve => setTimeout(resolve, 0))
})
// mock foxact/use-clipboard - not available in test environment