test(workflow): reorganize specs into __tests__ and align with shared test infrastructure (#33625)

Co-authored-by: CodingOnStar <hanxujiang@dify.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Coding On Star
2026-03-18 16:40:28 +08:00
committed by GitHub
parent 387e5a345f
commit db4deb1d6b
39 changed files with 3538 additions and 203 deletions

View File

@ -1,90 +1,68 @@
import type { WebhookTriggerNodeType } from '../types'
import type { NodePanelProps } from '@/app/components/workflow/types'
import type { PanelProps } from '@/types/workflow'
import { fireEvent, render, screen } from '@testing-library/react'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { BlockEnum } from '@/app/components/workflow/types'
import Panel from '../panel'
const {
mockHandleStatusCodeChange,
mockGenerateWebhookUrl,
mockHandleMethodChange,
mockHandleContentTypeChange,
mockHandleHeadersChange,
mockHandleParamsChange,
mockHandleBodyChange,
mockHandleResponseBodyChange,
} = vi.hoisted(() => ({
mockHandleStatusCodeChange: vi.fn(),
mockGenerateWebhookUrl: vi.fn(),
mockHandleMethodChange: vi.fn(),
mockHandleContentTypeChange: vi.fn(),
mockHandleHeadersChange: vi.fn(),
mockHandleParamsChange: vi.fn(),
mockHandleBodyChange: vi.fn(),
mockHandleResponseBodyChange: vi.fn(),
}))
const mockConfigState = {
readOnly: false,
inputs: {
method: 'POST',
webhook_url: 'https://example.com/webhook',
webhook_debug_url: '',
content_type: 'application/json',
headers: [],
params: [],
body: [],
status_code: 200,
response_body: 'ok',
variables: [],
},
}
vi.mock('../use-config', () => ({
DEFAULT_STATUS_CODE: 200,
MAX_STATUS_CODE: 399,
normalizeStatusCode: (statusCode: number) => Math.min(Math.max(statusCode, 200), 399),
useConfig: () => ({
readOnly: false,
inputs: {
method: 'POST',
webhook_url: 'https://example.com/webhook',
webhook_debug_url: '',
content_type: 'application/json',
headers: [],
params: [],
body: [],
status_code: 200,
response_body: '',
},
handleMethodChange: vi.fn(),
handleContentTypeChange: vi.fn(),
handleHeadersChange: vi.fn(),
handleParamsChange: vi.fn(),
handleBodyChange: vi.fn(),
readOnly: mockConfigState.readOnly,
inputs: mockConfigState.inputs,
handleMethodChange: mockHandleMethodChange,
handleContentTypeChange: mockHandleContentTypeChange,
handleHeadersChange: mockHandleHeadersChange,
handleParamsChange: mockHandleParamsChange,
handleBodyChange: mockHandleBodyChange,
handleStatusCodeChange: mockHandleStatusCodeChange,
handleResponseBodyChange: vi.fn(),
handleResponseBodyChange: mockHandleResponseBodyChange,
generateWebhookUrl: mockGenerateWebhookUrl,
}),
}))
vi.mock('@/app/components/base/input-with-copy', () => ({
default: () => <div data-testid="input-with-copy" />,
}))
vi.mock('@/app/components/base/select', () => ({
SimpleSelect: () => <div data-testid="simple-select" />,
}))
vi.mock('@/app/components/base/tooltip', () => ({
default: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}))
vi.mock('@/app/components/workflow/nodes/_base/components/field', () => ({
default: ({ title, children }: { title: React.ReactNode, children: React.ReactNode }) => (
<section>
<div>{title}</div>
{children}
</section>
),
}))
vi.mock('@/app/components/workflow/nodes/_base/components/output-vars', () => ({
default: () => <div data-testid="output-vars" />,
}))
vi.mock('@/app/components/workflow/nodes/_base/components/split', () => ({
default: () => <div data-testid="split" />,
}))
vi.mock('../components/header-table', () => ({
default: () => <div data-testid="header-table" />,
}))
vi.mock('../components/parameter-table', () => ({
default: () => <div data-testid="parameter-table" />,
}))
vi.mock('../components/paragraph-input', () => ({
default: () => <div data-testid="paragraph-input" />,
}))
vi.mock('../utils/render-output-vars', () => ({
OutputVariablesContent: () => <div data-testid="output-variables-content" />,
}))
const getStatusCodeInput = () => {
return screen.getAllByDisplayValue('200')
.find(element => element.getAttribute('aria-hidden') !== 'true') as HTMLInputElement
}
describe('WebhookTriggerPanel', () => {
const panelProps: NodePanelProps<WebhookTriggerNodeType> = {
@ -100,7 +78,7 @@ describe('WebhookTriggerPanel', () => {
body: [],
async_mode: false,
status_code: 200,
response_body: '',
response_body: 'ok',
variables: [],
},
panelProps: {} as PanelProps,
@ -108,26 +86,65 @@ describe('WebhookTriggerPanel', () => {
beforeEach(() => {
vi.clearAllMocks()
mockConfigState.readOnly = false
mockConfigState.inputs = {
method: 'POST',
webhook_url: 'https://example.com/webhook',
webhook_debug_url: '',
content_type: 'application/json',
headers: [],
params: [],
body: [],
status_code: 200,
response_body: 'ok',
variables: [],
}
})
it('should update the status code when users enter a parseable value', () => {
render(<Panel {...panelProps} />)
describe('Rendering', () => {
it('should render the real panel fields without generating a new webhook url when one already exists', () => {
render(<Panel {...panelProps} />)
fireEvent.change(screen.getByRole('textbox'), { target: { value: '201' } })
expect(screen.getByDisplayValue('https://example.com/webhook')).toBeInTheDocument()
expect(screen.getByText('application/json')).toBeInTheDocument()
expect(screen.getByDisplayValue('ok')).toBeInTheDocument()
expect(mockGenerateWebhookUrl).not.toHaveBeenCalled()
})
expect(mockHandleStatusCodeChange).toHaveBeenCalledWith(201)
it('should request a webhook url when the node is writable and missing one', async () => {
mockConfigState.inputs = {
...mockConfigState.inputs,
webhook_url: '',
}
render(<Panel {...panelProps} />)
await waitFor(() => {
expect(mockGenerateWebhookUrl).toHaveBeenCalledTimes(1)
})
})
})
it('should ignore clear changes until the value is committed', () => {
render(<Panel {...panelProps} />)
describe('Status Code Input', () => {
it('should update the status code when users enter a parseable value', () => {
render(<Panel {...panelProps} />)
const input = screen.getByRole('textbox')
fireEvent.change(input, { target: { value: '' } })
fireEvent.change(getStatusCodeInput(), { target: { value: '201' } })
expect(mockHandleStatusCodeChange).not.toHaveBeenCalled()
expect(mockHandleStatusCodeChange).toHaveBeenCalledWith(201)
})
fireEvent.blur(input)
it('should ignore clear changes until the value is committed', () => {
render(<Panel {...panelProps} />)
expect(mockHandleStatusCodeChange).toHaveBeenCalledWith(200)
const input = getStatusCodeInput()
fireEvent.change(input, { target: { value: '' } })
expect(mockHandleStatusCodeChange).not.toHaveBeenCalled()
fireEvent.blur(input)
expect(mockHandleStatusCodeChange).toHaveBeenCalledWith(200)
})
})
})