Files
ComfyUI_frontend/browser_tests/tests/load3d/preview3dExecution.spec.ts
2026-04-09 22:13:30 -07:00

172 lines
4.6 KiB
TypeScript

import { expect } from '@playwright/test'
import {
cameraStatesClose,
preview3dPipelineTest as test,
Preview3DPipelineContext,
waitForAppBootstrapped
} from '@e2e/fixtures/helpers/Preview3DPipelineFixture'
import { assetPath } from '@e2e/fixtures/utils/paths'
async function seedLoad3dWithCubeObj(
pipeline: Preview3DPipelineContext
): Promise<void> {
const { comfyPage, load3d } = pipeline
const fileChooserPromise = comfyPage.page.waitForEvent('filechooser')
await load3d.getUploadButton('upload 3d model').click()
const fileChooser = await fileChooserPromise
await fileChooser.setFiles(assetPath('cube.obj'))
await expect
.poll(
() =>
pipeline.getModelFileWidgetValue(Preview3DPipelineContext.loadNodeId),
{ timeout: 15_000 }
)
.toContain('cube.obj')
await load3d.waitForModelLoaded()
await comfyPage.nextFrame()
}
async function alignPreview3dWorkflowUiSettings(
pipeline: Preview3DPipelineContext
): Promise<void> {
await pipeline.comfyPage.settings.setSetting('Comfy.VueNodes.Enabled', true)
await pipeline.comfyPage.settings.setSetting(
'Comfy.Workflow.WorkflowTabsPosition',
'Sidebar'
)
}
test.describe('Preview3D execution flow', { tag: ['@node', '@slow'] }, () => {
test('Preview3D loads model from execution output', async ({
preview3dPipeline: pipeline
}) => {
test.setTimeout(120_000)
await seedLoad3dWithCubeObj(pipeline)
await pipeline.comfyPage.command.executeCommand('Comfy.QueuePrompt')
await expect
.poll(
() =>
pipeline.getModelFileWidgetValue(
Preview3DPipelineContext.previewNodeId
),
{ timeout: 90_000 }
)
.not.toBe('')
const modelPath = await pipeline.getModelFileWidgetValue(
Preview3DPipelineContext.previewNodeId
)
await expect(
modelPath.length,
'Preview3D model path populated'
).toBeGreaterThan(4)
await expect
.poll(
() =>
pipeline.getLastTimeModelFile(Preview3DPipelineContext.previewNodeId),
{ timeout: 5000 }
)
.toBe(modelPath)
await pipeline.preview3d.waitForModelLoaded()
await expect
.poll(async () => {
const b = await pipeline.preview3d.canvas.boundingBox()
return (b?.width ?? 0) > 0 && (b?.height ?? 0) > 0
})
.toBe(true)
})
test('Preview3D restores last model and camera after save and full reload', async ({
preview3dPipeline: pipeline
}) => {
test.setTimeout(180_000)
await seedLoad3dWithCubeObj(pipeline)
await pipeline.comfyPage.command.executeCommand('Comfy.QueuePrompt')
await expect
.poll(
() =>
pipeline.getModelFileWidgetValue(
Preview3DPipelineContext.previewNodeId
),
{ timeout: 90_000 }
)
.not.toBe('')
await pipeline.preview3d.waitForModelLoaded()
const savedPath = await pipeline.getModelFileWidgetValue(
Preview3DPipelineContext.previewNodeId
)
const savedCamera = await pipeline.getCameraStateFromProperties(
Preview3DPipelineContext.previewNodeId
)
expect(savedCamera, 'Camera state present after execution').not.toBeNull()
const workflowName = `p3d-restore-${Date.now().toString(36)}`
await pipeline.comfyPage.menu.workflowsTab.open()
await pipeline.comfyPage.menu.topbar.saveWorkflow(workflowName)
await pipeline.comfyPage.page.reload({ waitUntil: 'networkidle' })
await waitForAppBootstrapped(pipeline.comfyPage)
await alignPreview3dWorkflowUiSettings(pipeline)
const tab = pipeline.comfyPage.menu.workflowsTab
await tab.open()
await tab.getPersistedItem(workflowName).click()
await pipeline.comfyPage.workflow.waitForWorkflowIdle(15_000)
await pipeline.comfyPage.vueNodes.waitForNodes()
await expect
.poll(
() =>
pipeline.getModelFileWidgetValue(
Preview3DPipelineContext.previewNodeId
),
{ timeout: 30_000 }
)
.toBe(savedPath)
await expect
.poll(
() =>
pipeline.getLastTimeModelFile(Preview3DPipelineContext.previewNodeId),
{ timeout: 5000 }
)
.toBe(savedPath)
await pipeline.preview3d.waitForModelLoaded()
await expect
.poll(async () => {
const b = await pipeline.preview3d.canvas.boundingBox()
return (b?.width ?? 0) > 0 && (b?.height ?? 0) > 0
})
.toBe(true)
await expect
.poll(async () =>
cameraStatesClose(
await pipeline.getCameraStateFromProperties(
Preview3DPipelineContext.previewNodeId
),
savedCamera,
2e-2
)
)
.toBe(true)
})
})