mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-03 04:31:58 +00:00
refactor: extract shared createMockWidget factory for widget component tests (#9423)
## Summary Extract a shared `createMockWidget` test factory to eliminate duplicated `SimplifiedWidget` object construction across 13 widget component test files. ## Changes - **What**: Add `widgetTestUtils.ts` with a generic `createMockWidget<T>` factory providing sensible defaults (`name`, `type`, `options`). Refactor 13 test files to delegate to it via thin local wrappers that supply component-specific defaults (combo values, slider ranges, etc.). ## Review Focus - The shared factory only covers `SimplifiedWidget`-based tests. Three files using different base types (`NodeWidgets.test.ts`, `useRemoteWidget.test.ts`, `useComboWidget.test.ts`) are intentionally excluded. - `mountComponent` helpers remain per-file since plugin/component setups vary too much to share. Fixes #5554 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9423-refactor-extract-shared-createMockWidget-factory-for-widget-component-tests-31a6d73d36508159b65ee0e7b49212c3) by [Unito](https://www.unito.io) --------- Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
import WidgetTextarea from './WidgetTextarea.vue'
|
||||
import { createMockWidget } from './widgetTestUtils'
|
||||
|
||||
const mockCopyToClipboard = vi.hoisted(() => vi.fn())
|
||||
|
||||
@@ -13,18 +14,17 @@ vi.mock('@/composables/useCopyToClipboard', () => ({
|
||||
})
|
||||
}))
|
||||
|
||||
function createMockWidget(
|
||||
function createTextareaWidget(
|
||||
value: string = 'default text',
|
||||
options: SimplifiedWidget['options'] = {},
|
||||
options: SimplifiedWidget<string>['options'] = {},
|
||||
callback?: (value: string) => void
|
||||
): SimplifiedWidget<string> {
|
||||
return {
|
||||
name: 'test_textarea',
|
||||
type: 'string',
|
||||
) {
|
||||
return createMockWidget<string>({
|
||||
value,
|
||||
name: 'test_textarea',
|
||||
options,
|
||||
callback
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function mountComponent(
|
||||
@@ -67,7 +67,7 @@ async function setTextareaValueAndTrigger(
|
||||
describe('WidgetTextarea Value Binding', () => {
|
||||
describe('Vue Event Emission', () => {
|
||||
it('emits Vue event when textarea value changes on blur', async () => {
|
||||
const widget = createMockWidget('hello')
|
||||
const widget = createTextareaWidget('hello')
|
||||
const wrapper = mountComponent(widget, 'hello')
|
||||
|
||||
await setTextareaValueAndTrigger(wrapper, 'world', 'blur')
|
||||
@@ -78,7 +78,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('emits Vue event when textarea value changes on input', async () => {
|
||||
const widget = createMockWidget('initial')
|
||||
const widget = createTextareaWidget('initial')
|
||||
const wrapper = mountComponent(widget, 'initial')
|
||||
|
||||
await setTextareaValueAndTrigger(wrapper, 'new content', 'input')
|
||||
@@ -89,7 +89,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('handles empty string values', async () => {
|
||||
const widget = createMockWidget('something')
|
||||
const widget = createTextareaWidget('something')
|
||||
const wrapper = mountComponent(widget, 'something')
|
||||
|
||||
await setTextareaValueAndTrigger(wrapper, '')
|
||||
@@ -100,7 +100,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('handles multiline text correctly', async () => {
|
||||
const widget = createMockWidget('single line')
|
||||
const widget = createTextareaWidget('single line')
|
||||
const wrapper = mountComponent(widget, 'single line')
|
||||
|
||||
const multilineText = 'Line 1\nLine 2\nLine 3'
|
||||
@@ -112,7 +112,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('handles special characters correctly', async () => {
|
||||
const widget = createMockWidget('normal')
|
||||
const widget = createTextareaWidget('normal')
|
||||
const wrapper = mountComponent(widget, 'normal')
|
||||
|
||||
const specialText = 'special @#$%^&*()[]{}|\\:";\'<>?,./'
|
||||
@@ -124,7 +124,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('handles missing callback gracefully', async () => {
|
||||
const widget = createMockWidget('test', {}, undefined)
|
||||
const widget = createTextareaWidget('test', {}, undefined)
|
||||
const wrapper = mountComponent(widget, 'test')
|
||||
|
||||
await setTextareaValueAndTrigger(wrapper, 'new value')
|
||||
@@ -138,7 +138,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
|
||||
describe('User Interactions', () => {
|
||||
it('emits update:modelValue on blur', async () => {
|
||||
const widget = createMockWidget('original')
|
||||
const widget = createTextareaWidget('original')
|
||||
const wrapper = mountComponent(widget, 'original')
|
||||
|
||||
await setTextareaValueAndTrigger(wrapper, 'updated')
|
||||
@@ -149,7 +149,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('emits update:modelValue on input', async () => {
|
||||
const widget = createMockWidget('start')
|
||||
const widget = createTextareaWidget('start')
|
||||
const wrapper = mountComponent(widget, 'start')
|
||||
|
||||
await setTextareaValueAndTrigger(wrapper, 'finish', 'input')
|
||||
@@ -162,7 +162,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
|
||||
describe('Component Rendering', () => {
|
||||
it('renders textarea component', () => {
|
||||
const widget = createMockWidget('test value')
|
||||
const widget = createTextareaWidget('test value')
|
||||
const wrapper = mountComponent(widget, 'test value')
|
||||
|
||||
const textarea = wrapper.find('textarea')
|
||||
@@ -170,7 +170,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('displays initial value in textarea', () => {
|
||||
const widget = createMockWidget('initial content')
|
||||
const widget = createTextareaWidget('initial content')
|
||||
const wrapper = mountComponent(widget, 'initial content')
|
||||
|
||||
const textarea = wrapper.find('textarea')
|
||||
@@ -183,7 +183,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('uses widget name as placeholder when no placeholder provided', () => {
|
||||
const widget = createMockWidget('test')
|
||||
const widget = createTextareaWidget('test')
|
||||
const wrapper = mountComponent(widget, 'test')
|
||||
|
||||
const textareaLabel = wrapper.find('label')
|
||||
@@ -191,7 +191,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('uses provided placeholder when specified', () => {
|
||||
const widget = createMockWidget('test')
|
||||
const widget = createTextareaWidget('test')
|
||||
const wrapper = mountComponent(
|
||||
widget,
|
||||
'test',
|
||||
@@ -209,7 +209,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('hides copy button when not read-only', async () => {
|
||||
const widget = createMockWidget('test')
|
||||
const widget = createTextareaWidget('test')
|
||||
const wrapper = mountComponent(widget, 'test', false)
|
||||
|
||||
const button = wrapper.find('button')
|
||||
@@ -217,7 +217,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('copy button has invisible class by default when read-only', () => {
|
||||
const widget = createMockWidget('test', { read_only: true })
|
||||
const widget = createTextareaWidget('test', { read_only: true })
|
||||
const wrapper = mountComponent(widget, 'test', true)
|
||||
|
||||
const button = wrapper.find('button')
|
||||
@@ -226,7 +226,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('copy button has group-hover:visible class when read-only, and copies on click', async () => {
|
||||
const widget = createMockWidget('test value', { read_only: true })
|
||||
const widget = createTextareaWidget('test value', { read_only: true })
|
||||
const wrapper = mountComponent(widget, 'test value', true)
|
||||
|
||||
const button = wrapper.find('button')
|
||||
@@ -241,7 +241,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('handles very long text', async () => {
|
||||
const widget = createMockWidget('short')
|
||||
const widget = createTextareaWidget('short')
|
||||
const wrapper = mountComponent(widget, 'short')
|
||||
|
||||
const longText = 'a'.repeat(10000)
|
||||
@@ -253,7 +253,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('handles unicode characters', async () => {
|
||||
const widget = createMockWidget('ascii')
|
||||
const widget = createTextareaWidget('ascii')
|
||||
const wrapper = mountComponent(widget, 'ascii')
|
||||
|
||||
const unicodeText = '🎨 Unicode: αβγ 中文 العربية 🚀'
|
||||
@@ -265,7 +265,7 @@ describe('WidgetTextarea Value Binding', () => {
|
||||
})
|
||||
|
||||
it('handles text with tabs and spaces', async () => {
|
||||
const widget = createMockWidget('normal')
|
||||
const widget = createTextareaWidget('normal')
|
||||
const wrapper = mountComponent(widget, 'normal')
|
||||
|
||||
const formattedText = '\tIndented line\n Spaced line\n\t\tDouble indent'
|
||||
|
||||
Reference in New Issue
Block a user