mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 10:42:44 +00:00
chore: migrate tests from tests-ui/ to colocate with source files (#7811)
## Summary Migrates all unit tests from `tests-ui/` to colocate with their source files in `src/`, improving discoverability and maintainability. ## Changes - **What**: Relocated all unit tests to be adjacent to the code they test, following the `<source>.test.ts` naming convention - **Config**: Updated `vitest.config.ts` to remove `tests-ui` include pattern and `@tests-ui` alias - **Docs**: Moved testing documentation to `docs/testing/` with updated paths and patterns ## Review Focus - Migration patterns documented in `temp/plans/migrate-tests-ui-to-src.md` - Tests use `@/` path aliases instead of relative imports - Shared fixtures placed in `__fixtures__/` directories ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7811-chore-migrate-tests-from-tests-ui-to-colocate-with-source-files-2da6d73d36508147a4cce85365dee614) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -1,481 +0,0 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useComfyRegistryService } from '@/services/comfyRegistryService'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { useInstalledPacks } from '@/workbench/extensions/manager/composables/nodePack/useInstalledPacks'
|
||||
import { useConflictAcknowledgment } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment'
|
||||
import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection'
|
||||
import { useComfyManagerService } from '@/workbench/extensions/manager/services/comfyManagerService'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
import { useConflictDetectionStore } from '@/workbench/extensions/manager/stores/conflictDetectionStore'
|
||||
import type { ConflictDetectionResult } from '@/workbench/extensions/manager/types/conflictDetectionTypes'
|
||||
import { checkVersionCompatibility } from '@/workbench/extensions/manager/utils/versionUtil'
|
||||
|
||||
// Mock @vueuse/core until function
|
||||
vi.mock('@vueuse/core', async () => {
|
||||
const actual = await vi.importActual('@vueuse/core')
|
||||
return {
|
||||
...actual,
|
||||
until: vi.fn(() => ({
|
||||
toBe: vi.fn(() => Promise.resolve())
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('@/workbench/extensions/manager/services/comfyManagerService', () => ({
|
||||
useComfyManagerService: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/services/comfyRegistryService', () => ({
|
||||
useComfyRegistryService: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/stores/systemStatsStore', () => ({
|
||||
useSystemStatsStore: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/utils/versionUtil', () => ({
|
||||
getFrontendVersion: vi.fn(() => '1.24.0'),
|
||||
checkVersionCompatibility: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/utils/systemCompatibility', () => ({
|
||||
checkOSCompatibility: vi.fn(),
|
||||
checkAcceleratorCompatibility: vi.fn(),
|
||||
normalizeOSList: vi.fn((list) => list)
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/utils/conflictUtils', () => ({
|
||||
consolidateConflictsByPackage: vi.fn((results) => results),
|
||||
createBannedConflict: vi.fn((isBanned) =>
|
||||
isBanned
|
||||
? {
|
||||
type: 'banned',
|
||||
current_value: 'installed',
|
||||
required_value: 'not_banned'
|
||||
}
|
||||
: null
|
||||
),
|
||||
createPendingConflict: vi.fn((isPending) =>
|
||||
isPending
|
||||
? {
|
||||
type: 'pending',
|
||||
current_value: 'installed',
|
||||
required_value: 'not_pending'
|
||||
}
|
||||
: null
|
||||
),
|
||||
generateConflictSummary: vi.fn((results, duration) => ({
|
||||
total_packages: results.length,
|
||||
compatible_packages: results.filter(
|
||||
(r: ConflictDetectionResult) => r.is_compatible
|
||||
).length,
|
||||
conflicted_packages: results.filter(
|
||||
(r: ConflictDetectionResult) => r.has_conflict
|
||||
).length,
|
||||
banned_packages: 0,
|
||||
pending_packages: 0,
|
||||
conflicts_by_type_details: {},
|
||||
last_check_timestamp: new Date().toISOString(),
|
||||
check_duration_ms: duration
|
||||
}))
|
||||
}))
|
||||
|
||||
vi.mock(
|
||||
'@/workbench/extensions/manager/composables/useConflictAcknowledgment',
|
||||
() => ({
|
||||
useConflictAcknowledgment: vi.fn()
|
||||
})
|
||||
)
|
||||
|
||||
vi.mock(
|
||||
'@/workbench/extensions/manager/composables/nodePack/useInstalledPacks',
|
||||
() => ({
|
||||
useInstalledPacks: vi.fn()
|
||||
})
|
||||
)
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({
|
||||
useComfyManagerStore: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/stores/conflictDetectionStore', () => ({
|
||||
useConflictDetectionStore: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/workbench/extensions/manager/composables/useManagerState', () => ({
|
||||
useManagerState: vi.fn(() => ({
|
||||
isNewManagerUI: { value: true }
|
||||
}))
|
||||
}))
|
||||
|
||||
describe('useConflictDetection', () => {
|
||||
let pinia: ReturnType<typeof createPinia>
|
||||
|
||||
const mockComfyManagerService = {
|
||||
getImportFailInfoBulk: vi.fn(),
|
||||
isLoading: ref(false),
|
||||
error: ref<string | null>(null)
|
||||
} as unknown as ReturnType<typeof useComfyManagerService>
|
||||
|
||||
const mockRegistryService = {
|
||||
getBulkNodeVersions: vi.fn(),
|
||||
isLoading: ref(false),
|
||||
error: ref<string | null>(null)
|
||||
} as unknown as ReturnType<typeof useComfyRegistryService>
|
||||
|
||||
// Create a ref that can be modified in tests
|
||||
const mockInstalledPacksWithVersions = ref<{ id: string; version: string }[]>(
|
||||
[]
|
||||
)
|
||||
|
||||
const mockInstalledPacks = {
|
||||
startFetchInstalled: vi.fn(),
|
||||
installedPacks: ref<components['schemas']['Node'][]>([]),
|
||||
installedPacksWithVersions: computed(
|
||||
() => mockInstalledPacksWithVersions.value
|
||||
),
|
||||
isReady: ref(false),
|
||||
isLoading: ref(false),
|
||||
error: ref<unknown>(null)
|
||||
} as unknown as ReturnType<typeof useInstalledPacks>
|
||||
|
||||
const mockManagerStore = {
|
||||
isPackEnabled: vi.fn()
|
||||
} as unknown as ReturnType<typeof useComfyManagerStore>
|
||||
|
||||
// Create refs that can be used to control computed properties
|
||||
const mockConflictedPackages = ref<ConflictDetectionResult[]>([])
|
||||
|
||||
const mockConflictStore = {
|
||||
hasConflicts: computed(() =>
|
||||
mockConflictedPackages.value.some((p) => p.has_conflict)
|
||||
),
|
||||
conflictedPackages: mockConflictedPackages,
|
||||
bannedPackages: computed(() =>
|
||||
mockConflictedPackages.value.filter((p) =>
|
||||
p.conflicts?.some((c) => c.type === 'banned')
|
||||
)
|
||||
),
|
||||
securityPendingPackages: computed(() =>
|
||||
mockConflictedPackages.value.filter((p) =>
|
||||
p.conflicts?.some((c) => c.type === 'pending')
|
||||
)
|
||||
),
|
||||
setConflictedPackages: vi.fn(),
|
||||
clearConflicts: vi.fn()
|
||||
} as unknown as ReturnType<typeof useConflictDetectionStore>
|
||||
|
||||
const mockIsInitialized = ref(true)
|
||||
const mockSystemStatsStore = {
|
||||
systemStats: {
|
||||
system: {
|
||||
os: 'darwin', // sys.platform returns 'darwin' for macOS
|
||||
ram_total: 17179869184,
|
||||
ram_free: 8589934592,
|
||||
comfyui_version: '0.3.41',
|
||||
required_frontend_version: '1.24.0',
|
||||
python_version:
|
||||
'3.11.0 (main, Oct 13 2023, 09:34:16) [Clang 15.0.0 (clang-1500.0.40.1)]',
|
||||
pytorch_version: '2.1.0',
|
||||
embedded_python: false,
|
||||
argv: ['--enable-manager']
|
||||
},
|
||||
devices: [
|
||||
{
|
||||
name: 'Apple M1 Pro',
|
||||
type: 'mps',
|
||||
index: 0,
|
||||
vram_total: 17179869184,
|
||||
vram_free: 8589934592,
|
||||
torch_vram_total: 17179869184,
|
||||
torch_vram_free: 8589934592
|
||||
}
|
||||
]
|
||||
},
|
||||
isInitialized: mockIsInitialized,
|
||||
$state: {} as never,
|
||||
$patch: vi.fn(),
|
||||
$reset: vi.fn(),
|
||||
$subscribe: vi.fn(),
|
||||
$onAction: vi.fn(),
|
||||
$dispose: vi.fn(),
|
||||
$id: 'systemStats',
|
||||
_customProperties: new Set<string>()
|
||||
} as unknown as ReturnType<typeof useSystemStatsStore>
|
||||
|
||||
const mockAcknowledgment = {
|
||||
checkComfyUIVersionChange: vi.fn(),
|
||||
acknowledgmentState: computed(() => ({})),
|
||||
shouldShowConflictModal: computed(() => false),
|
||||
shouldShowRedDot: computed(() => false),
|
||||
shouldShowManagerBanner: computed(() => false),
|
||||
dismissRedDotNotification: vi.fn(),
|
||||
dismissWarningBanner: vi.fn(),
|
||||
markConflictsAsSeen: vi.fn()
|
||||
} as unknown as ReturnType<typeof useConflictAcknowledgment>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
pinia = createPinia()
|
||||
setActivePinia(pinia)
|
||||
|
||||
// Setup mocks
|
||||
vi.mocked(useComfyManagerService).mockReturnValue(mockComfyManagerService)
|
||||
vi.mocked(useComfyRegistryService).mockReturnValue(mockRegistryService)
|
||||
vi.mocked(useSystemStatsStore).mockReturnValue(mockSystemStatsStore)
|
||||
vi.mocked(useConflictAcknowledgment).mockReturnValue(mockAcknowledgment)
|
||||
vi.mocked(useInstalledPacks).mockReturnValue(mockInstalledPacks)
|
||||
vi.mocked(useComfyManagerStore).mockReturnValue(mockManagerStore)
|
||||
vi.mocked(useConflictDetectionStore).mockReturnValue(mockConflictStore)
|
||||
|
||||
// Reset mock implementations
|
||||
vi.mocked(mockInstalledPacks.startFetchInstalled).mockResolvedValue(
|
||||
undefined
|
||||
)
|
||||
vi.mocked(mockManagerStore.isPackEnabled).mockReturnValue(true)
|
||||
vi.mocked(mockRegistryService.getBulkNodeVersions).mockResolvedValue({
|
||||
node_versions: []
|
||||
})
|
||||
vi.mocked(mockComfyManagerService.getImportFailInfoBulk).mockResolvedValue(
|
||||
{}
|
||||
)
|
||||
|
||||
// Reset the installedPacksWithVersions data
|
||||
mockInstalledPacksWithVersions.value = []
|
||||
// Reset conflicted packages
|
||||
mockConflictedPackages.value = []
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
describe('system environment collection', () => {
|
||||
it('should collect system environment correctly', async () => {
|
||||
const { collectSystemEnvironment } = useConflictDetection()
|
||||
const environment = await collectSystemEnvironment()
|
||||
|
||||
expect(environment).toEqual({
|
||||
comfyui_version: '0.3.41',
|
||||
frontend_version: '1.24.0',
|
||||
os: 'darwin',
|
||||
accelerator: 'mps'
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle missing system stats gracefully', async () => {
|
||||
mockSystemStatsStore.systemStats = null as never
|
||||
|
||||
const { collectSystemEnvironment } = useConflictDetection()
|
||||
const environment = await collectSystemEnvironment()
|
||||
|
||||
// When systemStats is null, empty strings are used as fallback
|
||||
expect(environment).toEqual({
|
||||
comfyui_version: '',
|
||||
frontend_version: '1.24.0',
|
||||
os: '',
|
||||
accelerator: ''
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('conflict detection', () => {
|
||||
it('should detect version conflicts', async () => {
|
||||
// Setup installed packages
|
||||
mockInstalledPacks.isReady.value = true
|
||||
mockInstalledPacks.installedPacks.value = [
|
||||
{
|
||||
id: 'test-pack',
|
||||
name: 'Test Pack',
|
||||
latest_version: { version: '1.0.0' }
|
||||
} as components['schemas']['Node']
|
||||
]
|
||||
|
||||
mockInstalledPacksWithVersions.value = [
|
||||
{
|
||||
id: 'test-pack',
|
||||
version: '1.0.0'
|
||||
}
|
||||
]
|
||||
|
||||
// Mock registry response with version requirements
|
||||
vi.mocked(mockRegistryService.getBulkNodeVersions).mockResolvedValue({
|
||||
node_versions: [
|
||||
{
|
||||
status: 'success' as const,
|
||||
identifier: { node_id: 'test-pack', version: '1.0.0' },
|
||||
node_version: {
|
||||
supported_comfyui_version: '>=0.4.0',
|
||||
supported_comfyui_frontend_version: '>=2.0.0',
|
||||
supported_os: ['Windows', 'Linux', 'macOS'],
|
||||
supported_accelerators: ['CUDA', 'Metal', 'CPU'],
|
||||
status: 'NodeVersionStatusActive' as const,
|
||||
version: '1.0.0',
|
||||
publisher_id: 'test-publisher',
|
||||
node_id: 'test-pack',
|
||||
created_at: '2024-01-01T00:00:00Z'
|
||||
} as components['schemas']['NodeVersion']
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// Mock version checks to return conflicts
|
||||
vi.mocked(checkVersionCompatibility).mockImplementation(
|
||||
(type, current, required) => {
|
||||
if (type === 'comfyui_version' && required === '>=0.4.0') {
|
||||
return {
|
||||
type: 'comfyui_version',
|
||||
current_value: current || '0.3.41',
|
||||
required_value: '>=0.4.0'
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
)
|
||||
|
||||
const { runFullConflictAnalysis } = useConflictDetection()
|
||||
const result = await runFullConflictAnalysis()
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
expect(result.results).toHaveLength(1)
|
||||
expect(result.results[0].has_conflict).toBe(true)
|
||||
expect(result.results[0].conflicts).toContainEqual({
|
||||
type: 'comfyui_version',
|
||||
current_value: '0.3.41',
|
||||
required_value: '>=0.4.0'
|
||||
})
|
||||
})
|
||||
|
||||
it('should detect banned packages', async () => {
|
||||
mockInstalledPacks.isReady.value = true
|
||||
mockInstalledPacks.installedPacks.value = [
|
||||
{
|
||||
id: 'banned-pack',
|
||||
name: 'Banned Pack'
|
||||
} as components['schemas']['Node']
|
||||
]
|
||||
|
||||
mockInstalledPacksWithVersions.value = [
|
||||
{
|
||||
id: 'banned-pack',
|
||||
version: '1.0.0'
|
||||
}
|
||||
]
|
||||
|
||||
vi.mocked(mockRegistryService.getBulkNodeVersions).mockResolvedValue({
|
||||
node_versions: [
|
||||
{
|
||||
status: 'success' as const,
|
||||
identifier: { node_id: 'banned-pack', version: '1.0.0' },
|
||||
node_version: {
|
||||
status: 'NodeVersionStatusBanned' as const,
|
||||
version: '1.0.0',
|
||||
publisher_id: 'test-publisher',
|
||||
node_id: 'banned-pack',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
supported_comfyui_version: undefined,
|
||||
supported_comfyui_frontend_version: undefined,
|
||||
supported_os: undefined,
|
||||
supported_accelerators: undefined
|
||||
} as components['schemas']['NodeVersion']
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const { runFullConflictAnalysis } = useConflictDetection()
|
||||
const result = await runFullConflictAnalysis()
|
||||
|
||||
expect(result.results[0].conflicts).toContainEqual({
|
||||
type: 'banned',
|
||||
current_value: 'installed',
|
||||
required_value: 'not_banned'
|
||||
})
|
||||
})
|
||||
|
||||
it('should detect import failures', async () => {
|
||||
mockInstalledPacks.isReady.value = true
|
||||
mockInstalledPacksWithVersions.value = [
|
||||
{
|
||||
id: 'fail-pack',
|
||||
version: '1.0.0'
|
||||
}
|
||||
]
|
||||
|
||||
vi.mocked(
|
||||
mockComfyManagerService.getImportFailInfoBulk
|
||||
).mockResolvedValue({
|
||||
'fail-pack': {
|
||||
msg: 'Import error',
|
||||
name: 'fail-pack',
|
||||
path: '/path/to/pack'
|
||||
} as any // The actual API returns different structure than types
|
||||
})
|
||||
|
||||
// Mock registry response for the package
|
||||
vi.mocked(mockRegistryService.getBulkNodeVersions).mockResolvedValue({
|
||||
node_versions: []
|
||||
})
|
||||
|
||||
const { runFullConflictAnalysis } = useConflictDetection()
|
||||
const result = await runFullConflictAnalysis()
|
||||
|
||||
expect(result.results).toHaveLength(1)
|
||||
// Import failure should match the actual implementation
|
||||
expect(result.results[0].conflicts).toContainEqual({
|
||||
type: 'import_failed',
|
||||
current_value: 'installed',
|
||||
required_value: 'Import error'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('computed properties', () => {
|
||||
it('should expose conflict status from store', () => {
|
||||
mockConflictedPackages.value = [
|
||||
{
|
||||
package_id: 'test',
|
||||
package_name: 'Test',
|
||||
has_conflict: true,
|
||||
is_compatible: false,
|
||||
conflicts: []
|
||||
}
|
||||
]
|
||||
|
||||
useConflictDetection()
|
||||
|
||||
// The hasConflicts computed should be true since we have a conflict
|
||||
expect(mockConflictedPackages.value).toHaveLength(1)
|
||||
expect(mockConflictedPackages.value[0].has_conflict).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('initialization', () => {
|
||||
it('should initialize without errors', async () => {
|
||||
// Mock that installed packs are ready
|
||||
mockInstalledPacks.isReady.value = true
|
||||
mockInstalledPacksWithVersions.value = []
|
||||
|
||||
// Ensure startFetchInstalled resolves
|
||||
vi.mocked(mockInstalledPacks.startFetchInstalled).mockResolvedValue(
|
||||
undefined
|
||||
)
|
||||
|
||||
const { initializeConflictDetection } = useConflictDetection()
|
||||
|
||||
// Set a timeout to prevent hanging
|
||||
await expect(
|
||||
Promise.race([
|
||||
initializeConflictDetection(),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Timeout')), 1000)
|
||||
)
|
||||
])
|
||||
).resolves.not.toThrow()
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user