From e0af6d07aab648893cfedd0b6413ab2c2aef8f72 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Thu, 29 Oct 2026 03:27:11 +0000 Subject: [PATCH] test(web): replace fake workflow controls with behavioral tests (#45025) --- .../variable/__tests__/var-list.spec.tsx | 330 ++++++++------- .../__tests__/method-item.spec.tsx | 386 +++++++++--------- .../__tests__/panel-memory-section.spec.tsx | 198 +++++---- .../components/__tests__/var-item.spec.tsx | 66 ++- 4 files changed, 540 insertions(+), 440 deletions(-) diff --git a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-list.spec.tsx b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-list.spec.tsx index c8fde76a771..c37c9bbd244 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-list.spec.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/__tests__/var-list.spec.tsx @@ -1,163 +1,201 @@ +import type { CodeNodeType } from '@/app/components/workflow/nodes/code/types' import type { Variable } from '@/app/components/workflow/types' -import { render, screen } from '@testing-library/react' +import { screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { useState } from 'react' -import { VarType } from '@/app/components/workflow/types' +import { createEdge, createNode } from '@/app/components/workflow/__tests__/fixtures' +import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' +import { BlockEnum, VarType } from '@/app/components/workflow/types' +import { renderWorkflowEditor } from '@/test/workflow-editor' import VarList from '../var-list' -vi.mock('../var-reference-picker', () => ({ - default: () => , +const initialVariables: Variable[] = ['alpha', 'beta', 'gamma'].map((variable) => ({ + variable, + value_selector: ['source', variable], + value_type: VarType.string, })) +function SortableVariables({ + initial = initialVariables, + readonly = false, +}: { + initial?: Variable[] + readonly?: boolean +}) { + const [variables, setVariables] = useState(initial) + return ( + <> + + {JSON.stringify(variables)} + + ) +} + +const renderVariables = (props: Parameters[0] = {}) => { + const sourceData: CodeNodeType = { + title: 'Source', + desc: '', + type: BlockEnum.Code, + code_language: CodeLanguage.javascript, + code: 'function main() { return {} }', + variables: [], + outputs: Object.fromEntries( + initialVariables.map(({ variable }) => [variable, { type: VarType.string, children: null }]), + ), + } + const source = createNode({ + id: 'source', + data: sourceData, + }) + const consumerData: CodeNodeType = { + title: 'Consumer', + desc: '', + type: BlockEnum.Code, + code_language: CodeLanguage.javascript, + code: 'function main() { return {} }', + variables: initialVariables, + outputs: {}, + } + const consumer = createNode({ id: 'consumer', data: consumerData }) + return renderWorkflowEditor(, { + nodes: [source, consumer], + edges: [ + createEdge({ + source: 'source', + target: 'consumer', + data: { sourceType: BlockEnum.Code, targetType: BlockEnum.Code }, + }), + ], + initialStoreState: { isWorkflowDataLoaded: true }, + reactFlowProps: { + edgesFocusable: false, + nodesFocusable: false, + proOptions: { hideAttribution: true }, + }, + }) +} + +const savedVariables = () => screen.getByRole('status', { name: 'Saved variables' }) + describe('VarList', () => { it('normalizes a variable name through its labeled input', async () => { const user = userEvent.setup() - const onChange = vi.fn() - - function EditableVariable() { - const [list, setList] = useState([ - { - variable: 'input', - value_selector: ['node-id', 'value'], - value_type: VarType.string, - }, - ]) - return ( - { - setList(next) - onChange(next) - }} - /> - ) - } - render() + renderVariables({ initial: [initialVariables[0]!] }) const input = screen.getByRole('textbox', { name: 'workflow.common.variableNamePlaceholder' }) await user.clear(input) await user.paste('renamed input') - expect(onChange).toHaveBeenCalledWith([expect.objectContaining({ variable: 'renamed_input' })]) + expect(savedVariables()).toHaveTextContent( + JSON.stringify([{ ...initialVariables[0], variable: 'renamed_input' }]), + ) + }) + + it('tabs through each variable from the reorder handle to its name, value actions and remove button', async () => { + const user = userEvent.setup() + renderVariables() + const handles = screen.getAllByRole('button', { pressed: false }) + const names = screen.getAllByRole('textbox', { + name: 'workflow.common.variableNamePlaceholder', + }) + const values = initialVariables.map(({ variable }) => + screen.getByRole('button', { name: new RegExp(`Source.*${variable}.*string`) }), + ) + const clearButtons = screen.getAllByRole('button', { name: 'common.operation.clear' }) + const pickerFocusTargets = screen.getAllByRole('textbox', { name: '' }) + const removeButtons = screen.getAllByRole('button', { name: 'common.operation.remove' }) + + for (let index = 0; index < initialVariables.length; index++) { + for (const control of [ + handles[index], + names[index], + values[index], + clearButtons[index], + pickerFocusTargets[index], + removeButtons[index], + ]) { + await user.tab() + expect(control).toHaveFocus() + } + } + + await user.tab({ shift: true }) + expect(pickerFocusTargets[2]).toHaveFocus() + await user.tab({ shift: true }) + expect(clearButtons[2]).toHaveFocus() + await user.tab({ shift: true }) + expect(values[2]).toHaveFocus() + await user.tab({ shift: true }) + expect(names[2]).toHaveFocus() + await user.tab({ shift: true }) + expect(handles[2]).toHaveFocus() + }) + + it('previews variable ordering, commits only on confirmation, and keeps the moved handle focused', async () => { + const user = userEvent.setup() + renderVariables() + const handle = screen.getAllByRole('button', { pressed: false })[0]! + await user.tab() + expect(handle).toHaveFocus() + await user.keyboard('{Enter}{ArrowDown}') + expect( + screen + .getAllByRole('textbox', { name: 'workflow.common.variableNamePlaceholder' }) + .map((input) => (input as HTMLInputElement).value), + ).toEqual(['beta', 'alpha', 'gamma']) + expect(savedVariables()).toHaveTextContent(JSON.stringify(initialVariables)) + expect(screen.getByRole('button', { pressed: true })).toHaveFocus() + await user.keyboard('{Enter}') + expect(savedVariables()).toHaveTextContent( + JSON.stringify([initialVariables[1], initialVariables[0], initialVariables[2]]), + ) + expect(screen.getAllByRole('button', { pressed: false })[1]).toHaveFocus() + }) + + it('cancels a variable reorder and leaves arrow keys inside name inputs available for editing', async () => { + const user = userEvent.setup() + renderVariables() + await user.tab() + await user.tab() + expect( + screen.getAllByRole('textbox', { name: 'workflow.common.variableNamePlaceholder' })[0], + ).toHaveFocus() + await user.keyboard('{ArrowDown}') + expect(savedVariables()).toHaveTextContent(JSON.stringify(initialVariables)) + const handle = screen.getAllByRole('button', { pressed: false })[0]! + await user.tab({ shift: true }) + expect(handle).toHaveFocus() + await user.keyboard(' {ArrowDown}{Escape}') + expect( + screen + .getAllByRole('textbox', { name: 'workflow.common.variableNamePlaceholder' }) + .map((input) => (input as HTMLInputElement).value), + ).toEqual(['alpha', 'beta', 'gamma']) + expect(savedVariables()).toHaveTextContent(JSON.stringify(initialVariables)) + expect(handle).toHaveFocus() + }) + + it('does not expose variable sorting in readonly mode', () => { + renderVariables({ readonly: true }) + expect(screen.queryByRole('button', { pressed: false })).not.toBeInTheDocument() + expect(savedVariables()).toHaveTextContent(JSON.stringify(initialVariables)) + }) + + it('cancels a preview before deleting the variable whose remove button was activated', async () => { + const user = userEvent.setup() + renderVariables() + const handle = screen.getAllByRole('button', { pressed: false })[0]! + await user.tab() + expect(handle).toHaveFocus() + await user.keyboard('{Enter}{ArrowDown}') + await user.click(screen.getAllByRole('button', { name: 'common.operation.remove' })[1]!) + expect(savedVariables()).toHaveTextContent( + JSON.stringify([initialVariables[1], initialVariables[2]]), + ) + expect( + screen + .getAllByRole('textbox', { name: 'workflow.common.variableNamePlaceholder' }) + .map((input) => (input as HTMLInputElement).value), + ).toEqual(['beta', 'gamma']) }) }) - -const initialVariables: Variable[] = ['alpha', 'beta', 'gamma'].map((variable) => ({ - variable, - value_selector: ['node-id', variable], - value_type: VarType.string, -})) - -function SortableVariables({ - onChange, - readonly = false, -}: { - onChange: (items: Variable[]) => void - readonly?: boolean -}) { - const [variables, setVariables] = useState(initialVariables) - return ( - { - onChange(items) - setVariables(items) - }} - /> - ) -} - -it('tabs through each variable from the reorder handle to its name, value and remove button', async () => { - const user = userEvent.setup() - render() - const handles = screen.getAllByRole('button', { pressed: false }) - const names = screen.getAllByRole('textbox') - const values = screen.getAllByRole('button', { name: 'Variable value' }) - const removeButtons = screen.getAllByRole('button', { name: 'common.operation.remove' }) - - for (let index = 0; index < initialVariables.length; index++) { - for (const control of [handles[index], names[index], values[index], removeButtons[index]]) { - await user.tab() - expect(control).toHaveFocus() - } - } - - await user.tab({ shift: true }) - expect(values[2]).toHaveFocus() - await user.tab({ shift: true }) - expect(names[2]).toHaveFocus() - await user.tab({ shift: true }) - expect(handles[2]).toHaveFocus() -}) - -it('previews variable ordering, commits only on confirmation, and keeps the moved handle focused', async () => { - const user = userEvent.setup() - const onChange = vi.fn() - render() - expect(onChange).not.toHaveBeenCalled() - const handle = screen.getAllByRole('button', { pressed: false })[0]! - await user.tab() - expect(handle).toHaveFocus() - await user.keyboard('{Enter}{ArrowDown}') - expect(screen.getAllByRole('textbox').map((input) => (input as HTMLInputElement).value)).toEqual([ - 'beta', - 'alpha', - 'gamma', - ]) - expect(onChange).not.toHaveBeenCalled() - expect(screen.getByRole('button', { pressed: true })).toHaveFocus() - await user.keyboard('{Enter}') - expect(onChange).toHaveBeenCalledExactlyOnceWith([ - initialVariables[1], - initialVariables[0], - initialVariables[2], - ]) - expect(screen.getAllByRole('button', { pressed: false })[1]).toHaveFocus() -}) - -it('cancels a variable reorder and leaves arrow keys inside name inputs available for editing', async () => { - const user = userEvent.setup() - const onChange = vi.fn() - render() - await user.tab() - await user.tab() - expect(screen.getAllByRole('textbox')[0]).toHaveFocus() - await user.keyboard('{ArrowDown}') - expect(onChange).not.toHaveBeenCalled() - const handle = screen.getAllByRole('button', { pressed: false })[0]! - await user.tab({ shift: true }) - expect(handle).toHaveFocus() - await user.keyboard(' {ArrowDown}{Escape}') - expect(screen.getAllByRole('textbox').map((input) => (input as HTMLInputElement).value)).toEqual([ - 'alpha', - 'beta', - 'gamma', - ]) - expect(onChange).not.toHaveBeenCalled() - expect(handle).toHaveFocus() -}) - -it('does not expose variable sorting in readonly mode', () => { - render() - expect(screen.queryByRole('button', { pressed: false })).not.toBeInTheDocument() -}) - -it('cancels a preview before deleting the variable whose remove button was activated', async () => { - const user = userEvent.setup() - const onChange = vi.fn() - render() - const handle = screen.getAllByRole('button', { pressed: false })[0]! - await user.tab() - expect(handle).toHaveFocus() - await user.keyboard('{Enter}{ArrowDown}') - await user.click(screen.getAllByRole('button', { name: 'common.operation.remove' })[1]!) - expect(onChange).toHaveBeenCalledExactlyOnceWith([initialVariables[1], initialVariables[2]]) - expect(screen.getAllByRole('textbox').map((input) => (input as HTMLInputElement).value)).toEqual([ - 'beta', - 'gamma', - ]) -}) diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/__tests__/method-item.spec.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/__tests__/method-item.spec.tsx index f86f7e738fe..bdec2ff4dbc 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/__tests__/method-item.spec.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/__tests__/method-item.spec.tsx @@ -1,77 +1,49 @@ -import type { ReactElement } from 'react' -import type { EmailConfig, FormInputItem } from '../../../types' +import type { ComponentProps } from 'react' +import type { DeliveryMethod, EmailConfig, FormInputItem, HumanInputNodeType } from '../../../types' import type { Node, NodeOutPutVar } from '@/app/components/workflow/types' -import { screen } from '@testing-library/react' +import { screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { InputVarType } from '@/app/components/workflow/types' -import { createAccountProfileQueryWrapper } from '@/test/console/account-profile' -import { render as renderWithConsoleState } from '@/test/console/render' +import { useState } from 'react' +import { replacePromptEditorText } from '@/app/components/base/prompt-editor/plugins/__tests__/test-helpers' +import { + createEdge, + createNode, + createStartNode, +} from '@/app/components/workflow/__tests__/fixtures' +import { BlockEnum, InputVarType, VarType } from '@/app/components/workflow/types' +import { renderWorkflowEditor } from '@/test/workflow-editor' import { DeliveryMethodType } from '../../../types' import DeliveryMethodItem from '../method-item' -type EmailConfigureModalProps = { - open: boolean - config?: EmailConfig - onOpenChange: (open: boolean) => void - onConfirm: (data: EmailConfig) => void -} +vi.mock('@/service/console', async (importOriginal) => { + const actual = await importOriginal() + const { withConsoleResponses } = await import('@/test/console/service-responses') + return { + ...actual, + consoleQuery: withConsoleResponses(actual.consoleQuery, { + 'workspaces.current.members.get': () => ({ accounts: [] }), + }), + } +}) -type TestEmailSenderProps = { - open: boolean - onOpenChange: (open: boolean) => void - jumpToEmailConfigModal: () => void -} - -const mockConsoleState = vi.hoisted(() => ({ - userProfile: { - email: 'owner@example.com', - }, -})) - -const render = (ui: ReactElement) => - renderWithConsoleState(ui, { - wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile), +vi.mock('react-i18next', async () => { + const actual = await vi.importActual('react-i18next') + const { createInstance } = await vi.importActual('i18next') + const { createReactI18nextMock } = await import('@/test/i18n-mock') + const { default: translations } = await import('@/i18n/locales/en-US/workflow-human-input.json') + const i18n = createInstance() + await i18n.init({ + lng: 'en-US', + fallbackLng: false, + keySeparator: false, + resources: { 'en-US': { workflowHumanInput: translations } }, }) - -vi.mock('../email-configure-modal', () => ({ - default: (props: EmailConfigureModalProps) => { - return props.open ? ( -
- - -
- ) : null - }, -})) - -vi.mock('../test-email-sender', () => ({ - default: (props: TestEmailSenderProps) => { - return props.open ? ( -
- - -
- ) : null - }, -})) + return { + ...actual, + ...createReactI18nextMock(), + Trans: (props: ComponentProps) => , + } +}) const createEmailConfig = (overrides: Partial = {}): EmailConfig => ({ recipients: { @@ -96,177 +68,201 @@ const formInputs: FormInputItem[] = [ }, ] -const availableNodes = [ - { - id: 'start', - data: { - title: 'Start', - type: 'start', - }, - }, -] as unknown as Node[] - -const nodesOutputVars = [ +const nodesOutputVars: NodeOutPutVar[] = [ { nodeId: 'start', title: 'Start', - vars: [], + vars: [{ variable: 'name', type: VarType.string }], }, -] as NodeOutPutVar[] +] + +function DeliveryMethodHarness({ + availableNodes, + initialMethod, + readonly = false, +}: { + availableNodes: Node[] + initialMethod: DeliveryMethod + readonly?: boolean +}) { + const [method, setMethod] = useState(initialMethod) + return ( + <> + {method && ( + setMethod((current) => (current?.type === type ? null : current))} + readonly={readonly} + /> + )} + + {method ? JSON.stringify(method) : 'removed'} + + + ) +} + +const renderMethod = (initialMethod: DeliveryMethod, readonly = false) => { + const start = createStartNode({ + id: 'start', + data: { + variables: [ + { variable: 'name', label: 'Name', type: InputVarType.textInput, required: false }, + ], + }, + }) + const humanInputData: HumanInputNodeType = { + title: 'Human input', + desc: '', + type: BlockEnum.HumanInput, + delivery_methods: [initialMethod], + form_content: 'Hello {{#url#}}', + inputs: formInputs, + user_actions: [], + timeout: 3, + timeout_unit: 'day', + } + const humanInput = createNode({ id: 'human-input', data: humanInputData }) + return renderWorkflowEditor( + , + { + nodes: [start, humanInput], + edges: [ + createEdge({ + source: 'start', + target: 'human-input', + data: { sourceType: BlockEnum.Start, targetType: BlockEnum.HumanInput }, + }), + ], + }, + ) +} + +const savedMethod = () => screen.getByRole('status', { name: 'Saved delivery method' }) describe('human-input/delivery-method/method-item', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - it('should toggle and delete a webapp delivery method', async () => { + it('toggles and deletes a webapp delivery method through controlled owner state', async () => { const user = userEvent.setup() - const handleChange = vi.fn() - const handleDelete = vi.fn() + renderMethod({ id: 'webapp-1', type: DeliveryMethodType.WebApp, enabled: true }) - render( - , + const enabled = screen.getByRole('switch') + expect(enabled).toBeChecked() + await user.click(enabled) + expect(enabled).not.toBeChecked() + expect(savedMethod()).toHaveTextContent( + JSON.stringify({ id: 'webapp-1', type: DeliveryMethodType.WebApp, enabled: false }), ) - await user.click(screen.getByRole('switch')) - expect(handleChange).toHaveBeenCalledWith({ - id: 'webapp-1', - type: DeliveryMethodType.WebApp, - enabled: false, + await user.click(screen.getByRole('button', { name: 'common.operation.remove' })) + expect(savedMethod()).toHaveTextContent('removed') + expect(screen.queryByRole('switch')).not.toBeInTheDocument() + }) + + it('uses the real test sender and saves subject and body edits from the real configuration form', async () => { + const user = userEvent.setup() + // The jump button exists only for non-debug email with specific recipients; a debug fixture + // cannot reach this production branch. + renderMethod({ + id: 'email-1', + type: DeliveryMethodType.Email, + enabled: true, + config: createEmailConfig(), }) - const deleteButton = screen.getByRole('button', { name: 'common.operation.remove' }) - - await user.click(deleteButton) - expect(handleDelete).toHaveBeenCalledWith(DeliveryMethodType.WebApp) - }) - - it('should open configure and test flows for an email method with config', async () => { - const user = userEvent.setup() - const handleChange = vi.fn() - const handleDelete = vi.fn() - - render( - , - ) - - expect(screen.getByText('DEBUG'))!.toBeInTheDocument() - - const testButton = screen.getByRole('button', { name: /emailSender.testSendTipInDebugMode/ }) + const testButton = screen.getByRole('button', { name: /emailSender.testSendTip/ }) + await user.click(testButton) + let sender = screen.getByRole('dialog', { name: /emailSender.title/ }) + await user.click(within(sender).getByRole('button', { name: 'common.operation.close' })) + await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument()) await user.click(testButton) - expect(screen.getByTestId('test-email-sender'))!.toBeInTheDocument() - - await user.click(screen.getByRole('button', { name: 'close-test-sender' })) - expect(screen.queryByTestId('test-email-sender')).not.toBeInTheDocument() - - await user.click(testButton) - await user.click(screen.getByRole('button', { name: 'jump-to-config' })) - expect(screen.queryByTestId('test-email-sender')).not.toBeInTheDocument() - expect(screen.getByTestId('email-configure-modal'))!.toBeInTheDocument() - - await user.click(screen.getByRole('button', { name: 'close-email-config' })) - expect(screen.queryByTestId('email-configure-modal')).not.toBeInTheDocument() + sender = screen.getByRole('dialog', { name: /emailSender.title/ }) + await user.click(within(sender).getByRole('button', { name: 'enable Debug Mode' })) + const configure = await screen.findByRole('dialog', { name: /emailConfigure.title/ }) + expect(screen.queryByRole('dialog', { name: /emailSender.title/ })).not.toBeInTheDocument() + await user.click(within(configure).getByRole('button', { name: 'common.operation.cancel' })) + await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument()) await user.click(screen.getByRole('button', { name: 'workflow.common.configure' })) - expect(screen.getByTestId('email-configure-modal'))!.toBeInTheDocument() + const subject = screen.getByRole('textbox', { name: /emailConfigure.subject$/ }) + await user.clear(subject) + await user.type(subject, 'Configured subject') + const body = screen.getByRole('textbox', { name: /emailConfigure.body$/ }) + await replacePromptEditorText(body, 'Configured body {{#url#}}') + await user.click(screen.getByRole('button', { name: 'common.operation.save' })) - await user.click(screen.getByRole('button', { name: 'confirm-email-config' })) - expect(handleChange).toHaveBeenCalledWith( - expect.objectContaining({ + await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument()) + expect(savedMethod()).toHaveTextContent( + JSON.stringify({ id: 'email-1', type: DeliveryMethodType.Email, - config: expect.objectContaining({ + enabled: true, + config: createEmailConfig({ subject: 'Configured subject', + body: 'Configured body {{#url#}}', }), }), ) await user.click(screen.getByRole('button', { name: 'common.operation.remove' })) - expect(handleDelete).toHaveBeenCalledWith(DeliveryMethodType.Email) + expect(savedMethod()).toHaveTextContent('removed') }) - it('should open email config from the unconfigured button and from the test sender jump action', async () => { + it('opens and dismisses the real configuration form for an unconfigured email method', async () => { const user = userEvent.setup() - render( - , - ) + const method: DeliveryMethod = { + id: 'email-2', + type: DeliveryMethodType.Email, + enabled: false, + config: undefined, + } + renderMethod(method) await user.click( screen.getByRole('button', { name: /workflowHumanInput.nodes.humanInput.deliveryMethod.notConfigured/i, }), ) - expect(screen.getByTestId('email-configure-modal'))!.toBeInTheDocument() - - await user.click(screen.getByRole('button', { name: 'close-email-config' })) - expect(screen.queryByTestId('email-configure-modal')).not.toBeInTheDocument() + const configure = screen.getByRole('dialog', { name: /emailConfigure.title/ }) + expect(within(configure).getByRole('textbox', { name: /emailConfigure.subject$/ })).toHaveValue( + '', + ) + await user.click(within(configure).getByRole('button', { name: 'common.operation.close' })) + await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument()) + expect(savedMethod()).toHaveTextContent(JSON.stringify(method)) }) - it('should keep actions disabled in readonly mode', async () => { + it('keeps actions disabled in readonly mode without changing owner state', async () => { const user = userEvent.setup() - const handleChange = vi.fn() + const method: DeliveryMethod = { + id: 'email-3', + type: DeliveryMethodType.Email, + enabled: true, + config: createEmailConfig(), + } + renderMethod(method, true) - render( - , - ) - - await user.click(screen.getByRole('switch')) - expect(handleChange).not.toHaveBeenCalled() + const enabled = screen.getByRole('switch') + expect(enabled).toHaveAttribute('aria-disabled', 'true') + await user.click(enabled) + expect(enabled).toBeChecked() expect( screen.queryByRole('button', { name: 'common.operation.remove' }), ).not.toBeInTheDocument() expect( screen.queryByRole('button', { name: 'workflow.common.configure' }), ).not.toBeInTheDocument() - expect(screen.queryByTestId('email-configure-modal')).not.toBeInTheDocument() - expect(screen.queryByTestId('test-email-sender')).not.toBeInTheDocument() + expect(screen.queryByRole('dialog')).not.toBeInTheDocument() + expect(savedMethod()).toHaveTextContent(JSON.stringify(method)) }) }) diff --git a/web/app/components/workflow/nodes/llm/components/__tests__/panel-memory-section.spec.tsx b/web/app/components/workflow/nodes/llm/components/__tests__/panel-memory-section.spec.tsx index 57987e5696a..7555ce02f9e 100644 --- a/web/app/components/workflow/nodes/llm/components/__tests__/panel-memory-section.spec.tsx +++ b/web/app/components/workflow/nodes/llm/components/__tests__/panel-memory-section.spec.tsx @@ -1,39 +1,24 @@ import type { LLMNodeType } from '../../types' import type { Memory, Node, NodeOutPutVar } from '@/app/components/workflow/types' -import { render, screen } from '@testing-library/react' +import { screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { useState } from 'react' +import { replacePromptEditorText } from '@/app/components/base/prompt-editor/plugins/__tests__/test-helpers' +import { createNode, createStartNode } from '@/app/components/workflow/__tests__/fixtures' +import { BlockEnum } from '@/app/components/workflow/types' +import { renderWorkflowEditor } from '@/test/workflow-editor' import PanelMemorySection from '../panel-memory-section' -vi.mock('@/app/components/workflow/nodes/_base/components/prompt/editor', () => ({ - default: ({ - value, - onChange, - readOnly, - }: { - value: string - onChange: (value: string) => void - readOnly?: boolean - }) => ( -