dify/web/features/agent-v2/roster/components/__tests__/create-agent-dialog.spec.tsx
Stephen Zhou a84c2d36a3
style: format with vp fmt (#38803)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-12 15:57:46 +00:00

202 lines
6.4 KiB
TypeScript

import { act, render, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { CreateAgentDialog } from '../create-agent-dialog'
const mutationMock = vi.hoisted(() => ({
isPending: false,
mutate: vi.fn(),
}))
const toastMock = vi.hoisted(() => ({
error: vi.fn(),
success: vi.fn(),
}))
const routerPushMock = vi.hoisted(() => vi.fn())
vi.mock('@tanstack/react-query', () => ({
useMutation: () => ({
isPending: mutationMock.isPending,
mutate: mutationMock.mutate,
}),
}))
vi.mock('@langgenius/dify-ui/toast', () => ({
toast: toastMock,
}))
vi.mock('@/next/navigation', () => ({
useRouter: () => ({
push: routerPushMock,
}),
}))
vi.mock('@/service/client', () => ({
consoleQuery: {
agent: {
post: {
mutationOptions: vi.fn(() => ({})),
},
},
},
}))
describe('CreateAgentDialog', () => {
beforeEach(() => {
vi.clearAllMocks()
mutationMock.isPending = false
})
it('submits agent app fields and default icon fields when creating an agent', async () => {
const user = userEvent.setup()
render(<CreateAgentDialog />)
await user.click(screen.getByRole('button', { name: /agentV2\.roster\.createAgent/ }))
const dialog = await screen.findByRole('dialog', { name: 'agentV2.roster.createDialog.title' })
await user.type(
within(dialog).getByRole('textbox', { name: 'agentV2.roster.createForm.nameLabel' }),
' Research Agent ',
)
await user.type(
within(dialog).getByRole('textbox', { name: /agentV2\.roster\.createForm\.roleLabel/ }),
' Research Assistant ',
)
await user.type(
within(dialog).getByPlaceholderText('agentV2.roster.createForm.descriptionPlaceholder'),
' Find and summarize market materials. ',
)
await user.click(within(dialog).getByRole('button', { name: 'common.operation.create' }))
expect(mutationMock.mutate).toHaveBeenCalledWith(
{
body: {
name: 'Research Agent',
description: 'Find and summarize market materials.',
role: 'Research Assistant',
icon_type: 'emoji',
icon: '🧸',
icon_background: '#F5F3FF',
},
},
expect.objectContaining({
onSuccess: expect.any(Function),
}),
)
const mutationOptions = mutationMock.mutate.mock.calls[0]?.[1]
expect(mutationOptions).not.toHaveProperty('onError')
})
it('navigates to the new agent configure page after creating an agent', async () => {
const user = userEvent.setup()
render(<CreateAgentDialog />)
await user.click(screen.getByRole('button', { name: /agentV2\.roster\.createAgent/ }))
const dialog = await screen.findByRole('dialog', { name: 'agentV2.roster.createDialog.title' })
await user.type(
within(dialog).getByRole('textbox', { name: 'agentV2.roster.createForm.nameLabel' }),
'Research Agent',
)
await user.click(within(dialog).getByRole('button', { name: 'common.operation.create' }))
const mutationOptions = mutationMock.mutate.mock.calls[0]?.[1]
await act(async () => {
mutationOptions.onSuccess({ id: 'agent-1' })
})
expect(toastMock.success).toHaveBeenCalledWith('agentV2.roster.createSuccess')
expect(routerPushMock).toHaveBeenCalledWith('/agents/agent-1/configure')
})
it('shows a field error when creating with an empty name', async () => {
const user = userEvent.setup()
render(<CreateAgentDialog />)
await user.click(screen.getByRole('button', { name: /agentV2\.roster\.createAgent/ }))
const dialog = await screen.findByRole('dialog', { name: 'agentV2.roster.createDialog.title' })
await user.type(
within(dialog).getByRole('textbox', { name: /agentV2\.roster\.createForm\.roleLabel/ }),
'Research Assistant',
)
await user.click(within(dialog).getByRole('button', { name: 'common.operation.create' }))
expect(
await within(dialog).findByText('agentV2.roster.createForm.nameRequired'),
).toBeInTheDocument()
expect(toastMock.error).not.toHaveBeenCalled()
expect(mutationMock.mutate).not.toHaveBeenCalled()
})
it('marks role and description as optional', async () => {
const user = userEvent.setup()
render(<CreateAgentDialog />)
await user.click(screen.getByRole('button', { name: /agentV2\.roster\.createAgent/ }))
const dialog = await screen.findByRole('dialog', { name: 'agentV2.roster.createDialog.title' })
expect(
within(dialog).getByRole('textbox', {
name: /agentV2\.roster\.createForm\.roleLabel.*common\.label\.optional/,
}),
).not.toBeRequired()
expect(
within(dialog).getByRole('textbox', {
name: /agentV2\.roster\.createForm\.descriptionLabel.*common\.label\.optional/,
}),
).not.toBeRequired()
})
it('submits an empty role when role is left blank', async () => {
const user = userEvent.setup()
render(<CreateAgentDialog />)
await user.click(screen.getByRole('button', { name: /agentV2\.roster\.createAgent/ }))
const dialog = await screen.findByRole('dialog', { name: 'agentV2.roster.createDialog.title' })
await user.type(
within(dialog).getByRole('textbox', { name: 'agentV2.roster.createForm.nameLabel' }),
'Research Agent',
)
await user.click(within(dialog).getByRole('button', { name: 'common.operation.create' }))
expect(mutationMock.mutate).toHaveBeenCalledWith(
{
body: {
name: 'Research Agent',
description: '',
role: '',
icon_type: 'emoji',
icon: '🧸',
icon_background: '#F5F3FF',
},
},
expect.objectContaining({
onSuccess: expect.any(Function),
}),
)
})
it('keeps the form open when the backdrop is clicked', async () => {
const user = userEvent.setup()
render(<CreateAgentDialog />)
await user.click(screen.getByRole('button', { name: /agentV2\.roster\.createAgent/ }))
const dialog = await screen.findByRole('dialog', { name: 'agentV2.roster.createDialog.title' })
const backdrop = document.body.querySelector('.bg-background-overlay') as HTMLElement
await user.click(backdrop)
expect(dialog).toBeInTheDocument()
await user.click(within(dialog).getByRole('button', { name: 'common.operation.cancel' }))
await waitFor(() => {
expect(
screen.queryByRole('dialog', { name: 'agentV2.roster.createDialog.title' }),
).not.toBeInTheDocument()
})
})
})