mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 07:00:23 +00:00
[test] Add component tests for some Vue Widget components (#5409)
* add component tests for vue widgets * [refactor] improve widget test readability and type safety - addresses @DrJKL's review feedback - Add mountComponent utility function for consistent test setup - Add setInputValueAndTrigger helper to batch common test operations - Replace type assertions with proper instanceof checks for type safety - Remove duplicate test setup code to improve test readability - Fix TypeScript errors in WidgetSlider tests These changes address all review comments by making tests easier to read and understand while ensuring proper type checking. * [refactor] apply consistent test patterns to WidgetSelect.test.ts - Add mountComponent utility function for consistent test setup - Add setSelectValueAndEmit helper to batch select operations - Remove repetitive mount boilerplate code throughout tests - Maintain existing test coverage while improving readability This ensures all widget component tests follow the same patterns established in WidgetInputText and WidgetSlider tests.
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import type { InputTextProps } from 'primevue/inputtext'
|
||||
import Textarea from 'primevue/textarea'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
import WidgetInputText from './WidgetInputText.vue'
|
||||
|
||||
describe('WidgetInputText Value Binding', () => {
|
||||
const createMockWidget = (
|
||||
value: string = 'default',
|
||||
options: Partial<InputTextProps> = {},
|
||||
callback?: (value: string) => void
|
||||
): SimplifiedWidget<string> => ({
|
||||
name: 'test_input',
|
||||
type: 'string',
|
||||
value,
|
||||
options,
|
||||
callback
|
||||
})
|
||||
|
||||
const mountComponent = (
|
||||
widget: SimplifiedWidget<string>,
|
||||
modelValue: string,
|
||||
readonly = false
|
||||
) => {
|
||||
return mount(WidgetInputText, {
|
||||
global: {
|
||||
plugins: [PrimeVue],
|
||||
components: { InputText, Textarea }
|
||||
},
|
||||
props: {
|
||||
widget,
|
||||
modelValue,
|
||||
readonly
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const setInputValueAndTrigger = async (
|
||||
wrapper: ReturnType<typeof mount>,
|
||||
value: string,
|
||||
trigger: 'blur' | 'keydown.enter' = 'blur'
|
||||
) => {
|
||||
const input = wrapper.find('input[type="text"]')
|
||||
if (!(input.element instanceof HTMLInputElement)) {
|
||||
throw new Error('Input element not found or is not an HTMLInputElement')
|
||||
}
|
||||
await input.setValue(value)
|
||||
await input.trigger(trigger)
|
||||
return input
|
||||
}
|
||||
|
||||
describe('Vue Event Emission', () => {
|
||||
it('emits Vue event when input value changes on blur', async () => {
|
||||
const widget = createMockWidget('hello')
|
||||
const wrapper = mountComponent(widget, 'hello')
|
||||
|
||||
await setInputValueAndTrigger(wrapper, 'world', 'blur')
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('world')
|
||||
})
|
||||
|
||||
it('emits Vue event when enter key is pressed', async () => {
|
||||
const widget = createMockWidget('initial')
|
||||
const wrapper = mountComponent(widget, 'initial')
|
||||
|
||||
await setInputValueAndTrigger(wrapper, 'new value', 'keydown.enter')
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('new value')
|
||||
})
|
||||
|
||||
it('handles empty string values', async () => {
|
||||
const widget = createMockWidget('something')
|
||||
const wrapper = mountComponent(widget, 'something')
|
||||
|
||||
await setInputValueAndTrigger(wrapper, '')
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('')
|
||||
})
|
||||
|
||||
it('handles special characters correctly', async () => {
|
||||
const widget = createMockWidget('normal')
|
||||
const wrapper = mountComponent(widget, 'normal')
|
||||
|
||||
const specialText = 'special @#$%^&*()[]{}|\\:";\'<>?,./'
|
||||
await setInputValueAndTrigger(wrapper, specialText)
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain(specialText)
|
||||
})
|
||||
|
||||
it('handles missing callback gracefully', async () => {
|
||||
const widget = createMockWidget('test', {}, undefined)
|
||||
const wrapper = mountComponent(widget, 'test')
|
||||
|
||||
await setInputValueAndTrigger(wrapper, 'new value')
|
||||
|
||||
// Should still emit Vue event
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('new value')
|
||||
})
|
||||
})
|
||||
|
||||
describe('User Interactions', () => {
|
||||
it('emits update:modelValue on blur', async () => {
|
||||
const widget = createMockWidget('original')
|
||||
const wrapper = mountComponent(widget, 'original')
|
||||
|
||||
await setInputValueAndTrigger(wrapper, 'updated')
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('updated')
|
||||
})
|
||||
|
||||
it('emits update:modelValue on enter key', async () => {
|
||||
const widget = createMockWidget('start')
|
||||
const wrapper = mountComponent(widget, 'start')
|
||||
|
||||
await setInputValueAndTrigger(wrapper, 'finish', 'keydown.enter')
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('finish')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Readonly Mode', () => {
|
||||
it('disables input when readonly', () => {
|
||||
const widget = createMockWidget('readonly test')
|
||||
const wrapper = mountComponent(widget, 'readonly test', true)
|
||||
|
||||
const input = wrapper.find('input[type="text"]')
|
||||
if (!(input.element instanceof HTMLInputElement)) {
|
||||
throw new Error('Input element not found or is not an HTMLInputElement')
|
||||
}
|
||||
expect(input.element.disabled).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Component Rendering', () => {
|
||||
it('always renders InputText component', () => {
|
||||
const widget = createMockWidget('test value')
|
||||
const wrapper = mountComponent(widget, 'test value')
|
||||
|
||||
// WidgetInputText always uses InputText, not Textarea
|
||||
const input = wrapper.find('input[type="text"]')
|
||||
expect(input.exists()).toBe(true)
|
||||
|
||||
// Should not render textarea (that's handled by WidgetTextarea component)
|
||||
const textarea = wrapper.find('textarea')
|
||||
expect(textarea.exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('handles very long strings', async () => {
|
||||
const widget = createMockWidget('short')
|
||||
const wrapper = mountComponent(widget, 'short')
|
||||
|
||||
const longString = 'a'.repeat(10000)
|
||||
await setInputValueAndTrigger(wrapper, longString)
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain(longString)
|
||||
})
|
||||
|
||||
it('handles unicode characters', async () => {
|
||||
const widget = createMockWidget('ascii')
|
||||
const wrapper = mountComponent(widget, 'ascii')
|
||||
|
||||
const unicodeText = '🎨 Unicode: αβγ 中文 العربية 🚀'
|
||||
await setInputValueAndTrigger(wrapper, unicodeText)
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain(unicodeText)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,187 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import Select from 'primevue/select'
|
||||
import type { SelectProps } from 'primevue/select'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
import WidgetSelect from './WidgetSelect.vue'
|
||||
|
||||
describe('WidgetSelect Value Binding', () => {
|
||||
const createMockWidget = (
|
||||
value: string = 'option1',
|
||||
options: Partial<
|
||||
SelectProps & { values?: string[]; return_index?: boolean }
|
||||
> = {},
|
||||
callback?: (value: string | number | undefined) => void
|
||||
): SimplifiedWidget<string | number | undefined> => ({
|
||||
name: 'test_select',
|
||||
type: 'combo',
|
||||
value,
|
||||
options: {
|
||||
values: ['option1', 'option2', 'option3'],
|
||||
...options
|
||||
},
|
||||
callback
|
||||
})
|
||||
|
||||
const mountComponent = (
|
||||
widget: SimplifiedWidget<string | number | undefined>,
|
||||
modelValue: string | number | undefined,
|
||||
readonly = false
|
||||
) => {
|
||||
return mount(WidgetSelect, {
|
||||
props: {
|
||||
widget,
|
||||
modelValue,
|
||||
readonly
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue],
|
||||
components: { Select }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const setSelectValueAndEmit = async (
|
||||
wrapper: ReturnType<typeof mount>,
|
||||
value: string
|
||||
) => {
|
||||
const select = wrapper.findComponent({ name: 'Select' })
|
||||
await select.setValue(value)
|
||||
return wrapper.emitted('update:modelValue')
|
||||
}
|
||||
|
||||
describe('Vue Event Emission', () => {
|
||||
it('emits Vue event when selection changes', async () => {
|
||||
const widget = createMockWidget('option1')
|
||||
const wrapper = mountComponent(widget, 'option1')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, 'option2')
|
||||
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('option2')
|
||||
})
|
||||
|
||||
it('emits string value for different options', async () => {
|
||||
const widget = createMockWidget('option1')
|
||||
const wrapper = mountComponent(widget, 'option1')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, 'option3')
|
||||
|
||||
expect(emitted).toBeDefined()
|
||||
// Should emit the string value
|
||||
expect(emitted![0]).toContain('option3')
|
||||
})
|
||||
|
||||
it('handles custom option values', async () => {
|
||||
const customOptions = ['custom_a', 'custom_b', 'custom_c']
|
||||
const widget = createMockWidget('custom_a', { values: customOptions })
|
||||
const wrapper = mountComponent(widget, 'custom_a')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, 'custom_b')
|
||||
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('custom_b')
|
||||
})
|
||||
|
||||
it('handles missing callback gracefully', async () => {
|
||||
const widget = createMockWidget('option1', {}, undefined)
|
||||
const wrapper = mountComponent(widget, 'option1')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, 'option2')
|
||||
|
||||
// Should emit Vue event
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('option2')
|
||||
})
|
||||
|
||||
it('handles value changes gracefully', async () => {
|
||||
const widget = createMockWidget('option1')
|
||||
const wrapper = mountComponent(widget, 'option1')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, 'option2')
|
||||
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('option2')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Readonly Mode', () => {
|
||||
it('disables the select component when readonly', async () => {
|
||||
const widget = createMockWidget('option1')
|
||||
const wrapper = mountComponent(widget, 'option1', true)
|
||||
|
||||
const select = wrapper.findComponent({ name: 'Select' })
|
||||
expect(select.props('disabled')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Option Handling', () => {
|
||||
it('handles empty options array', async () => {
|
||||
const widget = createMockWidget('', { values: [] })
|
||||
const wrapper = mountComponent(widget, '')
|
||||
|
||||
const select = wrapper.findComponent({ name: 'Select' })
|
||||
expect(select.props('options')).toEqual([])
|
||||
})
|
||||
|
||||
it('handles single option', async () => {
|
||||
const widget = createMockWidget('only_option', {
|
||||
values: ['only_option']
|
||||
})
|
||||
const wrapper = mountComponent(widget, 'only_option')
|
||||
|
||||
const select = wrapper.findComponent({ name: 'Select' })
|
||||
const options = select.props('options')
|
||||
expect(options).toHaveLength(1)
|
||||
expect(options[0]).toEqual('only_option')
|
||||
})
|
||||
|
||||
it('handles options with special characters', async () => {
|
||||
const specialOptions = [
|
||||
'option with spaces',
|
||||
'option@#$%',
|
||||
'option/with\\slashes'
|
||||
]
|
||||
const widget = createMockWidget(specialOptions[0], {
|
||||
values: specialOptions
|
||||
})
|
||||
const wrapper = mountComponent(widget, specialOptions[0])
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, specialOptions[1])
|
||||
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain(specialOptions[1])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('handles selection of non-existent option gracefully', async () => {
|
||||
const widget = createMockWidget('option1')
|
||||
const wrapper = mountComponent(widget, 'option1')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(
|
||||
wrapper,
|
||||
'non_existent_option'
|
||||
)
|
||||
|
||||
// Should still emit Vue event with the value
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('non_existent_option')
|
||||
})
|
||||
|
||||
it('handles numeric string options correctly', async () => {
|
||||
const numericOptions = ['1', '2', '10', '100']
|
||||
const widget = createMockWidget('1', { values: numericOptions })
|
||||
const wrapper = mountComponent(widget, '1')
|
||||
|
||||
const emitted = await setSelectValueAndEmit(wrapper, '100')
|
||||
|
||||
// Should maintain string type in emitted event
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain('100')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,131 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import Slider from 'primevue/slider'
|
||||
import type { SliderProps } from 'primevue/slider'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
import WidgetSlider from './WidgetSlider.vue'
|
||||
|
||||
describe('WidgetSlider Value Binding', () => {
|
||||
const createMockWidget = (
|
||||
value: number = 5,
|
||||
options: Partial<SliderProps & { precision?: number }> = {},
|
||||
callback?: (value: number) => void
|
||||
): SimplifiedWidget<number> => ({
|
||||
name: 'test_slider',
|
||||
type: 'float',
|
||||
value,
|
||||
options: { min: 0, max: 100, step: 1, precision: 0, ...options },
|
||||
callback
|
||||
})
|
||||
|
||||
const mountComponent = (
|
||||
widget: SimplifiedWidget<number>,
|
||||
modelValue: number,
|
||||
readonly = false
|
||||
) => {
|
||||
return mount(WidgetSlider, {
|
||||
global: {
|
||||
plugins: [PrimeVue],
|
||||
components: { InputText, Slider }
|
||||
},
|
||||
props: {
|
||||
widget,
|
||||
modelValue,
|
||||
readonly
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getNumberInput = (wrapper: ReturnType<typeof mount>) => {
|
||||
const input = wrapper.find('input[type="number"]')
|
||||
if (!(input.element instanceof HTMLInputElement)) {
|
||||
throw new Error(
|
||||
'Number input element not found or is not an HTMLInputElement'
|
||||
)
|
||||
}
|
||||
return { element: input.element }
|
||||
}
|
||||
|
||||
describe('Props and Values', () => {
|
||||
it('passes modelValue to slider component', () => {
|
||||
const widget = createMockWidget(5)
|
||||
const wrapper = mountComponent(widget, 5)
|
||||
|
||||
const slider = wrapper.findComponent({ name: 'Slider' })
|
||||
expect(slider.props('modelValue')).toBe(5)
|
||||
})
|
||||
|
||||
it('handles different initial values', () => {
|
||||
const widget1 = createMockWidget(5)
|
||||
const wrapper1 = mountComponent(widget1, 5)
|
||||
|
||||
const widget2 = createMockWidget(10)
|
||||
const wrapper2 = mountComponent(widget2, 10)
|
||||
|
||||
const slider1 = wrapper1.findComponent({ name: 'Slider' })
|
||||
expect(slider1.props('modelValue')).toBe(5)
|
||||
|
||||
const slider2 = wrapper2.findComponent({ name: 'Slider' })
|
||||
expect(slider2.props('modelValue')).toBe(10)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Component Rendering', () => {
|
||||
it('renders slider component', () => {
|
||||
const widget = createMockWidget(5)
|
||||
const wrapper = mountComponent(widget, 5)
|
||||
|
||||
expect(wrapper.findComponent({ name: 'Slider' }).exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('renders input field', () => {
|
||||
const widget = createMockWidget(5)
|
||||
const wrapper = mountComponent(widget, 5)
|
||||
|
||||
expect(wrapper.find('input[type="number"]').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('displays initial value in input field', () => {
|
||||
const widget = createMockWidget(42)
|
||||
const wrapper = mountComponent(widget, 42)
|
||||
|
||||
const input = getNumberInput(wrapper)
|
||||
expect(input.element.value).toBe('42')
|
||||
})
|
||||
|
||||
it('disables components in readonly mode', () => {
|
||||
const widget = createMockWidget(5)
|
||||
const wrapper = mountComponent(widget, 5, true)
|
||||
|
||||
const slider = wrapper.findComponent({ name: 'Slider' })
|
||||
expect(slider.props('disabled')).toBe(true)
|
||||
|
||||
const input = getNumberInput(wrapper)
|
||||
expect(input.element.disabled).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Widget Options', () => {
|
||||
it('passes widget options to PrimeVue components', () => {
|
||||
const widget = createMockWidget(5, { min: -10, max: 50 })
|
||||
const wrapper = mountComponent(widget, 5)
|
||||
|
||||
const slider = wrapper.findComponent({ name: 'Slider' })
|
||||
expect(slider.props('min')).toBe(-10)
|
||||
expect(slider.props('max')).toBe(50)
|
||||
})
|
||||
|
||||
it('handles negative value ranges', () => {
|
||||
const widget = createMockWidget(0, { min: -100, max: 100 })
|
||||
const wrapper = mountComponent(widget, 0)
|
||||
|
||||
const slider = wrapper.findComponent({ name: 'Slider' })
|
||||
expect(slider.props('min')).toBe(-100)
|
||||
expect(slider.props('max')).toBe(100)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,160 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import ToggleSwitch from 'primevue/toggleswitch'
|
||||
import type { ToggleSwitchProps } from 'primevue/toggleswitch'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
import WidgetToggleSwitch from './WidgetToggleSwitch.vue'
|
||||
|
||||
describe('WidgetToggleSwitch Value Binding', () => {
|
||||
const createMockWidget = (
|
||||
value: boolean = false,
|
||||
options: Partial<ToggleSwitchProps> = {},
|
||||
callback?: (value: boolean) => void
|
||||
): SimplifiedWidget<boolean> => ({
|
||||
name: 'test_toggle',
|
||||
type: 'boolean',
|
||||
value,
|
||||
options,
|
||||
callback
|
||||
})
|
||||
|
||||
const mountComponent = (
|
||||
widget: SimplifiedWidget<boolean>,
|
||||
modelValue: boolean,
|
||||
readonly = false
|
||||
) => {
|
||||
return mount(WidgetToggleSwitch, {
|
||||
props: {
|
||||
widget,
|
||||
modelValue,
|
||||
readonly
|
||||
},
|
||||
global: {
|
||||
plugins: [PrimeVue],
|
||||
components: { ToggleSwitch }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Vue Event Emission', () => {
|
||||
it('emits Vue event when toggled from false to true', async () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
await toggle.setValue(true)
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain(true)
|
||||
})
|
||||
|
||||
it('emits Vue event when toggled from true to false', async () => {
|
||||
const widget = createMockWidget(true)
|
||||
const wrapper = mountComponent(widget, true)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
await toggle.setValue(false)
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toBeDefined()
|
||||
expect(emitted![0]).toContain(false)
|
||||
})
|
||||
|
||||
it('handles value changes gracefully', async () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false)
|
||||
|
||||
// Should not throw when changing values
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
await toggle.setValue(true)
|
||||
await toggle.setValue(false)
|
||||
|
||||
// Should emit events for all changes
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toHaveLength(2)
|
||||
expect(emitted![0]).toContain(true)
|
||||
expect(emitted![1]).toContain(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Component Rendering', () => {
|
||||
it('renders toggle switch component', () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false)
|
||||
|
||||
expect(wrapper.findComponent({ name: 'ToggleSwitch' }).exists()).toBe(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('displays correct initial state for false', () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
expect(toggle.props('modelValue')).toBe(false)
|
||||
})
|
||||
|
||||
it('displays correct initial state for true', () => {
|
||||
const widget = createMockWidget(true)
|
||||
const wrapper = mountComponent(widget, true)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
expect(toggle.props('modelValue')).toBe(true)
|
||||
})
|
||||
|
||||
it('disables component in readonly mode', () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false, true)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
expect(toggle.props('disabled')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Multiple Value Changes', () => {
|
||||
it('handles rapid toggling correctly', async () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
|
||||
// Rapid toggle sequence
|
||||
await toggle.setValue(true)
|
||||
await toggle.setValue(false)
|
||||
await toggle.setValue(true)
|
||||
|
||||
// Should have emitted 3 Vue events with correct values
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toHaveLength(3)
|
||||
expect(emitted![0]).toContain(true)
|
||||
expect(emitted![1]).toContain(false)
|
||||
expect(emitted![2]).toContain(true)
|
||||
})
|
||||
|
||||
it('maintains state consistency during multiple changes', async () => {
|
||||
const widget = createMockWidget(false)
|
||||
const wrapper = mountComponent(widget, false)
|
||||
|
||||
const toggle = wrapper.findComponent({ name: 'ToggleSwitch' })
|
||||
|
||||
// Multiple state changes
|
||||
await toggle.setValue(true)
|
||||
await toggle.setValue(false)
|
||||
await toggle.setValue(true)
|
||||
await toggle.setValue(false)
|
||||
|
||||
const emitted = wrapper.emitted('update:modelValue')
|
||||
expect(emitted).toHaveLength(4)
|
||||
// Verify alternating pattern
|
||||
expect(emitted![0]).toContain(true)
|
||||
expect(emitted![1]).toContain(false)
|
||||
expect(emitted![2]).toContain(true)
|
||||
expect(emitted![3]).toContain(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user