From c52f18f205796faef113a3ff4abe3af77904ef8b Mon Sep 17 00:00:00 2001
From: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Date: Wed, 1 Apr 2026 11:18:32 +0800
Subject: [PATCH] suppress all and fix typecheck
---
web/app/components/base/markdown/index.tsx | 2 +-
.../card/__tests__/card-more-info.spec.tsx | 50 -------
.../marketplace/__tests__/atoms.spec.tsx | 50 +++----
.../__tests__/hooks-integration.spec.tsx | 4 +-
.../marketplace/__tests__/hooks.spec.tsx | 12 +-
.../marketplace/__tests__/index.spec.tsx | 77 ++++++----
.../__tests__/plugin-type-switch.spec.tsx | 22 +--
.../marketplace/__tests__/state.spec.tsx | 34 ++---
.../sticky-search-and-switch-wrapper.spec.tsx | 87 ------------
.../marketplace/__tests__/utils.spec.ts | 64 +++++----
.../plugins/marketplace/hydration-server.tsx | 1 -
.../marketplace/list/__tests__/index.spec.tsx | 6 +-
.../search-box/__tests__/index.spec.tsx | 6 +-
.../plugins/marketplace/search-params.ts | 1 -
.../components/plugins/plugin-page/index.tsx | 3 +-
.../tools/marketplace/__tests__/hooks.spec.ts | 4 +-
.../marketplace/__tests__/index.spec.tsx | 14 +-
web/eslint-suppressions.json | 134 +++++++++++++++++-
18 files changed, 289 insertions(+), 282 deletions(-)
delete mode 100644 web/app/components/plugins/card/__tests__/card-more-info.spec.tsx
delete mode 100644 web/app/components/plugins/marketplace/__tests__/sticky-search-and-switch-wrapper.spec.tsx
diff --git a/web/app/components/base/markdown/index.tsx b/web/app/components/base/markdown/index.tsx
index 8a340963ab5..5915816d7ac 100644
--- a/web/app/components/base/markdown/index.tsx
+++ b/web/app/components/base/markdown/index.tsx
@@ -45,7 +45,7 @@ export const Markdown = memo((props: MarkdownProps) => {
({
- default: ({ downloadCount }: { downloadCount: number }) => (
- {downloadCount}
- ),
-}))
-
-describe('CardMoreInfo', () => {
- it('renders tags with # prefix', () => {
- render()
- expect(screen.getByText('search')).toBeInTheDocument()
- expect(screen.getByText('agent')).toBeInTheDocument()
- // # prefixes
- const hashmarks = screen.getAllByText('#')
- expect(hashmarks).toHaveLength(2)
- })
-
- it('renders download count when provided', () => {
- render()
- expect(screen.getByTestId('download-count')).toHaveTextContent('1000')
- })
-
- it('does not render download count when undefined', () => {
- render()
- expect(screen.queryByTestId('download-count')).not.toBeInTheDocument()
- })
-
- it('renders separator between download count and tags', () => {
- render()
- expect(screen.getByText('·')).toBeInTheDocument()
- })
-
- it('does not render separator when no tags', () => {
- render()
- expect(screen.queryByText('·')).not.toBeInTheDocument()
- })
-
- it('does not render separator when no download count', () => {
- render()
- expect(screen.queryByText('·')).not.toBeInTheDocument()
- })
-
- it('handles empty tags array', () => {
- const { container } = render()
- expect(container.firstChild).toBeInTheDocument()
- })
-})
diff --git a/web/app/components/plugins/marketplace/__tests__/atoms.spec.tsx b/web/app/components/plugins/marketplace/__tests__/atoms.spec.tsx
index 0a532f537dd..16cb6aef565 100644
--- a/web/app/components/plugins/marketplace/__tests__/atoms.spec.tsx
+++ b/web/app/components/plugins/marketplace/__tests__/atoms.spec.tsx
@@ -4,16 +4,16 @@ import { Provider as JotaiProvider } from 'jotai'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createNuqsTestWrapper } from '@/test/nuqs-testing'
import {
- useActivePluginType,
+ useActivePluginCategory,
useFilterPluginTags,
useMarketplaceMoreClick,
+ useMarketplacePluginSort,
+ useMarketplacePluginSortValue,
useMarketplaceSearchMode,
- useMarketplaceSort,
- useMarketplaceSortValue,
- useSearchPluginText,
- useSetMarketplaceSort,
+ useSearchText,
+ useSetMarketplacePluginSort,
} from '../atoms'
-import { DEFAULT_SORT } from '../constants'
+import { DEFAULT_PLUGIN_SORT } from '../constants'
const createWrapper = (searchParams = '') => {
const { wrapper: NuqsWrapper } = createNuqsTestWrapper({ searchParams })
@@ -34,24 +34,24 @@ describe('Marketplace sort atoms', () => {
it('should return default sort value from useMarketplaceSort', () => {
const { wrapper } = createWrapper()
- const { result } = renderHook(() => useMarketplaceSort(), { wrapper })
+ const { result } = renderHook(() => useMarketplacePluginSort(), { wrapper })
- expect(result.current[0]).toEqual(DEFAULT_SORT)
+ expect(result.current[0]).toEqual(DEFAULT_PLUGIN_SORT)
expect(typeof result.current[1]).toBe('function')
})
it('should return default sort value from useMarketplaceSortValue', () => {
const { wrapper } = createWrapper()
- const { result } = renderHook(() => useMarketplaceSortValue(), { wrapper })
+ const { result } = renderHook(() => useMarketplacePluginSortValue(), { wrapper })
- expect(result.current).toEqual(DEFAULT_SORT)
+ expect(result.current).toEqual(DEFAULT_PLUGIN_SORT)
})
it('should return setter from useSetMarketplaceSort', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => ({
- setSort: useSetMarketplaceSort(),
- sortValue: useMarketplaceSortValue(),
+ setSort: useSetMarketplacePluginSort(),
+ sortValue: useMarketplacePluginSortValue(),
}), { wrapper })
act(() => {
@@ -63,7 +63,7 @@ describe('Marketplace sort atoms', () => {
it('should update sort value via useMarketplaceSort setter', () => {
const { wrapper } = createWrapper()
- const { result } = renderHook(() => useMarketplaceSort(), { wrapper })
+ const { result } = renderHook(() => useMarketplacePluginSort(), { wrapper })
act(() => {
result.current[1]({ sortBy: 'created_at', sortOrder: 'ASC' })
@@ -73,14 +73,14 @@ describe('Marketplace sort atoms', () => {
})
})
-describe('useSearchPluginText', () => {
+describe('useSearchText', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should return empty string as default', () => {
const { wrapper } = createWrapper()
- const { result } = renderHook(() => useSearchPluginText(), { wrapper })
+ const { result } = renderHook(() => useSearchText(), { wrapper })
expect(result.current[0]).toBe('')
expect(typeof result.current[1]).toBe('function')
@@ -88,14 +88,14 @@ describe('useSearchPluginText', () => {
it('should parse q from search params', () => {
const { wrapper } = createWrapper('?q=hello')
- const { result } = renderHook(() => useSearchPluginText(), { wrapper })
+ const { result } = renderHook(() => useSearchText(), { wrapper })
expect(result.current[0]).toBe('hello')
})
it('should expose a setter function for search text', async () => {
const { wrapper } = createWrapper()
- const { result } = renderHook(() => useSearchPluginText(), { wrapper })
+ const { result } = renderHook(() => useSearchText(), { wrapper })
await act(async () => {
result.current[1]('search term')
@@ -105,21 +105,21 @@ describe('useSearchPluginText', () => {
})
})
-describe('useActivePluginType', () => {
+describe('useActivePluginCategory', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should return "all" as default category', () => {
const { wrapper } = createWrapper()
- const { result } = renderHook(() => useActivePluginType(), { wrapper })
+ const { result } = renderHook(() => useActivePluginCategory(), { wrapper })
expect(result.current[0]).toBe('all')
})
it('should parse category from search params', () => {
const { wrapper } = createWrapper('?category=tool')
- const { result } = renderHook(() => useActivePluginType(), { wrapper })
+ const { result } = renderHook(() => useActivePluginCategory(), { wrapper })
expect(result.current[0]).toBe('tool')
})
@@ -202,8 +202,8 @@ describe('useMarketplaceMoreClick', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => ({
handleMoreClick: useMarketplaceMoreClick(),
- sort: useMarketplaceSortValue(),
- searchText: useSearchPluginText()[0],
+ sort: useMarketplacePluginSortValue(),
+ searchText: useSearchText()[0],
}), { wrapper })
const sortBefore = result.current.sort
@@ -222,7 +222,7 @@ describe('useMarketplaceMoreClick', () => {
const { result } = renderHook(() => ({
handleMoreClick: useMarketplaceMoreClick(),
- sort: useMarketplaceSortValue(),
+ sort: useMarketplacePluginSortValue(),
}), { wrapper })
act(() => {
@@ -240,13 +240,13 @@ describe('useMarketplaceMoreClick', () => {
const { wrapper } = createWrapper()
const { result } = renderHook(() => ({
handleMoreClick: useMarketplaceMoreClick(),
- sort: useMarketplaceSortValue(),
+ sort: useMarketplacePluginSortValue(),
}), { wrapper })
act(() => {
result.current.handleMoreClick({})
})
- expect(result.current.sort).toEqual(DEFAULT_SORT)
+ expect(result.current.sort).toEqual(DEFAULT_PLUGIN_SORT)
})
})
diff --git a/web/app/components/plugins/marketplace/__tests__/hooks-integration.spec.tsx b/web/app/components/plugins/marketplace/__tests__/hooks-integration.spec.tsx
index ac583d66c56..e7655877a4d 100644
--- a/web/app/components/plugins/marketplace/__tests__/hooks-integration.spec.tsx
+++ b/web/app/components/plugins/marketplace/__tests__/hooks-integration.spec.tsx
@@ -90,8 +90,8 @@ describe('useMarketplaceCollectionsAndPlugins (integration)', () => {
expect(result.current.isSuccess).toBe(true)
})
- expect(result.current.marketplaceCollections).toBeDefined()
- expect(result.current.marketplaceCollectionPluginsMap).toBeDefined()
+ expect(result.current.pluginCollections).toBeDefined()
+ expect(result.current.pluginCollectionPluginsMap).toBeDefined()
})
it('should handle query with empty params (truthy)', async () => {
diff --git a/web/app/components/plugins/marketplace/__tests__/hooks.spec.tsx b/web/app/components/plugins/marketplace/__tests__/hooks.spec.tsx
index 2555a41f6b3..80a3e27becd 100644
--- a/web/app/components/plugins/marketplace/__tests__/hooks.spec.tsx
+++ b/web/app/components/plugins/marketplace/__tests__/hooks.spec.tsx
@@ -118,10 +118,10 @@ describe('useMarketplaceCollectionsAndPlugins', () => {
expect(result.current.isLoading).toBe(false)
expect(result.current.isSuccess).toBe(false)
expect(typeof result.current.queryMarketplaceCollectionsAndPlugins).toBe('function')
- expect(typeof result.current.setMarketplaceCollections).toBe('function')
- expect(typeof result.current.setMarketplaceCollectionPluginsMap).toBe('function')
- expect(result.current.marketplaceCollections).toBeUndefined()
- expect(result.current.marketplaceCollectionPluginsMap).toBeUndefined()
+ expect(typeof result.current.setPluginCollections).toBe('function')
+ expect(typeof result.current.setPluginCollectionPluginsMap).toBe('function')
+ expect(result.current.pluginCollections).toBeUndefined()
+ expect(result.current.pluginCollectionPluginsMap).toBeUndefined()
})
})
@@ -427,8 +427,8 @@ describe('Hooks queryFn Coverage', () => {
await waitFor(() => {
expect(result.current.isSuccess).toBe(true)
})
- expect(result.current.marketplaceCollections).toBeDefined()
- expect(result.current.marketplaceCollectionPluginsMap).toBeDefined()
+ expect(result.current.pluginCollections).toBeDefined()
+ expect(result.current.pluginCollectionPluginsMap).toBeDefined()
})
it('should test getNextPageParam via fetchNextPage behavior', async () => {
diff --git a/web/app/components/plugins/marketplace/__tests__/index.spec.tsx b/web/app/components/plugins/marketplace/__tests__/index.spec.tsx
index e5a90801a5e..aaac2740a38 100644
--- a/web/app/components/plugins/marketplace/__tests__/index.spec.tsx
+++ b/web/app/components/plugins/marketplace/__tests__/index.spec.tsx
@@ -8,24 +8,44 @@ vi.mock('@/context/query-client', () => ({
}))
vi.mock('../hydration-server', () => ({
- HydrateQueryClient: ({ children }: { children: React.ReactNode }) => (
- {children}
+ HydrateQueryClient: ({
+ children,
+ isMarketplacePlatform,
+ }: {
+ children: React.ReactNode
+ isMarketplacePlatform?: boolean
+ }) => (
+ {children}
),
}))
-vi.mock('../description', () => ({
- default: () => Description
,
-}))
-
-vi.mock('../list/list-wrapper', () => ({
- default: ({ showInstallButton }: { showInstallButton: boolean }) => (
- ListWrapper
+vi.mock('../hydration-client', () => ({
+ HydrateClient: ({
+ children,
+ isMarketplacePlatform,
+ }: {
+ children: React.ReactNode
+ isMarketplacePlatform?: boolean
+ }) => (
+ {children}
),
}))
-vi.mock('../sticky-search-and-switch-wrapper', () => ({
- default: ({ pluginTypeSwitchClassName }: { pluginTypeSwitchClassName?: string }) => (
- StickyWrapper
+vi.mock('../marketplace-header', () => ({
+ default: ({
+ marketplaceNav,
+ }: {
+ marketplaceNav?: React.ReactNode
+ }) => (
+
+ {marketplaceNav}
+
+ ),
+}))
+
+vi.mock('../marketplace-content', () => ({
+ default: ({ showInstallButton }: { showInstallButton?: boolean }) => (
+ MarketplaceContent
),
}))
@@ -47,20 +67,20 @@ describe('Marketplace', () => {
const { getByTestId } = render(element as React.ReactElement)
expect(getByTestId('tanstack-initializer')).toBeInTheDocument()
- expect(getByTestId('hydration-client')).toBeInTheDocument()
- expect(getByTestId('description')).toBeInTheDocument()
- expect(getByTestId('sticky-wrapper')).toBeInTheDocument()
- expect(getByTestId('list-wrapper')).toBeInTheDocument()
+ expect(getByTestId('hydrate-query-client')).toBeInTheDocument()
+ expect(getByTestId('hydrate-client')).toBeInTheDocument()
+ expect(getByTestId('marketplace-header')).toBeInTheDocument()
+ expect(getByTestId('marketplace-content')).toBeInTheDocument()
})
- it('should pass showInstallButton=true by default to ListWrapper', async () => {
+ it('should pass showInstallButton=true by default to MarketplaceContent', async () => {
const Marketplace = (await import('../index')).default
const element = await Marketplace({})
const { getByTestId } = render(element as React.ReactElement)
- const listWrapper = getByTestId('list-wrapper')
- expect(listWrapper.getAttribute('data-show-install')).toBe('true')
+ const marketplaceContent = getByTestId('marketplace-content')
+ expect(marketplaceContent.getAttribute('data-show-install')).toBe('true')
})
it('should pass showInstallButton=false when specified', async () => {
@@ -69,27 +89,26 @@ describe('Marketplace', () => {
const { getByTestId } = render(element as React.ReactElement)
- const listWrapper = getByTestId('list-wrapper')
- expect(listWrapper.getAttribute('data-show-install')).toBe('false')
+ const marketplaceContent = getByTestId('marketplace-content')
+ expect(marketplaceContent.getAttribute('data-show-install')).toBe('false')
})
- it('should pass pluginTypeSwitchClassName to StickySearchAndSwitchWrapper', async () => {
+ it('should pass marketplaceNav to MarketplaceHeader', async () => {
const Marketplace = (await import('../index')).default
- const element = await Marketplace({ pluginTypeSwitchClassName: 'top-14' })
+ const element = await Marketplace({ marketplaceNav: Nav
})
const { getByTestId } = render(element as React.ReactElement)
- const stickyWrapper = getByTestId('sticky-wrapper')
- expect(stickyWrapper.getAttribute('data-classname')).toBe('top-14')
+ expect(getByTestId('nav')).toBeInTheDocument()
})
- it('should render without pluginTypeSwitchClassName', async () => {
+ it('should pass isMarketplacePlatform to hydrate wrappers', async () => {
const Marketplace = (await import('../index')).default
- const element = await Marketplace({})
+ const element = await Marketplace({ isMarketplacePlatform: true })
const { getByTestId } = render(element as React.ReactElement)
- const stickyWrapper = getByTestId('sticky-wrapper')
- expect(stickyWrapper.getAttribute('data-classname')).toBeNull()
+ expect(getByTestId('hydrate-query-client').getAttribute('data-marketplace-platform')).toBe('true')
+ expect(getByTestId('hydrate-client').getAttribute('data-marketplace-platform')).toBe('true')
})
})
diff --git a/web/app/components/plugins/marketplace/__tests__/plugin-type-switch.spec.tsx b/web/app/components/plugins/marketplace/__tests__/plugin-type-switch.spec.tsx
index 7cf3b10e25b..d950c30993b 100644
--- a/web/app/components/plugins/marketplace/__tests__/plugin-type-switch.spec.tsx
+++ b/web/app/components/plugins/marketplace/__tests__/plugin-type-switch.spec.tsx
@@ -3,7 +3,7 @@ import { fireEvent, render, screen } from '@testing-library/react'
import { Provider as JotaiProvider } from 'jotai'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createNuqsTestWrapper } from '@/test/nuqs-testing'
-import PluginTypeSwitch from '../plugin-type-switch'
+import { PluginCategorySwitch } from '../category-switch/plugin'
vi.mock('#i18n', () => ({
useTranslation: () => ({
@@ -35,14 +35,14 @@ const createWrapper = (searchParams = '') => {
return { Wrapper }
}
-describe('PluginTypeSwitch', () => {
+describe('PluginCategorySwitch', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should render all category options', () => {
const { Wrapper } = createWrapper()
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
expect(screen.getByText('All')).toBeInTheDocument()
expect(screen.getByText('Models')).toBeInTheDocument()
@@ -56,7 +56,7 @@ describe('PluginTypeSwitch', () => {
it('should apply active styling to current category', () => {
const { Wrapper } = createWrapper('?category=all')
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
const allButton = screen.getByText('All').closest('div')
expect(allButton?.className).toContain('!bg-components-main-nav-nav-button-bg-active')
@@ -64,7 +64,7 @@ describe('PluginTypeSwitch', () => {
it('should apply custom className', () => {
const { Wrapper } = createWrapper()
- const { container } = render(, { wrapper: Wrapper })
+ const { container } = render(, { wrapper: Wrapper })
const outerDiv = container.firstChild as HTMLElement
expect(outerDiv.className).toContain('custom-class')
@@ -72,7 +72,7 @@ describe('PluginTypeSwitch', () => {
it('should update category when option is clicked', () => {
const { Wrapper } = createWrapper('?category=all')
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
fireEvent.click(screen.getByText('Models'))
@@ -82,7 +82,7 @@ describe('PluginTypeSwitch', () => {
it('should handle clicking on category with collections (Tools)', () => {
const { Wrapper } = createWrapper('?category=model')
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
fireEvent.click(screen.getByText('Tools'))
@@ -92,7 +92,7 @@ describe('PluginTypeSwitch', () => {
it('should handle clicking on category without collections (Models)', () => {
const { Wrapper } = createWrapper('?category=all')
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
fireEvent.click(screen.getByText('Models'))
@@ -102,7 +102,7 @@ describe('PluginTypeSwitch', () => {
it('should handle clicking on bundles', () => {
const { Wrapper } = createWrapper('?category=all')
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
fireEvent.click(screen.getByText('Bundles'))
@@ -112,7 +112,7 @@ describe('PluginTypeSwitch', () => {
it('should handle clicking on each category', () => {
const { Wrapper } = createWrapper('?category=all')
- render(, { wrapper: Wrapper })
+ render(, { wrapper: Wrapper })
const categories = ['All', 'Models', 'Tools', 'Data Sources', 'Triggers', 'Agents', 'Extensions', 'Bundles']
categories.forEach((category) => {
@@ -125,7 +125,7 @@ describe('PluginTypeSwitch', () => {
it('should render icons for categories that have them', () => {
const { Wrapper } = createWrapper()
- const { container } = render(, { wrapper: Wrapper })
+ const { container } = render(, { wrapper: Wrapper })
// "All" has no icon (icon: null), others should have SVG icons
const svgs = container.querySelectorAll('svg')
diff --git a/web/app/components/plugins/marketplace/__tests__/state.spec.tsx b/web/app/components/plugins/marketplace/__tests__/state.spec.tsx
index f4330f31b4e..348b6d1ce09 100644
--- a/web/app/components/plugins/marketplace/__tests__/state.spec.tsx
+++ b/web/app/components/plugins/marketplace/__tests__/state.spec.tsx
@@ -55,7 +55,7 @@ const createWrapper = (searchParams = '') => {
return { Wrapper, queryClient }
}
-describe('useMarketplaceData', () => {
+describe('usePluginsMarketplaceData', () => {
beforeEach(() => {
vi.clearAllMocks()
@@ -80,7 +80,7 @@ describe('useMarketplaceData', () => {
})
it('should return initial state with loading and collections data', async () => {
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
const { Wrapper } = createWrapper('?category=all')
// Create a mock container for scroll
@@ -88,14 +88,14 @@ describe('useMarketplaceData', () => {
container.id = 'marketplace-container'
document.body.appendChild(container)
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
await waitFor(() => {
expect(result.current.isLoading).toBe(false)
})
- expect(result.current.marketplaceCollections).toBeDefined()
- expect(result.current.marketplaceCollectionPluginsMap).toBeDefined()
+ expect(result.current.pluginCollections).toBeDefined()
+ expect(result.current.pluginCollectionPluginsMap).toBeDefined()
expect(result.current.page).toBeDefined()
expect(result.current.isFetchingNextPage).toBe(false)
@@ -103,14 +103,14 @@ describe('useMarketplaceData', () => {
})
it('should return search mode data when search text is present', async () => {
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
const { Wrapper } = createWrapper('?category=all&q=test')
const container = document.createElement('div')
container.id = 'marketplace-container'
document.body.appendChild(container)
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
await waitFor(() => {
expect(result.current.isLoading).toBe(false)
@@ -123,7 +123,7 @@ describe('useMarketplaceData', () => {
})
it('should return plugins undefined in collection mode (not search mode)', async () => {
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
// "all" category with no search → collection mode
const { Wrapper } = createWrapper('?category=all')
@@ -131,7 +131,7 @@ describe('useMarketplaceData', () => {
container.id = 'marketplace-container'
document.body.appendChild(container)
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
await waitFor(() => {
expect(result.current.isLoading).toBe(false)
@@ -144,14 +144,14 @@ describe('useMarketplaceData', () => {
})
it('should enable search for category without collections (e.g. model)', async () => {
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
const { Wrapper } = createWrapper('?category=model')
const container = document.createElement('div')
container.id = 'marketplace-container'
document.body.appendChild(container)
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
await waitFor(() => {
expect(result.current.isLoading).toBe(false)
@@ -177,7 +177,7 @@ describe('useMarketplaceData', () => {
},
})
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
// Use "model" to force search mode
const { Wrapper } = createWrapper('?category=model')
@@ -189,7 +189,7 @@ describe('useMarketplaceData', () => {
Object.defineProperty(container, 'scrollHeight', { value: 1000, writable: true, configurable: true })
Object.defineProperty(container, 'clientHeight', { value: 200, writable: true, configurable: true })
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
// Wait for data to fully load (isFetching becomes false, plugins become available)
await waitFor(() => {
@@ -206,7 +206,7 @@ describe('useMarketplaceData', () => {
})
it('should handle tags filter in search mode', async () => {
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
// tags in URL triggers search mode
const { Wrapper } = createWrapper('?category=all&tags=search')
@@ -214,7 +214,7 @@ describe('useMarketplaceData', () => {
container.id = 'marketplace-container'
document.body.appendChild(container)
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
await waitFor(() => {
expect(result.current.isLoading).toBe(false)
@@ -238,7 +238,7 @@ describe('useMarketplaceData', () => {
},
})
- const { useMarketplaceData } = await import('../state')
+ const { usePluginsMarketplaceData } = await import('../state')
const { Wrapper } = createWrapper('?category=model')
const container = document.createElement('div')
@@ -249,7 +249,7 @@ describe('useMarketplaceData', () => {
Object.defineProperty(container, 'scrollHeight', { value: 1000, writable: true, configurable: true })
Object.defineProperty(container, 'clientHeight', { value: 200, writable: true, configurable: true })
- const { result } = renderHook(() => useMarketplaceData(), { wrapper: Wrapper })
+ const { result } = renderHook(() => usePluginsMarketplaceData(), { wrapper: Wrapper })
await waitFor(() => {
expect(result.current.plugins).toBeDefined()
diff --git a/web/app/components/plugins/marketplace/__tests__/sticky-search-and-switch-wrapper.spec.tsx b/web/app/components/plugins/marketplace/__tests__/sticky-search-and-switch-wrapper.spec.tsx
deleted file mode 100644
index 1876692dadc..00000000000
--- a/web/app/components/plugins/marketplace/__tests__/sticky-search-and-switch-wrapper.spec.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import type { ReactNode } from 'react'
-import { render } from '@testing-library/react'
-import { Provider as JotaiProvider } from 'jotai'
-import { beforeEach, describe, expect, it, vi } from 'vitest'
-import { createNuqsTestWrapper } from '@/test/nuqs-testing'
-import StickySearchAndSwitchWrapper from '../sticky-search-and-switch-wrapper'
-
-vi.mock('#i18n', () => ({
- useTranslation: () => ({
- t: (key: string) => key,
- }),
-}))
-
-// Mock child components to isolate wrapper logic
-vi.mock('../plugin-type-switch', () => ({
- default: () => PluginTypeSwitch
,
-}))
-
-vi.mock('../search-box/search-box-wrapper', () => ({
- default: () => SearchBoxWrapper
,
-}))
-
-const createWrapper = () => {
- const { wrapper: NuqsWrapper } = createNuqsTestWrapper()
- const Wrapper = ({ children }: { children: ReactNode }) => (
-
-
- {children}
-
-
- )
- return { Wrapper }
-}
-
-describe('StickySearchAndSwitchWrapper', () => {
- beforeEach(() => {
- vi.clearAllMocks()
- })
-
- it('should render SearchBoxWrapper and PluginTypeSwitch', () => {
- const { Wrapper } = createWrapper()
- const { getByTestId } = render(
- ,
- { wrapper: Wrapper },
- )
-
- expect(getByTestId('search-box-wrapper')).toBeInTheDocument()
- expect(getByTestId('plugin-type-switch')).toBeInTheDocument()
- })
-
- it('should not apply sticky class when no pluginTypeSwitchClassName', () => {
- const { Wrapper } = createWrapper()
- const { container } = render(
- ,
- { wrapper: Wrapper },
- )
-
- const outerDiv = container.firstChild as HTMLElement
- expect(outerDiv.className).toContain('mt-4')
- expect(outerDiv.className).not.toContain('sticky')
- })
-
- it('should apply sticky class when pluginTypeSwitchClassName contains top-', () => {
- const { Wrapper } = createWrapper()
- const { container } = render(
- ,
- { wrapper: Wrapper },
- )
-
- const outerDiv = container.firstChild as HTMLElement
- expect(outerDiv.className).toContain('sticky')
- expect(outerDiv.className).toContain('z-10')
- expect(outerDiv.className).toContain('top-10')
- })
-
- it('should not apply sticky class when pluginTypeSwitchClassName does not contain top-', () => {
- const { Wrapper } = createWrapper()
- const { container } = render(
- ,
- { wrapper: Wrapper },
- )
-
- const outerDiv = container.firstChild as HTMLElement
- expect(outerDiv.className).not.toContain('sticky')
- expect(outerDiv.className).toContain('custom-class')
- })
-})
diff --git a/web/app/components/plugins/marketplace/__tests__/utils.spec.ts b/web/app/components/plugins/marketplace/__tests__/utils.spec.ts
index 92bed9be62c..6514b01031a 100644
--- a/web/app/components/plugins/marketplace/__tests__/utils.spec.ts
+++ b/web/app/components/plugins/marketplace/__tests__/utils.spec.ts
@@ -23,9 +23,11 @@ const mockSearchAdvanced = vi.fn()
vi.mock('@/service/client', () => ({
marketplaceClient: {
- collections: (...args: unknown[]) => mockCollections(...args),
- collectionPlugins: (...args: unknown[]) => mockCollectionPlugins(...args),
- searchAdvanced: (...args: unknown[]) => mockSearchAdvanced(...args),
+ plugins: {
+ collections: (...args: unknown[]) => mockCollections(...args),
+ collectionPlugins: (...args: unknown[]) => mockCollectionPlugins(...args),
+ searchAdvanced: (...args: unknown[]) => mockSearchAdvanced(...args),
+ },
},
}))
@@ -134,69 +136,69 @@ describe('getPluginDetailLinkInMarketplace', () => {
})
})
-describe('getMarketplaceListCondition', () => {
+describe('getPluginCondition', () => {
it('should return category condition for tool', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition(PluginCategoryEnum.tool)).toBe('category=tool')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition(PluginCategoryEnum.tool)).toBe('category=tool')
})
it('should return category condition for model', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition(PluginCategoryEnum.model)).toBe('category=model')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition(PluginCategoryEnum.model)).toBe('category=model')
})
it('should return category condition for agent', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition(PluginCategoryEnum.agent)).toBe('category=agent-strategy')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition(PluginCategoryEnum.agent)).toBe('category=agent')
})
it('should return category condition for datasource', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition(PluginCategoryEnum.datasource)).toBe('category=datasource')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition(PluginCategoryEnum.datasource)).toBe('category=datasource')
})
it('should return category condition for trigger', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition(PluginCategoryEnum.trigger)).toBe('category=trigger')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition(PluginCategoryEnum.trigger)).toBe('category=trigger')
})
it('should return endpoint category for extension', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition(PluginCategoryEnum.extension)).toBe('category=endpoint')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition(PluginCategoryEnum.extension)).toBe('category=endpoint')
})
it('should return type condition for bundle', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition('bundle')).toBe('type=bundle')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition('bundle')).toBe('type=bundle')
})
it('should return empty string for all', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition('all')).toBe('')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition('all')).toBe('')
})
it('should return empty string for unknown type', async () => {
- const { getMarketplaceListCondition } = await import('../utils')
- expect(getMarketplaceListCondition('unknown')).toBe('')
+ const { getPluginCondition } = await import('../utils')
+ expect(getPluginCondition('unknown')).toBe('')
})
})
-describe('getMarketplaceListFilterType', () => {
+describe('getPluginFilterType', () => {
it('should return undefined for all', async () => {
- const { getMarketplaceListFilterType } = await import('../utils')
- expect(getMarketplaceListFilterType(PLUGIN_TYPE_SEARCH_MAP.all)).toBeUndefined()
+ const { getPluginFilterType } = await import('../utils')
+ expect(getPluginFilterType(PLUGIN_TYPE_SEARCH_MAP.all)).toBeUndefined()
})
it('should return bundle for bundle', async () => {
- const { getMarketplaceListFilterType } = await import('../utils')
- expect(getMarketplaceListFilterType(PLUGIN_TYPE_SEARCH_MAP.bundle)).toBe('bundle')
+ const { getPluginFilterType } = await import('../utils')
+ expect(getPluginFilterType(PLUGIN_TYPE_SEARCH_MAP.bundle)).toBe('bundle')
})
it('should return plugin for other categories', async () => {
- const { getMarketplaceListFilterType } = await import('../utils')
- expect(getMarketplaceListFilterType(PLUGIN_TYPE_SEARCH_MAP.tool)).toBe('plugin')
- expect(getMarketplaceListFilterType(PLUGIN_TYPE_SEARCH_MAP.model)).toBe('plugin')
- expect(getMarketplaceListFilterType(PLUGIN_TYPE_SEARCH_MAP.agent)).toBe('plugin')
+ const { getPluginFilterType } = await import('../utils')
+ expect(getPluginFilterType(PLUGIN_TYPE_SEARCH_MAP.tool)).toBe('plugin')
+ expect(getPluginFilterType(PLUGIN_TYPE_SEARCH_MAP.model)).toBe('plugin')
+ expect(getPluginFilterType(PLUGIN_TYPE_SEARCH_MAP.agent)).toBe('plugin')
})
})
diff --git a/web/app/components/plugins/marketplace/hydration-server.tsx b/web/app/components/plugins/marketplace/hydration-server.tsx
index e04016ff98a..1a6e65af1a7 100644
--- a/web/app/components/plugins/marketplace/hydration-server.tsx
+++ b/web/app/components/plugins/marketplace/hydration-server.tsx
@@ -1,5 +1,4 @@
import type { SearchParams } from 'nuqs/server'
-import type { MarketplaceSearchParams } from './search-params'
import type { CreatorSearchParams, PluginsSearchParams, TemplateSearchParams } from './types'
import { dehydrate, HydrationBoundary } from '@tanstack/react-query'
import { headers } from 'next/headers'
diff --git a/web/app/components/plugins/marketplace/list/__tests__/index.spec.tsx b/web/app/components/plugins/marketplace/list/__tests__/index.spec.tsx
index b8deb4e6b0f..8bd930f2103 100644
--- a/web/app/components/plugins/marketplace/list/__tests__/index.spec.tsx
+++ b/web/app/components/plugins/marketplace/list/__tests__/index.spec.tsx
@@ -1,4 +1,4 @@
-import type { MarketplaceCollection, SearchParamsFromCollection } from '../../types'
+import type { PluginCollection, SearchParamsFromCollection } from '../../types'
import type { Plugin } from '@/app/components/plugins/types'
import { fireEvent, render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
@@ -103,8 +103,8 @@ vi.mock('@/i18n-config/language', () => ({
}))
// Mock marketplace utils
-vi.mock('../utils', async (importOriginal) => {
- const actual = await importOriginal()
+vi.mock('../../utils', async (importOriginal) => {
+ const actual = await importOriginal()
return {
...actual,
getPluginLinkInMarketplace: (plugin: Plugin, _params?: Record) =>
diff --git a/web/app/components/plugins/marketplace/search-box/__tests__/index.spec.tsx b/web/app/components/plugins/marketplace/search-box/__tests__/index.spec.tsx
index 6c58d9ce7b4..fcafc9e7481 100644
--- a/web/app/components/plugins/marketplace/search-box/__tests__/index.spec.tsx
+++ b/web/app/components/plugins/marketplace/search-box/__tests__/index.spec.tsx
@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import { PluginCategoryEnum } from '../../../types'
import SearchBox from '../index'
import SearchBoxWrapper from '../search-box-wrapper'
+import SearchDropdown from '../search-dropdown'
import MarketplaceTrigger from '../trigger/marketplace'
import ToolSelectorTrigger from '../trigger/tool-selector'
@@ -80,7 +81,6 @@ const {
vi.mock('../../atoms', () => ({
useSearchText: () => [mockSearchText, mockHandleSearchTextChange],
- useSearchPluginText: () => [mockSearchPluginText, mockHandleSearchPluginTextChange],
useFilterPluginTags: () => [mockFilterPluginTags, mockHandleFilterPluginTagsChange],
useActivePluginCategory: () => [mockActivePluginCategory, vi.fn()],
useMarketplacePluginSortValue: () => mockSortValue,
@@ -92,8 +92,8 @@ vi.mock('../../atoms', () => ({
searchModeAtom: {},
}))
-vi.mock('../utils', async () => {
- const actual = await vi.importActual('../utils')
+vi.mock('../../utils', async () => {
+ const actual = await vi.importActual('../../utils')
return {
...actual,
mapUnifiedPluginToPlugin: (item: Plugin) => item,
diff --git a/web/app/components/plugins/marketplace/search-params.ts b/web/app/components/plugins/marketplace/search-params.ts
index 5979e7c7c29..f3b2aad3a53 100644
--- a/web/app/components/plugins/marketplace/search-params.ts
+++ b/web/app/components/plugins/marketplace/search-params.ts
@@ -1,5 +1,4 @@
import type { inferParserType } from 'nuqs/server'
-import type { ActivePluginType } from './constants'
import { parseAsArrayOf, parseAsString, parseAsStringEnum } from 'nuqs/server'
export const CREATION_TYPE = {
diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx
index 5034a287cfe..7e10de1cb33 100644
--- a/web/app/components/plugins/plugin-page/index.tsx
+++ b/web/app/components/plugins/plugin-page/index.tsx
@@ -18,16 +18,15 @@ import { MARKETPLACE_API_PREFIX, SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@
import { useGlobalPublicStore } from '@/context/global-public-context'
import useDocumentTitle from '@/hooks/use-document-title'
import { usePluginInstallation } from '@/hooks/use-query-params'
-import Link from '@/next/link'
import { fetchBundleInfoFromMarketPlace, fetchManifestFromMarketPlace } from '@/service/plugins'
import { sleep } from '@/utils'
import { PLUGIN_PAGE_TABS_MAP } from '../hooks'
import InstallFromLocalPackage from '../install-plugin/install-from-local-package'
import InstallFromMarketplace from '../install-plugin/install-from-marketplace'
import { PLUGIN_TYPE_SEARCH_MAP } from '../marketplace/constants'
+import SearchBoxWrapper from '../marketplace/search-box/search-box-wrapper'
import { usePluginPageContext } from './context'
import { PluginPageContextProvider } from './context-provider'
-import SearchBoxWrapper from '../marketplace/search-box/search-box-wrapper'
import DebugInfo from './debug-info'
import InstallPluginDropdown from './install-plugin-dropdown'
import { SubmitRequestDropdown } from './nav-operations'
diff --git a/web/app/components/tools/marketplace/__tests__/hooks.spec.ts b/web/app/components/tools/marketplace/__tests__/hooks.spec.ts
index 14244f763cb..c704446a683 100644
--- a/web/app/components/tools/marketplace/__tests__/hooks.spec.ts
+++ b/web/app/components/tools/marketplace/__tests__/hooks.spec.ts
@@ -3,7 +3,7 @@ import type { Collection } from '@/app/components/tools/types'
import { act, renderHook, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { SCROLL_BOTTOM_THRESHOLD } from '@/app/components/plugins/marketplace/constants'
-import { getMarketplaceListCondition } from '@/app/components/plugins/marketplace/utils'
+import { getPluginCondition } from '@/app/components/plugins/marketplace/utils'
import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { CollectionType } from '@/app/components/tools/types'
import { useMarketplace } from '../hooks'
@@ -141,7 +141,7 @@ describe('useMarketplace', () => {
await waitFor(() => {
expect(mockQueryMarketplaceCollectionsAndPlugins).toHaveBeenCalledWith({
category: PluginCategoryEnum.tool,
- condition: getMarketplaceListCondition(PluginCategoryEnum.tool),
+ condition: getPluginCondition(PluginCategoryEnum.tool),
exclude: ['plugin-c'],
type: 'plugin',
})
diff --git a/web/app/components/tools/marketplace/__tests__/index.spec.tsx b/web/app/components/tools/marketplace/__tests__/index.spec.tsx
index 43c303b0753..b17387c28e9 100644
--- a/web/app/components/tools/marketplace/__tests__/index.spec.tsx
+++ b/web/app/components/tools/marketplace/__tests__/index.spec.tsx
@@ -13,8 +13,8 @@ import Marketplace from '../index'
const listRenderSpy = vi.fn()
vi.mock('@/app/components/plugins/marketplace/list', () => ({
default: (props: {
- marketplaceCollections: unknown[]
- marketplaceCollectionPluginsMap: Record
+ pluginCollections: unknown[]
+ pluginCollectionPluginsMap: Record
plugins?: unknown[]
showInstallButton?: boolean
}) => {
@@ -84,8 +84,8 @@ const createPlugin = (overrides: Partial = {}): Plugin => ({
const createMarketplaceContext = (overrides: Partial> = {}) => ({
isLoading: false,
- marketplaceCollections: [],
- marketplaceCollectionPluginsMap: {},
+ pluginCollections: [],
+ pluginCollectionPluginsMap: {},
plugins: [],
handleScroll: vi.fn(),
page: 1,
@@ -104,7 +104,7 @@ describe('Marketplace', () => {
const marketplaceContext = createMarketplaceContext({ isLoading: true, page: 1 })
render(
{
})
render(
{
const showMarketplacePanel = vi.fn()
const { container } = render(