Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import { mount } from '@vue/test-utils'
import PrimeVue from 'primevue/config'
import InputNumber from 'primevue/inputnumber'
import { describe, expect, it } from 'vitest'

import type { SimplifiedWidget } from '@/types/simplifiedWidget'

import WidgetInputNumberInput from './WidgetInputNumberInput.vue'

function createMockWidget(
value: number = 0,
type: 'int' | 'float' = 'int',
options: SimplifiedWidget['options'] = {},
callback?: (value: number) => void
): SimplifiedWidget<number> {
return {
name: 'test_input_number',
type,
value,
options,
callback
}
}

function mountComponent(
widget: SimplifiedWidget<number>,
modelValue: number,
readonly = false
) {
return mount(WidgetInputNumberInput, {
global: {
plugins: [PrimeVue],
components: { InputNumber }
},
props: {
widget,
modelValue,
readonly
}
})
}

function getNumberInput(wrapper: ReturnType<typeof mount>) {
const input = wrapper.get<HTMLInputElement>('input[inputmode="numeric"]')
return input.element
}

describe('WidgetInputNumberInput Value Binding', () => {
it('displays initial value in input field', () => {
const widget = createMockWidget(42, 'int')
const wrapper = mountComponent(widget, 42)

const input = getNumberInput(wrapper)
expect(input.value).toBe('42')
})

it('emits update:modelValue when value changes', async () => {
const widget = createMockWidget(10, 'int')
const wrapper = mountComponent(widget, 10)

const inputNumber = wrapper.findComponent(InputNumber)
await inputNumber.vm.$emit('update:modelValue', 20)

const emitted = wrapper.emitted('update:modelValue')
expect(emitted).toBeDefined()
expect(emitted![0]).toContain(20)
})

it('handles negative values', () => {
const widget = createMockWidget(-5, 'int')
const wrapper = mountComponent(widget, -5)

const input = getNumberInput(wrapper)
expect(input.value).toBe('-5')
})

it('handles decimal values for float type', () => {
const widget = createMockWidget(3.14, 'float')
const wrapper = mountComponent(widget, 3.14)

const input = getNumberInput(wrapper)
expect(input.value).toBe('3.14')
})
})

describe('WidgetInputNumberInput Component Rendering', () => {
it('renders InputNumber component with show-buttons', () => {
const widget = createMockWidget(5, 'int')
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.exists()).toBe(true)
expect(inputNumber.props('showButtons')).toBe(true)
})

it('disables input when readonly', () => {
const widget = createMockWidget(5, 'int', {}, undefined)
const wrapper = mountComponent(widget, 5, true)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('disabled')).toBe(true)
})

it('sets button layout to horizontal', () => {
const widget = createMockWidget(5, 'int')
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('buttonLayout')).toBe('horizontal')
})

it('sets size to small', () => {
const widget = createMockWidget(5, 'int')
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('size')).toBe('small')
})
})

describe('WidgetInputNumberInput Step Value', () => {
it('defaults to 0 for unrestricted stepping', () => {
const widget = createMockWidget(5, 'int')
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('step')).toBe(0)
})

it('uses step2 value when provided', () => {
const widget = createMockWidget(5, 'int', { step2: 0.5 })
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('step')).toBe(0.5)
})

it('calculates step from precision for precision 0', () => {
const widget = createMockWidget(5, 'int', { precision: 0 })
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('step')).toBe(1)
})

it('calculates step from precision for precision 1', () => {
const widget = createMockWidget(5, 'float', { precision: 1 })
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('step')).toBe(0.1)
})

it('calculates step from precision for precision 2', () => {
const widget = createMockWidget(5, 'float', { precision: 2 })
const wrapper = mountComponent(widget, 5)

const inputNumber = wrapper.findComponent(InputNumber)
expect(inputNumber.props('step')).toBe(0.01)
})
})

describe('WidgetInputNumberInput Grouping Behavior', () => {
it('displays numbers without commas by default for int widgets', () => {
const widget = createMockWidget(1000, 'int')
const wrapper = mountComponent(widget, 1000)

const input = getNumberInput(wrapper)
expect(input.value).toBe('1000')
expect(input.value).not.toContain(',')
})

it('displays numbers without commas by default for float widgets', () => {
const widget = createMockWidget(1000.5, 'float')
const wrapper = mountComponent(widget, 1000.5)

const input = getNumberInput(wrapper)
expect(input.value).toBe('1000.5')
expect(input.value).not.toContain(',')
})

it('displays numbers with commas when grouping enabled', () => {
const widget = createMockWidget(1000, 'int', { useGrouping: true })
const wrapper = mountComponent(widget, 1000)

const input = getNumberInput(wrapper)
expect(input.value).toBe('1,000')
expect(input.value).toContain(',')
})
Comment on lines +182 to +189
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idle thought: Very much not something I think is important to test right now, but does the PrimeVue component handle the internationalization of the separator?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a locale prop https://primevue.org/inputnumber/#api.inputnumber.props.locale. I'm assuming they have intelligent default.


it('displays numbers without commas when grouping explicitly disabled', () => {
const widget = createMockWidget(1000, 'int', { useGrouping: false })
const wrapper = mountComponent(widget, 1000)

const input = getNumberInput(wrapper)
expect(input.value).toBe('1000')
expect(input.value).not.toContain(',')
})

it('displays numbers without commas when useGrouping option is undefined', () => {
const widget = createMockWidget(1000, 'int', { useGrouping: undefined })
const wrapper = mountComponent(widget, 1000)

const input = getNumberInput(wrapper)
expect(input.value).toBe('1000')
expect(input.value).not.toContain(',')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ const stepValue = computed(() => {
// Default to 'any' for unrestricted stepping
return 0
})

// Disable grouping separators by default unless explicitly enabled by the node author
const useGrouping = computed(() => {
return props.widget.options?.useGrouping === true
})
</script>

<template>
Expand All @@ -60,6 +65,7 @@ const stepValue = computed(() => {
size="small"
:disabled="readonly"
:step="stepValue"
:use-grouping="useGrouping"
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
:pt="{
incrementButton:
Expand Down