dify/web/app/components/header/account-setting/data-source-page-new/item.spec.tsx
mahammadasim ce8354a42a
test: Add unit tests for Data Source Integrations (Notion, Website) and Modals (#32313)
Co-authored-by: akashseth-ifp <akash.seth@infocusp.com>
2026-02-23 13:00:02 +08:00

154 lines
5.2 KiB
TypeScript

import type { DataSourceCredential } from './types'
import { fireEvent, render, screen } from '@testing-library/react'
import { CredentialTypeEnum } from '@/app/components/plugins/plugin-auth/types'
import Item from './item'
/**
* Item Component Tests
* Using Unit approach to focus on the renaming logic and view state.
*/
// Helper to trigger rename via the real Operator component's dropdown
const triggerRename = async () => {
const dropdownTrigger = screen.getByRole('button')
fireEvent.click(dropdownTrigger)
const renameOption = await screen.findByText('common.operation.rename')
fireEvent.click(renameOption)
}
describe('Item Component', () => {
const mockOnAction = vi.fn()
const mockCredentialItem: DataSourceCredential = {
id: 'test-id',
name: 'Test Credential',
credential: {},
type: CredentialTypeEnum.OAUTH2,
is_default: false,
avatar_url: '',
}
beforeEach(() => {
vi.clearAllMocks()
})
describe('Initial View Mode', () => {
it('should render the credential name and "connected" status', () => {
// Act
render(<Item credentialItem={mockCredentialItem} onAction={mockOnAction} />)
// Assert
expect(screen.getByText('Test Credential')).toBeInTheDocument()
expect(screen.getByText('connected')).toBeInTheDocument()
expect(screen.getByRole('button')).toBeInTheDocument() // Dropdown trigger
})
})
describe('Rename Mode Interactions', () => {
it('should switch to rename mode when Trigger Rename is clicked', async () => {
// Arrange
render(<Item credentialItem={mockCredentialItem} onAction={mockOnAction} />)
// Act
await triggerRename()
expect(screen.getByPlaceholderText('common.placeholder.input')).toBeInTheDocument()
expect(screen.getByText('common.operation.save')).toBeInTheDocument()
expect(screen.getByText('common.operation.cancel')).toBeInTheDocument()
})
it('should update rename input value when changed', async () => {
// Arrange
render(<Item credentialItem={mockCredentialItem} onAction={mockOnAction} />)
await triggerRename()
const input = screen.getByPlaceholderText('common.placeholder.input')
// Act
fireEvent.change(input, { target: { value: 'Updated Name' } })
// Assert
expect(input).toHaveValue('Updated Name')
})
it('should call onAction with "rename" and correct payload when Save is clicked', async () => {
// Arrange
render(<Item credentialItem={mockCredentialItem} onAction={mockOnAction} />)
await triggerRename()
const input = screen.getByPlaceholderText('common.placeholder.input')
fireEvent.change(input, { target: { value: 'New Name' } })
// Act
fireEvent.click(screen.getByText('common.operation.save'))
// Assert
expect(mockOnAction).toHaveBeenCalledWith(
'rename',
mockCredentialItem,
{
credential_id: 'test-id',
name: 'New Name',
},
)
// Should switch back to view mode
expect(screen.queryByPlaceholderText('common.placeholder.input')).not.toBeInTheDocument()
expect(screen.getByText('Test Credential')).toBeInTheDocument()
})
it('should exit rename mode without calling onAction when Cancel is clicked', async () => {
// Arrange
render(<Item credentialItem={mockCredentialItem} onAction={mockOnAction} />)
await triggerRename()
const input = screen.getByPlaceholderText('common.placeholder.input')
fireEvent.change(input, { target: { value: 'Cancelled Name' } })
// Act
fireEvent.click(screen.getByText('common.operation.cancel'))
// Assert
expect(mockOnAction).not.toHaveBeenCalled()
// Should switch back to view mode
expect(screen.queryByPlaceholderText('common.placeholder.input')).not.toBeInTheDocument()
expect(screen.getByText('Test Credential')).toBeInTheDocument()
})
})
describe('Event Bubbling', () => {
it('should stop event propagation when interacting with rename mode elements', async () => {
// Arrange
const parentClick = vi.fn()
render(
<div onClick={parentClick}>
<Item credentialItem={mockCredentialItem} onAction={mockOnAction} />
</div>,
)
// Act & Assert
// We need to enter rename mode first
await triggerRename()
parentClick.mockClear()
fireEvent.click(screen.getByPlaceholderText('common.placeholder.input'))
expect(parentClick).not.toHaveBeenCalled()
fireEvent.click(screen.getByText('common.operation.save'))
expect(parentClick).not.toHaveBeenCalled()
// Re-enter rename mode for cancel test
await triggerRename()
parentClick.mockClear()
fireEvent.click(screen.getByText('common.operation.cancel'))
expect(parentClick).not.toHaveBeenCalled()
})
})
describe('Error Handling', () => {
it('should not throw if onAction is missing', async () => {
// Arrange & Act
// @ts-expect-error - Testing runtime tolerance for missing prop
render(<Item credentialItem={mockCredentialItem} onAction={undefined} />)
await triggerRename()
// Assert
expect(() => fireEvent.click(screen.getByText('common.operation.save'))).not.toThrow()
})
})
})