Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 102 additions & 4 deletions web/src/features/task-plugins/__tests__/plugins-table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import userEvent from '@testing-library/user-event'
import { Toaster } from 'sonner'
import { afterEach, expect, test, vi } from 'vitest'

import { PageFooterProvider } from '@/components/layout/components/page-footer'
import {
MODEL_PRICING_ISSUES_QUERY_KEY,
type ModelPricingIssue,
Expand All @@ -43,7 +44,8 @@ afterEach(() => {
function renderPlugins(
enabled: boolean,
view: 'card' | 'table' = 'card',
source: TaskPluginListItem['source'] = 'override'
source: TaskPluginListItem['source'] = 'override',
additionalPlugins: { key: string; name: string }[] = []
) {
localStorage.setItem('task-plugins-view-mode', view)
const item: TaskPluginListItem = {
Expand Down Expand Up @@ -75,18 +77,114 @@ function renderPlugins(
},
})
clients.push(client)
client.setQueryData(['task-plugins'], [item])
client.setQueryData(
['task-plugins'],
[
item,
...additionalPlugins.map((meta) => ({
...item,
meta: { ...item.meta, ...meta },
})),
]
)
vi.spyOn(api, 'get').mockResolvedValue({
data: { success: true, data: [{ ...item, enabled: !enabled }] },
})
render(
const footer = document.createElement('div')
const rendered = render(
<QueryClientProvider client={client}>
<PluginsTable onDetails={() => undefined} onUpload={() => undefined} />
<PageFooterProvider container={footer}>
<PluginsTable onDetails={() => undefined} onUpload={() => undefined} />
</PageFooterProvider>
</QueryClientProvider>
)
rendered.container.append(footer)
return screen.getAllByRole('switch', { name: 'Enable plugin example' })[0]
}

test.each(['card', 'table'] as const)(
'%s view: searching filters plugin names and keys and clearing restores the list',
async (view) => {
const user = userEvent.setup()
renderPlugins(true, view, 'factory', [
{ key: 'google', name: 'Google Veo (Gemini API)' },
{ key: 'vertex-ai', name: 'Google Veo (Vertex AI)' },
{ key: 'doubao', name: 'Doubao Video' },
])
const search = screen.getByPlaceholderText('Filter plugins...')

await user.type(search, 'GOOGLE')
await waitFor(() => {
expect(
screen.queryAllByRole('switch', { name: 'Enable plugin example' })
).toHaveLength(0)
expect(
screen.queryAllByRole('switch', { name: 'Enable plugin doubao' })
).toHaveLength(0)
})
expect(
screen.getAllByRole('switch', { name: 'Enable plugin google' }).length
).toBeGreaterThan(0)
expect(
screen.getAllByRole('switch', { name: 'Enable plugin vertex-ai' }).length
).toBeGreaterThan(0)

await user.clear(search)
await user.type(search, 'vertex-ai')
await waitFor(() =>
expect(
screen.queryAllByRole('switch', { name: 'Enable plugin google' })
).toHaveLength(0)
)
expect(
screen.getAllByRole('switch', { name: 'Enable plugin vertex-ai' }).length
).toBeGreaterThan(0)

await user.clear(search)
await user.type(search, 'no-matching-plugin')
await screen.findByText('No task plugins found')
expect(screen.queryAllByRole('switch')).toHaveLength(0)

await user.clear(search)
await waitFor(() => {
for (const key of ['example', 'google', 'vertex-ai', 'doubao']) {
expect(
screen.getAllByRole('switch', { name: `Enable plugin ${key}` }).length
).toBeGreaterThan(0)
}
})
}
)

test('searching from a later page uses filtered pagination and clearing restores all pages', async () => {
const user = userEvent.setup()
renderPlugins(true, 'table', 'factory', [
...Array.from({ length: 20 }, (_, index) => ({
key: `plugin-${index}`,
name: `Plugin ${index}`,
})),
{ key: 'google', name: 'Google Veo' },
])
const next = screen.getByRole('button', { name: 'Go to next page' })
const previous = screen.getByRole('button', { name: 'Go to previous page' })
expect(next).toBeEnabled()
await user.click(next)
expect(previous).toBeEnabled()

const search = screen.getByPlaceholderText('Filter plugins...')
await user.type(search, 'google')
await waitFor(() => {
expect(
screen.getByRole('switch', { name: 'Enable plugin google' })
).toBeVisible()
expect(previous).toBeDisabled()
expect(next).toBeDisabled()
})

await user.clear(search)
await waitFor(() => expect(next).toBeEnabled())
})

test.each([
['card', true],
['card', false],
Expand Down
2 changes: 1 addition & 1 deletion web/src/features/task-plugins/components/plugins-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,10 @@ export function PluginsTable(props: PluginsTableProps) {
const { table } = useDataTable({
data: pluginsQuery.data ?? [],
columns,
totalCount: pluginsQuery.data?.length ?? 0,
columnFilters,
onColumnFiltersChange: setColumnFilters,
globalFilter,
globalFilterFn: 'includesString',
onGlobalFilterChange: setGlobalFilter,
withFilteredRowModel: true,
withPaginationRowModel: true,
Expand Down
Loading