import { describe, expect, it, vi } from 'vitest' vi.unmock('@/blocks/registry') import { extractWorkflowName, parseWorkflowJson, sanitizePathSegment, } from '@/lib/workflows/operations/import-export' function createLegacyState() { return { blocks: { 'start-1': { id: 'start-1', type: 'start_trigger', name: 'Start', position: { x: 0, y: 0 }, enabled: true, subBlocks: { inputFormat: { id: 'inputFormat', type: 'input-format', value: [], }, undefined: { type: 'unknown', value: 'stale duplicate', }, }, outputs: {}, data: {}, }, }, edges: [], loops: {}, parallels: {}, variables: {}, metadata: { name: 'Wrapped Workflow', }, } } describe('workflow import/export parsing', () => { it('parses workflow exports wrapped in an API data envelope', () => { const content = JSON.stringify({ data: { version: '1.0', exportedAt: '2026-05-07T06:45:06.892Z', workflow: { name: 'Wrapped Workflow', }, state: createLegacyState(), }, }) const result = parseWorkflowJson(content, false) expect(result.errors).toEqual([]) expect(result.data?.blocks['start-1']).toBeDefined() expect(result.data?.blocks['start-1'].subBlocks.inputFormat).toEqual({ id: 'inputFormat', type: 'input-format', value: [], }) expect(result.data?.blocks['start-1'].subBlocks.undefined).toBeUndefined() }) it('extracts workflow names from wrapped exports', () => { const content = JSON.stringify({ data: { workflow: { name: 'Wrapped Workflow', }, state: createLegacyState(), }, }) expect(extractWorkflowName(content, 'wf.json')).toBe('Wrapped Workflow') }) it('parses API envelopes that contain state without an export version', () => { const content = JSON.stringify({ data: { workflow: { name: 'API Workflow', }, state: createLegacyState(), }, }) const result = parseWorkflowJson(content, false) expect(result.errors).toEqual([]) expect(result.data?.blocks['start-1']).toBeDefined() expect(result.data?.blocks['start-1'].subBlocks.undefined).toBeUndefined() }) it('preserves malformed legacy renamed subBlocks during import parsing', () => { const state = { ...createLegacyState(), blocks: { knowledge: { id: 'knowledge', type: 'knowledge', name: 'Knowledge', position: { x: 0, y: 0 }, enabled: true, subBlocks: { operation: { id: 'operation', type: 'dropdown', value: 'search' }, knowledgeBaseId: { id: 'knowledgeBaseId', type: 'unknown', value: 'kb-uuid-123', }, }, outputs: {}, data: {}, }, }, } const content = JSON.stringify({ data: { workflow: { name: 'Knowledge Workflow' }, state } }) const result = parseWorkflowJson(content, false) expect(result.errors).toEqual([]) expect(result.data?.blocks.knowledge.subBlocks.knowledgeBaseId).toBeUndefined() expect(result.data?.blocks.knowledge.subBlocks.knowledgeBaseSelector).toEqual({ id: 'knowledgeBaseSelector', type: 'knowledge-base-selector', value: 'kb-uuid-123', }) }) }) describe('sanitizePathSegment', () => { it('should preserve ASCII alphanumeric characters', () => { expect(sanitizePathSegment('workflow-123_abc')).toBe('workflow-123_abc') }) it('should replace spaces with dashes', () => { expect(sanitizePathSegment('my workflow')).toBe('my-workflow') }) it('should replace special characters with dashes', () => { expect(sanitizePathSegment('workflow!@#')).toBe('workflow-') }) it('should preserve Korean characters (BUG REPRODUCTION)', () => { expect(sanitizePathSegment('한글')).toBe('한글') }) it('should preserve other Unicode characters', () => { expect(sanitizePathSegment('日本語')).toBe('日本語') }) it('should remove filesystem unsafe characters', () => { expect(sanitizePathSegment('work/flow?name*')).not.toContain('/') expect(sanitizePathSegment('work/flow?name*')).not.toContain('?') expect(sanitizePathSegment('work/flow?name*')).not.toContain('*') }) })