mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
fix: properly type extractWorkflow return (#7646)
## Summary Type `extractWorkflow` return as `ComfyWorkflowJSON | undefined` instead of `unknown` for better type safety downstream. ## Context This is a small preparatory PR to slim down the Jobs API migration PR (PR 2 of 3). ## Test plan - [x] TypeCheck passes - [x] Lint passes 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7646-fix-properly-type-extractWorkflow-return-2ce6d73d365081c794eac3669632271f) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -257,35 +257,66 @@ describe('fetchJobs', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('extractWorkflow', () => {
|
describe('extractWorkflow', () => {
|
||||||
it('extracts workflow from nested structure', () => {
|
const validWorkflow = {
|
||||||
|
version: 0.4,
|
||||||
|
last_node_id: 1,
|
||||||
|
last_link_id: 0,
|
||||||
|
nodes: [],
|
||||||
|
links: []
|
||||||
|
}
|
||||||
|
|
||||||
|
it('extracts and validates workflow from nested structure', async () => {
|
||||||
const jobDetail = {
|
const jobDetail = {
|
||||||
...createMockJob('job1', 'completed'),
|
...createMockJob('job1', 'completed'),
|
||||||
workflow: {
|
workflow: {
|
||||||
extra_data: {
|
extra_data: {
|
||||||
extra_pnginfo: {
|
extra_pnginfo: {
|
||||||
workflow: { nodes: [], links: [] }
|
workflow: validWorkflow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflow = extractWorkflow(jobDetail)
|
const workflow = await extractWorkflow(jobDetail)
|
||||||
|
|
||||||
expect(workflow).toEqual({ nodes: [], links: [] })
|
expect(workflow).toEqual(validWorkflow)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns undefined if workflow not present', () => {
|
it('returns undefined if workflow not present', async () => {
|
||||||
const jobDetail = createMockJob('job1', 'completed')
|
const jobDetail = createMockJob('job1', 'completed')
|
||||||
|
|
||||||
const workflow = extractWorkflow(jobDetail)
|
const workflow = await extractWorkflow(jobDetail)
|
||||||
|
|
||||||
expect(workflow).toBeUndefined()
|
expect(workflow).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns undefined for undefined input', () => {
|
it('returns undefined for undefined input', async () => {
|
||||||
const workflow = extractWorkflow(undefined)
|
const workflow = await extractWorkflow(undefined)
|
||||||
|
|
||||||
expect(workflow).toBeUndefined()
|
expect(workflow).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('returns undefined for invalid workflow and logs warning', async () => {
|
||||||
|
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||||
|
const jobDetail = {
|
||||||
|
...createMockJob('job1', 'completed'),
|
||||||
|
workflow: {
|
||||||
|
extra_data: {
|
||||||
|
extra_pnginfo: {
|
||||||
|
workflow: { invalid: 'data' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const workflow = await extractWorkflow(jobDetail)
|
||||||
|
|
||||||
|
expect(workflow).toBeUndefined()
|
||||||
|
expect(consoleSpy).toHaveBeenCalledWith(
|
||||||
|
'[extractWorkflow] Workflow validation failed:',
|
||||||
|
expect.any(String)
|
||||||
|
)
|
||||||
|
consoleSpy.mockRestore()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
* All distributions use the /jobs endpoint.
|
* All distributions use the /jobs endpoint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||||
|
import { validateComfyWorkflow } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||||
import type { PromptId } from '@/schemas/apiSchema'
|
import type { PromptId } from '@/schemas/apiSchema'
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -135,12 +137,25 @@ export async function fetchJobDetail(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts workflow from job detail response.
|
* Extracts and validates workflow from job detail response.
|
||||||
* The workflow is nested at: workflow.extra_data.extra_pnginfo.workflow
|
* The workflow is nested at: workflow.extra_data.extra_pnginfo.workflow
|
||||||
* Full workflow validation happens downstream via validateComfyWorkflow.
|
*
|
||||||
|
* Uses Zod validation via validateComfyWorkflow to ensure the workflow
|
||||||
|
* conforms to the expected schema. Logs validation failures for debugging
|
||||||
|
* but still returns undefined to allow graceful degradation.
|
||||||
*/
|
*/
|
||||||
export function extractWorkflow(job: JobDetail | undefined): unknown {
|
export async function extractWorkflow(
|
||||||
|
job: JobDetail | undefined
|
||||||
|
): Promise<ComfyWorkflowJSON | undefined> {
|
||||||
const parsed = zWorkflowContainer.safeParse(job?.workflow)
|
const parsed = zWorkflowContainer.safeParse(job?.workflow)
|
||||||
if (!parsed.success) return undefined
|
if (!parsed.success) return undefined
|
||||||
return parsed.data.extra_data?.extra_pnginfo?.workflow
|
|
||||||
|
const rawWorkflow = parsed.data.extra_data?.extra_pnginfo?.workflow
|
||||||
|
if (!rawWorkflow) return undefined
|
||||||
|
|
||||||
|
const validated = await validateComfyWorkflow(rawWorkflow, (error) => {
|
||||||
|
console.warn('[extractWorkflow] Workflow validation failed:', error)
|
||||||
|
})
|
||||||
|
|
||||||
|
return validated ?? undefined
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user