diff --git a/src/scripts/app.ts b/src/scripts/app.ts index d7b1e3a4a..c095f1af3 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -929,20 +929,25 @@ export class ComfyApp { } async getNodeDefs(): Promise> { - const translateNodeDef = (def: ComfyNodeDefV1): ComfyNodeDefV1 => ({ - ...def, - display_name: st( - `nodeDefs.${def.name}.display_name`, - def.display_name ?? def.name - ), - description: def.description - ? st(`nodeDefs.${def.name}.description`, def.description) - : '', - category: def.category - .split('/') - .map((category: string) => st(`nodeCategories.${category}`, category)) - .join('/') - }) + const translateNodeDef = (def: ComfyNodeDefV1): ComfyNodeDefV1 => { + // Use object info display_name as fallback before using name + const objectInfoDisplayName = def.display_name || def.name + + return { + ...def, + display_name: st( + `nodeDefs.${def.name}.display_name`, + objectInfoDisplayName + ), + description: def.description + ? st(`nodeDefs.${def.name}.description`, def.description) + : '', + category: def.category + .split('/') + .map((category: string) => st(`nodeCategories.${category}`, category)) + .join('/') + } + } return _.mapValues(await api.getNodeDefs(), (def) => translateNodeDef(def)) } diff --git a/tests-ui/tests/scripts/app.getNodeDefs.test.ts b/tests-ui/tests/scripts/app.getNodeDefs.test.ts new file mode 100644 index 000000000..1818f6ed7 --- /dev/null +++ b/tests-ui/tests/scripts/app.getNodeDefs.test.ts @@ -0,0 +1,133 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import { st } from '@/i18n' +import type { ComfyNodeDef as ComfyNodeDefV1 } from '@/schemas/nodeDefSchema' +import { api } from '@/scripts/api' +import { app as comfyApp } from '@/scripts/app' + +vi.mock('@/scripts/api', () => ({ + api: { + getNodeDefs: vi.fn(), + apiURL: vi.fn((path: string) => path), + addEventListener: vi.fn(), + getUserData: vi.fn(), + storeUserData: vi.fn() + } +})) + +vi.mock('@/i18n', () => ({ + st: vi.fn((_key: string, fallback: string) => fallback), + t: vi.fn((key: string) => key), + te: vi.fn(() => false) +})) + +describe('ComfyApp.getNodeDefs', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('should use object info display_name when available', async () => { + const mockNodeDefs: Record = { + TestNode: { + name: 'TestNode', + display_name: 'Custom Display Name', + category: 'test', + description: 'Test description', + input: {}, + output: [], + output_node: false, + python_module: 'test.module' + } + } + + vi.mocked(api.getNodeDefs).mockResolvedValue(mockNodeDefs) + + const result = await comfyApp.getNodeDefs() + + // st should be called with the object info display_name as fallback + expect(vi.mocked(st)).toHaveBeenCalledWith( + 'nodeDefs.TestNode.display_name', + 'Custom Display Name' + ) + expect(result.TestNode.display_name).toBe('Custom Display Name') + }) + + it('should fall back to name when display_name is missing', async () => { + const mockNodeDefs: Record = { + TestNode: { + name: 'TestNode', + display_name: '', + category: 'test', + description: 'Test description', + input: {}, + output: [], + output_node: false, + python_module: 'test.module' + } + } + + vi.mocked(api.getNodeDefs).mockResolvedValue(mockNodeDefs) + + const result = await comfyApp.getNodeDefs() + + // When display_name is empty, should fall back to name + expect(vi.mocked(st)).toHaveBeenCalledWith( + 'nodeDefs.TestNode.display_name', + 'TestNode' + ) + expect(result.TestNode.display_name).toBe('TestNode') + }) + + it('should prioritize translation over object info display_name', async () => { + const mockNodeDefs: Record = { + TestNode: { + name: 'TestNode', + display_name: 'Object Info Display Name', + category: 'test', + description: 'Test description', + input: {}, + output: [], + output_node: false, + python_module: 'test.module' + } + } + + vi.mocked(api.getNodeDefs).mockResolvedValue(mockNodeDefs) + // Mock st to return a translation instead of fallback + vi.mocked(st).mockReturnValue('Translated Display Name') + + const result = await comfyApp.getNodeDefs() + + expect(result.TestNode.display_name).toBe('Translated Display Name') + }) + + it('should handle nodes with undefined display_name', async () => { + const mockNodeDefs: Record = { + TestNode: { + name: 'TestNode', + display_name: undefined as any, + category: 'test', + description: 'Test description', + input: {}, + output: [], + output_node: false, + python_module: 'test.module' + } + } + + vi.mocked(api.getNodeDefs).mockResolvedValue(mockNodeDefs) + // Reset st to return fallback instead of translation + vi.mocked(st).mockImplementation( + (_key: string, fallback: string) => fallback + ) + + const result = await comfyApp.getNodeDefs() + + // When display_name is undefined, should fall back to name + expect(vi.mocked(st)).toHaveBeenCalledWith( + 'nodeDefs.TestNode.display_name', + 'TestNode' + ) + expect(result.TestNode.display_name).toBe('TestNode') + }) +})