mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
## Summary Extract internal logic from the 2 remaining VTU holdout components into composables, enabling full VTL migration. ## Changes - **What**: Extract `useProcessedWidgets` from `NodeWidgets.vue` (486→135 LOC) and `useWidgetSelectItems`/`useWidgetSelectActions` from `WidgetSelectDropdown.vue` (563→170 LOC). Rewrite both component test files as composable unit tests + slim behavioral VTL tests. Remove `@vue/test-utils` devDependency. - **Dependencies**: Removes `@vue/test-utils` ## Review Focus - Composable extraction is mechanical — no logic changes, just moving code into testable units - `useProcessedWidgets` handles widget deduplication, promotion border styling, error detection, and identity resolution (~290 LOC) - `useWidgetSelectItems` handles the full computed chain from widget values → dropdown items including cloud asset mode and multi-output job resolution (~350 LOC) - `useWidgetSelectActions` handles selection resolution and file upload (~120 LOC) - 40 new composable-level unit tests replace 13 `wrapper.vm.*` accesses across the 2 holdout files ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10966-refactor-extract-composables-from-VTU-holdout-components-complete-VTL-migration-33c6d73d36508148a3a4ccf346722d6d) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { render, screen } from '@testing-library/vue'
|
|
import userEvent from '@testing-library/user-event'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { createI18n } from 'vue-i18n'
|
|
|
|
import LinearWelcome from './LinearWelcome.vue'
|
|
|
|
const { hasNodes, hasOutputs, enterBuilder } = vi.hoisted(() => {
|
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
const { ref } = require('vue')
|
|
return {
|
|
hasNodes: ref(false),
|
|
hasOutputs: ref(false),
|
|
enterBuilder: vi.fn()
|
|
}
|
|
})
|
|
|
|
vi.mock('@/composables/useAppMode', () => ({
|
|
useAppMode: () => ({ setMode: vi.fn() })
|
|
}))
|
|
|
|
vi.mock('@/composables/useWorkflowTemplateSelectorDialog', () => ({
|
|
useWorkflowTemplateSelectorDialog: () => ({ show: vi.fn() })
|
|
}))
|
|
|
|
vi.mock('@/stores/appModeStore', () => ({
|
|
useAppModeStore: () => ({
|
|
hasNodes,
|
|
hasOutputs,
|
|
enterBuilder
|
|
})
|
|
}))
|
|
|
|
vi.mock('@/platform/workflow/management/stores/workflowStore', () => ({
|
|
useWorkflowStore: () => ({
|
|
activeWorkflow: null
|
|
})
|
|
}))
|
|
|
|
const i18n = createI18n({ legacy: false, locale: 'en', missingWarn: false })
|
|
|
|
function renderComponent(
|
|
opts: { hasNodes?: boolean; hasOutputs?: boolean } = {}
|
|
) {
|
|
hasNodes.value = opts.hasNodes ?? false
|
|
hasOutputs.value = opts.hasOutputs ?? false
|
|
return render(LinearWelcome, {
|
|
global: { plugins: [i18n] }
|
|
})
|
|
}
|
|
|
|
describe('LinearWelcome', () => {
|
|
beforeEach(() => {
|
|
hasNodes.value = false
|
|
hasOutputs.value = false
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
it('shows empty workflow text when there are no nodes', () => {
|
|
renderComponent({ hasNodes: false })
|
|
expect(
|
|
screen.getByTestId('linear-welcome-empty-workflow')
|
|
).toBeInTheDocument()
|
|
expect(
|
|
screen.queryByTestId('linear-welcome-build-app')
|
|
).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('shows build app button when there are nodes but no outputs', () => {
|
|
renderComponent({ hasNodes: true, hasOutputs: false })
|
|
expect(
|
|
screen.queryByTestId('linear-welcome-empty-workflow')
|
|
).not.toBeInTheDocument()
|
|
expect(screen.getByTestId('linear-welcome-build-app')).toBeInTheDocument()
|
|
})
|
|
|
|
it('clicking build app button calls enterBuilder', async () => {
|
|
const user = userEvent.setup()
|
|
renderComponent({ hasNodes: true, hasOutputs: false })
|
|
await user.click(screen.getByTestId('linear-welcome-build-app'))
|
|
expect(enterBuilder).toHaveBeenCalled()
|
|
})
|
|
})
|