mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
Merge commit 'fb41b215' into sandboxed-agent-rebase
Made-with: Cursor # Conflicts: # .devcontainer/post_create_command.sh # api/commands.py # api/core/agent/cot_agent_runner.py # api/core/agent/fc_agent_runner.py # api/core/app/apps/workflow_app_runner.py # api/core/app/entities/queue_entities.py # api/core/app/entities/task_entities.py # api/core/workflow/workflow_entry.py # api/dify_graph/enums.py # api/dify_graph/graph/graph.py # api/dify_graph/graph_events/node.py # api/dify_graph/model_runtime/entities/message_entities.py # api/dify_graph/node_events/node.py # api/dify_graph/nodes/agent/agent_node.py # api/dify_graph/nodes/base/__init__.py # api/dify_graph/nodes/base/entities.py # api/dify_graph/nodes/base/node.py # api/dify_graph/nodes/llm/entities.py # api/dify_graph/nodes/llm/node.py # api/dify_graph/nodes/tool/tool_node.py # api/pyproject.toml # api/uv.lock # web/app/components/base/avatar/__tests__/index.spec.tsx # web/app/components/base/avatar/index.tsx # web/app/components/base/date-and-time-picker/time-picker/__tests__/index.spec.tsx # web/app/components/base/file-uploader/file-from-link-or-local/index.tsx # web/app/components/base/prompt-editor/index.tsx # web/app/components/datasets/metadata/edit-metadata-batch/modal.tsx # web/app/components/header/account-dropdown/index.spec.tsx # web/app/components/share/text-generation/index.tsx # web/app/components/workflow/block-selector/tool/action-item.tsx # web/app/components/workflow/block-selector/trigger-plugin/action-item.tsx # web/app/components/workflow/hooks/use-edges-interactions.ts # web/app/components/workflow/hooks/use-nodes-interactions.ts # web/app/components/workflow/index.tsx # web/app/components/workflow/nodes/_base/components/editor/code-editor/index.tsx # web/app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx # web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-item.tsx # web/app/components/workflow/nodes/loop/use-interactions.ts # web/contract/router.ts # web/env.ts # web/eslint-suppressions.json # web/package.json # web/pnpm-lock.yaml
This commit is contained in:
@ -134,5 +134,46 @@ describe('ConfigJinaReaderModal Component', () => {
|
||||
resolveSave!({ result: 'success' })
|
||||
await waitFor(() => expect(mockOnSaved).toHaveBeenCalledTimes(1))
|
||||
})
|
||||
|
||||
it('should show encryption info and external link in the modal', async () => {
|
||||
render(<ConfigJinaReaderModal onCancel={mockOnCancel} onSaved={mockOnSaved} />)
|
||||
|
||||
// Verify PKCS1_OAEP link exists
|
||||
const pkcsLink = screen.getByText('PKCS1_OAEP')
|
||||
expect(pkcsLink.closest('a')).toHaveAttribute('href', 'https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html')
|
||||
|
||||
// Verify the Jina Reader external link
|
||||
const jinaLink = screen.getByRole('link', { name: /datasetCreation\.jinaReader\.getApiKeyLinkText/i })
|
||||
expect(jinaLink).toHaveAttribute('target', '_blank')
|
||||
})
|
||||
|
||||
it('should return early when save is clicked while already saving (isSaving guard)', async () => {
|
||||
const user = userEvent.setup()
|
||||
// Arrange - a save that never resolves so isSaving stays true
|
||||
let resolveFirst: (value: { result: 'success' }) => void
|
||||
const neverResolves = new Promise<{ result: 'success' }>((resolve) => {
|
||||
resolveFirst = resolve
|
||||
})
|
||||
vi.mocked(createDataSourceApiKeyBinding).mockReturnValue(neverResolves)
|
||||
render(<ConfigJinaReaderModal onCancel={mockOnCancel} onSaved={mockOnSaved} />)
|
||||
|
||||
const apiKeyInput = screen.getByPlaceholderText('datasetCreation.jinaReader.apiKeyPlaceholder')
|
||||
await user.type(apiKeyInput, 'valid-key')
|
||||
|
||||
const saveBtn = screen.getByRole('button', { name: /common\.operation\.save/i })
|
||||
// First click - starts saving, isSaving becomes true
|
||||
await user.click(saveBtn)
|
||||
expect(createDataSourceApiKeyBinding).toHaveBeenCalledTimes(1)
|
||||
|
||||
// Second click using fireEvent bypasses disabled check - hits isSaving guard
|
||||
const { fireEvent: fe } = await import('@testing-library/react')
|
||||
fe.click(saveBtn)
|
||||
// Still only called once because isSaving=true returns early
|
||||
expect(createDataSourceApiKeyBinding).toHaveBeenCalledTimes(1)
|
||||
|
||||
// Cleanup
|
||||
resolveFirst!({ result: 'success' })
|
||||
await waitFor(() => expect(mockOnSaved).toHaveBeenCalled())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -195,4 +195,57 @@ describe('DataSourceWebsite Component', () => {
|
||||
expect(removeDataSourceApiKeyBinding).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Firecrawl Save Flow', () => {
|
||||
it('should re-fetch sources after saving Firecrawl configuration', async () => {
|
||||
// Arrange
|
||||
await renderAndWait(DataSourceProvider.fireCrawl)
|
||||
fireEvent.click(screen.getByText('common.dataSource.configure'))
|
||||
expect(screen.getByText('datasetCreation.firecrawl.configFirecrawl')).toBeInTheDocument()
|
||||
vi.mocked(fetchDataSources).mockClear()
|
||||
|
||||
// Act - fill in required API key field and save
|
||||
const apiKeyInput = screen.getByPlaceholderText('datasetCreation.firecrawl.apiKeyPlaceholder')
|
||||
fireEvent.change(apiKeyInput, { target: { value: 'test-key' } })
|
||||
fireEvent.click(screen.getByRole('button', { name: /common\.operation\.save/i }))
|
||||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(fetchDataSources).toHaveBeenCalled()
|
||||
expect(screen.queryByText('datasetCreation.firecrawl.configFirecrawl')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Cancel Flow', () => {
|
||||
it('should close watercrawl modal when cancel is clicked', async () => {
|
||||
// Arrange
|
||||
await renderAndWait(DataSourceProvider.waterCrawl)
|
||||
fireEvent.click(screen.getByText('common.dataSource.configure'))
|
||||
expect(screen.getByText('datasetCreation.watercrawl.configWatercrawl')).toBeInTheDocument()
|
||||
|
||||
// Act
|
||||
fireEvent.click(screen.getByRole('button', { name: /common\.operation\.cancel/i }))
|
||||
|
||||
// Assert - modal closed
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('datasetCreation.watercrawl.configWatercrawl')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should close jina reader modal when cancel is clicked', async () => {
|
||||
// Arrange
|
||||
await renderAndWait(DataSourceProvider.jinaReader)
|
||||
fireEvent.click(screen.getByText('common.dataSource.configure'))
|
||||
expect(screen.getByText('datasetCreation.jinaReader.configJinaReader')).toBeInTheDocument()
|
||||
|
||||
// Act
|
||||
fireEvent.click(screen.getByRole('button', { name: /common\.operation\.cancel/i }))
|
||||
|
||||
// Assert - modal closed
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('datasetCreation.jinaReader.configJinaReader')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user