mirror of https://github.com/langgenius/dify.git
test: add testcase for config prompt components (#29491)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
1a877bb4d0
commit
6419ce02c7
|
|
@ -0,0 +1,49 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import ConfirmAddVar from './index'
|
||||||
|
|
||||||
|
jest.mock('react-i18next', () => ({
|
||||||
|
useTranslation: () => ({
|
||||||
|
t: (key: string) => key,
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('../../base/var-highlight', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: ({ name }: { name: string }) => <span data-testid="var-highlight">{name}</span>,
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('ConfirmAddVar', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render variable names', () => {
|
||||||
|
render(<ConfirmAddVar varNameArr={['foo', 'bar']} onConfirm={jest.fn()} onCancel={jest.fn()} onHide={jest.fn()} />)
|
||||||
|
|
||||||
|
const highlights = screen.getAllByTestId('var-highlight')
|
||||||
|
expect(highlights).toHaveLength(2)
|
||||||
|
expect(highlights[0]).toHaveTextContent('foo')
|
||||||
|
expect(highlights[1]).toHaveTextContent('bar')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should trigger cancel actions', () => {
|
||||||
|
const onConfirm = jest.fn()
|
||||||
|
const onCancel = jest.fn()
|
||||||
|
render(<ConfirmAddVar varNameArr={['foo']} onConfirm={onConfirm} onCancel={onCancel} onHide={jest.fn()} />)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('common.operation.cancel'))
|
||||||
|
|
||||||
|
expect(onCancel).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should trigger confirm actions', () => {
|
||||||
|
const onConfirm = jest.fn()
|
||||||
|
const onCancel = jest.fn()
|
||||||
|
render(<ConfirmAddVar varNameArr={['foo']} onConfirm={onConfirm} onCancel={onCancel} onHide={jest.fn()} />)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('common.operation.add'))
|
||||||
|
|
||||||
|
expect(onConfirm).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import EditModal from './edit-modal'
|
||||||
|
import type { ConversationHistoriesRole } from '@/models/debug'
|
||||||
|
|
||||||
|
jest.mock('react-i18next', () => ({
|
||||||
|
useTranslation: () => ({
|
||||||
|
t: (key: string) => key,
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('@/app/components/base/modal', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('Conversation history edit modal', () => {
|
||||||
|
const data: ConversationHistoriesRole = {
|
||||||
|
user_prefix: 'user',
|
||||||
|
assistant_prefix: 'assistant',
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render provided prefixes', () => {
|
||||||
|
render(<EditModal isShow saveLoading={false} data={data} onClose={jest.fn()} onSave={jest.fn()} />)
|
||||||
|
|
||||||
|
expect(screen.getByDisplayValue('user')).toBeInTheDocument()
|
||||||
|
expect(screen.getByDisplayValue('assistant')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should update prefixes and save changes', () => {
|
||||||
|
const onSave = jest.fn()
|
||||||
|
render(<EditModal isShow saveLoading={false} data={data} onClose={jest.fn()} onSave={onSave} />)
|
||||||
|
|
||||||
|
fireEvent.change(screen.getByDisplayValue('user'), { target: { value: 'member' } })
|
||||||
|
fireEvent.change(screen.getByDisplayValue('assistant'), { target: { value: 'helper' } })
|
||||||
|
fireEvent.click(screen.getByText('common.operation.save'))
|
||||||
|
|
||||||
|
expect(onSave).toHaveBeenCalledWith({
|
||||||
|
user_prefix: 'member',
|
||||||
|
assistant_prefix: 'helper',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should call close handler', () => {
|
||||||
|
const onClose = jest.fn()
|
||||||
|
render(<EditModal isShow saveLoading={false} data={data} onClose={onClose} onSave={jest.fn()} />)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('common.operation.cancel'))
|
||||||
|
|
||||||
|
expect(onClose).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { render, screen } from '@testing-library/react'
|
||||||
|
import HistoryPanel from './history-panel'
|
||||||
|
|
||||||
|
jest.mock('react-i18next', () => ({
|
||||||
|
useTranslation: () => ({
|
||||||
|
t: (key: string) => key,
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mockDocLink = jest.fn(() => 'doc-link')
|
||||||
|
jest.mock('@/context/i18n', () => ({
|
||||||
|
useDocLink: () => mockDocLink,
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('@/app/components/app/configuration/base/operation-btn', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: ({ onClick }: { onClick: () => void }) => (
|
||||||
|
<button type="button" data-testid="edit-button" onClick={onClick}>
|
||||||
|
edit
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
jest.mock('@/app/components/app/configuration/base/feature-panel', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('HistoryPanel', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render warning content and link when showWarning is true', () => {
|
||||||
|
render(<HistoryPanel showWarning onShowEditModal={jest.fn()} />)
|
||||||
|
|
||||||
|
expect(screen.getByText('appDebug.feature.conversationHistory.tip')).toBeInTheDocument()
|
||||||
|
const link = screen.getByText('appDebug.feature.conversationHistory.learnMore')
|
||||||
|
expect(link).toHaveAttribute('href', 'doc-link')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should hide warning when showWarning is false', () => {
|
||||||
|
render(<HistoryPanel showWarning={false} onShowEditModal={jest.fn()} />)
|
||||||
|
|
||||||
|
expect(screen.queryByText('appDebug.feature.conversationHistory.tip')).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,351 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import Prompt, { type IPromptProps } from './index'
|
||||||
|
import ConfigContext from '@/context/debug-configuration'
|
||||||
|
import { MAX_PROMPT_MESSAGE_LENGTH } from '@/config'
|
||||||
|
import { type PromptItem, PromptRole, type PromptVariable } from '@/models/debug'
|
||||||
|
import { AppModeEnum, ModelModeType } from '@/types/app'
|
||||||
|
|
||||||
|
jest.mock('react-i18next', () => ({
|
||||||
|
useTranslation: () => ({
|
||||||
|
t: (key: string) => key,
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
|
type DebugConfiguration = {
|
||||||
|
isAdvancedMode: boolean
|
||||||
|
currentAdvancedPrompt: PromptItem | PromptItem[]
|
||||||
|
setCurrentAdvancedPrompt: (prompt: PromptItem | PromptItem[], isUserChanged?: boolean) => void
|
||||||
|
modelModeType: ModelModeType
|
||||||
|
dataSets: Array<{
|
||||||
|
id: string
|
||||||
|
name?: string
|
||||||
|
}>
|
||||||
|
hasSetBlockStatus: {
|
||||||
|
context: boolean
|
||||||
|
history: boolean
|
||||||
|
query: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultPromptVariables: PromptVariable[] = [
|
||||||
|
{ key: 'var', name: 'Variable', type: 'string', required: true },
|
||||||
|
]
|
||||||
|
|
||||||
|
let mockSimplePromptInputProps: IPromptProps | null = null
|
||||||
|
|
||||||
|
jest.mock('./simple-prompt-input', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: (props: IPromptProps) => {
|
||||||
|
mockSimplePromptInputProps = props
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-testid="simple-prompt-input"
|
||||||
|
data-mode={props.mode}
|
||||||
|
data-template={props.promptTemplate}
|
||||||
|
data-readonly={props.readonly ?? false}
|
||||||
|
data-no-title={props.noTitle ?? false}
|
||||||
|
data-gradient-border={props.gradientBorder ?? false}
|
||||||
|
data-editor-height={props.editorHeight ?? ''}
|
||||||
|
data-no-resize={props.noResize ?? false}
|
||||||
|
onClick={() => props.onChange?.('mocked prompt', props.promptVariables)}
|
||||||
|
>
|
||||||
|
SimplePromptInput Mock
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
type AdvancedMessageInputProps = {
|
||||||
|
isChatMode: boolean
|
||||||
|
type: PromptRole
|
||||||
|
value: string
|
||||||
|
onTypeChange: (value: PromptRole) => void
|
||||||
|
canDelete: boolean
|
||||||
|
onDelete: () => void
|
||||||
|
onChange: (value: string) => void
|
||||||
|
promptVariables: PromptVariable[]
|
||||||
|
isContextMissing: boolean
|
||||||
|
onHideContextMissingTip: () => void
|
||||||
|
noResize?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.mock('./advanced-prompt-input', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: (props: AdvancedMessageInputProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-testid="advanced-message-input"
|
||||||
|
data-type={props.type}
|
||||||
|
data-value={props.value}
|
||||||
|
data-chat-mode={props.isChatMode}
|
||||||
|
data-can-delete={props.canDelete}
|
||||||
|
data-context-missing={props.isContextMissing}
|
||||||
|
>
|
||||||
|
<button type="button" onClick={() => props.onChange('updated text')}>
|
||||||
|
change
|
||||||
|
</button>
|
||||||
|
<button type="button" onClick={() => props.onTypeChange(PromptRole.assistant)}>
|
||||||
|
type
|
||||||
|
</button>
|
||||||
|
<button type="button" onClick={props.onDelete}>
|
||||||
|
delete
|
||||||
|
</button>
|
||||||
|
<button type="button" onClick={props.onHideContextMissingTip}>
|
||||||
|
hide-context
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
const getContextValue = (overrides: Partial<DebugConfiguration> = {}): DebugConfiguration => {
|
||||||
|
return {
|
||||||
|
setCurrentAdvancedPrompt: jest.fn(),
|
||||||
|
isAdvancedMode: false,
|
||||||
|
currentAdvancedPrompt: [],
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
dataSets: [],
|
||||||
|
hasSetBlockStatus: {
|
||||||
|
context: false,
|
||||||
|
history: false,
|
||||||
|
query: false,
|
||||||
|
},
|
||||||
|
...overrides,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderComponent = (
|
||||||
|
props: Partial<IPromptProps> = {},
|
||||||
|
contextOverrides: Partial<DebugConfiguration> = {},
|
||||||
|
) => {
|
||||||
|
const mergedProps: IPromptProps = {
|
||||||
|
mode: AppModeEnum.CHAT,
|
||||||
|
promptTemplate: 'initial template',
|
||||||
|
promptVariables: defaultPromptVariables,
|
||||||
|
onChange: jest.fn(),
|
||||||
|
...props,
|
||||||
|
}
|
||||||
|
const contextValue = getContextValue(contextOverrides)
|
||||||
|
|
||||||
|
return {
|
||||||
|
contextValue,
|
||||||
|
...render(
|
||||||
|
<ConfigContext.Provider value={contextValue as any}>
|
||||||
|
<Prompt {...mergedProps} />
|
||||||
|
</ConfigContext.Provider>,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Prompt config component', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
mockSimplePromptInputProps = null
|
||||||
|
})
|
||||||
|
|
||||||
|
// Rendering simple mode
|
||||||
|
it('should render simple prompt when advanced mode is disabled', () => {
|
||||||
|
const onChange = jest.fn()
|
||||||
|
renderComponent({ onChange }, { isAdvancedMode: false })
|
||||||
|
|
||||||
|
const simplePrompt = screen.getByTestId('simple-prompt-input')
|
||||||
|
expect(simplePrompt).toBeInTheDocument()
|
||||||
|
expect(simplePrompt).toHaveAttribute('data-mode', AppModeEnum.CHAT)
|
||||||
|
expect(mockSimplePromptInputProps?.promptTemplate).toBe('initial template')
|
||||||
|
fireEvent.click(simplePrompt)
|
||||||
|
expect(onChange).toHaveBeenCalledWith('mocked prompt', defaultPromptVariables)
|
||||||
|
expect(screen.queryByTestId('advanced-message-input')).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Rendering advanced chat messages
|
||||||
|
it('should render advanced chat prompts and show context missing tip when dataset context is not set', () => {
|
||||||
|
const currentAdvancedPrompt: PromptItem[] = [
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
{ role: PromptRole.assistant, text: 'second' },
|
||||||
|
]
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
dataSets: [{ id: 'ds' } as unknown as DebugConfiguration['dataSets'][number]],
|
||||||
|
hasSetBlockStatus: { context: false, history: true, query: true },
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const renderedMessages = screen.getAllByTestId('advanced-message-input')
|
||||||
|
expect(renderedMessages).toHaveLength(2)
|
||||||
|
expect(renderedMessages[0]).toHaveAttribute('data-context-missing', 'true')
|
||||||
|
fireEvent.click(screen.getAllByText('hide-context')[0])
|
||||||
|
expect(screen.getAllByTestId('advanced-message-input')[0]).toHaveAttribute('data-context-missing', 'false')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Chat message mutations
|
||||||
|
it('should update chat prompt value and call setter with user change flag', () => {
|
||||||
|
const currentAdvancedPrompt: PromptItem[] = [
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
{ role: PromptRole.assistant, text: 'second' },
|
||||||
|
]
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getAllByText('change')[0])
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith(
|
||||||
|
[
|
||||||
|
{ role: PromptRole.user, text: 'updated text' },
|
||||||
|
{ role: PromptRole.assistant, text: 'second' },
|
||||||
|
],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should update chat prompt role when type changes', () => {
|
||||||
|
const currentAdvancedPrompt: PromptItem[] = [
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
{ role: PromptRole.user, text: 'second' },
|
||||||
|
]
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getAllByText('type')[1])
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith(
|
||||||
|
[
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
{ role: PromptRole.assistant, text: 'second' },
|
||||||
|
],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should delete chat prompt item', () => {
|
||||||
|
const currentAdvancedPrompt: PromptItem[] = [
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
{ role: PromptRole.assistant, text: 'second' },
|
||||||
|
]
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getAllByText('delete')[0])
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith([{ role: PromptRole.assistant, text: 'second' }])
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add message behavior
|
||||||
|
it('should append a mirrored role message when clicking add in chat mode', () => {
|
||||||
|
const currentAdvancedPrompt: PromptItem[] = [
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
]
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('appDebug.promptMode.operation.addMessage'))
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith([
|
||||||
|
{ role: PromptRole.user, text: 'first' },
|
||||||
|
{ role: PromptRole.assistant, text: '' },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should append a user role when the last chat prompt is from assistant', () => {
|
||||||
|
const currentAdvancedPrompt: PromptItem[] = [
|
||||||
|
{ role: PromptRole.assistant, text: 'reply' },
|
||||||
|
]
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('appDebug.promptMode.operation.addMessage'))
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith([
|
||||||
|
{ role: PromptRole.assistant, text: 'reply' },
|
||||||
|
{ role: PromptRole.user, text: '' },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should insert a system message when adding to an empty chat prompt list', () => {
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt: [],
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('appDebug.promptMode.operation.addMessage'))
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith([{ role: PromptRole.system, text: '' }])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not show add button when reaching max prompt length', () => {
|
||||||
|
const prompts: PromptItem[] = Array.from({ length: MAX_PROMPT_MESSAGE_LENGTH }, (_, index) => ({
|
||||||
|
role: PromptRole.user,
|
||||||
|
text: `item-${index}`,
|
||||||
|
}))
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt: prompts,
|
||||||
|
modelModeType: ModelModeType.chat,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.queryByText('appDebug.promptMode.operation.addMessage')).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Completion mode
|
||||||
|
it('should update completion prompt value and flag as user change', () => {
|
||||||
|
const setCurrentAdvancedPrompt = jest.fn()
|
||||||
|
renderComponent(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
isAdvancedMode: true,
|
||||||
|
currentAdvancedPrompt: { role: PromptRole.user, text: 'single' },
|
||||||
|
modelModeType: ModelModeType.completion,
|
||||||
|
setCurrentAdvancedPrompt,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText('change'))
|
||||||
|
|
||||||
|
expect(setCurrentAdvancedPrompt).toHaveBeenCalledWith({ role: PromptRole.user, text: 'updated text' }, true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import MessageTypeSelector from './message-type-selector'
|
||||||
|
import { PromptRole } from '@/models/debug'
|
||||||
|
|
||||||
|
describe('MessageTypeSelector', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render current value and keep options hidden by default', () => {
|
||||||
|
render(<MessageTypeSelector value={PromptRole.user} onChange={jest.fn()} />)
|
||||||
|
|
||||||
|
expect(screen.getByText(PromptRole.user)).toBeInTheDocument()
|
||||||
|
expect(screen.queryByText(PromptRole.system)).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should toggle option list when clicking the selector', () => {
|
||||||
|
render(<MessageTypeSelector value={PromptRole.system} onChange={jest.fn()} />)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText(PromptRole.system))
|
||||||
|
|
||||||
|
expect(screen.getByText(PromptRole.user)).toBeInTheDocument()
|
||||||
|
expect(screen.getByText(PromptRole.assistant)).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should call onChange with selected type and close the list', () => {
|
||||||
|
const onChange = jest.fn()
|
||||||
|
render(<MessageTypeSelector value={PromptRole.assistant} onChange={onChange} />)
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText(PromptRole.assistant))
|
||||||
|
fireEvent.click(screen.getByText(PromptRole.user))
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith(PromptRole.user)
|
||||||
|
expect(screen.queryByText(PromptRole.system)).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap'
|
||||||
|
|
||||||
|
describe('PromptEditorHeightResizeWrap', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
jest.useFakeTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.runOnlyPendingTimers()
|
||||||
|
jest.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render children, footer, and hide resize handler when requested', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<PromptEditorHeightResizeWrap
|
||||||
|
className="wrapper"
|
||||||
|
height={150}
|
||||||
|
minHeight={100}
|
||||||
|
onHeightChange={jest.fn()}
|
||||||
|
footer={<div>footer</div>}
|
||||||
|
hideResize
|
||||||
|
>
|
||||||
|
<div>content</div>
|
||||||
|
</PromptEditorHeightResizeWrap>,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText('content')).toBeInTheDocument()
|
||||||
|
expect(screen.getByText('footer')).toBeInTheDocument()
|
||||||
|
expect(container.querySelector('.cursor-row-resize')).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should resize height with mouse events and clamp to minHeight', () => {
|
||||||
|
const onHeightChange = jest.fn()
|
||||||
|
|
||||||
|
const { container } = render(
|
||||||
|
<PromptEditorHeightResizeWrap
|
||||||
|
height={150}
|
||||||
|
minHeight={100}
|
||||||
|
onHeightChange={onHeightChange}
|
||||||
|
>
|
||||||
|
<div>content</div>
|
||||||
|
</PromptEditorHeightResizeWrap>,
|
||||||
|
)
|
||||||
|
|
||||||
|
const handle = container.querySelector('.cursor-row-resize')
|
||||||
|
expect(handle).not.toBeNull()
|
||||||
|
|
||||||
|
fireEvent.mouseDown(handle as Element, { clientY: 100 })
|
||||||
|
expect(document.body.style.userSelect).toBe('none')
|
||||||
|
|
||||||
|
fireEvent.mouseMove(document, { clientY: 130 })
|
||||||
|
jest.runAllTimers()
|
||||||
|
expect(onHeightChange).toHaveBeenLastCalledWith(180)
|
||||||
|
|
||||||
|
onHeightChange.mockClear()
|
||||||
|
fireEvent.mouseMove(document, { clientY: -100 })
|
||||||
|
jest.runAllTimers()
|
||||||
|
expect(onHeightChange).toHaveBeenLastCalledWith(100)
|
||||||
|
|
||||||
|
fireEvent.mouseUp(document)
|
||||||
|
expect(document.body.style.userSelect).toBe('')
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue