mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
Merge branch 'main' into sandboxed-agent-rebase
Made-with: Cursor # Conflicts: # api/tests/unit_tests/controllers/console/app/test_message.py # api/tests/unit_tests/controllers/console/app/test_statistic.py # api/tests/unit_tests/controllers/console/app/test_workflow_draft_variable.py # api/tests/unit_tests/controllers/console/auth/test_data_source_bearer_auth.py # api/tests/unit_tests/controllers/console/auth/test_data_source_oauth.py # api/tests/unit_tests/controllers/console/auth/test_oauth_server.py # web/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx # web/app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx # web/app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx # web/app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx # web/app/components/header/account-setting/data-source-page/panel/config-item.tsx # web/app/components/header/account-setting/data-source-page/panel/index.tsx # web/app/components/workflow/nodes/knowledge-retrieval/node.tsx # web/package.json # web/pnpm-lock.yaml
This commit is contained in:
@ -0,0 +1,204 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import type { DocExtractorNodeType } from '../types'
|
||||
import type { PanelProps } from '@/types/workflow'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { LanguagesSupported } from '@/i18n-config/language'
|
||||
import { BlockEnum } from '../../../types'
|
||||
import Node from '../node'
|
||||
import Panel from '../panel'
|
||||
import useConfig from '../use-config'
|
||||
|
||||
let mockLocale = 'en-US'
|
||||
|
||||
vi.mock('reactflow', async () => {
|
||||
const actual = await vi.importActual<typeof import('reactflow')>('reactflow')
|
||||
return {
|
||||
...actual,
|
||||
useNodes: () => [
|
||||
{
|
||||
id: 'node-1',
|
||||
data: {
|
||||
title: 'Input Files',
|
||||
type: BlockEnum.Start,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/variable/variable-label', () => ({
|
||||
VariableLabelInNode: ({
|
||||
variables,
|
||||
nodeTitle,
|
||||
nodeType,
|
||||
}: {
|
||||
variables: string[]
|
||||
nodeTitle?: string
|
||||
nodeType?: BlockEnum
|
||||
}) => <div>{`${nodeTitle}:${nodeType}:${variables.join('.')}`}</div>,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/field', () => ({
|
||||
__esModule: true,
|
||||
default: ({ title, children }: { title: ReactNode, children: ReactNode }) => (
|
||||
<div>
|
||||
<div>{title}</div>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/output-vars', () => ({
|
||||
__esModule: true,
|
||||
default: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
||||
VarItem: ({ name, type }: { name: string, type: string }) => <div>{`${name}:${type}`}</div>,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/split', () => ({
|
||||
__esModule: true,
|
||||
default: () => <div>split</div>,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-reference-picker', () => ({
|
||||
__esModule: true,
|
||||
default: ({
|
||||
onChange,
|
||||
}: {
|
||||
onChange: (value: string[]) => void
|
||||
}) => <button type="button" onClick={() => onChange(['node-1', 'files'])}>pick-file-var</button>,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/hooks/use-node-help-link', () => ({
|
||||
useNodeHelpLink: () => 'https://docs.example.com/document-extractor',
|
||||
}))
|
||||
|
||||
vi.mock('@/service/use-common', () => ({
|
||||
useFileSupportTypes: () => ({
|
||||
data: {
|
||||
allowed_extensions: ['PDF', 'md', 'md', 'DOCX'],
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/i18n', () => ({
|
||||
useLocale: () => mockLocale,
|
||||
}))
|
||||
|
||||
vi.mock('../use-config', () => ({
|
||||
__esModule: true,
|
||||
default: vi.fn(),
|
||||
}))
|
||||
|
||||
const mockUseConfig = vi.mocked(useConfig)
|
||||
|
||||
const createData = (overrides: Partial<DocExtractorNodeType> = {}): DocExtractorNodeType => ({
|
||||
title: 'Document Extractor',
|
||||
desc: '',
|
||||
type: BlockEnum.DocExtractor,
|
||||
variable_selector: ['node-1', 'files'],
|
||||
is_array_file: false,
|
||||
...overrides,
|
||||
})
|
||||
|
||||
const createConfigResult = (overrides: Partial<ReturnType<typeof useConfig>> = {}): ReturnType<typeof useConfig> => ({
|
||||
readOnly: false,
|
||||
inputs: createData(),
|
||||
handleVarChanges: vi.fn(),
|
||||
filterVar: () => true,
|
||||
...overrides,
|
||||
})
|
||||
|
||||
const panelProps: PanelProps = {
|
||||
getInputVars: vi.fn(() => []),
|
||||
toVarInputs: vi.fn(() => []),
|
||||
runInputData: {},
|
||||
runInputDataRef: { current: {} },
|
||||
setRunInputData: vi.fn(),
|
||||
runResult: null,
|
||||
}
|
||||
|
||||
describe('document-extractor path', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockLocale = 'en-US'
|
||||
mockUseConfig.mockReturnValue(createConfigResult())
|
||||
})
|
||||
|
||||
it('should render nothing when the node input variable is not configured', () => {
|
||||
const { container } = render(
|
||||
<Node
|
||||
id="doc-node"
|
||||
data={createData({
|
||||
variable_selector: [],
|
||||
})}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(container).toBeEmptyDOMElement()
|
||||
})
|
||||
|
||||
it('should render the selected input variable on the node', () => {
|
||||
render(
|
||||
<Node
|
||||
id="doc-node"
|
||||
data={createData()}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('workflow.nodes.docExtractor.inputVar')).toBeInTheDocument()
|
||||
expect(screen.getByText('Input Files:start:node-1.files')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should wire panel input changes and format supported file types for english locales', async () => {
|
||||
const user = userEvent.setup()
|
||||
const handleVarChanges = vi.fn()
|
||||
|
||||
mockUseConfig.mockReturnValueOnce(createConfigResult({
|
||||
inputs: createData({
|
||||
is_array_file: false,
|
||||
}),
|
||||
handleVarChanges,
|
||||
}))
|
||||
|
||||
render(
|
||||
<Panel
|
||||
id="doc-node"
|
||||
data={createData()}
|
||||
panelProps={panelProps}
|
||||
/>,
|
||||
)
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'pick-file-var' }))
|
||||
|
||||
expect(handleVarChanges).toHaveBeenCalledWith(['node-1', 'files'])
|
||||
expect(screen.getByText('workflow.nodes.docExtractor.supportFileTypes:{"types":"pdf, markdown, docx"}')).toBeInTheDocument()
|
||||
expect(screen.getByRole('link', { name: 'workflow.nodes.docExtractor.learnMore' })).toHaveAttribute(
|
||||
'href',
|
||||
'https://docs.example.com/document-extractor',
|
||||
)
|
||||
expect(screen.getByText('text:string')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should use chinese separators and array output types when the input is an array of files', () => {
|
||||
mockLocale = LanguagesSupported[1]
|
||||
mockUseConfig.mockReturnValueOnce(createConfigResult({
|
||||
inputs: createData({
|
||||
is_array_file: true,
|
||||
}),
|
||||
}))
|
||||
|
||||
render(
|
||||
<Panel
|
||||
id="doc-node"
|
||||
data={createData({
|
||||
is_array_file: true,
|
||||
})}
|
||||
panelProps={panelProps}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('workflow.nodes.docExtractor.supportFileTypes:{"types":"pdf、 markdown、 docx"}')).toBeInTheDocument()
|
||||
expect(screen.getByText('text:array[string]')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user