chore: some test (#30148)

Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
This commit is contained in:
Joel 2025-12-25 19:45:27 +08:00 committed by GitHub
parent 08d5eee993
commit 0f3ffbee2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 747 additions and 0 deletions

View File

@ -0,0 +1,136 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { AppModeEnum } from '@/types/app'
import Apps from './index'
const mockUseExploreAppList = vi.fn()
vi.mock('ahooks', () => ({
useDebounceFn: (fn: () => void) => ({
run: () => setTimeout(fn, 0),
cancel: vi.fn(),
flush: () => fn(),
}),
}))
vi.mock('@/context/app-context', () => ({
useAppContext: () => ({ isCurrentWorkspaceEditor: true }),
}))
vi.mock('use-context-selector', async () => {
const actual = await vi.importActual<typeof import('use-context-selector')>('use-context-selector')
return {
...actual,
useContext: () => ({ hasEditPermission: true }),
}
})
vi.mock('@/hooks/use-tab-searchparams', () => ({
useTabSearchParams: () => ['Recommended', vi.fn()],
}))
vi.mock('@/service/use-explore', () => ({
useExploreAppList: () => mockUseExploreAppList(),
}))
vi.mock('@/app/components/app/type-selector', () => ({
__esModule: true,
default: ({ value, onChange }: { value: AppModeEnum[], onChange: (value: AppModeEnum[]) => void }) => (
<button data-testid="type-selector" onClick={() => onChange([...value, 'chat' as AppModeEnum])}>{value.join(',')}</button>
),
}))
vi.mock('../app-card', () => ({
__esModule: true,
default: ({ app, onCreate }: { app: any, onCreate: () => void }) => (
<div
data-testid="app-card"
data-name={app.app.name}
onClick={onCreate}
>
{app.app.name}
</div>
),
}))
vi.mock('@/app/components/explore/create-app-modal', () => ({
__esModule: true,
default: () => <div data-testid="create-from-template-modal" />,
}))
vi.mock('@/app/components/base/toast', () => ({
default: { notify: vi.fn() },
}))
vi.mock('@/app/components/base/amplitude', () => ({
trackEvent: vi.fn(),
}))
vi.mock('@/service/apps', () => ({
importDSL: vi.fn().mockResolvedValue({ app_id: '1' }),
}))
vi.mock('@/service/explore', () => ({
fetchAppDetail: vi.fn().mockResolvedValue({
export_data: 'dsl',
mode: 'chat',
}),
}))
vi.mock('@/app/components/workflow/plugin-dependency/hooks', () => ({
usePluginDependencies: () => ({
handleCheckPluginDependencies: vi.fn(),
}),
}))
vi.mock('@/utils/app-redirection', () => ({
getRedirection: vi.fn(),
}))
vi.mock('next/navigation', () => ({
useRouter: () => ({ push: vi.fn() }),
}))
const createAppEntry = (name: string, category: string) => ({
app_id: name,
category,
app: {
id: name,
name,
icon_type: 'emoji',
icon: '🙂',
icon_background: '#000',
icon_url: null,
description: 'desc',
mode: AppModeEnum.CHAT,
},
})
describe('Apps', () => {
const defaultData = {
allList: [
createAppEntry('Alpha', 'Cat A'),
createAppEntry('Bravo', 'Cat B'),
],
categories: ['Cat A', 'Cat B'],
}
beforeEach(() => {
vi.clearAllMocks()
mockUseExploreAppList.mockReturnValue({
data: defaultData,
isLoading: false,
})
})
it('renders template cards when data is available', () => {
render(<Apps />)
expect(screen.getAllByTestId('app-card')).toHaveLength(2)
expect(screen.getByText('Alpha')).toBeInTheDocument()
expect(screen.getByText('Bravo')).toBeInTheDocument()
})
it('opens create modal when a template card is clicked', () => {
render(<Apps />)
fireEvent.click(screen.getAllByTestId('app-card')[0])
expect(screen.getByTestId('create-from-template-modal')).toBeInTheDocument()
})
it('shows no template message when list is empty', () => {
mockUseExploreAppList.mockReturnValueOnce({
data: { allList: [], categories: [] },
isLoading: false,
})
render(<Apps />)
expect(screen.getByText('app.newApp.noTemplateFound')).toBeInTheDocument()
expect(screen.getByText('app.newApp.noTemplateFoundTip')).toBeInTheDocument()
})
})

View File

@ -0,0 +1,38 @@
import { fireEvent, render, screen } from '@testing-library/react'
import Sidebar, { AppCategories } from './sidebar'
vi.mock('@remixicon/react', () => ({
RiStickyNoteAddLine: () => <span>sticky</span>,
RiThumbUpLine: () => <span>thumb</span>,
}))
describe('Sidebar', () => {
it('renders recommended and custom categories', () => {
render(<Sidebar current={AppCategories.RECOMMENDED} categories={['Cat A', 'Cat B']} />)
expect(screen.getByText('app.newAppFromTemplate.sidebar.Recommended')).toBeInTheDocument()
expect(screen.getByText('Cat A')).toBeInTheDocument()
expect(screen.getByText('Cat B')).toBeInTheDocument()
})
it('notifies callbacks when items are clicked', () => {
const onClick = vi.fn()
const onCreate = vi.fn()
render(
<Sidebar
current="Cat A"
categories={['Cat A']}
onClick={onClick}
onCreateFromBlank={onCreate}
/>,
)
fireEvent.click(screen.getByText('app.newAppFromTemplate.sidebar.Recommended'))
expect(onClick).toHaveBeenCalledWith(AppCategories.RECOMMENDED)
fireEvent.click(screen.getByText('Cat A'))
expect(onClick).toHaveBeenCalledWith('Cat A')
fireEvent.click(screen.getByText('app.newApp.startFromBlank'))
expect(onCreate).toHaveBeenCalled()
})
})

View File

@ -0,0 +1,217 @@
import type { ReactNode } from 'react'
import type { ModalContextState } from '@/context/modal-context'
import type { ProviderContextState } from '@/context/provider-context'
import type { AppDetailResponse } from '@/models/app'
import type { AppSSO } from '@/types/app'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { Plan } from '@/app/components/billing/type'
import { baseProviderContextValue } from '@/context/provider-context'
import { AppModeEnum } from '@/types/app'
import SettingsModal from './index'
vi.mock('react-i18next', async () => {
const actual = await vi.importActual<typeof import('react-i18next')>('react-i18next')
return {
...actual,
useTranslation: () => ({
t: (key: string, options?: Record<string, unknown>) => {
if (options?.returnObjects)
return [`${key}-feature-1`, `${key}-feature-2`]
if (options)
return `${key}:${JSON.stringify(options)}`
return key
},
i18n: {
language: 'en',
changeLanguage: vi.fn(),
},
}),
Trans: ({ children }: { children?: ReactNode }) => <>{children}</>,
}
})
const mockNotify = vi.fn()
const mockOnClose = vi.fn()
const mockOnSave = vi.fn()
const mockSetShowPricingModal = vi.fn()
const mockSetShowAccountSettingModal = vi.fn()
const mockUseProviderContext = vi.fn<() => ProviderContextState>()
const buildModalContext = (): ModalContextState => ({
setShowAccountSettingModal: mockSetShowAccountSettingModal,
setShowApiBasedExtensionModal: vi.fn(),
setShowModerationSettingModal: vi.fn(),
setShowExternalDataToolModal: vi.fn(),
setShowPricingModal: mockSetShowPricingModal,
setShowAnnotationFullModal: vi.fn(),
setShowModelModal: vi.fn(),
setShowExternalKnowledgeAPIModal: vi.fn(),
setShowModelLoadBalancingModal: vi.fn(),
setShowOpeningModal: vi.fn(),
setShowUpdatePluginModal: vi.fn(),
setShowEducationExpireNoticeModal: vi.fn(),
setShowTriggerEventsLimitModal: vi.fn(),
})
vi.mock('@/context/modal-context', () => ({
useModalContext: () => buildModalContext(),
}))
vi.mock('@/app/components/base/toast', async () => {
const actual = await vi.importActual<typeof import('@/app/components/base/toast')>('@/app/components/base/toast')
return {
...actual,
useToastContext: () => ({
notify: mockNotify,
close: vi.fn(),
}),
}
})
vi.mock('@/context/i18n', async () => {
const actual = await vi.importActual<typeof import('@/context/i18n')>('@/context/i18n')
return {
...actual,
useDocLink: () => (path?: string) => `https://docs.example.com${path ?? ''}`,
}
})
vi.mock('@/context/provider-context', async () => {
const actual = await vi.importActual<typeof import('@/context/provider-context')>('@/context/provider-context')
return {
...actual,
useProviderContext: () => mockUseProviderContext(),
}
})
const mockAppInfo = {
site: {
title: 'Test App',
icon_type: 'emoji',
icon: '😀',
icon_background: '#ABCDEF',
icon_url: 'https://example.com/icon.png',
description: 'A description',
chat_color_theme: '#123456',
chat_color_theme_inverted: true,
copyright: '© Dify',
privacy_policy: '',
custom_disclaimer: 'Disclaimer',
default_language: 'en-US',
show_workflow_steps: true,
use_icon_as_answer_icon: true,
},
mode: AppModeEnum.ADVANCED_CHAT,
enable_sso: false,
} as unknown as AppDetailResponse & Partial<AppSSO>
const renderSettingsModal = () => render(
<SettingsModal
isChat
isShow
appInfo={mockAppInfo}
onClose={mockOnClose}
onSave={mockOnSave}
/>,
)
describe('SettingsModal', () => {
beforeEach(() => {
mockNotify.mockClear()
mockOnClose.mockClear()
mockOnSave.mockClear()
mockSetShowPricingModal.mockClear()
mockSetShowAccountSettingModal.mockClear()
mockUseProviderContext.mockReturnValue({
...baseProviderContextValue,
enableBilling: true,
plan: {
...baseProviderContextValue.plan,
type: Plan.sandbox,
},
webappCopyrightEnabled: true,
})
})
it('should render the modal and expose the expanded settings section', async () => {
renderSettingsModal()
expect(screen.getByText('appOverview.overview.appInfo.settings.title')).toBeInTheDocument()
const showMoreEntry = screen.getByText('appOverview.overview.appInfo.settings.more.entry')
fireEvent.click(showMoreEntry)
await waitFor(() => {
expect(screen.getByPlaceholderText('appOverview.overview.appInfo.settings.more.copyRightPlaceholder')).toBeInTheDocument()
expect(screen.getByPlaceholderText('appOverview.overview.appInfo.settings.more.privacyPolicyPlaceholder')).toBeInTheDocument()
})
})
it('should notify the user when the name is empty', async () => {
renderSettingsModal()
const nameInput = screen.getByPlaceholderText('app.appNamePlaceholder')
fireEvent.change(nameInput, { target: { value: '' } })
fireEvent.click(screen.getByText('common.operation.save'))
await waitFor(() => {
expect(mockNotify).toHaveBeenCalledWith(expect.objectContaining({ message: 'app.newApp.nameNotEmpty' }))
})
expect(mockOnSave).not.toHaveBeenCalled()
})
it('should validate the theme color and show an error when the hex is invalid', async () => {
renderSettingsModal()
const colorInput = screen.getByPlaceholderText('E.g #A020F0')
fireEvent.change(colorInput, { target: { value: 'not-a-hex' } })
fireEvent.click(screen.getByText('common.operation.save'))
await waitFor(() => {
expect(mockNotify).toHaveBeenCalledWith(expect.objectContaining({
message: 'appOverview.overview.appInfo.settings.invalidHexMessage',
}))
})
expect(mockOnSave).not.toHaveBeenCalled()
})
it('should validate the privacy policy URL when advanced settings are open', async () => {
renderSettingsModal()
fireEvent.click(screen.getByText('appOverview.overview.appInfo.settings.more.entry'))
const privacyInput = screen.getByPlaceholderText('appOverview.overview.appInfo.settings.more.privacyPolicyPlaceholder')
// eslint-disable-next-line sonarjs/no-clear-text-protocols
fireEvent.change(privacyInput, { target: { value: 'ftp://invalid-url' } })
fireEvent.click(screen.getByText('common.operation.save'))
await waitFor(() => {
expect(mockNotify).toHaveBeenCalledWith(expect.objectContaining({
message: 'appOverview.overview.appInfo.settings.invalidPrivacyPolicy',
}))
})
expect(mockOnSave).not.toHaveBeenCalled()
})
it('should save valid settings and close the modal', async () => {
mockOnSave.mockResolvedValueOnce(undefined)
renderSettingsModal()
fireEvent.click(screen.getByText('common.operation.save'))
await waitFor(() => expect(mockOnSave).toHaveBeenCalled())
expect(mockOnSave).toHaveBeenCalledWith(expect.objectContaining({
title: mockAppInfo.site.title,
description: mockAppInfo.site.description,
default_language: mockAppInfo.site.default_language,
chat_color_theme: mockAppInfo.site.chat_color_theme,
chat_color_theme_inverted: mockAppInfo.site.chat_color_theme_inverted,
prompt_public: false,
copyright: mockAppInfo.site.copyright,
privacy_policy: mockAppInfo.site.privacy_policy,
custom_disclaimer: mockAppInfo.site.custom_disclaimer,
icon_type: 'emoji',
icon: mockAppInfo.site.icon,
icon_background: mockAppInfo.site.icon_background,
show_workflow_steps: mockAppInfo.site.show_workflow_steps,
use_icon_as_answer_icon: mockAppInfo.site.use_icon_as_answer_icon,
enable_sso: mockAppInfo.enable_sso,
}))
expect(mockOnClose).toHaveBeenCalled()
})
})

View File

@ -0,0 +1,60 @@
import type { Credential } from '@/app/components/tools/types'
import { act, fireEvent, render, screen } from '@testing-library/react'
import { AuthHeaderPrefix, AuthType } from '@/app/components/tools/types'
import ConfigCredential from './config-credentials'
describe('ConfigCredential', () => {
const baseCredential: Credential = {
auth_type: AuthType.none,
}
const mockOnChange = vi.fn()
const mockOnHide = vi.fn()
beforeEach(() => {
vi.clearAllMocks()
})
it('renders and calls onHide when cancel is pressed', async () => {
await act(async () => {
render(
<ConfigCredential
credential={baseCredential}
onChange={mockOnChange}
onHide={mockOnHide}
/>,
)
})
fireEvent.click(screen.getByText('common.operation.cancel'))
expect(mockOnHide).toHaveBeenCalledTimes(1)
expect(mockOnChange).not.toHaveBeenCalled()
})
it('allows selecting apiKeyHeader and submits the new credential', async () => {
await act(async () => {
render(
<ConfigCredential
credential={baseCredential}
onChange={mockOnChange}
onHide={mockOnHide}
/>,
)
})
fireEvent.click(screen.getByText('tools.createTool.authMethod.types.api_key_header'))
const headerInput = screen.getByPlaceholderText('tools.createTool.authMethod.types.apiKeyPlaceholder')
const valueInput = screen.getByPlaceholderText('tools.createTool.authMethod.types.apiValuePlaceholder')
fireEvent.change(headerInput, { target: { value: 'X-Auth' } })
fireEvent.change(valueInput, { target: { value: 'sEcReT' } })
fireEvent.click(screen.getByText('common.operation.save'))
expect(mockOnChange).toHaveBeenCalledWith({
auth_type: AuthType.apiKeyHeader,
api_key_header: 'X-Auth',
api_key_header_prefix: AuthHeaderPrefix.custom,
api_key_value: 'sEcReT',
})
expect(mockOnHide).toHaveBeenCalled()
})
})

View File

@ -0,0 +1,55 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { importSchemaFromURL } from '@/service/tools'
import Toast from '../../base/toast'
import examples from './examples'
import GetSchema from './get-schema'
vi.mock('@/service/tools', () => ({
importSchemaFromURL: vi.fn(),
}))
const importSchemaFromURLMock = vi.mocked(importSchemaFromURL)
describe('GetSchema', () => {
const notifySpy = vi.spyOn(Toast, 'notify')
const mockOnChange = vi.fn()
beforeEach(() => {
vi.clearAllMocks()
notifySpy.mockClear()
importSchemaFromURLMock.mockReset()
render(<GetSchema onChange={mockOnChange} />)
})
it('shows an error when the URL is not http', () => {
fireEvent.click(screen.getByText('tools.createTool.importFromUrl'))
const input = screen.getByPlaceholderText('tools.createTool.importFromUrlPlaceHolder')
// eslint-disable-next-line sonarjs/no-clear-text-protocols
fireEvent.change(input, { target: { value: 'ftp://invalid' } })
fireEvent.click(screen.getByText('common.operation.ok'))
expect(notifySpy).toHaveBeenCalledWith({
type: 'error',
message: 'tools.createTool.urlError',
})
})
it('imports schema from url when valid', async () => {
fireEvent.click(screen.getByText('tools.createTool.importFromUrl'))
const input = screen.getByPlaceholderText('tools.createTool.importFromUrlPlaceHolder')
fireEvent.change(input, { target: { value: 'https://example.com' } })
importSchemaFromURLMock.mockResolvedValueOnce({ schema: 'result-schema' })
fireEvent.click(screen.getByText('common.operation.ok'))
await waitFor(() => {
expect(mockOnChange).toHaveBeenCalledWith('result-schema')
})
})
it('selects example schema when example option clicked', () => {
fireEvent.click(screen.getByText('tools.createTool.examples'))
fireEvent.click(screen.getByText(`tools.createTool.exampleOptions.${examples[0].key}`))
expect(mockOnChange).toHaveBeenCalledWith(examples[0].content)
})
})

View File

@ -0,0 +1,154 @@
import type { ModalContextState } from '@/context/modal-context'
import type { ProviderContextState } from '@/context/provider-context'
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import Toast from '@/app/components/base/toast'
import { Plan } from '@/app/components/billing/type'
import { parseParamsSchema } from '@/service/tools'
import EditCustomCollectionModal from './index'
vi.mock('ahooks', async () => {
const actual = await vi.importActual<typeof import('ahooks')>('ahooks')
return {
...actual,
useDebounce: (value: unknown) => value,
}
})
vi.mock('@/service/tools', () => ({
parseParamsSchema: vi.fn(),
}))
const parseParamsSchemaMock = vi.mocked(parseParamsSchema)
const mockSetShowPricingModal = vi.fn()
const mockSetShowAccountSettingModal = vi.fn()
vi.mock('@/context/modal-context', () => ({
useModalContext: (): ModalContextState => ({
setShowAccountSettingModal: mockSetShowAccountSettingModal,
setShowApiBasedExtensionModal: vi.fn(),
setShowModerationSettingModal: vi.fn(),
setShowExternalDataToolModal: vi.fn(),
setShowPricingModal: mockSetShowPricingModal,
setShowAnnotationFullModal: vi.fn(),
setShowModelModal: vi.fn(),
setShowExternalKnowledgeAPIModal: vi.fn(),
setShowModelLoadBalancingModal: vi.fn(),
setShowOpeningModal: vi.fn(),
setShowUpdatePluginModal: vi.fn(),
setShowEducationExpireNoticeModal: vi.fn(),
setShowTriggerEventsLimitModal: vi.fn(),
}),
}))
const mockUseProviderContext = vi.fn()
vi.mock('@/context/provider-context', () => ({
useProviderContext: () => mockUseProviderContext(),
}))
vi.mock('@/context/i18n', async () => {
const actual = await vi.importActual<typeof import('@/context/i18n')>('@/context/i18n')
return {
...actual,
useDocLink: () => (path?: string) => `https://docs.example.com${path ?? ''}`,
}
})
describe('EditCustomCollectionModal', () => {
const mockOnHide = vi.fn()
const mockOnAdd = vi.fn()
const mockOnEdit = vi.fn()
const mockOnRemove = vi.fn()
const toastNotifySpy = vi.spyOn(Toast, 'notify')
beforeEach(() => {
vi.clearAllMocks()
toastNotifySpy.mockClear()
parseParamsSchemaMock.mockResolvedValue({
parameters_schema: [],
schema_type: 'openapi',
})
mockUseProviderContext.mockReturnValue({
plan: {
type: Plan.sandbox,
},
enableBilling: false,
webappCopyrightEnabled: true,
} as ProviderContextState)
})
const renderModal = () => render(
<EditCustomCollectionModal
payload={undefined}
onHide={mockOnHide}
onAdd={mockOnAdd}
onEdit={mockOnEdit}
onRemove={mockOnRemove}
/>,
)
it('shows an error when the provider name is missing', async () => {
renderModal()
const schemaInput = screen.getByPlaceholderText('tools.createTool.schemaPlaceHolder')
fireEvent.change(schemaInput, { target: { value: '{}' } })
await waitFor(() => {
expect(parseParamsSchemaMock).toHaveBeenCalledWith('{}')
})
fireEvent.click(screen.getByText('common.operation.save'))
await waitFor(() => {
expect(toastNotifySpy).toHaveBeenCalledWith(expect.objectContaining({
message: 'common.errorMsg.fieldRequired:{"field":"tools.createTool.name"}',
type: 'error',
}))
})
expect(mockOnAdd).not.toHaveBeenCalled()
})
it('shows an error when the schema is missing', async () => {
renderModal()
const providerInput = screen.getByPlaceholderText('tools.createTool.toolNamePlaceHolder')
fireEvent.change(providerInput, { target: { value: 'provider' } })
fireEvent.click(screen.getByText('common.operation.save'))
await waitFor(() => {
expect(toastNotifySpy).toHaveBeenCalledWith(expect.objectContaining({
message: 'common.errorMsg.fieldRequired:{"field":"tools.createTool.schema"}',
type: 'error',
}))
})
expect(mockOnAdd).not.toHaveBeenCalled()
})
it('saves a valid custom collection', async () => {
renderModal()
const providerInput = screen.getByPlaceholderText('tools.createTool.toolNamePlaceHolder')
fireEvent.change(providerInput, { target: { value: 'provider' } })
const schemaInput = screen.getByPlaceholderText('tools.createTool.schemaPlaceHolder')
fireEvent.change(schemaInput, { target: { value: '{}' } })
await waitFor(() => {
expect(parseParamsSchemaMock).toHaveBeenCalledWith('{}')
})
await act(async () => {
fireEvent.click(screen.getByText('common.operation.save'))
})
await waitFor(() => {
expect(mockOnAdd).toHaveBeenCalledWith(expect.objectContaining({
provider: 'provider',
schema: '{}',
schema_type: 'openapi',
credentials: {
auth_type: 'none',
},
labels: [],
}))
expect(toastNotifySpy).not.toHaveBeenCalled()
})
})
})

View File

@ -0,0 +1,87 @@
import type { CustomCollectionBackend, CustomParamSchema } from '@/app/components/tools/types'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { AuthType } from '@/app/components/tools/types'
import I18n from '@/context/i18n'
import { testAPIAvailable } from '@/service/tools'
import TestApi from './test-api'
vi.mock('@/service/tools', () => ({
testAPIAvailable: vi.fn(),
}))
const testAPIAvailableMock = vi.mocked(testAPIAvailable)
describe('TestApi', () => {
const customCollection: CustomCollectionBackend = {
provider: 'custom',
credentials: {
auth_type: AuthType.none,
},
schema_type: 'openapi',
schema: '{ }',
icon: { background: '', content: '' },
privacy_policy: '',
custom_disclaimer: '',
id: 'test-id',
labels: [],
}
const tool: CustomParamSchema = {
operation_id: 'testOp',
summary: 'summary',
method: 'GET',
server_url: 'https://api.example.com',
parameters: [{
name: 'limit',
label: {
en_US: 'Limit',
zh_Hans: '限制',
},
// eslint-disable-next-line ts/no-explicit-any
} as any],
}
const renderTestApi = () => {
const providerValue = {
locale: 'en-US',
i18n: {},
setLocaleOnClient: vi.fn(),
}
return render(
<I18n.Provider value={providerValue as any}>
<TestApi
customCollection={customCollection}
tool={tool}
onHide={vi.fn()}
/>
</I18n.Provider>,
)
}
beforeEach(() => {
vi.clearAllMocks()
})
it('renders parameters and runs the API test', async () => {
testAPIAvailableMock.mockResolvedValueOnce({ result: 'ok' })
renderTestApi()
const parameterInput = screen.getAllByRole('textbox')[0]
fireEvent.change(parameterInput, { target: { value: '5' } })
fireEvent.click(screen.getByRole('button', { name: 'tools.test.title' }))
await waitFor(() => {
expect(testAPIAvailableMock).toHaveBeenCalledWith({
provider_name: customCollection.provider,
tool_name: tool.operation_id,
credentials: {
auth_type: AuthType.none,
},
schema_type: customCollection.schema_type,
schema: customCollection.schema,
parameters: {
limit: '5',
},
})
expect(screen.getByText('ok')).toBeInTheDocument()
})
})
})