mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-08 16:17:58 +00:00
## Summary Adds an app mode validation warning so users can see when a workflow has errors before running and jump directly back to graph mode to review them. ## Changes - **What**: Adds a reusable app mode warning banner above the Run button when the execution error store reports workflow errors, including validation and missing asset states. - **What**: Reuses the existing graph-error navigation flow so the warning action switches out of app mode and opens the Errors panel in graph mode. - **What**: Updates the app mode Run button icon and accessible label in the warning state while keeping the Run action non-blocking. - **What**: Adds unit coverage for the warning render/accessibility state and an E2E flow that triggers a validation failure, dismisses the overlay, and opens graph errors from the app mode warning. - **Breaking**: None. - **Dependencies**: None. ## Review Focus The warning intentionally mirrors graph mode behavior: it surfaces the error state but does not prevent the user from clicking Run. This avoids turning display-level validation signals into hard execution blockers. The warning is driven by the existing `hasAnyError` aggregate, so missing nodes, missing models, and missing media are included alongside prompt/node/execution errors. ## Tests - `pnpm format` - `pnpm lint` - `pnpm typecheck` - `pnpm test:unit` - `pnpm knip` - `pnpm test:browser:local browser_tests/tests/appModeValidationWarning.spec.ts` ## Screenshots <img width="461" height="994" alt="스크린샷 2026-06-25 오후 7 00 55" src="https://github.com/user-attachments/assets/f8fc20bf-d572-46b5-9fa4-312e7c4c8076" />
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import {
|
|
ComfyPage,
|
|
comfyPageFixture as test,
|
|
comfyExpect as expect
|
|
} from '@e2e/fixtures/ComfyPage'
|
|
import { TestIds } from '@e2e/fixtures/selectors'
|
|
|
|
test.describe('Linear Mode', { tag: '@ui' }, () => {
|
|
test('Displays linear controls when app mode active', async ({
|
|
comfyPage
|
|
}) => {
|
|
await comfyPage.appMode.enterAppModeWithInputs([])
|
|
|
|
await expect(comfyPage.page.getByTestId('linear-widgets')).toBeVisible()
|
|
})
|
|
|
|
test('Run button visible in linear mode', async ({ comfyPage }) => {
|
|
await comfyPage.appMode.enterAppModeWithInputs([])
|
|
|
|
await expect(
|
|
comfyPage.page.getByTestId(TestIds.linear.runButton)
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('Workflow info section visible', async ({ comfyPage }) => {
|
|
await comfyPage.appMode.enterAppModeWithInputs([])
|
|
|
|
await expect(
|
|
comfyPage.page.getByTestId('linear-workflow-info')
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('Returns to graph mode', async ({ comfyPage }) => {
|
|
await comfyPage.appMode.enterAppModeWithInputs([])
|
|
|
|
await expect(comfyPage.page.getByTestId('linear-widgets')).toBeVisible()
|
|
|
|
await comfyPage.appMode.toggleAppMode()
|
|
|
|
await expect(comfyPage.canvas).toBeVisible()
|
|
await expect(comfyPage.page.getByTestId('linear-widgets')).toBeHidden()
|
|
})
|
|
|
|
test('Canvas not visible in app mode', async ({ comfyPage }) => {
|
|
await comfyPage.appMode.enterAppModeWithInputs([])
|
|
|
|
await expect(comfyPage.page.getByTestId('linear-widgets')).toBeVisible()
|
|
await expect(comfyPage.canvas).toBeHidden()
|
|
})
|
|
|
|
test('Spinner persists until workflow loaded', async ({
|
|
page,
|
|
request
|
|
}, testInfo) => {
|
|
const comfyPage = new ComfyPage(page, request)
|
|
const { parallelIndex } = testInfo
|
|
const username = `playwright-test-${parallelIndex}`
|
|
const userId = await comfyPage.setupUser(username)
|
|
comfyPage.userIds[parallelIndex] = userId
|
|
|
|
await page.goto(`${comfyPage.url}/api/users`)
|
|
await page.evaluate((id) => {
|
|
localStorage.clear()
|
|
sessionStorage.clear()
|
|
localStorage.setItem('Comfy.userId', id)
|
|
}, comfyPage.id)
|
|
|
|
const splash = page.locator('#splash-loader')
|
|
|
|
let notifyWorkflowRequested!: () => void
|
|
const workflowRequested = new Promise<void>(
|
|
(r) => (notifyWorkflowRequested = r)
|
|
)
|
|
let unblockRequest!: () => void
|
|
const requestUnblocked = new Promise<void>((r) => (unblockRequest = r))
|
|
|
|
await page.route('**/templates/default.json', async (route) => {
|
|
notifyWorkflowRequested()
|
|
await requestUnblocked
|
|
return route.continue()
|
|
})
|
|
|
|
await comfyPage.goto({ url: `${comfyPage.url}/?template=default` })
|
|
await workflowRequested
|
|
|
|
await comfyPage.nextFrame()
|
|
await expect(splash).toBeVisible()
|
|
unblockRequest()
|
|
await expect(splash).toBeHidden()
|
|
})
|
|
})
|