mirror of
https://github.com/langgenius/dify.git
synced 2026-03-04 15:26:21 +08:00
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import type { NamedExoticComponent } from 'react'
|
|
import type { ChatContextValue } from '@/app/components/base/chat/chat/context'
|
|
import { render, screen } from '@testing-library/react'
|
|
import userEvent from '@testing-library/user-event'
|
|
// markdown-button.spec.tsx
|
|
import * as React from 'react'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { ChatContextProvider } from '@/app/components/base/chat/chat/context'
|
|
|
|
import MarkdownButton from './button'
|
|
|
|
// Only mock the URL utility so behavior is deterministic
|
|
const isValidUrlSpy = vi.fn()
|
|
vi.mock('./utils', () => ({
|
|
isValidUrl: (u: string) => isValidUrlSpy(u),
|
|
})) // test subject
|
|
|
|
type TestNode = {
|
|
properties?: {
|
|
dataVariant?: string
|
|
dataMessage?: string
|
|
dataLink?: string
|
|
dataSize?: string
|
|
}
|
|
children?: Array<{ value?: string }>
|
|
}
|
|
|
|
describe('MarkdownButton (integration)', () => {
|
|
const onSendSpy = vi.fn()
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
function renderWithCtx(node: TestNode) {
|
|
// Provide minimal ChatContext; cast to ChatContextValue to satisfy the provider signature
|
|
const ctx = {
|
|
onSend: (msg: unknown) => onSendSpy(msg),
|
|
// other props are optional at runtime; assert type to satisfy TS
|
|
} as unknown as ChatContextValue
|
|
|
|
return render(
|
|
<ChatContextProvider {...ctx}>
|
|
<MarkdownButton node={node as unknown as Record<string, unknown>} />
|
|
</ChatContextProvider>,
|
|
)
|
|
}
|
|
|
|
it('renders button text from node children', () => {
|
|
const node: TestNode = { children: [{ value: 'Click me' }], properties: {} }
|
|
renderWithCtx(node)
|
|
expect(screen.getByRole('button')).toHaveTextContent('Click me')
|
|
})
|
|
|
|
it('opens new tab when link is valid and does not call onSend', async () => {
|
|
isValidUrlSpy.mockReturnValue(true)
|
|
const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null)
|
|
const user = userEvent.setup()
|
|
|
|
const node: TestNode = {
|
|
properties: { dataLink: 'https://example.com' },
|
|
children: [{ value: 'Go' }],
|
|
}
|
|
|
|
renderWithCtx(node)
|
|
await user.click(screen.getByRole('button'))
|
|
|
|
expect(isValidUrlSpy).toHaveBeenCalledWith('https://example.com')
|
|
expect(openSpy).toHaveBeenCalledWith('https://example.com', '_blank')
|
|
expect(onSendSpy).not.toHaveBeenCalled()
|
|
|
|
openSpy.mockRestore()
|
|
})
|
|
|
|
it('calls onSend when link is invalid but message exists', async () => {
|
|
isValidUrlSpy.mockReturnValue(false)
|
|
const user = userEvent.setup()
|
|
|
|
const node: TestNode = {
|
|
properties: { dataLink: 'not-a-url', dataMessage: 'hello!' },
|
|
children: [{ value: 'Send' }],
|
|
}
|
|
|
|
renderWithCtx(node)
|
|
await user.click(screen.getByRole('button'))
|
|
|
|
expect(isValidUrlSpy).toHaveBeenCalledWith('not-a-url')
|
|
expect(onSendSpy).toHaveBeenCalledTimes(1)
|
|
expect(onSendSpy).toHaveBeenCalledWith('hello!')
|
|
})
|
|
|
|
it('does nothing when no link and no message', async () => {
|
|
isValidUrlSpy.mockReturnValue(false)
|
|
const user = userEvent.setup()
|
|
|
|
const node: TestNode = { properties: {}, children: [{ value: 'Empty' }] }
|
|
renderWithCtx(node)
|
|
await user.click(screen.getByRole('button'))
|
|
|
|
expect(isValidUrlSpy).not.toHaveBeenCalled()
|
|
expect(onSendSpy).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('calls onSend when message present and no link', async () => {
|
|
const user = userEvent.setup()
|
|
const node: TestNode = {
|
|
properties: { dataMessage: 'msg-only' },
|
|
children: [{ value: 'Msg' }],
|
|
}
|
|
|
|
renderWithCtx(node)
|
|
await user.click(screen.getByRole('button'))
|
|
|
|
expect(onSendSpy).toHaveBeenCalledWith('msg-only')
|
|
})
|
|
|
|
it('has displayName set to MarkdownButton', () => {
|
|
const comp = MarkdownButton as NamedExoticComponent<{ node: unknown }>
|
|
expect(comp.displayName).toBe('MarkdownButton')
|
|
})
|
|
})
|