mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-30 21:09:53 +00:00
## Summary Moves the fetch and post-fetch logic associated with the asset browser into the component and shows a loading state while fetching. To test, use this branch: https://github.com/comfyanonymous/ComfyUI/pull/10045 https://github.com/user-attachments/assets/718974d5-efc7-46a0-bcd6-e82596d4c389 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6189-load-assets-browser-before-fetch-completes-and-show-loading-state-2946d73d365081879d1bd05d86e8c036) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com>
180 lines
5.3 KiB
TypeScript
180 lines
5.3 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import { useAssetBrowserDialog } from '@/platform/assets/composables/useAssetBrowserDialog'
|
|
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
|
import { useDialogStore } from '@/stores/dialogStore'
|
|
|
|
vi.mock('@/stores/dialogStore')
|
|
|
|
vi.mock('@/i18n', () => ({
|
|
t: (key: string, params?: Record<string, string>) => {
|
|
if (params) {
|
|
return `${key}:${JSON.stringify(params)}`
|
|
}
|
|
return key
|
|
}
|
|
}))
|
|
|
|
function createMockAsset(overrides: Partial<AssetItem> = {}): AssetItem {
|
|
return {
|
|
id: 'asset-123',
|
|
name: 'test-model.safetensors',
|
|
size: 1024,
|
|
created_at: '2025-10-01T00:00:00Z',
|
|
tags: ['models', 'checkpoints'],
|
|
user_metadata: {
|
|
filename: 'models/checkpoints/test-model.safetensors'
|
|
},
|
|
...overrides
|
|
}
|
|
}
|
|
|
|
function setupDialogMocks() {
|
|
const mockShowDialog = vi.fn()
|
|
const mockCloseDialog = vi.fn()
|
|
vi.mocked(useDialogStore, { partial: true }).mockReturnValue({
|
|
showDialog: mockShowDialog,
|
|
closeDialog: mockCloseDialog
|
|
})
|
|
|
|
return { mockShowDialog, mockCloseDialog }
|
|
}
|
|
|
|
describe('useAssetBrowserDialog', () => {
|
|
describe('Asset Selection Flow', () => {
|
|
it('auto-closes dialog when asset is selected', async () => {
|
|
const { mockShowDialog, mockCloseDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
const onAssetSelected = vi.fn()
|
|
|
|
await assetBrowserDialog.show({
|
|
nodeType: 'CheckpointLoaderSimple',
|
|
inputName: 'ckpt_name',
|
|
onAssetSelected
|
|
})
|
|
|
|
const dialogCall = mockShowDialog.mock.calls[0][0]
|
|
const onSelectHandler = dialogCall.props.onSelect
|
|
|
|
const mockAsset = {
|
|
id: 'test-asset-id',
|
|
name: 'test.safetensors',
|
|
size: 1024,
|
|
created_at: '2025-10-01T00:00:00Z',
|
|
tags: ['models', 'checkpoints'],
|
|
user_metadata: { filename: 'selected-asset-path' }
|
|
}
|
|
onSelectHandler(mockAsset)
|
|
|
|
expect(onAssetSelected).toHaveBeenCalledWith(mockAsset)
|
|
expect(mockCloseDialog).toHaveBeenCalledWith({
|
|
key: 'global-asset-browser'
|
|
})
|
|
})
|
|
|
|
it('closes dialog when close handler is called', async () => {
|
|
const { mockShowDialog, mockCloseDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
|
|
await assetBrowserDialog.show({
|
|
nodeType: 'CheckpointLoaderSimple',
|
|
inputName: 'ckpt_name'
|
|
})
|
|
|
|
const dialogCall = mockShowDialog.mock.calls[0][0]
|
|
const onCloseHandler = dialogCall.props.onClose
|
|
|
|
onCloseHandler()
|
|
|
|
expect(mockCloseDialog).toHaveBeenCalledWith({
|
|
key: 'global-asset-browser'
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('.browse() method', () => {
|
|
it('opens asset browser dialog with tag-based filtering', async () => {
|
|
const { mockShowDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
await assetBrowserDialog.browse({
|
|
assetType: 'models',
|
|
title: 'Model Library'
|
|
})
|
|
|
|
expect(mockShowDialog).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
key: 'global-asset-browser',
|
|
props: expect.objectContaining({
|
|
showLeftPanel: true,
|
|
assetType: 'models'
|
|
})
|
|
})
|
|
)
|
|
})
|
|
|
|
it('calls onAssetSelected callback when asset is selected', async () => {
|
|
const { mockShowDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
const mockAsset = createMockAsset()
|
|
const onAssetSelected = vi.fn()
|
|
await assetBrowserDialog.browse({
|
|
assetType: 'models',
|
|
onAssetSelected
|
|
})
|
|
|
|
const dialogCall = mockShowDialog.mock.calls[0][0]
|
|
const onSelectHandler = dialogCall.props.onSelect
|
|
|
|
onSelectHandler(mockAsset)
|
|
|
|
expect(onAssetSelected).toHaveBeenCalledWith(mockAsset)
|
|
})
|
|
|
|
it('closes dialog after asset selection', async () => {
|
|
const { mockShowDialog, mockCloseDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
const mockAsset = createMockAsset()
|
|
await assetBrowserDialog.browse({
|
|
assetType: 'models'
|
|
})
|
|
|
|
const dialogCall = mockShowDialog.mock.calls[0][0]
|
|
const onSelectHandler = dialogCall.props.onSelect
|
|
|
|
onSelectHandler(mockAsset)
|
|
|
|
expect(mockCloseDialog).toHaveBeenCalledWith({
|
|
key: 'global-asset-browser'
|
|
})
|
|
})
|
|
|
|
it('uses custom title when provided', async () => {
|
|
const { mockShowDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
await assetBrowserDialog.browse({
|
|
assetType: 'models',
|
|
title: 'Custom Model Browser'
|
|
})
|
|
|
|
const dialogCall = mockShowDialog.mock.calls[0][0]
|
|
expect(dialogCall.props.title).toBe('Custom Model Browser')
|
|
})
|
|
})
|
|
|
|
describe('.show() behavior', () => {
|
|
it('opens dialog without pre-fetched assets', async () => {
|
|
const { mockShowDialog } = setupDialogMocks()
|
|
const assetBrowserDialog = useAssetBrowserDialog()
|
|
|
|
await assetBrowserDialog.show({
|
|
nodeType: 'CheckpointLoaderSimple',
|
|
inputName: 'ckpt_name'
|
|
})
|
|
|
|
const dialogCall = mockShowDialog.mock.calls[0][0]
|
|
expect(dialogCall.props.nodeType).toBe('CheckpointLoaderSimple')
|
|
expect(dialogCall.props.assets).toBeUndefined()
|
|
})
|
|
})
|
|
})
|