Skip to content

Commit 2680e7c

Browse files
committed
UIEXT-2930: Add changeValue unit tests
UIEXT-2930 (Add configurable step size to NumberInputWidget)
1 parent ea56800 commit 2680e7c

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

packages/components/src/components/forms/NumberInput/__tests__/NumberInput.test.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe("NumberInput", () => {
99
beforeEach(() => {
1010
props = {
1111
modelValue: 10,
12+
stepSize: 1,
1213
min: 0,
1314
max: 20,
1415
title: "knime",
@@ -172,4 +173,124 @@ describe("NumberInput", () => {
172173
expect(getParsedValueSpy).toHaveNthReturnedWith(2, 1.5);
173174
expect(wrapper.vm.localValue).toBe(1.5);
174175
});
176+
177+
describe("changeValue", () => {
178+
it("increments value by the specified amount when valid", () => {
179+
expect(wrapper.vm.getParsedValue()).toBe(10);
180+
wrapper.vm.changeValue(5);
181+
expect(wrapper.vm.getParsedValue()).toBe(15);
182+
});
183+
184+
it("decrements value by the specified amount when valid", () => {
185+
expect(wrapper.vm.getParsedValue()).toBe(10);
186+
wrapper.vm.changeValue(-2);
187+
expect(wrapper.vm.getParsedValue()).toBe(8);
188+
});
189+
190+
it("respects step size for double precision", async () => {
191+
await wrapper.setProps({ modelValue: 10.5, type: "double" });
192+
wrapper.vm.changeValue(0.1);
193+
expect(wrapper.vm.getParsedValue()).toBe(10.6);
194+
});
195+
196+
it("handles large step sizes correctly (100)", async () => {
197+
await wrapper.setProps({ modelValue: 0, max: 1000 });
198+
wrapper.vm.changeValue(100);
199+
expect(wrapper.vm.getParsedValue()).toBe(100);
200+
wrapper.vm.changeValue(100);
201+
expect(wrapper.vm.getParsedValue()).toBe(200);
202+
wrapper.vm.changeValue(-100);
203+
expect(wrapper.vm.getParsedValue()).toBe(100);
204+
});
205+
206+
it("handles very small step sizes correctly (0.001)", async () => {
207+
await wrapper.setProps({ modelValue: 1.0, type: "double" });
208+
wrapper.vm.changeValue(0.001);
209+
expect(wrapper.vm.getParsedValue()).toBeCloseTo(1.001, 3);
210+
wrapper.vm.changeValue(0.001);
211+
expect(wrapper.vm.getParsedValue()).toBeCloseTo(1.002, 3);
212+
wrapper.vm.changeValue(-0.001);
213+
expect(wrapper.vm.getParsedValue()).toBeCloseTo(1.001, 3);
214+
});
215+
216+
it("snaps to nearest step (double)", async () => {
217+
await wrapper.setProps({ modelValue: 1.001, type: "double" });
218+
wrapper.vm.changeValue(0.01);
219+
expect(wrapper.vm.getParsedValue()).toBeCloseTo(1.01, 3);
220+
});
221+
222+
it("snaps to nearest step (integer)", async () => {
223+
await wrapper.setProps({ modelValue: 123, max: 1000, type: "integer" });
224+
wrapper.vm.changeValue(100);
225+
expect(wrapper.vm.getParsedValue()).toBe(200);
226+
227+
await wrapper.setProps({ modelValue: 10, type: "integer" });
228+
wrapper.vm.changeValue(-3);
229+
expect(wrapper.vm.getParsedValue()).toBe(6);
230+
});
231+
232+
it("handles multiple small increments without floating point errors", async () => {
233+
await wrapper.setProps({ modelValue: 0, type: "double" });
234+
// Add 0.1 ten times
235+
for (let i = 0; i < 10; i++) {
236+
wrapper.vm.changeValue(0.1);
237+
}
238+
// Should be 1.0, not 0.9999999999999999 or similar
239+
expect(wrapper.vm.getParsedValue()).toBeCloseTo(1.0, 1);
240+
});
241+
242+
it("emits update:modelValue event when value changes", () => {
243+
wrapper.vm.changeValue(1);
244+
expect(wrapper.emitted("update:modelValue")).toBeTruthy();
245+
expect(wrapper.emitted("update:modelValue").at(-1)[0]).toBe(11);
246+
});
247+
248+
it("rounds values to avoid floating point precision issues", () => {
249+
wrapper.vm.changeValue(0.1);
250+
wrapper.vm.changeValue(0.1);
251+
wrapper.vm.changeValue(0.1);
252+
// Should be 10.3, not 10.300000000000001
253+
expect(wrapper.vm.getParsedValue()).toBeCloseTo(10.3, 1);
254+
});
255+
256+
it("uses findNearestValidValue when current value is invalid", async () => {
257+
const findNearestValidValueSpy = vi.spyOn(
258+
wrapper.vm,
259+
"findNearestValidValue",
260+
);
261+
await wrapper.setProps({ modelValue: -5 }); // Below min (0)
262+
wrapper.vm.changeValue(1);
263+
expect(findNearestValidValueSpy).toHaveBeenCalledWith(-5);
264+
});
265+
266+
it("does not change value when increment would exceed max", async () => {
267+
await wrapper.setProps({ modelValue: 19, max: 20 });
268+
wrapper.vm.changeValue(5); // Would make it 24, which is > max
269+
expect(wrapper.vm.getParsedValue()).toBe(19); // Should stay at 19
270+
});
271+
272+
it("does not change value when decrement would go below min", async () => {
273+
await wrapper.setProps({ modelValue: 1, min: 0 });
274+
wrapper.vm.changeValue(-5); // Would make it -4, which is < min
275+
expect(wrapper.vm.getParsedValue()).toBe(1); // Should stay at 1
276+
});
277+
278+
it("changes to nearest valid value when currently invalid and incrementing in valid direction", async () => {
279+
await wrapper.setProps({ modelValue: -5, min: 0 }); // Invalid: below min
280+
wrapper.vm.changeValue(1); // Increment towards valid range
281+
expect(wrapper.vm.getParsedValue()).toBe(1); // Should jump to min (0) + increment (1)
282+
});
283+
284+
it("changes to nearest valid value when currently invalid and decrementing in valid direction", async () => {
285+
await wrapper.setProps({ modelValue: 25, max: 20 }); // Invalid: above max
286+
wrapper.vm.changeValue(-1); // Decrement towards valid range
287+
expect(wrapper.vm.getParsedValue()).toBe(19); // Should jump to max (20) + increment (-1)
288+
});
289+
290+
it("gracefully handles an interval of 0", () => {
291+
expect(wrapper.vm.getParsedValue()).toBe(10);
292+
wrapper.vm.changeValue(0);
293+
expect(wrapper.vm.getParsedValue()).toBe(10);
294+
});
295+
});
175296
});

0 commit comments

Comments
 (0)