import { getLocalVue } from "@tests/vitest/helpers"; import { mount } from "@vue/test-utils"; import flushPromises from "flush-promises"; import { describe, expect, it, vi } from "vitest"; import FormNumber from "./FormNumber.vue"; const localVue = getLocalVue(); describe("FormNumber", () => { const mountFormNumber = async (props) => await mount(FormNumber, { propsData: props, localVue, }); const getInput = async (wrapper) => await wrapper.find("input[type='number']"); const getInputRange = async (wrapper) => await wrapper.find("input[type='range']"); const getAlert = async (wrapper) => await wrapper.find("[role='alert']"); it("renders a number input with appropriate type", async () => { const wrapperFloat = await mountFormNumber({ value: 1, type: "float" }); const inputFloat = await getInput(wrapperFloat); expect(inputFloat.exists()).toBe(true); wrapperFloat.destroy(); const wrapperInteger = await mountFormNumber({ value: 1, type: "integer" }); const inputInteger = await getInput(wrapperInteger); expect(inputInteger.exists()).toBe(true); wrapperInteger.destroy(); }); it("renders a range input only when both min and max are defined and max > min", async () => { const assertRange = async (props, shouldExist) => { const wrapper = await mountFormNumber(props); const inputRange = await getInputRange(wrapper); expect(inputRange.exists()).toBe(shouldExist); wrapper.destroy(); }; const props = { value: 50, type: "float" }; // if min or max is not defined, range shouldn't be rendered await assertRange(props, false); props.min = 1; await assertRange(props, false); props.max = 100; await assertRange(props, true); // test usecase: range should be rendered on 0 props.min = 0; await assertRange(props, true); // test usecase: if max < min range shouldn't be rendered props.max = -100; await assertRange(props, false); }); it("shows an alert when the entered value is outside the defined min/max range", async () => { const checkOutOfRangeAlert = async (number) => { const props = { value: 50, type: "float", min: 10, max: 100 }; const wrapper = await mountFormNumber(props); const input = await getInput(wrapper); await input.setValue(number); await input.trigger("change"); const alert = await getAlert(wrapper); expect(alert.exists()).toBeTruthy(); expect(alert.text().includes(`${number} is out`)).toBeTruthy(); wrapper.destroy(); }; const numberBiggerThanRange = [110, Number.MAX_VALUE]; const numberSmallerThanRange = [1, 0, -1, Number.MIN_VALUE]; //alert should be shown for (const value of numberSmallerThanRange) { await checkOutOfRangeAlert(value); } for (const value of numberBiggerThanRange) { await checkOutOfRangeAlert(value); } }); it("shows a validation alert when entering a decimal for integer type", async () => { const checkFractionsAlert = async (key) => { const wrapper = await mountFormNumber(props); const input = await getInput(wrapper); await input.trigger("keypress", { key: key, }); await flushPromises(); const alert = await getAlert(wrapper); expect(alert.exists()).toBeTruthy(); wrapper.destroy(); }; const props = { value: 50, type: "integer", min: 10, max: 100 }; const keys = ["."]; for (const key of keys) { await checkFractionsAlert(key); } }); it("blocks '.' for integer type", async () => { const integerWrapper = await mountFormNumber({ value: "", type: "integer" }); const integerInput = await getInput(integerWrapper); const preventDefaultInteger = vi.fn(); await integerInput.trigger("keypress", { key: ".", preventDefault: preventDefaultInteger, }); expect(preventDefaultInteger).toHaveBeenCalled(); integerWrapper.destroy(); }); it("allows '.' for float type", async () => { const floatWrapper = await mountFormNumber({ value: "", type: "float" }); const floatInput = await getInput(floatWrapper); const preventDefaultFloat = vi.fn(); await floatInput.trigger("keypress", { key: ".", preventDefault: preventDefaultFloat, }); expect(preventDefaultFloat).not.toHaveBeenCalled(); floatWrapper.destroy(); }); it("allows typing '-' when negative numbers are permitted", async () => { const props = { value: "", type: "float" }; const wrapper = await mountFormNumber(props); const input = await getInput(wrapper); const preventDefault = vi.fn(); await input.trigger("keypress", { key: "-", preventDefault, }); expect(preventDefault).not.toHaveBeenCalled(); wrapper.destroy(); }); it("blocks typing '-' when min is non-negative", async () => { const props = { value: "", type: "float", min: 0, max: 100 }; const wrapper = await mountFormNumber(props); const input = await getInput(wrapper); const preventDefault = vi.fn(); await input.trigger("keypress", { key: "-", preventDefault, }); expect(preventDefault).toHaveBeenCalled(); wrapper.destroy(); }); it("computes the correct step value based on float precision", async () => { const expectStep = async (value, expectedStep) => { const props = { value: value, type: "float", min: 0, max: 1 }; const wrapper = await mountFormNumber(props); expect(wrapper.vm.step).toBe(expectedStep); }; //minimum step 0.1 - maximum step 0.001 const testValues = [ { value: undefined, step: 0.1 }, { value: "", step: 0.1 }, { value: 0, step: 0.1 }, { value: 0.5, step: 0.1 }, { value: 0.55, step: 0.01 }, { value: 0.555, step: 0.001 }, { value: 0.5555, step: 0.001 }, { value: 25e-100, step: 0.001 }, ]; for (let index = 0; index < testValues.length; index++) { expectStep(testValues[index].value, testValues[index].step); } }); });