dify/web/app/components/share/text-generation/__tests__/text-generation-result-panel.spec.tsx
Coding On Star 7e1dc3c122
refactor(web): split share text-generation and add high-coverage tests (#33408)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-03-13 19:10:24 +08:00

191 lines
5.7 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.getByText('share.generation.batchFailed.retry')).toBeInTheDocument()
expect(screen.getByRole('status', { name: 'appApi.loading' })).toBeInTheDocument()
fireEvent.click(screen.getByText('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)
})
})