dify/web/app/components/share/text-generation/__tests__/text-generation-result-panel.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

201 lines
5.8 KiB
TypeScript

import type { PromptConfig } from '@/models/debug'
import type { SiteInfo } from '@/models/share'
import type { VisionSettings } from '@/types/app'
import { fireEvent, render, screen } from '@testing-library/react'
import { AppSourceType } from '@/service/share'
import { Resolution, TransferMethod } from '@/types/app'
import TextGenerationResultPanel from '../text-generation-result-panel'
import { TaskStatus } from '../types'
const resPropsSpy = vi.fn()
const resDownloadPropsSpy = vi.fn()
vi.mock('@/app/components/share/text-generation/result', () => ({
default: (props: Record<string, unknown>) => {
resPropsSpy(props)
return <div data-testid={`res-${String(props.taskId ?? 'single')}`} />
},
}))
vi.mock('@/app/components/share/text-generation/run-batch/res-download', () => ({
default: (props: Record<string, unknown>) => {
resDownloadPropsSpy(props)
return <div data-testid="res-download-mock" />
},
}))
const promptConfig: PromptConfig = {
prompt_template: 'template',
prompt_variables: [{ key: 'name', name: 'Name', type: 'string', required: true }],
}
const siteInfo: SiteInfo = {
title: 'Text Generation',
description: 'Share description',
icon_type: 'emoji',
icon: 'robot',
}
const visionConfig: VisionSettings = {
enabled: false,
number_limits: 2,
detail: Resolution.low,
transfer_methods: [TransferMethod.local_file],
}
const batchTasks = [
{
id: 1,
status: TaskStatus.completed,
params: { inputs: { name: 'Alpha' } },
}!,
{
id: 2,
status: TaskStatus.failed,
params: { inputs: { name: 'Beta' } },
}!,
]
const baseProps = {
allFailedTaskList: [],
allSuccessTaskList: [],
allTaskList: batchTasks,
appId: 'app-123',
appSourceType: AppSourceType.webApp,
completionFiles: [],
controlRetry: 88,
controlSend: 77,
controlStopResponding: 66,
exportRes: [{ Name: 'Alpha', 'share.generation.completionResult': 'Done' }!],
handleCompleted: vi.fn(),
handleRetryAllFailedTask: vi.fn(),
handleSaveMessage: vi.fn(async () => {}),
inputs: { name: 'Alice' },
isCallBatchAPI: false,
isPC: true,
isShowResultPanel: true,
isWorkflow: false,
moreLikeThisEnabled: true,
noPendingTask: true,
onHideResultPanel: vi.fn(),
onRunControlChange: vi.fn(),
onRunStart: vi.fn(),
onShowResultPanel: vi.fn(),
promptConfig,
resultExisted: true,
showTaskList: batchTasks,
siteInfo,
textToSpeechEnabled: true,
visionConfig,
}
describe('TextGenerationResultPanel', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should render a single result in run-once mode and pass non-batch props', () => {
render(<TextGenerationResultPanel {...baseProps} />)
expect(screen.getByTestId('res-single'))!.toBeInTheDocument()
expect(resPropsSpy).toHaveBeenCalledWith(
expect.objectContaining({
appId: 'app-123',
appSourceType: AppSourceType.webApp,
completionFiles: [],
controlSend: 77,
controlStopResponding: 66,
hideInlineStopButton: true,
inputs: { name: 'Alice' },
isCallBatchAPI: false,
moreLikeThisEnabled: true,
taskId: undefined,
}),
)
expect(screen.queryByTestId('res-download-mock')).not.toBeInTheDocument()
})
it('should render batch results, download entry, loading area, and retry banner', () => {
const handleRetryAllFailedTask = vi.fn()
render(
<TextGenerationResultPanel
{...baseProps}
allFailedTaskList={[batchTasks[1]!]}
allSuccessTaskList={[batchTasks[0]!]}
isCallBatchAPI
noPendingTask={false}
handleRetryAllFailedTask={handleRetryAllFailedTask}
/>,
)
expect(screen.getByTestId('res-1'))!.toBeInTheDocument()
expect(screen.getByTestId('res-2'))!.toBeInTheDocument()
expect(resPropsSpy).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
inputs: { name: 'Alpha' },
isError: false,
controlRetry: 0,
taskId: 1,
onRunControlChange: undefined,
}),
)
expect(resPropsSpy).toHaveBeenNthCalledWith(
2,
expect.objectContaining({
inputs: { name: 'Beta' },
isError: true,
controlRetry: 88,
taskId: 2,
}),
)
expect(screen.getByText('share.generation.executions:{"num":2}'))!.toBeInTheDocument()
expect(screen.getByTestId('res-download-mock'))!.toBeInTheDocument()
expect(resDownloadPropsSpy).toHaveBeenCalledWith(
expect.objectContaining({
isMobile: false,
values: baseProps.exportRes,
}),
)
expect(screen.getByText('share.generation.batchFailed.info:{"num":1}'))!.toBeInTheDocument()
expect(
screen.getByRole('button', { name: 'share.generation.batchFailed.retry' }),
)!.toBeInTheDocument()
expect(screen.getByRole('status', { name: 'appApi.loading' }))!.toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: 'share.generation.batchFailed.retry' }))
expect(handleRetryAllFailedTask).toHaveBeenCalledTimes(1)
})
it('should toggle mobile result panel handle between show and hide actions', () => {
const onHideResultPanel = vi.fn()
const onShowResultPanel = vi.fn()
const { rerender } = render(
<TextGenerationResultPanel
{...baseProps}
isPC={false}
isShowResultPanel={true}
onHideResultPanel={onHideResultPanel}
onShowResultPanel={onShowResultPanel}
/>,
)
fireEvent.click(document.querySelector('.cursor-grab') as HTMLElement)
expect(onHideResultPanel).toHaveBeenCalledTimes(1)
rerender(
<TextGenerationResultPanel
{...baseProps}
isPC={false}
isShowResultPanel={false}
onHideResultPanel={onHideResultPanel}
onShowResultPanel={onShowResultPanel}
/>,
)
fireEvent.click(document.querySelector('.cursor-grab') as HTMLElement)
expect(onShowResultPanel).toHaveBeenCalledTimes(1)
})
})