Skip to content

Commit 75faab2

Browse files
committed
add tests - fix history_v2/:prompt_id fmt
1 parent 6dc75e2 commit 75faab2

File tree

6 files changed

+215
-12
lines changed

6 files changed

+215
-12
lines changed

browser_tests/fixtures/utils/taskHistory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export default class TaskHistory {
7373
return route.fulfill({
7474
status: 200,
7575
contentType: 'application/json',
76-
body: JSON.stringify(this.tasks)
76+
body: JSON.stringify({ history: this.tasks })
7777
})
7878
}
7979

@@ -95,7 +95,7 @@ export default class TaskHistory {
9595

9696
async setupRoutes() {
9797
return this.comfyPage.page.route(
98-
/.*\/api\/(view|history)(\?.*)?$/,
98+
/.*\/api\/(view|history|history_v2)(\?.*)?$/,
9999
async (route) => {
100100
const request = route.request()
101101
const method = request.method()

browser_tests/tests/sidebar/workflows.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,14 @@ test.describe('Workflows sidebar', () => {
187187

188188
test('Can save workflow as with same name', async ({ comfyPage }) => {
189189
await comfyPage.menu.topbar.saveWorkflow('workflow5.json')
190+
await comfyPage.nextFrame()
190191
expect(await comfyPage.menu.workflowsTab.getOpenedWorkflowNames()).toEqual([
191192
'workflow5.json'
192193
])
193194

194195
await comfyPage.menu.topbar.saveWorkflowAs('workflow5.json')
195196
await comfyPage.confirmDialog.click('overwrite')
197+
await comfyPage.nextFrame()
196198
expect(await comfyPage.menu.workflowsTab.getOpenedWorkflowNames()).toEqual([
197199
'workflow5.json'
198200
])

src/components/sidebar/tabs/QueueSidebarTab.vue

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,11 @@ const menuItems = computed<MenuItem[]>(() => {
214214
void workflowService.loadTaskWorkflow(menuTargetTask.value)
215215
}
216216
},
217-
disabled:
218-
!menuTargetTask.value?.workflow &&
219-
!(
220-
menuTargetTask.value?.isHistory &&
221-
menuTargetTask.value?.prompt.prompt_id
222-
)
217+
disabled: !(
218+
menuTargetTask.value?.workflow ||
219+
(menuTargetTask.value?.isHistory &&
220+
menuTargetTask.value?.prompt.prompt_id)
221+
)
223222
},
224223
{
225224
label: t('g.goToNode'),

src/scripts/api.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -743,13 +743,13 @@ export class ComfyApi extends EventTarget {
743743
const json = await res.json()
744744

745745
// The /history_v2/{prompt_id} endpoint returns data for a specific prompt
746-
// The response format is: { prompt_id: { prompt: [...], outputs: {...}, status: {...} } }
746+
// The response format is: { prompt_id: { prompt: {priority, prompt_id, extra_data}, outputs: {...}, status: {...} } }
747747
const historyItem = json[prompt_id]
748748
if (!historyItem) return null
749749

750-
// Extract workflow from the prompt array
751-
// prompt[3] contains extra_data which has extra_pnginfo.workflow
752-
const workflow = historyItem.prompt?.[3]?.extra_pnginfo?.workflow
750+
// Extract workflow from the prompt object
751+
// prompt.extra_data contains extra_pnginfo.workflow
752+
const workflow = historyItem.prompt?.extra_data?.extra_pnginfo?.workflow
753753
return workflow || null
754754
} catch (error) {
755755
console.error(`Failed to fetch workflow for prompt ${prompt_id}:`, error)

tests-ui/tests/scripts/api.test.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
HistoryResponse,
55
RawHistoryItem
66
} from '../../../src/schemas/apiSchema'
7+
import type { ComfyWorkflowJSON } from '../../../src/schemas/comfyWorkflowSchema'
78
import { ComfyApi } from '../../../src/scripts/api'
89

910
describe('ComfyApi getHistory', () => {
@@ -124,3 +125,124 @@ describe('ComfyApi getHistory', () => {
124125
})
125126
})
126127
})
128+
129+
describe('ComfyApi getWorkflowFromHistory', () => {
130+
let api: ComfyApi
131+
132+
beforeEach(() => {
133+
api = new ComfyApi()
134+
})
135+
136+
const mockWorkflow: ComfyWorkflowJSON = {
137+
last_node_id: 1,
138+
last_link_id: 0,
139+
nodes: [],
140+
links: [],
141+
groups: [],
142+
config: {},
143+
extra: {},
144+
version: 0.4
145+
}
146+
147+
it('should fetch workflow data for a specific prompt', async () => {
148+
const promptId = 'test_prompt_id'
149+
const mockResponse = {
150+
[promptId]: {
151+
prompt: {
152+
priority: 0,
153+
prompt_id: promptId,
154+
extra_data: {
155+
extra_pnginfo: {
156+
workflow: mockWorkflow
157+
}
158+
}
159+
},
160+
outputs: {},
161+
status: {
162+
status_str: 'success',
163+
completed: true,
164+
messages: []
165+
}
166+
}
167+
}
168+
169+
const mockFetchApi = vi.fn().mockResolvedValue({
170+
json: vi.fn().mockResolvedValue(mockResponse)
171+
})
172+
api.fetchApi = mockFetchApi
173+
174+
const result = await api.getWorkflowFromHistory(promptId)
175+
176+
expect(mockFetchApi).toHaveBeenCalledWith(`/history_v2/${promptId}`)
177+
expect(result).toEqual(mockWorkflow)
178+
})
179+
180+
it('should return null when prompt_id is not found', async () => {
181+
const promptId = 'non_existent_prompt'
182+
const mockResponse = {}
183+
184+
const mockFetchApi = vi.fn().mockResolvedValue({
185+
json: vi.fn().mockResolvedValue(mockResponse)
186+
})
187+
api.fetchApi = mockFetchApi
188+
189+
const result = await api.getWorkflowFromHistory(promptId)
190+
191+
expect(mockFetchApi).toHaveBeenCalledWith(`/history_v2/${promptId}`)
192+
expect(result).toBeNull()
193+
})
194+
195+
it('should return null when workflow data is missing', async () => {
196+
const promptId = 'test_prompt_id'
197+
const mockResponse = {
198+
[promptId]: {
199+
prompt: {
200+
priority: 0,
201+
prompt_id: promptId,
202+
extra_data: {}
203+
},
204+
outputs: {},
205+
status: {
206+
status_str: 'success',
207+
completed: true,
208+
messages: []
209+
}
210+
}
211+
}
212+
213+
const mockFetchApi = vi.fn().mockResolvedValue({
214+
json: vi.fn().mockResolvedValue(mockResponse)
215+
})
216+
api.fetchApi = mockFetchApi
217+
218+
const result = await api.getWorkflowFromHistory(promptId)
219+
220+
expect(result).toBeNull()
221+
})
222+
223+
it('should handle API errors gracefully', async () => {
224+
const promptId = 'test_prompt_id'
225+
const mockFetchApi = vi.fn().mockRejectedValue(new Error('Network error'))
226+
api.fetchApi = mockFetchApi
227+
228+
const result = await api.getWorkflowFromHistory(promptId)
229+
230+
expect(result).toBeNull()
231+
})
232+
233+
it('should handle malformed response gracefully', async () => {
234+
const promptId = 'test_prompt_id'
235+
const mockResponse = {
236+
[promptId]: null
237+
}
238+
239+
const mockFetchApi = vi.fn().mockResolvedValue({
240+
json: vi.fn().mockResolvedValue(mockResponse)
241+
})
242+
api.fetchApi = mockFetchApi
243+
244+
const result = await api.getWorkflowFromHistory(promptId)
245+
246+
expect(result).toBeNull()
247+
})
248+
})

tests-ui/tests/store/queueStore.test.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,86 @@ import { describe, expect, it } from 'vitest'
33
import { TaskItemImpl } from '@/stores/queueStore'
44

55
describe('TaskItemImpl', () => {
6+
describe('prompt property accessors', () => {
7+
it('should correctly access queueIndex from priority', () => {
8+
const taskItem = new TaskItemImpl('Pending', {
9+
priority: 5,
10+
prompt_id: 'test-id',
11+
extra_data: { client_id: 'client-id' }
12+
})
13+
14+
expect(taskItem.queueIndex).toBe(5)
15+
})
16+
17+
it('should correctly access promptId from prompt_id', () => {
18+
const taskItem = new TaskItemImpl('History', {
19+
priority: 0,
20+
prompt_id: 'unique-prompt-id',
21+
extra_data: { client_id: 'client-id' }
22+
})
23+
24+
expect(taskItem.promptId).toBe('unique-prompt-id')
25+
})
26+
27+
it('should correctly access extraData', () => {
28+
const extraData = {
29+
client_id: 'client-id',
30+
extra_pnginfo: {
31+
workflow: {
32+
last_node_id: 1,
33+
last_link_id: 0,
34+
nodes: [],
35+
links: [],
36+
groups: [],
37+
config: {},
38+
extra: {},
39+
version: 0.4
40+
}
41+
}
42+
}
43+
const taskItem = new TaskItemImpl('Running', {
44+
priority: 1,
45+
prompt_id: 'test-id',
46+
extra_data: extraData
47+
})
48+
49+
expect(taskItem.extraData).toEqual(extraData)
50+
})
51+
52+
it('should correctly access workflow from extraPngInfo', () => {
53+
const workflow = {
54+
last_node_id: 1,
55+
last_link_id: 0,
56+
nodes: [],
57+
links: [],
58+
groups: [],
59+
config: {},
60+
extra: {},
61+
version: 0.4
62+
}
63+
const taskItem = new TaskItemImpl('History', {
64+
priority: 0,
65+
prompt_id: 'test-id',
66+
extra_data: {
67+
client_id: 'client-id',
68+
extra_pnginfo: { workflow }
69+
}
70+
})
71+
72+
expect(taskItem.workflow).toEqual(workflow)
73+
})
74+
75+
it('should return undefined workflow when extraPngInfo is missing', () => {
76+
const taskItem = new TaskItemImpl('History', {
77+
priority: 0,
78+
prompt_id: 'test-id',
79+
extra_data: { client_id: 'client-id' }
80+
})
81+
82+
expect(taskItem.workflow).toBeUndefined()
83+
})
84+
})
85+
686
it('should remove animated property from outputs during construction', () => {
787
const taskItem = new TaskItemImpl(
888
'History',

0 commit comments

Comments
 (0)