mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 15:10:06 +00:00
* [feat] add Comfy.Assets.UseAssetAPI to CORE_SETTINGS * [feat] create AssetService 1. Add service for accessing new Asset API 2. Add fallback model paths logic so empty model directories appear for the user. 3. Copious tests for them all. Co-Authored-By: Claude <noreply@anthropic.com> * [feat] switch between assets and file paths for model data * [feat] ignore assets with "missing" tag * [fix] formatting and style * [fix] call assets API with the correct filters * [feat] elminate unused modelPath code * [fix] remove stray comment * [fix] model manager api was not parsed correctly --------- Co-authored-by: Claude <noreply@anthropic.com>
151 lines
4.2 KiB
TypeScript
151 lines
4.2 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { api } from '@/scripts/api'
|
|
import { assetService } from '@/services/assetService'
|
|
|
|
// Test data constants
|
|
const MOCK_ASSETS = {
|
|
checkpoints: {
|
|
id: 'uuid-1',
|
|
name: 'model1.safetensors',
|
|
tags: ['models', 'checkpoints'],
|
|
size: 123456
|
|
},
|
|
loras: {
|
|
id: 'uuid-2',
|
|
name: 'model2.safetensors',
|
|
tags: ['models', 'loras'],
|
|
size: 654321
|
|
},
|
|
vae: {
|
|
id: 'uuid-3',
|
|
name: 'vae1.safetensors',
|
|
tags: ['models', 'vae'],
|
|
size: 789012
|
|
}
|
|
} as const
|
|
|
|
// Helper functions
|
|
function mockApiResponse(assets: any[], options = {}) {
|
|
const response = {
|
|
assets,
|
|
total: assets.length,
|
|
has_more: false,
|
|
...options
|
|
}
|
|
vi.mocked(api.fetchApi).mockResolvedValueOnce(Response.json(response))
|
|
return response
|
|
}
|
|
|
|
function mockApiError(status: number, statusText = 'Error') {
|
|
vi.mocked(api.fetchApi).mockResolvedValueOnce(
|
|
new Response(null, { status, statusText })
|
|
)
|
|
}
|
|
|
|
describe('assetService', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks()
|
|
vi.spyOn(api, 'fetchApi')
|
|
})
|
|
|
|
describe('getAssetModelFolders', () => {
|
|
it('should extract directory names from asset tags and filter blacklisted ones', async () => {
|
|
const assets = [
|
|
{
|
|
id: 'uuid-1',
|
|
name: 'checkpoint1.safetensors',
|
|
tags: ['models', 'checkpoints'],
|
|
size: 123456
|
|
},
|
|
{
|
|
id: 'uuid-2',
|
|
name: 'config.yaml',
|
|
tags: ['models', 'configs'], // Blacklisted
|
|
size: 654321
|
|
},
|
|
{
|
|
id: 'uuid-3',
|
|
name: 'vae1.safetensors',
|
|
tags: ['models', 'vae'],
|
|
size: 789012
|
|
}
|
|
]
|
|
mockApiResponse(assets)
|
|
|
|
const result = await assetService.getAssetModelFolders()
|
|
|
|
expect(api.fetchApi).toHaveBeenCalledWith('/assets?include_tags=models')
|
|
expect(result).toHaveLength(2)
|
|
|
|
const folderNames = result.map((f) => f.name)
|
|
expect(folderNames).toEqual(['checkpoints', 'vae'])
|
|
expect(folderNames).not.toContain('configs')
|
|
})
|
|
|
|
it('should handle errors and empty responses', async () => {
|
|
// Empty response
|
|
mockApiResponse([])
|
|
const emptyResult = await assetService.getAssetModelFolders()
|
|
expect(emptyResult).toHaveLength(0)
|
|
|
|
// Network error
|
|
vi.mocked(api.fetchApi).mockRejectedValueOnce(new Error('Network error'))
|
|
await expect(assetService.getAssetModelFolders()).rejects.toThrow(
|
|
'Network error'
|
|
)
|
|
|
|
// HTTP error
|
|
mockApiError(500)
|
|
await expect(assetService.getAssetModelFolders()).rejects.toThrow(
|
|
'Unable to load model folders: Server returned 500. Please try again.'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('getAssetModels', () => {
|
|
it('should return filtered models for folder', async () => {
|
|
const assets = [
|
|
{ ...MOCK_ASSETS.checkpoints, name: 'valid.safetensors' },
|
|
{ ...MOCK_ASSETS.checkpoints, name: undefined }, // Invalid name
|
|
{ ...MOCK_ASSETS.loras, name: 'lora.safetensors' }, // Wrong tag
|
|
{
|
|
id: 'uuid-4',
|
|
name: 'missing-model.safetensors',
|
|
tags: ['models', 'checkpoints', 'missing'], // Has missing tag
|
|
size: 654321
|
|
}
|
|
]
|
|
mockApiResponse(assets)
|
|
|
|
const result = await assetService.getAssetModels('checkpoints')
|
|
|
|
expect(api.fetchApi).toHaveBeenCalledWith(
|
|
'/assets?include_tags=models,checkpoints'
|
|
)
|
|
expect(result).toEqual([
|
|
expect.objectContaining({ name: 'valid.safetensors', pathIndex: 0 })
|
|
])
|
|
})
|
|
|
|
it('should handle errors and empty responses', async () => {
|
|
// Empty response
|
|
mockApiResponse([])
|
|
const emptyResult = await assetService.getAssetModels('nonexistent')
|
|
expect(emptyResult).toEqual([])
|
|
|
|
// Network error
|
|
vi.mocked(api.fetchApi).mockRejectedValueOnce(new Error('Network error'))
|
|
await expect(assetService.getAssetModels('checkpoints')).rejects.toThrow(
|
|
'Network error'
|
|
)
|
|
|
|
// HTTP error
|
|
mockApiError(404)
|
|
await expect(assetService.getAssetModels('checkpoints')).rejects.toThrow(
|
|
'Unable to load models for checkpoints: Server returned 404. Please try again.'
|
|
)
|
|
})
|
|
})
|
|
})
|