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:
Novice
2026-03-24 11:19:50 +08:00
294 changed files with 20298 additions and 13491 deletions

View File

@ -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()
})
})