mirror of https://github.com/langgenius/dify.git
fix
This commit is contained in:
parent
b58bc077a7
commit
5eada5dbcc
|
|
@ -12,8 +12,16 @@ vi.mock('@/config', () => ({
|
|||
}))
|
||||
|
||||
const mockToastNotify = vi.fn()
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: { notify: (...args: unknown[]) => mockToastNotify(...args) },
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign((message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }), {
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
const mockUploadGitHub = vi.fn()
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ export const useGitHubReleases = () => {
|
|||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
toast.error(error.message,)
|
||||
toast.error(error.message)
|
||||
}
|
||||
else {
|
||||
toast.error('Failed to fetch repository releases',)
|
||||
toast.error('Failed to fetch repository releases')
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ export const useGitHubUpload = () => {
|
|||
return GitHubPackage
|
||||
}
|
||||
catch (error) {
|
||||
toast.error('Error uploading package',)
|
||||
toast.error('Error uploading package')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import * as React from 'react'
|
|||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { InstallStepFromGitHub } from '../../types'
|
||||
import Installed from '../base/installed'
|
||||
|
|
@ -166,10 +166,10 @@ const InstallFromGitHub: React.FC<InstallFromGitHubProps> = ({ updatePayload, on
|
|||
>
|
||||
<div className="flex items-start gap-2 self-stretch pb-3 pl-6 pr-14 pt-6">
|
||||
<div className="flex grow flex-col items-start gap-1">
|
||||
<div className="title-2xl-semi-bold self-stretch text-text-primary">
|
||||
<div className="self-stretch text-text-primary title-2xl-semi-bold">
|
||||
{getTitle()}
|
||||
</div>
|
||||
<div className="system-xs-regular self-stretch text-text-tertiary">
|
||||
<div className="self-stretch text-text-tertiary system-xs-regular">
|
||||
{!([InstallStepFromGitHub.uploadFailed, InstallStepFromGitHub.installed, InstallStepFromGitHub.installFailed].includes(state.step)) && t('installFromGitHub.installNote', { ns: 'plugin' })}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import type { PluginDetail } from '../../types'
|
|||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import * as amplitude from '@/app/components/base/amplitude'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { PluginSource } from '../../types'
|
||||
import DetailHeader from '../detail-header'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { EndpointListItem, PluginDetail } from '../../types'
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import EndpointCard from '../endpoint-card'
|
||||
|
||||
const mockHandleChange = vi.fn()
|
||||
|
|
@ -9,6 +8,22 @@ const mockEnableEndpoint = vi.fn()
|
|||
const mockDisableEndpoint = vi.fn()
|
||||
const mockDeleteEndpoint = vi.fn()
|
||||
const mockUpdateEndpoint = vi.fn()
|
||||
const mockToastNotify = vi.fn()
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
// Flags to control whether operations should fail
|
||||
const failureFlags = {
|
||||
|
|
@ -127,8 +142,6 @@ describe('EndpointCard', () => {
|
|||
failureFlags.disable = false
|
||||
failureFlags.delete = false
|
||||
failureFlags.update = false
|
||||
// Mock notifyToast to prevent toast elements from accumulating in DOM
|
||||
vi.spyOn(Toast, 'notify').mockImplementation(() => ({ clear: vi.fn() }))
|
||||
// Polyfill document.execCommand for copy-to-clipboard in jsdom
|
||||
if (typeof document.execCommand !== 'function') {
|
||||
document.execCommand = vi.fn().mockReturnValue(true)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,25 @@ import type { FormSchema } from '../../../base/form/types'
|
|||
import type { PluginDetail } from '../../types'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import EndpointModal from '../endpoint-modal'
|
||||
|
||||
const mockToastNotify = vi.fn()
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/use-i18n', () => ({
|
||||
useRenderI18nObject: () => (obj: Record<string, string> | string) =>
|
||||
typeof obj === 'string' ? obj : obj?.en_US || '',
|
||||
|
|
@ -69,11 +85,9 @@ const mockPluginDetail: PluginDetail = {
|
|||
describe('EndpointModal', () => {
|
||||
const mockOnCancel = vi.fn()
|
||||
const mockOnSaved = vi.fn()
|
||||
let mockToastNotify: ReturnType<typeof vi.spyOn>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockToastNotify = vi.spyOn(Toast, 'notify').mockImplementation(() => ({ clear: vi.fn() }))
|
||||
})
|
||||
|
||||
describe('Rendering', () => {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import type { ModalStates, VersionTarget } from '../use-detail-header-state'
|
|||
import { act, renderHook } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import * as amplitude from '@/app/components/base/amplitude'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { PluginSource } from '../../../../types'
|
||||
import { usePluginOperations } from '../use-plugin-operations'
|
||||
|
||||
|
|
@ -20,6 +19,7 @@ const {
|
|||
mockUninstallPlugin,
|
||||
mockFetchReleases,
|
||||
mockCheckForUpdates,
|
||||
mockToastNotify,
|
||||
} = vi.hoisted(() => {
|
||||
return {
|
||||
mockSetShowUpdatePluginModal: vi.fn(),
|
||||
|
|
@ -29,9 +29,25 @@ const {
|
|||
mockUninstallPlugin: vi.fn(() => Promise.resolve({ success: true })),
|
||||
mockFetchReleases: vi.fn(() => Promise.resolve([{ tag_name: 'v2.0.0' }])),
|
||||
mockCheckForUpdates: vi.fn(() => ({ needUpdate: true, toastProps: { type: 'success', message: 'Update available' } })),
|
||||
mockToastNotify: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/modal-context', () => ({
|
||||
useModalContext: () => ({
|
||||
setShowUpdatePluginModal: mockSetShowUpdatePluginModal,
|
||||
|
|
@ -124,7 +140,6 @@ describe('usePluginOperations', () => {
|
|||
modalStates = createModalStatesMock()
|
||||
versionPicker = createVersionPickerMock()
|
||||
mockOnUpdate = vi.fn()
|
||||
vi.spyOn(Toast, 'notify').mockImplementation(() => ({ clear: vi.fn() }))
|
||||
vi.spyOn(amplitude, 'trackEvent').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
|
|
@ -233,7 +248,7 @@ describe('usePluginOperations', () => {
|
|||
})
|
||||
|
||||
expect(mockCheckForUpdates).toHaveBeenCalled()
|
||||
expect(notifyToast).toHaveBeenCalled()
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({ type: 'success', message: 'Update available' })
|
||||
})
|
||||
|
||||
it('should show update plugin modal when update is needed', async () => {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export const usePluginOperations = ({
|
|||
}
|
||||
|
||||
if (!meta?.repo || !meta?.version || !meta?.package) {
|
||||
toast.error('Missing plugin metadata for GitHub update',)
|
||||
toast.error('Missing plugin metadata for GitHub update')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import Confirm from '@/app/components/base/confirm'
|
|||
import { CopyCheck } from '@/app/components/base/icons/src/vender/line/files'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import { addDefaultValue, toolCredentialToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||
import {
|
||||
useDeleteEndpoint,
|
||||
|
|
@ -47,7 +47,7 @@ const EndpointCard = ({
|
|||
await handleChange()
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common') })
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common' }))
|
||||
setActive(false)
|
||||
},
|
||||
})
|
||||
|
|
@ -57,7 +57,7 @@ const EndpointCard = ({
|
|||
hideDisableConfirm()
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common') })
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common' }))
|
||||
setActive(false)
|
||||
},
|
||||
})
|
||||
|
|
@ -83,7 +83,7 @@ const EndpointCard = ({
|
|||
hideDeleteConfirm()
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common') })
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common' }))
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ const EndpointCard = ({
|
|||
hideEndpointModalConfirm()
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common') })
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common' }))
|
||||
},
|
||||
})
|
||||
const handleUpdate = (state: Record<string, any>) => updateEndpoint({
|
||||
|
|
@ -139,7 +139,7 @@ const EndpointCard = ({
|
|||
<div className="rounded-xl bg-background-section-burn p-0.5">
|
||||
<div className="group rounded-[10px] border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg p-2.5 pl-3">
|
||||
<div className="flex items-center">
|
||||
<div className="system-md-semibold mb-1 flex h-6 grow items-center gap-1 text-text-secondary">
|
||||
<div className="mb-1 flex h-6 grow items-center gap-1 text-text-secondary system-md-semibold">
|
||||
<RiLoginCircleLine className="h-4 w-4" />
|
||||
<div>{data.name}</div>
|
||||
</div>
|
||||
|
|
@ -154,8 +154,8 @@ const EndpointCard = ({
|
|||
</div>
|
||||
{data.declaration.endpoints.filter(endpoint => !endpoint.hidden).map((endpoint, index) => (
|
||||
<div key={index} className="flex h-6 items-center">
|
||||
<div className="system-xs-regular w-12 shrink-0 text-text-tertiary">{endpoint.method}</div>
|
||||
<div className="group/item system-xs-regular flex grow items-center truncate text-text-secondary">
|
||||
<div className="w-12 shrink-0 text-text-tertiary system-xs-regular">{endpoint.method}</div>
|
||||
<div className="group/item flex grow items-center truncate text-text-secondary system-xs-regular">
|
||||
<div title={`${data.url}${endpoint.path}`} className="truncate">{`${data.url}${endpoint.path}`}</div>
|
||||
<Tooltip popupContent={t(`operation.${isCopied ? 'copied' : 'copy'}`, { ns: 'common' })} position="top">
|
||||
<ActionButton className="ml-2 hidden shrink-0 group-hover/item:flex" onClick={() => handleCopy(`${data.url}${endpoint.path}`)}>
|
||||
|
|
@ -168,13 +168,13 @@ const EndpointCard = ({
|
|||
</div>
|
||||
<div className="flex items-center justify-between p-2 pl-3">
|
||||
{active && (
|
||||
<div className="system-xs-semibold-uppercase flex items-center gap-1 text-util-colors-green-green-600">
|
||||
<div className="flex items-center gap-1 text-util-colors-green-green-600 system-xs-semibold-uppercase">
|
||||
<Indicator color="green" />
|
||||
{t('detailPanel.serviceOk', { ns: 'plugin' })}
|
||||
</div>
|
||||
)}
|
||||
{!active && (
|
||||
<div className="system-xs-semibold-uppercase flex items-center gap-1 text-text-tertiary">
|
||||
<div className="flex items-center gap-1 text-text-tertiary system-xs-semibold-uppercase">
|
||||
<Indicator color="gray" />
|
||||
{t('detailPanel.disabled', { ns: 'plugin' })}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const EndpointList = ({ detail }: Props) => {
|
|||
hideEndpointModal()
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common') })
|
||||
toast.error(t('actionMsg.modifiedUnsuccessfully', { ns: 'common' }))
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ const EndpointList = ({ detail }: Props) => {
|
|||
|
||||
return (
|
||||
<div className={cn('border-divider-subtle px-4 py-2', showTopBorder && 'border-t')}>
|
||||
<div className="system-sm-semibold-uppercase mb-1 flex h-6 items-center justify-between text-text-secondary">
|
||||
<div className="mb-1 flex h-6 items-center justify-between text-text-secondary system-sm-semibold-uppercase">
|
||||
<div className="flex items-center gap-0.5">
|
||||
{t('detailPanel.endpoints', { ns: 'plugin' })}
|
||||
<Tooltip
|
||||
|
|
@ -75,13 +75,13 @@ const EndpointList = ({ detail }: Props) => {
|
|||
<div className="flex h-8 w-8 items-center justify-center rounded-lg border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle">
|
||||
<RiApps2AddLine className="h-4 w-4 text-text-tertiary" />
|
||||
</div>
|
||||
<div className="system-xs-regular text-text-tertiary">{t('detailPanel.endpointsTip', { ns: 'plugin' })}</div>
|
||||
<div className="text-text-tertiary system-xs-regular">{t('detailPanel.endpointsTip', { ns: 'plugin' })}</div>
|
||||
<a
|
||||
href={docLink('/develop-plugin/getting-started/getting-started-dify-plugin')}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<div className="system-xs-regular inline-flex cursor-pointer items-center gap-1 text-text-accent">
|
||||
<div className="inline-flex cursor-pointer items-center gap-1 text-text-accent system-xs-regular">
|
||||
<RiBookOpenLine className="h-3 w-3" />
|
||||
{t('detailPanel.endpointsDocLink', { ns: 'plugin' })}
|
||||
</div>
|
||||
|
|
@ -95,7 +95,7 @@ const EndpointList = ({ detail }: Props) => {
|
|||
</ActionButton>
|
||||
</div>
|
||||
{data.endpoints.length === 0 && (
|
||||
<div className="system-xs-regular mb-1 flex justify-center rounded-[10px] bg-background-section p-3 text-text-tertiary">{t('detailPanel.endpointsEmpty', { ns: 'plugin' })}</div>
|
||||
<div className="mb-1 flex justify-center rounded-[10px] bg-background-section p-3 text-text-tertiary system-xs-regular">{t('detailPanel.endpointsEmpty', { ns: 'plugin' })}</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-2">
|
||||
{data.endpoints.map((item, index) => (
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { useTranslation } from 'react-i18next'
|
|||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Drawer from '@/app/components/base/drawer'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { ReadmeEntrance } from '../readme-panel/entrance'
|
||||
|
|
@ -48,7 +48,10 @@ const EndpointModal: FC<Props> = ({
|
|||
const handleSave = () => {
|
||||
for (const field of formSchemas) {
|
||||
if (field.required && !tempCredential[field.name]) {
|
||||
toast.error(t('errorMsg.fieldRequired', { ns: 'common', field: typeof field.label === 'string' ? field.label : getValueFromI18nObject(field.label as Record<string, string>)) })
|
||||
toast.error(t('errorMsg.fieldRequired', {
|
||||
ns: 'common',
|
||||
field: typeof field.label === 'string' ? field.label : getValueFromI18nObject(field.label as Record<string, string>),
|
||||
}))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -83,12 +86,12 @@ const EndpointModal: FC<Props> = ({
|
|||
<>
|
||||
<div className="p-4 pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="system-xl-semibold text-text-primary">{t('detailPanel.endpointModalTitle', { ns: 'plugin' })}</div>
|
||||
<div className="text-text-primary system-xl-semibold">{t('detailPanel.endpointModalTitle', { ns: 'plugin' })}</div>
|
||||
<ActionButton onClick={onCancel}>
|
||||
<RiCloseLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
<div className="system-xs-regular mt-0.5 text-text-tertiary">{t('detailPanel.endpointModalDesc', { ns: 'plugin' })}</div>
|
||||
<div className="mt-0.5 text-text-tertiary system-xs-regular">{t('detailPanel.endpointModalDesc', { ns: 'plugin' })}</div>
|
||||
<ReadmeEntrance pluginDetail={pluginDetail} className="px-0 pt-3" />
|
||||
</div>
|
||||
<div className="grow overflow-y-auto">
|
||||
|
|
@ -109,7 +112,7 @@ const EndpointModal: FC<Props> = ({
|
|||
href={item.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="body-xs-regular inline-flex items-center text-text-accent-secondary"
|
||||
className="inline-flex items-center text-text-accent-secondary body-xs-regular"
|
||||
>
|
||||
{t('howToGet', { ns: 'tools' })}
|
||||
<RiArrowRightUpLine className="ml-1 h-3 w-3" />
|
||||
|
|
|
|||
|
|
@ -4,11 +4,26 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|||
import { ConfigurationMethodEnum, ModelStatusEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
|
||||
// Import component after mocks
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import ModelParameterModal from '../index'
|
||||
|
||||
// ==================== Mock Setup ====================
|
||||
|
||||
const mockToastNotify = vi.fn()
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock provider context
|
||||
const mockProviderContextValue = {
|
||||
isAPIKeySet: true,
|
||||
|
|
@ -53,8 +68,6 @@ vi.mock('@/utils/completion-params', () => ({
|
|||
fetchAndMergeValidCompletionParams: (...args: unknown[]) => mockFetchAndMergeValidCompletionParams(...args),
|
||||
}))
|
||||
|
||||
const mockToastNotify = vi.spyOn(Toast, 'notify')
|
||||
|
||||
// Mock child components
|
||||
vi.mock('@/app/components/header/account-setting/model-provider-page/model-selector', () => ({
|
||||
default: ({ defaultModel, modelList, scopeFeatures, onSelect }: {
|
||||
|
|
@ -244,7 +257,6 @@ const setupModelLists = (config: {
|
|||
describe('ModelParameterModal', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockToastNotify.mockReturnValue({})
|
||||
mockProviderContextValue.isAPIKeySet = true
|
||||
mockProviderContextValue.modelProviders = []
|
||||
setupModelLists()
|
||||
|
|
@ -865,9 +877,7 @@ describe('ModelParameterModal', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(notifyToast).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ type: 'warning' }),
|
||||
)
|
||||
expect(mockToastNotify).toHaveBeenCalledWith(expect.objectContaining({ type: 'warning' }))
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -892,9 +902,7 @@ describe('ModelParameterModal', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(notifyToast).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ type: 'error' }),
|
||||
)
|
||||
expect(mockToastNotify).toHaveBeenCalledWith(expect.objectContaining({ type: 'error' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import {
|
|||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { ModelStatusEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import {
|
||||
useModelList,
|
||||
|
|
@ -22,7 +23,6 @@ import {
|
|||
import AgentModelTrigger from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger'
|
||||
import Trigger from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger'
|
||||
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { fetchAndMergeValidCompletionParams } from '@/utils/completion-params'
|
||||
|
|
@ -134,12 +134,11 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
|||
|
||||
const keys = Object.keys(removedDetails || {})
|
||||
if (keys.length) {
|
||||
toast.warning(`${t('modelProvider.parametersInvalidRemoved', { ns: 'common')}: ${keys.map(k => `${k} (${removedDetails[k]})`).join(', ')}`,
|
||||
})
|
||||
toast.warning(`${t('modelProvider.parametersInvalidRemoved', { ns: 'common' })}: ${keys.map(k => `${k} (${removedDetails[k]})`).join(', ')}`)
|
||||
}
|
||||
}
|
||||
catch {
|
||||
toast.error(t('error', { ns: 'common') })
|
||||
toast.error(t('error', { ns: 'common' }))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +151,8 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
|||
mode: targetModelItem?.model_properties.mode as string,
|
||||
completion_params: nextCompletionParams,
|
||||
}
|
||||
: {}))
|
||||
: {}),
|
||||
})
|
||||
}
|
||||
|
||||
const handleLLMParamsChange = (newParams: FormValue) => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,26 @@
|
|||
import type { TriggerLogEntity } from '@/app/components/workflow/block-selector/types'
|
||||
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import LogViewer from '../log-viewer'
|
||||
|
||||
const mockToastNotify = vi.fn()
|
||||
const mockWriteText = vi.fn()
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor', () => ({
|
||||
default: ({ value }: { value: unknown }) => (
|
||||
<div data-testid="code-editor">{JSON.stringify(value)}</div>
|
||||
|
|
@ -57,10 +71,6 @@ beforeEach(() => {
|
|||
},
|
||||
configurable: true,
|
||||
})
|
||||
vi.spyOn(Toast, 'notify').mockImplementation((args) => {
|
||||
mockToastNotify(args)
|
||||
return { clear: vi.fn() }
|
||||
})
|
||||
})
|
||||
|
||||
describe('LogViewer', () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import { SubscriptionSelectorView } from '../selector-view'
|
||||
|
||||
|
|
@ -26,6 +25,18 @@ vi.mock('@/service/use-triggers', () => ({
|
|||
useDeleteTriggerSubscription: () => ({ mutate: mockDelete, isPending: false }),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(vi.fn(), {
|
||||
success: vi.fn(),
|
||||
error: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
info: vi.fn(),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
const createSubscription = (overrides: Partial<TriggerSubscription> = {}): TriggerSubscription => ({
|
||||
id: 'sub-1',
|
||||
name: 'Subscription One',
|
||||
|
|
@ -42,7 +53,6 @@ const createSubscription = (overrides: Partial<TriggerSubscription> = {}): Trigg
|
|||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockSubscriptions = [createSubscription()]
|
||||
vi.spyOn(Toast, 'notify').mockImplementation(() => ({ clear: vi.fn() }))
|
||||
})
|
||||
|
||||
describe('SubscriptionSelectorView', () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import SubscriptionCard from '../subscription-card'
|
||||
|
||||
|
|
@ -30,6 +29,18 @@ vi.mock('@/service/use-triggers', () => ({
|
|||
useDeleteTriggerSubscription: () => ({ mutate: vi.fn(), isPending: false }),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(vi.fn(), {
|
||||
success: vi.fn(),
|
||||
error: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
info: vi.fn(),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
const createSubscription = (overrides: Partial<TriggerSubscription> = {}): TriggerSubscription => ({
|
||||
id: 'sub-1',
|
||||
name: 'Subscription One',
|
||||
|
|
@ -45,7 +56,6 @@ const createSubscription = (overrides: Partial<TriggerSubscription> = {}): Trigg
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
vi.spyOn(Toast, 'notify').mockImplementation(() => ({ clear: vi.fn() }))
|
||||
})
|
||||
|
||||
describe('SubscriptionCard', () => {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import type { SimpleDetail } from '../../../store'
|
|||
import type { TriggerOAuthConfig, TriggerProviderApiEntity, TriggerSubscription, TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { SupportedCreationMethods } from '@/app/components/plugins/types'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { SupportedCreationMethods } from '@/app/components/plugins/types'
|
||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import { CreateButtonType, CreateSubscriptionButton, DEFAULT_METHOD } from '../index'
|
||||
|
||||
|
|
|
|||
|
|
@ -87,9 +87,18 @@ vi.mock('@/hooks/use-oauth', () => ({
|
|||
|
||||
const mockToastNotify = vi.fn()
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
default: {
|
||||
notify: (params: unknown) => mockToastNotify(params),
|
||||
},
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
const mockClipboardWriteText = vi.fn()
|
||||
|
|
|
|||
|
|
@ -78,9 +78,18 @@ vi.mock('@/hooks/use-oauth', () => ({
|
|||
|
||||
const mockToastNotify = vi.fn()
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
default: {
|
||||
notify: (params: unknown) => mockToastNotify(params),
|
||||
},
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import type { BuildTriggerSubscriptionPayload } from '@/service/use-triggers'
|
|||
import { debounce } from 'es-toolkit/compat'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SupportedCreationMethods } from '@/app/components/plugins/types'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { SupportedCreationMethods } from '@/app/components/plugins/types'
|
||||
import { TriggerCredentialTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import {
|
||||
useBuildTriggerSubscription,
|
||||
|
|
@ -154,7 +154,7 @@ export const useCommonModalState = ({
|
|||
onError: async (error: unknown) => {
|
||||
const errorMessage = await parsePluginErrorMessage(error) || t('modal.errors.updateFailed', { ns: 'pluginTrigger' })
|
||||
console.error('Failed to update subscription builder:', error)
|
||||
toast.error(errorMessage,)
|
||||
toast.error(errorMessage)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -233,7 +233,7 @@ export const useCommonModalState = ({
|
|||
const handleVerify = useCallback(() => {
|
||||
// Guard against uninitialized state
|
||||
if (!detail?.provider || !subscriptionBuilder?.id) {
|
||||
toast.error('Subscription builder not initialized',)
|
||||
toast.error('Subscription builder not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ export const useCommonModalState = ({
|
|||
const credentials = apiKeyCredentialsFormValues.values
|
||||
|
||||
if (!Object.keys(credentials).length) {
|
||||
toast.error('Please fill in all required credentials',)
|
||||
toast.error('Please fill in all required credentials')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -275,7 +275,7 @@ export const useCommonModalState = ({
|
|||
// Handle create
|
||||
const handleCreate = useCallback(() => {
|
||||
if (!subscriptionBuilder) {
|
||||
toast.error('Subscription builder not found',)
|
||||
toast.error('Subscription builder not found')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ export const useCommonModalState = ({
|
|||
},
|
||||
onError: async (error: unknown) => {
|
||||
const errorMessage = await parsePluginErrorMessage(error) || t('subscription.createFailed', { ns: 'pluginTrigger' })
|
||||
toast.error(errorMessage,)
|
||||
toast.error(errorMessage)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -138,8 +138,7 @@ export const useOAuthClientState = ({
|
|||
toast.success(t('modal.oauth.remove.success', { ns: 'pluginTrigger' }))
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
toast.error(getErrorMessage(error, t('modal.oauth.remove.failed', { ns: 'pluginTrigger' })),
|
||||
})
|
||||
toast.error(getErrorMessage(error, t('modal.oauth.remove.failed', { ns: 'pluginTrigger' })))
|
||||
},
|
||||
})
|
||||
}, [providerName, deleteOAuth, onClose, t])
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ import { OAuthEditModal } from '../oauth-edit-modal'
|
|||
|
||||
const mockToastNotify = vi.fn()
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign((params: unknown) => mockToastNotify(params), {
|
||||
success: (params: unknown) => mockToastNotify(params),
|
||||
error: (params: unknown) => mockToastNotify(params),
|
||||
warning: (params: unknown) => mockToastNotify(params),
|
||||
info: (params: unknown) => mockToastNotify(params),
|
||||
toast: Object.assign((message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }), {
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import { EncryptedBottom } from '@/app/components/base/encrypted-bottom'
|
|||
import { BaseForm } from '@/app/components/base/form/components/base'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
import Modal from '@/app/components/base/modal/modal'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { useUpdateTriggerSubscription, useVerifyTriggerSubscription } from '@/service/use-triggers'
|
||||
import { parsePluginErrorMessage } from '@/utils/error-parser'
|
||||
import { ReadmeShowType } from '../../../readme-panel/store'
|
||||
|
|
@ -65,7 +65,7 @@ const StatusStep = ({ isActive, text, onClick, clickable }: {
|
|||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`system-2xs-semibold-uppercase flex items-center gap-1 ${isActive
|
||||
className={`flex items-center gap-1 system-2xs-semibold-uppercase ${isActive
|
||||
? 'text-state-accent-solid'
|
||||
: 'text-text-tertiary'} ${clickable ? 'cursor-pointer hover:text-text-secondary' : ''}`}
|
||||
onClick={clickable ? onClick : undefined}
|
||||
|
|
@ -150,7 +150,7 @@ export const ApiKeyEditModal = ({ onClose, subscription, pluginDetail }: Props)
|
|||
},
|
||||
onError: async (error: unknown) => {
|
||||
const errorMessage = await parsePluginErrorMessage(error) || t('modal.apiKey.verify.error', { ns: 'pluginTrigger' })
|
||||
toast.error(errorMessage,)
|
||||
toast.error(errorMessage)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -192,7 +192,7 @@ export const ApiKeyEditModal = ({ onClose, subscription, pluginDetail }: Props)
|
|||
},
|
||||
onError: async (error: unknown) => {
|
||||
const errorMessage = await parsePluginErrorMessage(error) || t('subscription.list.item.actions.edit.error', { ns: 'pluginTrigger' })
|
||||
toast.error(errorMessage,)
|
||||
toast.error(errorMessage)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { useTranslation } from 'react-i18next'
|
|||
import { BaseForm } from '@/app/components/base/form/components/base'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
import Modal from '@/app/components/base/modal/modal'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { useUpdateTriggerSubscription } from '@/service/use-triggers'
|
||||
import { ReadmeShowType } from '../../../readme-panel/store'
|
||||
import { usePluginStore } from '../../store'
|
||||
|
|
@ -99,8 +99,7 @@ export const ManualEditModal = ({ onClose, subscription, pluginDetail }: Props)
|
|||
onClose()
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
toast.error(getErrorMessage(error, t('subscription.list.item.actions.edit.error', { ns: 'pluginTrigger' })),
|
||||
})
|
||||
toast.error(getErrorMessage(error, t('subscription.list.item.actions.edit.error', { ns: 'pluginTrigger' })))
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { useTranslation } from 'react-i18next'
|
|||
import { BaseForm } from '@/app/components/base/form/components/base'
|
||||
import { FormTypeEnum } from '@/app/components/base/form/types'
|
||||
import Modal from '@/app/components/base/modal/modal'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
|
||||
import { useUpdateTriggerSubscription } from '@/service/use-triggers'
|
||||
import { ReadmeShowType } from '../../../readme-panel/store'
|
||||
import { usePluginStore } from '../../store'
|
||||
|
|
@ -99,8 +99,7 @@ export const OAuthEditModal = ({ onClose, subscription, pluginDetail }: Props) =
|
|||
onClose()
|
||||
},
|
||||
onError: (error: unknown) => {
|
||||
toast.error(getErrorMessage(error, t('subscription.list.item.actions.edit.error', { ns: 'pluginTrigger' })),
|
||||
})
|
||||
toast.error(getErrorMessage(error, t('subscription.list.item.actions.edit.error', { ns: 'pluginTrigger' })))
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -299,11 +299,11 @@ vi.mock('@/app/components/header/account-setting/model-provider-page/model-modal
|
|||
// Mock Toast - need to track notify calls for assertions
|
||||
const mockToastNotify = vi.fn()
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign((...args: unknown[]) => mockToastNotify(...args), {
|
||||
success: (...args: unknown[]) => mockToastNotify(...args),
|
||||
error: (...args: unknown[]) => mockToastNotify(...args),
|
||||
warning: (...args: unknown[]) => mockToastNotify(...args),
|
||||
info: (...args: unknown[]) => mockToastNotify(...args),
|
||||
toast: Object.assign((message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }), {
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -11,11 +11,15 @@ vi.mock('@/utils/classnames', () => ({
|
|||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
default: { notify: vi.fn() },
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast/context', () => ({
|
||||
useToastContext: () => ({ notify: vi.fn() }),
|
||||
toast: Object.assign(vi.fn(), {
|
||||
success: vi.fn(),
|
||||
error: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
info: vi.fn(),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
const mockFormSchemas = [
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import { useEffect, useState } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { addDefaultValue, toolCredentialToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||
import { fetchBuiltInToolCredential, fetchBuiltInToolCredentialSchema } from '@/service/tools'
|
||||
|
|
@ -49,7 +49,10 @@ const ToolCredentialForm: FC<Props> = ({
|
|||
return
|
||||
for (const field of credentialSchema) {
|
||||
if (field.required && !tempCredential[field.name]) {
|
||||
toast.error(t('errorMsg.fieldRequired', { ns: 'common', field: getValueFromI18nObject(field.label)) })
|
||||
toast.error(t('errorMsg.fieldRequired', {
|
||||
ns: 'common',
|
||||
field: getValueFromI18nObject(field.label),
|
||||
}))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { MetaData, PluginCategoryEnum } from '../../types'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
|
||||
// ==================== Imports (after mocks) ====================
|
||||
|
||||
|
|
@ -17,12 +16,29 @@ const {
|
|||
mockCheckForUpdates,
|
||||
mockSetShowUpdatePluginModal,
|
||||
mockInvalidateInstalledPluginList,
|
||||
mockToastNotify,
|
||||
} = vi.hoisted(() => ({
|
||||
mockUninstallPlugin: vi.fn(),
|
||||
mockFetchReleases: vi.fn(),
|
||||
mockCheckForUpdates: vi.fn(),
|
||||
mockSetShowUpdatePluginModal: vi.fn(),
|
||||
mockInvalidateInstalledPluginList: vi.fn(),
|
||||
mockToastNotify: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: Object.assign(
|
||||
(message: string, options?: { type?: string }) => mockToastNotify({ type: options?.type, message }),
|
||||
{
|
||||
success: (message: string) => mockToastNotify({ type: 'success', message }),
|
||||
error: (message: string) => mockToastNotify({ type: 'error', message }),
|
||||
warning: (message: string) => mockToastNotify({ type: 'warning', message }),
|
||||
info: (message: string) => mockToastNotify({ type: 'info', message }),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
},
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock uninstall plugin service
|
||||
|
|
@ -140,13 +156,8 @@ const getActionButtons = () => screen.getAllByRole('button')
|
|||
const queryActionButtons = () => screen.queryAllByRole('button')
|
||||
|
||||
describe('Action Component', () => {
|
||||
// Spy on notifyToast - real component but we track calls
|
||||
let toastNotifySpy: ReturnType<typeof vi.spyOn>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
// Spy on notifyToast and mock implementation to avoid DOM side effects
|
||||
toastNotifySpy = vi.spyOn(Toast, 'notify').mockImplementation(() => ({ clear: vi.fn() }))
|
||||
mockUninstallPlugin.mockResolvedValue({ success: true })
|
||||
mockFetchReleases.mockResolvedValue([])
|
||||
mockCheckForUpdates.mockReturnValue({
|
||||
|
|
@ -155,10 +166,6 @@ describe('Action Component', () => {
|
|||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
toastNotifySpy.mockRestore()
|
||||
})
|
||||
|
||||
// ==================== Rendering Tests ====================
|
||||
describe('Rendering', () => {
|
||||
it('should render delete button when isShowDelete is true', () => {
|
||||
|
|
@ -563,9 +570,9 @@ describe('Action Component', () => {
|
|||
render(<Action {...props} />)
|
||||
fireEvent.click(getActionButtons()[0])
|
||||
|
||||
// Assert - notifyToast is called with the toast props
|
||||
// Assert - toast is called with the translated payload
|
||||
await waitFor(() => {
|
||||
expect(toastNotifySpy).toHaveBeenCalledWith({ type: 'success', message: 'Already up to date' })
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({ type: 'success', message: 'Already up to date' })
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -5364,6 +5364,36 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/endpoint-card.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 2
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 5
|
||||
},
|
||||
"ts/no-explicit-any": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/endpoint-list.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
},
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 4
|
||||
},
|
||||
"ts/no-explicit-any": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/endpoint-modal.tsx": {
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 3
|
||||
},
|
||||
"ts/no-explicit-any": {
|
||||
"count": 7
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/model-list.tsx": {
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 2
|
||||
|
|
@ -5372,6 +5402,11 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/model-selector/index.tsx": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/model-selector/llm-params-panel.tsx": {
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 1
|
||||
|
|
@ -5424,6 +5459,11 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-oauth-client-state.ts": {
|
||||
"erasable-syntax-only/enums": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/subscription-list/create/index.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 3
|
||||
|
|
@ -5453,6 +5493,16 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/subscription-list/edit/manual-edit-modal.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/subscription-list/edit/oauth-edit-modal.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/plugins/plugin-detail-panel/subscription-list/index.tsx": {
|
||||
"react-refresh/only-export-components": {
|
||||
"count": 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue