mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
test(web): add comprehensive unit and integration tests for plugins and tools modules (#32220)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import type { AutoUpdateConfig } from './types'
|
||||
import type { AutoUpdateConfig } from '../types'
|
||||
import type { PluginDeclaration, PluginDetail } from '@/app/components/plugins/types'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
@ -7,91 +7,28 @@ import timezone from 'dayjs/plugin/timezone'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import * as React from 'react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { PluginCategoryEnum, PluginSource } from '../../types'
|
||||
import { defaultValue } from './config'
|
||||
import AutoUpdateSetting from './index'
|
||||
import NoDataPlaceholder from './no-data-placeholder'
|
||||
import NoPluginSelected from './no-plugin-selected'
|
||||
import PluginsPicker from './plugins-picker'
|
||||
import PluginsSelected from './plugins-selected'
|
||||
import StrategyPicker from './strategy-picker'
|
||||
import ToolItem from './tool-item'
|
||||
import ToolPicker from './tool-picker'
|
||||
import { AUTO_UPDATE_MODE, AUTO_UPDATE_STRATEGY } from './types'
|
||||
import { PluginCategoryEnum, PluginSource } from '../../../types'
|
||||
import { defaultValue } from '../config'
|
||||
import AutoUpdateSetting from '../index'
|
||||
import NoDataPlaceholder from '../no-data-placeholder'
|
||||
import NoPluginSelected from '../no-plugin-selected'
|
||||
import PluginsPicker from '../plugins-picker'
|
||||
import PluginsSelected from '../plugins-selected'
|
||||
import StrategyPicker from '../strategy-picker'
|
||||
import ToolItem from '../tool-item'
|
||||
import ToolPicker from '../tool-picker'
|
||||
import { AUTO_UPDATE_MODE, AUTO_UPDATE_STRATEGY } from '../types'
|
||||
import {
|
||||
convertLocalSecondsToUTCDaySeconds,
|
||||
convertUTCDaySecondsToLocalSeconds,
|
||||
dayjsToTimeOfDay,
|
||||
timeOfDayToDayjs,
|
||||
} from './utils'
|
||||
} from '../utils'
|
||||
|
||||
// Setup dayjs plugins
|
||||
dayjs.extend(utc)
|
||||
dayjs.extend(timezone)
|
||||
|
||||
// ================================
|
||||
// Mock External Dependencies Only
|
||||
// ================================
|
||||
|
||||
// Mock react-i18next
|
||||
vi.mock('react-i18next', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('react-i18next')>()
|
||||
return {
|
||||
...actual,
|
||||
Trans: ({ i18nKey, components }: { i18nKey: string, components?: Record<string, React.ReactNode> }) => {
|
||||
if (i18nKey === 'autoUpdate.changeTimezone' && components?.setTimezone) {
|
||||
return (
|
||||
<span>
|
||||
Change in
|
||||
{components.setTimezone}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return <span>{i18nKey}</span>
|
||||
},
|
||||
useTranslation: () => ({
|
||||
t: (key: string, options?: { ns?: string, num?: number }) => {
|
||||
const translations: Record<string, string> = {
|
||||
'autoUpdate.updateSettings': 'Update Settings',
|
||||
'autoUpdate.automaticUpdates': 'Automatic Updates',
|
||||
'autoUpdate.updateTime': 'Update Time',
|
||||
'autoUpdate.specifyPluginsToUpdate': 'Specify Plugins to Update',
|
||||
'autoUpdate.strategy.fixOnly.selectedDescription': 'Only apply bug fixes',
|
||||
'autoUpdate.strategy.latest.selectedDescription': 'Always update to latest',
|
||||
'autoUpdate.strategy.disabled.name': 'Disabled',
|
||||
'autoUpdate.strategy.disabled.description': 'No automatic updates',
|
||||
'autoUpdate.strategy.fixOnly.name': 'Bug Fixes Only',
|
||||
'autoUpdate.strategy.fixOnly.description': 'Only apply bug fixes and patches',
|
||||
'autoUpdate.strategy.latest.name': 'Latest Version',
|
||||
'autoUpdate.strategy.latest.description': 'Always update to the latest version',
|
||||
'autoUpdate.upgradeMode.all': 'All Plugins',
|
||||
'autoUpdate.upgradeMode.exclude': 'Exclude Selected',
|
||||
'autoUpdate.upgradeMode.partial': 'Selected Only',
|
||||
'autoUpdate.excludeUpdate': `Excluding ${options?.num || 0} plugins`,
|
||||
'autoUpdate.partialUPdate': `Updating ${options?.num || 0} plugins`,
|
||||
'autoUpdate.operation.clearAll': 'Clear All',
|
||||
'autoUpdate.operation.select': 'Select Plugins',
|
||||
'autoUpdate.upgradeModePlaceholder.partial': 'Select plugins to update',
|
||||
'autoUpdate.upgradeModePlaceholder.exclude': 'Select plugins to exclude',
|
||||
'autoUpdate.noPluginPlaceholder.noInstalled': 'No plugins installed',
|
||||
'autoUpdate.noPluginPlaceholder.noFound': 'No plugins found',
|
||||
'category.all': 'All',
|
||||
'category.models': 'Models',
|
||||
'category.tools': 'Tools',
|
||||
'category.agents': 'Agents',
|
||||
'category.extensions': 'Extensions',
|
||||
'category.datasources': 'Datasources',
|
||||
'category.triggers': 'Triggers',
|
||||
'category.bundles': 'Bundles',
|
||||
'searchTools': 'Search tools...',
|
||||
}
|
||||
const fullKey = options?.ns ? `${options.ns}.${key}` : key
|
||||
return translations[fullKey] || translations[key] || key
|
||||
},
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
// Mock app context
|
||||
const mockTimezone = 'America/New_York'
|
||||
vi.mock('@/context/app-context', () => ({
|
||||
@ -262,7 +199,7 @@ vi.mock('@/app/components/base/icons/src/vender/other', () => ({
|
||||
}))
|
||||
|
||||
// Mock PLUGIN_TYPE_SEARCH_MAP
|
||||
vi.mock('../../marketplace/constants', () => ({
|
||||
vi.mock('../../../marketplace/constants', () => ({
|
||||
PLUGIN_TYPE_SEARCH_MAP: {
|
||||
all: 'all',
|
||||
model: 'model',
|
||||
@ -574,7 +511,7 @@ describe('auto-update-setting', () => {
|
||||
|
||||
// Assert
|
||||
expect(screen.getByTestId('group-icon')).toBeInTheDocument()
|
||||
expect(screen.getByText('No plugins installed')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.noPluginPlaceholder.noInstalled')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render with noPlugins=false showing search icon', () => {
|
||||
@ -583,7 +520,7 @@ describe('auto-update-setting', () => {
|
||||
|
||||
// Assert
|
||||
expect(screen.getByTestId('search-menu-icon')).toBeInTheDocument()
|
||||
expect(screen.getByText('No plugins found')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.noPluginPlaceholder.noFound')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render with noPlugins=undefined (default) showing search icon', () => {
|
||||
@ -606,14 +543,11 @@ describe('auto-update-setting', () => {
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(NoDataPlaceholder).toBeDefined()
|
||||
expect((NoDataPlaceholder as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((NoDataPlaceholder as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
// NoPluginSelected Component Tests
|
||||
// ============================================================
|
||||
describe('NoPluginSelected (no-plugin-selected.tsx)', () => {
|
||||
describe('Rendering', () => {
|
||||
it('should render partial mode placeholder', () => {
|
||||
@ -621,7 +555,7 @@ describe('auto-update-setting', () => {
|
||||
render(<NoPluginSelected updateMode={AUTO_UPDATE_MODE.partial} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Select plugins to update')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeModePlaceholder.partial')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render exclude mode placeholder', () => {
|
||||
@ -629,21 +563,18 @@ describe('auto-update-setting', () => {
|
||||
render(<NoPluginSelected updateMode={AUTO_UPDATE_MODE.exclude} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Select plugins to exclude')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeModePlaceholder.exclude')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(NoPluginSelected).toBeDefined()
|
||||
expect((NoPluginSelected as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((NoPluginSelected as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
// PluginsSelected Component Tests
|
||||
// ============================================================
|
||||
describe('PluginsSelected (plugins-selected.tsx)', () => {
|
||||
describe('Rendering', () => {
|
||||
it('should render empty when no plugins', () => {
|
||||
@ -731,14 +662,11 @@ describe('auto-update-setting', () => {
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(PluginsSelected).toBeDefined()
|
||||
expect((PluginsSelected as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((PluginsSelected as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
// ToolItem Component Tests
|
||||
// ============================================================
|
||||
describe('ToolItem (tool-item.tsx)', () => {
|
||||
const defaultProps = {
|
||||
payload: createMockPluginDetail(),
|
||||
@ -825,14 +753,11 @@ describe('auto-update-setting', () => {
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(ToolItem).toBeDefined()
|
||||
expect((ToolItem as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((ToolItem as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
// StrategyPicker Component Tests
|
||||
// ============================================================
|
||||
describe('StrategyPicker (strategy-picker.tsx)', () => {
|
||||
const defaultProps = {
|
||||
value: AUTO_UPDATE_STRATEGY.disabled,
|
||||
@ -845,7 +770,7 @@ describe('auto-update-setting', () => {
|
||||
render(<StrategyPicker {...defaultProps} value={AUTO_UPDATE_STRATEGY.disabled} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByRole('button', { name: /disabled/i })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: /plugin\.autoUpdate\.strategy\.disabled\.name/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should not render dropdown content when closed', () => {
|
||||
@ -866,10 +791,10 @@ describe('auto-update-setting', () => {
|
||||
|
||||
// Wait for portal to open
|
||||
if (mockPortalOpen) {
|
||||
// Assert all options visible (use getAllByText for "Disabled" as it appears in both trigger and dropdown)
|
||||
expect(screen.getAllByText('Disabled').length).toBeGreaterThanOrEqual(1)
|
||||
expect(screen.getByText('Bug Fixes Only')).toBeInTheDocument()
|
||||
expect(screen.getByText('Latest Version')).toBeInTheDocument()
|
||||
// Assert all options visible (use getAllByText for strategy name as it appears in both trigger and dropdown)
|
||||
expect(screen.getAllByText('plugin.autoUpdate.strategy.disabled.name').length).toBeGreaterThanOrEqual(1)
|
||||
expect(screen.getByText('plugin.autoUpdate.strategy.fixOnly.name')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.strategy.latest.name')).toBeInTheDocument()
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -898,7 +823,7 @@ describe('auto-update-setting', () => {
|
||||
render(<StrategyPicker value={AUTO_UPDATE_STRATEGY.disabled} onChange={onChange} />)
|
||||
|
||||
// Find and click the "Bug Fixes Only" option
|
||||
const fixOnlyOption = screen.getByText('Bug Fixes Only').closest('div[class*="cursor-pointer"]')
|
||||
const fixOnlyOption = screen.getByText('plugin.autoUpdate.strategy.fixOnly.name').closest('div[class*="cursor-pointer"]')
|
||||
expect(fixOnlyOption).toBeInTheDocument()
|
||||
fireEvent.click(fixOnlyOption!)
|
||||
|
||||
@ -915,7 +840,7 @@ describe('auto-update-setting', () => {
|
||||
render(<StrategyPicker value={AUTO_UPDATE_STRATEGY.disabled} onChange={onChange} />)
|
||||
|
||||
// Find and click the "Latest Version" option
|
||||
const latestOption = screen.getByText('Latest Version').closest('div[class*="cursor-pointer"]')
|
||||
const latestOption = screen.getByText('plugin.autoUpdate.strategy.latest.name').closest('div[class*="cursor-pointer"]')
|
||||
expect(latestOption).toBeInTheDocument()
|
||||
fireEvent.click(latestOption!)
|
||||
|
||||
@ -932,7 +857,7 @@ describe('auto-update-setting', () => {
|
||||
render(<StrategyPicker value={AUTO_UPDATE_STRATEGY.fixOnly} onChange={onChange} />)
|
||||
|
||||
// Find and click the "Disabled" option - need to find the one in the dropdown, not the button
|
||||
const disabledOptions = screen.getAllByText('Disabled')
|
||||
const disabledOptions = screen.getAllByText('plugin.autoUpdate.strategy.disabled.name')
|
||||
// The second one should be in the dropdown
|
||||
const dropdownOption = disabledOptions.find(el => el.closest('div[class*="cursor-pointer"]'))
|
||||
expect(dropdownOption).toBeInTheDocument()
|
||||
@ -956,7 +881,7 @@ describe('auto-update-setting', () => {
|
||||
)
|
||||
|
||||
// Click an option
|
||||
const fixOnlyOption = screen.getByText('Bug Fixes Only').closest('div[class*="cursor-pointer"]')
|
||||
const fixOnlyOption = screen.getByText('plugin.autoUpdate.strategy.fixOnly.name').closest('div[class*="cursor-pointer"]')
|
||||
fireEvent.click(fixOnlyOption!)
|
||||
|
||||
// Assert - onChange is called but parent click handler should not propagate
|
||||
@ -972,7 +897,7 @@ describe('auto-update-setting', () => {
|
||||
|
||||
// Assert - RiCheckLine should be rendered (check icon)
|
||||
// Find all "Bug Fixes Only" texts and get the one in the dropdown (has cursor-pointer parent)
|
||||
const allFixOnlyTexts = screen.getAllByText('Bug Fixes Only')
|
||||
const allFixOnlyTexts = screen.getAllByText('plugin.autoUpdate.strategy.fixOnly.name')
|
||||
const dropdownOption = allFixOnlyTexts.find(el => el.closest('div[class*="cursor-pointer"]'))
|
||||
const optionContainer = dropdownOption?.closest('div[class*="cursor-pointer"]')
|
||||
expect(optionContainer).toBeInTheDocument()
|
||||
@ -988,7 +913,7 @@ describe('auto-update-setting', () => {
|
||||
render(<StrategyPicker value={AUTO_UPDATE_STRATEGY.disabled} onChange={vi.fn()} />)
|
||||
|
||||
// Assert - check the Latest Version option should not have check icon
|
||||
const latestOption = screen.getByText('Latest Version').closest('div[class*="cursor-pointer"]')
|
||||
const latestOption = screen.getByText('plugin.autoUpdate.strategy.latest.name').closest('div[class*="cursor-pointer"]')
|
||||
// The svg should only be in selected option, not in non-selected
|
||||
const checkIconContainer = latestOption?.querySelector('div.mr-1')
|
||||
// Non-selected option should have empty check icon container
|
||||
@ -997,9 +922,6 @@ describe('auto-update-setting', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
// ToolPicker Component Tests
|
||||
// ============================================================
|
||||
describe('ToolPicker (tool-picker.tsx)', () => {
|
||||
const defaultProps = {
|
||||
trigger: <button>Select Plugins</button>,
|
||||
@ -1199,7 +1121,7 @@ describe('auto-update-setting', () => {
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(ToolPicker).toBeDefined()
|
||||
expect((ToolPicker as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((ToolPicker as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1220,7 +1142,7 @@ describe('auto-update-setting', () => {
|
||||
render(<PluginsPicker {...defaultProps} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Select plugins to update')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeModePlaceholder.partial')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render selected plugins count and clear button when plugins selected', () => {
|
||||
@ -1228,8 +1150,8 @@ describe('auto-update-setting', () => {
|
||||
render(<PluginsPicker {...defaultProps} value={['plugin-1', 'plugin-2']} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText(/Updating 2 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('Clear All')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.partialUPdate:{"num":2}')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.operation.clearAll')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render select button', () => {
|
||||
@ -1237,7 +1159,7 @@ describe('auto-update-setting', () => {
|
||||
render(<PluginsPicker {...defaultProps} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Select Plugins')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.operation.select')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show exclude mode text when in exclude mode', () => {
|
||||
@ -1251,7 +1173,7 @@ describe('auto-update-setting', () => {
|
||||
)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText(/Excluding 1 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.excludeUpdate:{"num":1}')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1268,7 +1190,7 @@ describe('auto-update-setting', () => {
|
||||
onChange={onChange}
|
||||
/>,
|
||||
)
|
||||
fireEvent.click(screen.getByText('Clear All'))
|
||||
fireEvent.click(screen.getByText('plugin.autoUpdate.operation.clearAll'))
|
||||
|
||||
// Assert
|
||||
expect(onChange).toHaveBeenCalledWith([])
|
||||
@ -1278,7 +1200,7 @@ describe('auto-update-setting', () => {
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(PluginsPicker).toBeDefined()
|
||||
expect((PluginsPicker as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((PluginsPicker as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1298,7 +1220,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Update Settings')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.updateSettings')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render automatic updates label', () => {
|
||||
@ -1306,7 +1228,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Automatic Updates')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.automaticUpdates')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render strategy picker', () => {
|
||||
@ -1325,7 +1247,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Update Time')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.updateTime')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('time-picker')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
@ -1337,7 +1259,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.queryByText('Update Time')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('plugin.autoUpdate.updateTime')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('time-picker')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
@ -1352,7 +1274,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Select Plugins')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.operation.select')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should hide plugins picker when mode is update_all', () => {
|
||||
@ -1366,7 +1288,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.queryByText('Select Plugins')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('plugin.autoUpdate.operation.select')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1379,7 +1301,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Only apply bug fixes')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.strategy.fixOnly.selectedDescription')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show latest description when strategy is latest', () => {
|
||||
@ -1390,7 +1312,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Always update to latest')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.strategy.latest.selectedDescription')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show no description when strategy is disabled', () => {
|
||||
@ -1401,8 +1323,8 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.queryByText('Only apply bug fixes')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('Always update to latest')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('plugin.autoUpdate.strategy.fixOnly.selectedDescription')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('plugin.autoUpdate.strategy.latest.selectedDescription')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1420,7 +1342,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText(/Updating 2 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.partialUPdate:{"num":2}')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show exclude_plugins when mode is exclude', () => {
|
||||
@ -1436,7 +1358,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText(/Excluding 3 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.excludeUpdate:{"num":3}')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1502,7 +1424,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting payload={payload} onChange={onChange} />)
|
||||
|
||||
// Click clear all
|
||||
fireEvent.click(screen.getByText('Clear All'))
|
||||
fireEvent.click(screen.getByText('plugin.autoUpdate.operation.clearAll'))
|
||||
|
||||
// Assert
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
|
||||
@ -1523,7 +1445,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting payload={payload} onChange={onChange} />)
|
||||
|
||||
// Click clear all
|
||||
fireEvent.click(screen.getByText('Clear All'))
|
||||
fireEvent.click(screen.getByText('plugin.autoUpdate.operation.clearAll'))
|
||||
|
||||
// Assert
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
|
||||
@ -1538,8 +1460,8 @@ describe('auto-update-setting', () => {
|
||||
// Act
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert - timezone text is rendered
|
||||
expect(screen.getByText(/Change in/i)).toBeInTheDocument()
|
||||
// Assert - timezone Trans component is rendered
|
||||
expect(screen.getByText('autoUpdate.changeTimezone')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1571,7 +1493,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting payload={payload} onChange={onChange} />)
|
||||
|
||||
// Trigger a change (clear plugins)
|
||||
fireEvent.click(screen.getByText('Clear All'))
|
||||
fireEvent.click(screen.getByText('plugin.autoUpdate.operation.clearAll'))
|
||||
|
||||
// Assert - other values should be preserved
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({
|
||||
@ -1593,7 +1515,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting payload={payload} onChange={onChange} />)
|
||||
|
||||
// Plugin picker should not be visible in update_all mode
|
||||
expect(screen.queryByText('Clear All')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('plugin.autoUpdate.operation.clearAll')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -1604,14 +1526,14 @@ describe('auto-update-setting', () => {
|
||||
const { rerender } = render(<AutoUpdateSetting {...defaultProps} payload={payload1} />)
|
||||
|
||||
// Assert initial
|
||||
expect(screen.getByText('Only apply bug fixes')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.strategy.fixOnly.selectedDescription')).toBeInTheDocument()
|
||||
|
||||
// Act - change strategy
|
||||
const payload2 = createMockAutoUpdateConfig({ strategy_setting: AUTO_UPDATE_STRATEGY.latest })
|
||||
rerender(<AutoUpdateSetting {...defaultProps} payload={payload2} />)
|
||||
|
||||
// Assert updated
|
||||
expect(screen.getByText('Always update to latest')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.strategy.latest.selectedDescription')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('plugins should reflect correct list based on upgrade_mode', () => {
|
||||
@ -1625,7 +1547,7 @@ describe('auto-update-setting', () => {
|
||||
const { rerender } = render(<AutoUpdateSetting {...defaultProps} payload={partialPayload} />)
|
||||
|
||||
// Assert - partial mode shows include_plugins count
|
||||
expect(screen.getByText(/Updating 2 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.partialUPdate:{"num":2}')).toBeInTheDocument()
|
||||
|
||||
// Act - change to exclude mode
|
||||
const excludePayload = createMockAutoUpdateConfig({
|
||||
@ -1637,14 +1559,14 @@ describe('auto-update-setting', () => {
|
||||
rerender(<AutoUpdateSetting {...defaultProps} payload={excludePayload} />)
|
||||
|
||||
// Assert - exclude mode shows exclude_plugins count
|
||||
expect(screen.getByText(/Excluding 1 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.excludeUpdate:{"num":1}')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Component Memoization', () => {
|
||||
it('should be memoized with React.memo', () => {
|
||||
expect(AutoUpdateSetting).toBeDefined()
|
||||
expect((AutoUpdateSetting as any).$$typeof?.toString()).toContain('Symbol')
|
||||
expect((AutoUpdateSetting as { $$typeof?: symbol }).$$typeof?.toString()).toContain('Symbol')
|
||||
})
|
||||
})
|
||||
|
||||
@ -1661,7 +1583,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('Update Settings')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.updateSettings')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle null timezone gracefully', () => {
|
||||
@ -1697,9 +1619,9 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert
|
||||
expect(screen.getByText('All Plugins')).toBeInTheDocument()
|
||||
expect(screen.getByText('Exclude Selected')).toBeInTheDocument()
|
||||
expect(screen.getByText('Selected Only')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeMode.all')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeMode.exclude')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeMode.partial')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should highlight selected upgrade mode', () => {
|
||||
@ -1713,9 +1635,9 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting {...defaultProps} payload={payload} />)
|
||||
|
||||
// Assert - OptionCard component will be rendered for each mode
|
||||
expect(screen.getByText('All Plugins')).toBeInTheDocument()
|
||||
expect(screen.getByText('Exclude Selected')).toBeInTheDocument()
|
||||
expect(screen.getByText('Selected Only')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeMode.all')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeMode.exclude')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.upgradeMode.partial')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should call onChange when upgrade mode is changed', () => {
|
||||
@ -1730,7 +1652,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting payload={payload} onChange={onChange} />)
|
||||
|
||||
// Click on partial mode - find the option card for partial
|
||||
const partialOption = screen.getByText('Selected Only')
|
||||
const partialOption = screen.getByText('plugin.autoUpdate.upgradeMode.partial')
|
||||
fireEvent.click(partialOption)
|
||||
|
||||
// Assert
|
||||
@ -1769,7 +1691,7 @@ describe('auto-update-setting', () => {
|
||||
|
||||
// Assert - time picker and plugins visible
|
||||
expect(screen.getByTestId('time-picker')).toBeInTheDocument()
|
||||
expect(screen.getByText('Select Plugins')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.operation.select')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should maintain state consistency when switching modes', () => {
|
||||
@ -1786,7 +1708,7 @@ describe('auto-update-setting', () => {
|
||||
render(<AutoUpdateSetting payload={payload} onChange={onChange} />)
|
||||
|
||||
// Assert - partial mode shows include_plugins
|
||||
expect(screen.getByText(/Updating 1 plugins/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.autoUpdate.partialUPdate:{"num":1}')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,4 +1,4 @@
|
||||
import { convertLocalSecondsToUTCDaySeconds, convertUTCDaySecondsToLocalSeconds } from './utils'
|
||||
import { convertLocalSecondsToUTCDaySeconds, convertUTCDaySecondsToLocalSeconds } from '../utils'
|
||||
|
||||
describe('convertLocalSecondsToUTCDaySeconds', () => {
|
||||
it('should convert local seconds to UTC day seconds correctly', () => {
|
||||
Reference in New Issue
Block a user