mirror of
https://github.com/langgenius/dify.git
synced 2026-04-20 22:28:09 +08:00
Co-authored-by: CodingOnStar <hanxujiang@dify.ai> Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
396 lines
11 KiB
TypeScript
396 lines
11 KiB
TypeScript
import type { MetadataItemWithEdit } from '../types'
|
|
import { fireEvent, render, screen } from '@testing-library/react'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
import { DataType, UpdateType } from '../types'
|
|
import EditMetadatabatchItem from './edit-row'
|
|
|
|
type InputCombinedProps = {
|
|
type: DataType
|
|
value: string | number | null
|
|
onChange: (value: string | number) => void
|
|
readOnly?: boolean
|
|
}
|
|
|
|
type MultipleValueInputProps = {
|
|
onClear: () => void
|
|
readOnly?: boolean
|
|
}
|
|
|
|
type LabelProps = {
|
|
text: string
|
|
isDeleted?: boolean
|
|
}
|
|
|
|
type EditedBeaconProps = {
|
|
onReset: () => void
|
|
}
|
|
|
|
// Mock InputCombined component
|
|
vi.mock('./input-combined', () => ({
|
|
default: ({ type, value, onChange, readOnly }: InputCombinedProps) => (
|
|
<input
|
|
data-testid="input-combined"
|
|
data-type={type}
|
|
value={value || ''}
|
|
onChange={e => onChange(e.target.value)}
|
|
readOnly={readOnly}
|
|
/>
|
|
),
|
|
}))
|
|
|
|
// Mock InputHasSetMultipleValue component
|
|
vi.mock('./input-has-set-multiple-value', () => ({
|
|
default: ({ onClear, readOnly }: MultipleValueInputProps) => (
|
|
<div data-testid="multiple-value-input" data-readonly={readOnly}>
|
|
<button data-testid="clear-multiple" onClick={onClear}>Clear Multiple</button>
|
|
</div>
|
|
),
|
|
}))
|
|
|
|
// Mock Label component
|
|
vi.mock('./label', () => ({
|
|
default: ({ text, isDeleted }: LabelProps) => (
|
|
<div data-testid="label" data-deleted={isDeleted}>{text}</div>
|
|
),
|
|
}))
|
|
|
|
// Mock EditedBeacon component
|
|
vi.mock('./edited-beacon', () => ({
|
|
default: ({ onReset }: EditedBeaconProps) => (
|
|
<button data-testid="edited-beacon" onClick={onReset}>Reset</button>
|
|
),
|
|
}))
|
|
|
|
describe('EditMetadatabatchItem', () => {
|
|
const mockPayload: MetadataItemWithEdit = {
|
|
id: 'test-id',
|
|
name: 'test_field',
|
|
type: DataType.string,
|
|
value: 'test value',
|
|
isMultipleValue: false,
|
|
isUpdated: false,
|
|
}
|
|
|
|
describe('Rendering', () => {
|
|
it('should render without crashing', () => {
|
|
const { container } = render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(container.firstChild).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render label with payload name', () => {
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('label')).toHaveTextContent('test_field')
|
|
})
|
|
|
|
it('should render input combined for single value', () => {
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('input-combined')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render multiple value input when isMultipleValue is true', () => {
|
|
const multiplePayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
isMultipleValue: true,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={multiplePayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('multiple-value-input')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should render delete button icon', () => {
|
|
const { container } = render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
const svg = container.querySelector('svg')
|
|
expect(svg).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Updated State', () => {
|
|
it('should show edited beacon when isUpdated is true', () => {
|
|
const updatedPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
isUpdated: true,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={updatedPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('edited-beacon')).toBeInTheDocument()
|
|
})
|
|
|
|
it('should not show edited beacon when isUpdated is false', () => {
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.queryByTestId('edited-beacon')).not.toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('Deleted State', () => {
|
|
it('should pass isDeleted to label when updateType is delete', () => {
|
|
const deletedPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
updateType: UpdateType.delete,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={deletedPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('label')).toHaveAttribute('data-deleted', 'true')
|
|
})
|
|
|
|
it('should set readOnly on input when deleted', () => {
|
|
const deletedPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
updateType: UpdateType.delete,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={deletedPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('input-combined')).toHaveAttribute('readonly')
|
|
})
|
|
|
|
it('should have destructive styling on delete button when deleted', () => {
|
|
const deletedPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
updateType: UpdateType.delete,
|
|
}
|
|
const { container } = render(
|
|
<EditMetadatabatchItem
|
|
payload={deletedPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
const deleteButton = container.querySelector('.bg-state-destructive-hover')
|
|
expect(deleteButton).toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('User Interactions', () => {
|
|
it('should call onChange with updated payload when input changes', () => {
|
|
const handleChange = vi.fn()
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={handleChange}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
|
|
fireEvent.change(screen.getByTestId('input-combined'), { target: { value: 'new value' } })
|
|
|
|
expect(handleChange).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
...mockPayload,
|
|
value: 'new value',
|
|
}),
|
|
)
|
|
})
|
|
|
|
it('should call onRemove with id when delete button is clicked', () => {
|
|
const handleRemove = vi.fn()
|
|
const { container } = render(
|
|
<EditMetadatabatchItem
|
|
payload={mockPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={handleRemove}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
|
|
const deleteButton = container.querySelector('.cursor-pointer')
|
|
if (deleteButton)
|
|
fireEvent.click(deleteButton)
|
|
|
|
expect(handleRemove).toHaveBeenCalledWith('test-id')
|
|
})
|
|
|
|
it('should call onReset with id when reset beacon is clicked', () => {
|
|
const handleReset = vi.fn()
|
|
const updatedPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
isUpdated: true,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={updatedPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={handleReset}
|
|
/>,
|
|
)
|
|
|
|
fireEvent.click(screen.getByTestId('edited-beacon'))
|
|
|
|
expect(handleReset).toHaveBeenCalledWith('test-id')
|
|
})
|
|
|
|
it('should call onChange to clear multiple value', () => {
|
|
const handleChange = vi.fn()
|
|
const multiplePayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
isMultipleValue: true,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={multiplePayload}
|
|
onChange={handleChange}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
|
|
fireEvent.click(screen.getByTestId('clear-multiple'))
|
|
|
|
expect(handleChange).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
value: null,
|
|
isMultipleValue: false,
|
|
}),
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('Multiple Value State', () => {
|
|
it('should render multiple value input when isMultipleValue is true', () => {
|
|
const multiplePayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
isMultipleValue: true,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={multiplePayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('multiple-value-input')).toBeInTheDocument()
|
|
expect(screen.queryByTestId('input-combined')).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('should pass readOnly to multiple value input when deleted', () => {
|
|
const multipleDeletedPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
isMultipleValue: true,
|
|
updateType: UpdateType.delete,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={multipleDeletedPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('multiple-value-input')).toHaveAttribute('data-readonly', 'true')
|
|
})
|
|
})
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle payload with number type', () => {
|
|
const numberPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
type: DataType.number,
|
|
value: 42,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={numberPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('input-combined')).toHaveAttribute('data-type', DataType.number)
|
|
})
|
|
|
|
it('should handle payload with time type', () => {
|
|
const timePayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
type: DataType.time,
|
|
value: 1609459200,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={timePayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('input-combined')).toHaveAttribute('data-type', DataType.time)
|
|
})
|
|
|
|
it('should handle null value', () => {
|
|
const nullPayload: MetadataItemWithEdit = {
|
|
...mockPayload,
|
|
value: null,
|
|
}
|
|
render(
|
|
<EditMetadatabatchItem
|
|
payload={nullPayload}
|
|
onChange={vi.fn()}
|
|
onRemove={vi.fn()}
|
|
onReset={vi.fn()}
|
|
/>,
|
|
)
|
|
expect(screen.getByTestId('input-combined')).toBeInTheDocument()
|
|
})
|
|
})
|
|
})
|