mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Refactor conflict detection system and move to manager extension ### Description This PR refactors the conflict detection system, moving it from the global composables to the manager extension folder for better code organization. Additionally, it improves test type safety and adds comprehensive test coverage for utility functions. ### Main Changes #### 📦 Code Organization - **Moved conflict detection to manager extension** - Relocated all conflict detection related composables, stores, and utilities from global scope to `/workbench/extensions/manager/` for better modularity (https://github.com/Comfy-Org/ComfyUI_frontend/pull/5722) - **Moved from** `src/composables/useConflictDetection.ts` **to** `src/workbench/extensions/manager/composables/useConflictDetection.ts` - Moved related stores and composables to maintain cohesive module structure #### ♻️ Refactoring - **Extracted utility functions** - Split conflict detection logic into separate utility modules: - `conflictUtils.ts` - Conflict consolidation and summary generation - `systemCompatibility.ts` - OS and accelerator compatibility checking - `versionUtil.ts` - Version compatibility checking - **Removed duplicate state management** - Cleaned up redundant state and unused functions - **Improved naming conventions** - Renamed functions for better clarity - **Removed unused system environment code** - Cleaned up deprecated code #### 🔧 Test Improvements - **Fixed TypeScript errors** in all test files - removed all `any` type usage - **Added comprehensive test coverage**: - `conflictUtils.test.ts` - 299 lines of tests for conflict utilities - `systemCompatibility.test.ts` - 270 lines of tests for compatibility checking - `versionUtil.test.ts` - 342 lines of tests for version utilities - **Updated mock objects** to match actual implementations - **Aligned with backend changes** - Updated SystemStats structure to include `pytorch_version`, `embedded_python`, `required_frontend_version` #### 🐛 Bug Fixes - **Fixed OS detection bug** - Resolved issue where 'darwin' was incorrectly matched as 'Windows' due to containing 'win' substring - **Fixed import paths** - Updated all import paths after moving to manager extension - **Fixed unused exports** - Removed all unused function exports - **Fixed lint errors** - Resolved all ESLint and Prettier issues ### File Structure Changes ``` Before: src/ ├── composables/ │ └── useConflictDetection.ts (1374 lines) └── types/ After: src/ ├── utils/ │ ├── conflictUtils.ts (114 lines) │ ├── systemCompatibility.ts (125 lines) │ └── versionUtil.ts (enhanced) └── workbench/extensions/manager/ ├── composables/ │ ├── useConflictDetection.ts (758 lines) │ └── [other composables] └── stores/ └── conflictDetectionStore.ts ``` ### Testing All tests pass successfully: - ✅ **155 test files passed** - ✅ **2209 tests passed** - ⏩ 19 skipped (intentionally skipped subgraph-related tests) ### Impact - **Better code organization** - Manager-specific code is now properly isolated - **Improved maintainability** - Smaller, focused utility functions are easier to test and maintain - **Enhanced type safety** - No more `any` types in tests - **Comprehensive test coverage** - All utility functions are thoroughly tested ### Commits in this PR 1. OS detection bug fix and refactor 2. Remove unused system environment code 3. Improve function naming 4. Refactor conflict detection 5. Remove duplicate state and unused functions 6. Fix unused function exports 7. Move manager features to workbench extension folder 8. Fix import paths 9. Rename systemCompatibility file 10. Improve test type safety 11. Apply ESLint and Prettier fixes ## Screenshots (if applicable) [screen-capture.webm](https://github.com/user-attachments/assets/b4595604-3761-4d98-ae8e-5693cd0c95bd) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5436-Manager-refactor-conflict-detect-2686d73d36508186ba06f57dae3656e5) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com>
272 lines
8.1 KiB
TypeScript
272 lines
8.1 KiB
TypeScript
import { createPinia, setActivePinia } from 'pinia'
|
|
import { beforeEach, describe, expect, it } from 'vitest'
|
|
|
|
import { useConflictDetectionStore } from '@/workbench/extensions/manager/stores/conflictDetectionStore'
|
|
import type { ConflictDetectionResult } from '@/workbench/extensions/manager/types/conflictDetectionTypes'
|
|
|
|
describe('useConflictDetectionStore', () => {
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia())
|
|
})
|
|
|
|
const mockConflictedPackages: ConflictDetectionResult[] = [
|
|
{
|
|
package_id: 'ComfyUI-Manager',
|
|
package_name: 'ComfyUI-Manager',
|
|
has_conflict: true,
|
|
is_compatible: false,
|
|
conflicts: [
|
|
{
|
|
type: 'pending',
|
|
current_value: 'no_registry_data',
|
|
required_value: 'registry_data_available'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
package_id: 'comfyui-easy-use',
|
|
package_name: 'comfyui-easy-use',
|
|
has_conflict: true,
|
|
is_compatible: false,
|
|
conflicts: [
|
|
{
|
|
type: 'comfyui_version',
|
|
current_value: '0.3.43',
|
|
required_value: '<0.3.40'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
package_id: 'img2colors-comfyui-node',
|
|
package_name: 'img2colors-comfyui-node',
|
|
has_conflict: true,
|
|
is_compatible: false,
|
|
conflicts: [
|
|
{
|
|
type: 'banned',
|
|
current_value: 'installed',
|
|
required_value: 'not_banned'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
|
|
describe('initial state', () => {
|
|
it('should have empty initial state', () => {
|
|
const store = useConflictDetectionStore()
|
|
|
|
expect(store.conflictedPackages).toEqual([])
|
|
expect(store.isDetecting).toBe(false)
|
|
expect(store.lastDetectionTime).toBeNull()
|
|
expect(store.hasConflicts).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('setConflictedPackages', () => {
|
|
it('should set conflicted packages', () => {
|
|
const store = useConflictDetectionStore()
|
|
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
expect(store.conflictedPackages).toEqual(mockConflictedPackages)
|
|
expect(store.conflictedPackages).toHaveLength(3)
|
|
})
|
|
|
|
it('should update hasConflicts computed property', () => {
|
|
const store = useConflictDetectionStore()
|
|
|
|
expect(store.hasConflicts).toBe(false)
|
|
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
expect(store.hasConflicts).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('getConflictsForPackageByID', () => {
|
|
it('should find package by exact ID match', () => {
|
|
const store = useConflictDetectionStore()
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
const result = store.getConflictsForPackageByID('ComfyUI-Manager')
|
|
|
|
expect(result).toBeDefined()
|
|
expect(result?.package_id).toBe('ComfyUI-Manager')
|
|
expect(result?.conflicts).toHaveLength(1)
|
|
})
|
|
|
|
it('should return undefined for non-existent package', () => {
|
|
const store = useConflictDetectionStore()
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
const result = store.getConflictsForPackageByID('non-existent-package')
|
|
|
|
expect(result).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('bannedPackages', () => {
|
|
it('should filter packages with banned conflicts', () => {
|
|
const store = useConflictDetectionStore()
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
const bannedPackages = store.bannedPackages
|
|
|
|
expect(bannedPackages).toHaveLength(1)
|
|
expect(bannedPackages[0].package_id).toBe('img2colors-comfyui-node')
|
|
})
|
|
|
|
it('should return empty array when no banned packages', () => {
|
|
const store = useConflictDetectionStore()
|
|
const noBannedPackages = mockConflictedPackages.filter(
|
|
(pkg) => !pkg.conflicts.some((c) => c.type === 'banned')
|
|
)
|
|
store.setConflictedPackages(noBannedPackages)
|
|
|
|
const bannedPackages = store.bannedPackages
|
|
|
|
expect(bannedPackages).toHaveLength(0)
|
|
})
|
|
})
|
|
|
|
describe('securityPendingPackages', () => {
|
|
it('should filter packages with pending conflicts', () => {
|
|
const store = useConflictDetectionStore()
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
const securityPendingPackages = store.securityPendingPackages
|
|
|
|
expect(securityPendingPackages).toHaveLength(1)
|
|
expect(securityPendingPackages[0].package_id).toBe('ComfyUI-Manager')
|
|
})
|
|
})
|
|
|
|
describe('clearConflicts', () => {
|
|
it('should clear all conflicted packages', () => {
|
|
const store = useConflictDetectionStore()
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
expect(store.conflictedPackages).toHaveLength(3)
|
|
expect(store.hasConflicts).toBe(true)
|
|
|
|
store.clearConflicts()
|
|
|
|
expect(store.conflictedPackages).toEqual([])
|
|
expect(store.hasConflicts).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('detection state management', () => {
|
|
it('should set detecting state', () => {
|
|
const store = useConflictDetectionStore()
|
|
|
|
expect(store.isDetecting).toBe(false)
|
|
|
|
store.setDetecting(true)
|
|
|
|
expect(store.isDetecting).toBe(true)
|
|
|
|
store.setDetecting(false)
|
|
|
|
expect(store.isDetecting).toBe(false)
|
|
})
|
|
|
|
it('should set last detection time', () => {
|
|
const store = useConflictDetectionStore()
|
|
const timestamp = '2024-01-01T00:00:00Z'
|
|
|
|
expect(store.lastDetectionTime).toBeNull()
|
|
|
|
store.setLastDetectionTime(timestamp)
|
|
|
|
expect(store.lastDetectionTime).toBe(timestamp)
|
|
})
|
|
})
|
|
|
|
describe('reactivity', () => {
|
|
it('should update computed properties when conflicted packages change', () => {
|
|
const store = useConflictDetectionStore()
|
|
|
|
// Initially no conflicts
|
|
expect(store.hasConflicts).toBe(false)
|
|
expect(store.bannedPackages).toHaveLength(0)
|
|
|
|
// Add conflicts
|
|
store.setConflictedPackages(mockConflictedPackages)
|
|
|
|
// Computed properties should update
|
|
expect(store.hasConflicts).toBe(true)
|
|
expect(store.bannedPackages).toHaveLength(1)
|
|
expect(store.securityPendingPackages).toHaveLength(1)
|
|
|
|
// Clear conflicts
|
|
store.clearConflicts()
|
|
|
|
// Computed properties should update again
|
|
expect(store.hasConflicts).toBe(false)
|
|
expect(store.bannedPackages).toHaveLength(0)
|
|
expect(store.securityPendingPackages).toHaveLength(0)
|
|
})
|
|
})
|
|
|
|
describe('edge cases', () => {
|
|
it('should handle empty conflicts array', () => {
|
|
const store = useConflictDetectionStore()
|
|
store.setConflictedPackages([])
|
|
|
|
expect(store.conflictedPackages).toEqual([])
|
|
expect(store.hasConflicts).toBe(false)
|
|
expect(store.bannedPackages).toHaveLength(0)
|
|
expect(store.securityPendingPackages).toHaveLength(0)
|
|
})
|
|
|
|
it('should handle packages with multiple conflict types', () => {
|
|
const store = useConflictDetectionStore()
|
|
const multiConflictPackage: ConflictDetectionResult = {
|
|
package_id: 'multi-conflict-package',
|
|
package_name: 'Multi Conflict Package',
|
|
has_conflict: true,
|
|
is_compatible: false,
|
|
conflicts: [
|
|
{
|
|
type: 'banned',
|
|
current_value: 'installed',
|
|
required_value: 'not_banned'
|
|
},
|
|
{
|
|
type: 'pending',
|
|
current_value: 'no_registry_data',
|
|
required_value: 'registry_data_available'
|
|
}
|
|
]
|
|
}
|
|
|
|
store.setConflictedPackages([multiConflictPackage])
|
|
|
|
// Should appear in both banned and security pending
|
|
expect(store.bannedPackages).toHaveLength(1)
|
|
expect(store.securityPendingPackages).toHaveLength(1)
|
|
expect(store.bannedPackages[0].package_id).toBe('multi-conflict-package')
|
|
expect(store.securityPendingPackages[0].package_id).toBe(
|
|
'multi-conflict-package'
|
|
)
|
|
})
|
|
|
|
it('should handle packages with has_conflict false', () => {
|
|
const store = useConflictDetectionStore()
|
|
const noConflictPackage: ConflictDetectionResult = {
|
|
package_id: 'no-conflict-package',
|
|
package_name: 'No Conflict Package',
|
|
has_conflict: false,
|
|
is_compatible: true,
|
|
conflicts: []
|
|
}
|
|
|
|
store.setConflictedPackages([noConflictPackage])
|
|
|
|
// hasConflicts should check has_conflict property
|
|
expect(store.hasConflicts).toBe(false)
|
|
})
|
|
})
|
|
})
|