mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
test(web): add and enhance frontend automated tests across multiple modules (#32268)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
This commit is contained in:
@ -60,5 +60,11 @@ describe('Category', () => {
|
||||
const allCategoriesItem = screen.getByText('explore.apps.allCategories')
|
||||
expect(allCategoriesItem.className).toContain('bg-components-main-nav-nav-button-bg-active')
|
||||
})
|
||||
|
||||
it('should render raw category name when i18n key does not exist', () => {
|
||||
renderComponent({ list: ['CustomCategory', 'Recommended'] as AppCategory[] })
|
||||
|
||||
expect(screen.getByText('CustomCategory')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Mock } from 'vitest'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import type { CurrentTryAppParams } from '@/context/explore-context'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import ExploreContext from '@/context/explore-context'
|
||||
@ -55,9 +56,21 @@ vi.mock('@/hooks/use-document-title', () => ({
|
||||
default: vi.fn(),
|
||||
}))
|
||||
|
||||
const ContextReader = () => {
|
||||
const { hasEditPermission } = useContext(ExploreContext)
|
||||
return <div>{hasEditPermission ? 'edit-yes' : 'edit-no'}</div>
|
||||
const ContextReader = ({ triggerTryPanel }: { triggerTryPanel?: boolean }) => {
|
||||
const { hasEditPermission, setShowTryAppPanel, isShowTryAppPanel, currentApp } = useContext(ExploreContext)
|
||||
return (
|
||||
<div>
|
||||
{hasEditPermission ? 'edit-yes' : 'edit-no'}
|
||||
{isShowTryAppPanel && <span data-testid="try-panel-open">open</span>}
|
||||
{currentApp && <span data-testid="current-app">{currentApp.appId}</span>}
|
||||
{triggerTryPanel && (
|
||||
<>
|
||||
<button data-testid="show-try" onClick={() => setShowTryAppPanel(true, { appId: 'test-app' } as CurrentTryAppParams)}>show</button>
|
||||
<button data-testid="hide-try" onClick={() => setShowTryAppPanel(false)}>hide</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
describe('Explore', () => {
|
||||
@ -123,5 +136,69 @@ describe('Explore', () => {
|
||||
expect(mockReplace).toHaveBeenCalledWith('/datasets')
|
||||
})
|
||||
})
|
||||
|
||||
it('should skip permission check when membersData has no accounts', () => {
|
||||
; (useAppContext as Mock).mockReturnValue({
|
||||
userProfile: { id: 'user-1' },
|
||||
isCurrentWorkspaceDatasetOperator: false,
|
||||
});
|
||||
(useMembers as Mock).mockReturnValue({ data: undefined })
|
||||
|
||||
render((
|
||||
<Explore>
|
||||
<ContextReader />
|
||||
</Explore>
|
||||
))
|
||||
|
||||
expect(screen.getByText('edit-no')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Context: setShowTryAppPanel', () => {
|
||||
it('should set currentApp params when showing try panel', async () => {
|
||||
; (useAppContext as Mock).mockReturnValue({
|
||||
userProfile: { id: 'user-1' },
|
||||
isCurrentWorkspaceDatasetOperator: false,
|
||||
});
|
||||
(useMembers as Mock).mockReturnValue({ data: { accounts: [] } })
|
||||
|
||||
render((
|
||||
<Explore>
|
||||
<ContextReader triggerTryPanel />
|
||||
</Explore>
|
||||
))
|
||||
|
||||
fireEvent.click(screen.getByTestId('show-try'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('try-panel-open')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('current-app')).toHaveTextContent('test-app')
|
||||
})
|
||||
})
|
||||
|
||||
it('should clear currentApp params when hiding try panel', async () => {
|
||||
; (useAppContext as Mock).mockReturnValue({
|
||||
userProfile: { id: 'user-1' },
|
||||
isCurrentWorkspaceDatasetOperator: false,
|
||||
});
|
||||
(useMembers as Mock).mockReturnValue({ data: { accounts: [] } })
|
||||
|
||||
render((
|
||||
<Explore>
|
||||
<ContextReader triggerTryPanel />
|
||||
</Explore>
|
||||
))
|
||||
|
||||
fireEvent.click(screen.getByTestId('show-try'))
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('try-panel-open')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByTestId('hide-try'))
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('try-panel-open')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('current-app')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -2,6 +2,7 @@ import type { AppCardProps } from '../index'
|
||||
import type { App } from '@/models/explore'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import ExploreContext from '@/context/explore-context'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import AppCard from '../index'
|
||||
|
||||
@ -136,5 +137,32 @@ describe('AppCard', () => {
|
||||
|
||||
expect(screen.getByText('Sample App')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should call setShowTryAppPanel when try button is clicked', () => {
|
||||
const mockSetShowTryAppPanel = vi.fn()
|
||||
const app = createApp()
|
||||
|
||||
render(
|
||||
<ExploreContext.Provider
|
||||
value={{
|
||||
controlUpdateInstalledApps: 0,
|
||||
setControlUpdateInstalledApps: vi.fn(),
|
||||
hasEditPermission: false,
|
||||
installedApps: [],
|
||||
setInstalledApps: vi.fn(),
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: vi.fn(),
|
||||
isShowTryAppPanel: false,
|
||||
setShowTryAppPanel: mockSetShowTryAppPanel,
|
||||
}}
|
||||
>
|
||||
<AppCard app={app} canCreate={true} onCreate={vi.fn()} isExplore={true} />
|
||||
</ExploreContext.Provider>,
|
||||
)
|
||||
|
||||
fireEvent.click(screen.getByText('explore.appCard.try'))
|
||||
|
||||
expect(mockSetShowTryAppPanel).toHaveBeenCalledWith(true, { appId: 'app-id', app })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,44 +1,21 @@
|
||||
import type { Mock } from 'vitest'
|
||||
import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
|
||||
import type { CurrentTryAppParams } from '@/context/explore-context'
|
||||
import type { App } from '@/models/explore'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
|
||||
import ExploreContext from '@/context/explore-context'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import { fetchAppDetail } from '@/service/explore'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import AppList from '../index'
|
||||
|
||||
const allCategoriesEn = 'explore.apps.allCategories:{"lng":"en"}'
|
||||
let mockTabValue = allCategoriesEn
|
||||
const mockSetTab = vi.fn()
|
||||
let mockExploreData: { categories: string[], allList: App[] } | undefined = { categories: [], allList: [] }
|
||||
let mockIsLoading = false
|
||||
let mockIsError = false
|
||||
const mockHandleImportDSL = vi.fn()
|
||||
const mockHandleImportDSLConfirm = vi.fn()
|
||||
|
||||
vi.mock('nuqs', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('nuqs')>()
|
||||
return {
|
||||
...actual,
|
||||
useQueryState: () => [mockTabValue, mockSetTab],
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('ahooks', async () => {
|
||||
const actual = await vi.importActual<typeof import('ahooks')>('ahooks')
|
||||
const React = await vi.importActual<typeof import('react')>('react')
|
||||
return {
|
||||
...actual,
|
||||
useDebounceFn: (fn: (...args: unknown[]) => void) => {
|
||||
const fnRef = React.useRef(fn)
|
||||
fnRef.current = fn
|
||||
return {
|
||||
run: () => setTimeout(() => fnRef.current(), 0),
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/service/use-explore', () => ({
|
||||
useExploreAppList: () => ({
|
||||
data: mockExploreData,
|
||||
@ -85,6 +62,19 @@ vi.mock('@/app/components/explore/create-app-modal', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('../../try-app', () => ({
|
||||
default: ({ onCreate, onClose }: { onCreate: () => void, onClose: () => void }) => (
|
||||
<div data-testid="try-app-panel">
|
||||
<button data-testid="try-app-create" onClick={onCreate}>create</button>
|
||||
<button data-testid="try-app-close" onClick={onClose}>close</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('../../banner/banner', () => ({
|
||||
default: () => <div data-testid="explore-banner">banner</div>,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/app/create-from-dsl-modal/dsl-confirm-modal', () => ({
|
||||
default: ({ onConfirm, onCancel }: { onConfirm: () => void, onCancel: () => void }) => (
|
||||
<div data-testid="dsl-confirm-modal">
|
||||
@ -121,35 +111,41 @@ const createApp = (overrides: Partial<App> = {}): App => ({
|
||||
is_agent: overrides.is_agent ?? false,
|
||||
})
|
||||
|
||||
const renderWithContext = (hasEditPermission = false, onSuccess?: () => void) => {
|
||||
const renderWithContext = (hasEditPermission = false, onSuccess?: () => void, searchParams?: Record<string, string>) => {
|
||||
return render(
|
||||
<ExploreContext.Provider
|
||||
value={{
|
||||
controlUpdateInstalledApps: 0,
|
||||
setControlUpdateInstalledApps: vi.fn(),
|
||||
hasEditPermission,
|
||||
installedApps: [],
|
||||
setInstalledApps: vi.fn(),
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: vi.fn(),
|
||||
isShowTryAppPanel: false,
|
||||
setShowTryAppPanel: vi.fn(),
|
||||
}}
|
||||
>
|
||||
<AppList onSuccess={onSuccess} />
|
||||
</ExploreContext.Provider>,
|
||||
<NuqsTestingAdapter searchParams={searchParams}>
|
||||
<ExploreContext.Provider
|
||||
value={{
|
||||
controlUpdateInstalledApps: 0,
|
||||
setControlUpdateInstalledApps: vi.fn(),
|
||||
hasEditPermission,
|
||||
installedApps: [],
|
||||
setInstalledApps: vi.fn(),
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: vi.fn(),
|
||||
isShowTryAppPanel: false,
|
||||
setShowTryAppPanel: vi.fn(),
|
||||
}}
|
||||
>
|
||||
<AppList onSuccess={onSuccess} />
|
||||
</ExploreContext.Provider>
|
||||
</NuqsTestingAdapter>,
|
||||
)
|
||||
}
|
||||
|
||||
describe('AppList', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.clearAllMocks()
|
||||
mockTabValue = allCategoriesEn
|
||||
mockExploreData = { categories: [], allList: [] }
|
||||
mockIsLoading = false
|
||||
mockIsError = false
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render loading when the query is loading', () => {
|
||||
mockExploreData = undefined
|
||||
@ -175,13 +171,12 @@ describe('AppList', () => {
|
||||
|
||||
describe('Props', () => {
|
||||
it('should filter apps by selected category', () => {
|
||||
mockTabValue = 'Writing'
|
||||
mockExploreData = {
|
||||
categories: ['Writing', 'Translate'],
|
||||
allList: [createApp(), createApp({ app_id: 'app-2', app: { ...createApp().app, name: 'Beta' }, category: 'Translate' })],
|
||||
}
|
||||
|
||||
renderWithContext()
|
||||
renderWithContext(false, undefined, { category: 'Writing' })
|
||||
|
||||
expect(screen.getByText('Alpha')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Beta')).not.toBeInTheDocument()
|
||||
@ -199,13 +194,16 @@ describe('AppList', () => {
|
||||
const input = screen.getByPlaceholderText('common.operation.search')
|
||||
fireEvent.change(input, { target: { value: 'gam' } })
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Alpha')).not.toBeInTheDocument()
|
||||
expect(screen.getByText('Gamma')).toBeInTheDocument()
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
})
|
||||
|
||||
expect(screen.queryByText('Alpha')).not.toBeInTheDocument()
|
||||
expect(screen.getByText('Gamma')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle create flow and confirm DSL when pending', async () => {
|
||||
vi.useRealTimers()
|
||||
const onSuccess = vi.fn()
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
@ -247,16 +245,241 @@ describe('AppList', () => {
|
||||
|
||||
const input = screen.getByPlaceholderText('common.operation.search')
|
||||
fireEvent.change(input, { target: { value: 'gam' } })
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Alpha')).not.toBeInTheDocument()
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
})
|
||||
expect(screen.queryByText('Alpha')).not.toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByTestId('input-clear'))
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
})
|
||||
|
||||
expect(screen.getByText('Alpha')).toBeInTheDocument()
|
||||
expect(screen.getByText('Gamma')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render nothing when isError is true', () => {
|
||||
mockIsError = true
|
||||
mockExploreData = undefined
|
||||
|
||||
const { container } = renderWithContext()
|
||||
|
||||
expect(container.innerHTML).toBe('')
|
||||
})
|
||||
|
||||
it('should render nothing when data is undefined', () => {
|
||||
mockExploreData = undefined
|
||||
|
||||
const { container } = renderWithContext()
|
||||
|
||||
expect(container.innerHTML).toBe('')
|
||||
})
|
||||
|
||||
it('should reset filter when reset button is clicked', async () => {
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp(), createApp({ app_id: 'app-2', app: { ...createApp().app, name: 'Gamma' } })],
|
||||
}
|
||||
renderWithContext()
|
||||
|
||||
const input = screen.getByPlaceholderText('common.operation.search')
|
||||
fireEvent.change(input, { target: { value: 'gam' } })
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(500)
|
||||
})
|
||||
expect(screen.queryByText('Alpha')).not.toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByText('explore.apps.resetFilter'))
|
||||
|
||||
expect(screen.getByText('Alpha')).toBeInTheDocument()
|
||||
expect(screen.getByText('Gamma')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should close create modal via hide button', async () => {
|
||||
vi.useRealTimers()
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
|
||||
renderWithContext(true)
|
||||
fireEvent.click(screen.getByText('explore.appCard.addToWorkspace'))
|
||||
expect(await screen.findByTestId('create-app-modal')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByTestId('hide-create'))
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('create-app-modal')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should close create modal on successful DSL import', async () => {
|
||||
vi.useRealTimers()
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => {
|
||||
options.onSuccess?.()
|
||||
})
|
||||
|
||||
renderWithContext(true)
|
||||
fireEvent.click(screen.getByText('explore.appCard.addToWorkspace'))
|
||||
fireEvent.click(await screen.findByTestId('confirm-create'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Alpha')).toBeInTheDocument()
|
||||
expect(screen.getByText('Gamma')).toBeInTheDocument()
|
||||
expect(screen.queryByTestId('create-app-modal')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should cancel DSL confirm modal', async () => {
|
||||
vi.useRealTimers()
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onPending?: () => void }) => {
|
||||
options.onPending?.()
|
||||
})
|
||||
|
||||
renderWithContext(true)
|
||||
fireEvent.click(screen.getByText('explore.appCard.addToWorkspace'))
|
||||
fireEvent.click(await screen.findByTestId('confirm-create'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('dsl-confirm-modal')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByTestId('dsl-cancel'))
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('dsl-confirm-modal')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('TryApp Panel', () => {
|
||||
it('should open create modal from try app panel', async () => {
|
||||
vi.useRealTimers()
|
||||
const mockSetShowTryAppPanel = vi.fn()
|
||||
const app = createApp()
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [app],
|
||||
}
|
||||
|
||||
render(
|
||||
<NuqsTestingAdapter>
|
||||
<ExploreContext.Provider
|
||||
value={{
|
||||
controlUpdateInstalledApps: 0,
|
||||
setControlUpdateInstalledApps: vi.fn(),
|
||||
hasEditPermission: true,
|
||||
installedApps: [],
|
||||
setInstalledApps: vi.fn(),
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: vi.fn(),
|
||||
isShowTryAppPanel: true,
|
||||
setShowTryAppPanel: mockSetShowTryAppPanel,
|
||||
currentApp: { appId: 'app-1', app },
|
||||
}}
|
||||
>
|
||||
<AppList />
|
||||
</ExploreContext.Provider>
|
||||
</NuqsTestingAdapter>,
|
||||
)
|
||||
|
||||
const createBtn = screen.getByTestId('try-app-create')
|
||||
fireEvent.click(createBtn)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('create-app-modal')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should open create modal with null currApp when appParams has no app', async () => {
|
||||
vi.useRealTimers()
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
}
|
||||
|
||||
render(
|
||||
<NuqsTestingAdapter>
|
||||
<ExploreContext.Provider
|
||||
value={{
|
||||
controlUpdateInstalledApps: 0,
|
||||
setControlUpdateInstalledApps: vi.fn(),
|
||||
hasEditPermission: true,
|
||||
installedApps: [],
|
||||
setInstalledApps: vi.fn(),
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: vi.fn(),
|
||||
isShowTryAppPanel: true,
|
||||
setShowTryAppPanel: vi.fn(),
|
||||
currentApp: { appId: 'app-1' } as CurrentTryAppParams,
|
||||
}}
|
||||
>
|
||||
<AppList />
|
||||
</ExploreContext.Provider>
|
||||
</NuqsTestingAdapter>,
|
||||
)
|
||||
|
||||
fireEvent.click(screen.getByTestId('try-app-create'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('create-app-modal')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should render try app panel with empty appId when currentApp is undefined', () => {
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
}
|
||||
|
||||
render(
|
||||
<NuqsTestingAdapter>
|
||||
<ExploreContext.Provider
|
||||
value={{
|
||||
controlUpdateInstalledApps: 0,
|
||||
setControlUpdateInstalledApps: vi.fn(),
|
||||
hasEditPermission: true,
|
||||
installedApps: [],
|
||||
setInstalledApps: vi.fn(),
|
||||
isFetchingInstalledApps: false,
|
||||
setIsFetchingInstalledApps: vi.fn(),
|
||||
isShowTryAppPanel: true,
|
||||
setShowTryAppPanel: vi.fn(),
|
||||
}}
|
||||
>
|
||||
<AppList />
|
||||
</ExploreContext.Provider>
|
||||
</NuqsTestingAdapter>,
|
||||
)
|
||||
|
||||
expect(screen.getByTestId('try-app-panel')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Banner', () => {
|
||||
it('should render banner when enable_explore_banner is true', () => {
|
||||
useGlobalPublicStore.setState({
|
||||
systemFeatures: {
|
||||
...useGlobalPublicStore.getState().systemFeatures,
|
||||
enable_explore_banner: true,
|
||||
},
|
||||
})
|
||||
mockExploreData = {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
}
|
||||
|
||||
renderWithContext()
|
||||
|
||||
expect(screen.getByTestId('explore-banner')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,6 +4,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import TryApp from '../index'
|
||||
import { TypeEnum } from '../tab'
|
||||
|
||||
// Suppress expected React act() warnings from internal async state updates
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
|
||||
vi.mock('@/config', async (importOriginal) => {
|
||||
const actual = await importOriginal() as object
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user