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
180 changes: 141 additions & 39 deletions lib/src/number-input/NumberInput.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,14 @@ import userEvent from "@testing-library/user-event";
import DxcNumberInput from "./NumberInput.tsx";

describe("Number input component tests", () => {
test("Number input renders with label", () => {
const { getByText } = render(<DxcNumberInput label="Number input label" />);
test("Number input renders with label, helper text, placeholder and increment/decrement action buttons", () => {
const { getByLabelText, getByText, queryAllByRole } = render(
<DxcNumberInput label="Number input label" helperText="Helper text" placeholder="Placeholder" />
);
const number = getByLabelText("Number input label");
expect(getByText("Number input label")).toBeTruthy();
});

test("Number input renders with helper text", () => {
const { getByText } = render(<DxcNumberInput helperText="Helper text" />);
expect(getByText("Helper text")).toBeTruthy();
});

test("Number input renders with placeholder", () => {
const { getByLabelText } = render(<DxcNumberInput label="Number label" placeholder="Placeholder" />);
const number = getByLabelText("Number label");
expect(number.getAttribute("placeholder")).toBe("Placeholder");
});

test("Number input renders increment and decrement buttons", () => {
const { queryAllByRole } = render(<DxcNumberInput label="Number label" />);
expect(queryAllByRole("button").length).toBe(2);
});

Expand All @@ -45,19 +35,18 @@ describe("Number input component tests", () => {
test("Number input is not optional: required field, displays error if not filled in", () => {
const onBlur = jest.fn();
const onChange = jest.fn();
const { getByRole } = render(<DxcNumberInput onBlur={onBlur} onChange={onChange} />);
const input = getByRole("spinbutton");

userEvent.type(input, "1");
userEvent.clear(input);
fireEvent.blur(input);
const { getByLabelText } = render(<DxcNumberInput label="Number input label" onBlur={onBlur} onChange={onChange} />);
const number = getByLabelText("Number input label");
userEvent.type(number, "1");
userEvent.clear(number);
fireEvent.blur(number);
expect(onBlur).toHaveBeenCalled();
expect(onBlur).toHaveBeenCalledWith({ value: "", error: "This field is required. Please, enter a value." });
expect(onChange).toHaveBeenCalled();
expect(onChange).toHaveBeenCalledWith({ value: "", error: "This field is required. Please, enter a value." });
});

test("Suffix and prefix must be shown)", () => {
test("Suffix and prefix must be shown", () => {
const { getByText } = render(<DxcNumberInput label="Number input label" prefix="+34" suffix="USD" />);
expect(getByText("+34")).toBeTruthy();
expect(getByText("USD")).toBeTruthy();
Expand All @@ -80,20 +69,20 @@ describe("Number input component tests", () => {
expect(number.value).toBe("1");
});

test("Error message is shown if the value is less than the min value", () => {
test("Error message is shown if the typed value is less than the min value", () => {
const onChange = jest.fn(({ value, error }) => {
expect(value).toBe("1");
expect(error).toBe("Value must be greater than or equal to 5.");
expect(value).toBe("-1");
expect(error).toBe("Value must be greater than or equal to 0.");
});
const onBlur = jest.fn(({ value, error }) => {
expect(value).toBe("1");
expect(error).toBe("Value must be greater than or equal to 5.");
expect(value).toBe("-1");
expect(error).toBe("Value must be greater than or equal to 0.");
});
const { getByLabelText } = render(
<DxcNumberInput label="Number input label" min={5} onBlur={onBlur} onChange={onChange} />
<DxcNumberInput label="Number input label" min={0} onBlur={onBlur} onChange={onChange} />
);
const number = getByLabelText("Number input label");
userEvent.type(number, "1");
userEvent.type(number, "-1");
fireEvent.blur(number);
});

Expand All @@ -119,7 +108,7 @@ describe("Number input component tests", () => {
expect(number.value).toBe("5");
});

test("Error message is shown if the value is greater than the max value", () => {
test("Error message is shown if the typed value is greater than the max value", () => {
const onChange = jest.fn();
const onBlur = jest.fn();
const { getByLabelText } = render(
Expand Down Expand Up @@ -148,9 +137,9 @@ describe("Number input component tests", () => {
test("Decrement the value when it is greater than the max value", () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" max={10} />);
const number = getByLabelText("Number input label");
userEvent.type(number, "12");
userEvent.type(number, "120");
fireEvent.blur(number);
expect(number.value).toBe("12");
expect(number.value).toBe("120");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
expect(number.value).toBe("10");
Expand Down Expand Up @@ -178,7 +167,7 @@ describe("Number input component tests", () => {
expect(number.value).toBe("10");
});

test("Increment and decrement the value with step", () => {
test("Increment and decrement the value with an integer step", () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" step={5} />);
const number = getByLabelText("Number input label");
userEvent.type(number, "10");
Expand All @@ -196,6 +185,26 @@ describe("Number input component tests", () => {
expect(number.value).toBe("10");
});

test("Increment and decrement the value with a decimal step", () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" step={0.5} />);
const number = getByLabelText("Number input label");
userEvent.type(number, "-9");
fireEvent.blur(number);
expect(number.value).toBe("-9");
const increment = getAllByRole("button")[1];
userEvent.click(increment);
expect(number.value).toBe("-8.5");
userEvent.click(increment);
expect(number.value).toBe("-8");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
userEvent.click(decrement);
userEvent.click(decrement);
expect(number.value).toBe("-9.5");
userEvent.click(decrement);
expect(number.value).toBe("-10");
});

test("Increment and decrement the value with min, max and step", () => {
const onBlur = jest.fn();
const { getByLabelText, getAllByRole } = render(
Expand All @@ -211,16 +220,108 @@ describe("Number input component tests", () => {
userEvent.click(increment);
expect(number.value).toBe("13");
userEvent.click(increment);
expect(number.value).toBe("20");
expect(number.value).toBe("13");
userEvent.click(increment);
expect(number.value).toBe("20");
expect(number.value).toBe("13");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
expect(number.value).toBe("12");
userEvent.click(decrement);
expect(number.value).toBe("5");
userEvent.click(decrement);
expect(number.value).toBe("5");
userEvent.click(decrement);
});

test("Start incrementing from 0 when the min value is less than 0 and the max value is bigger than 0", () => {
const onBlur = jest.fn();
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={10} step={1} onBlur={onBlur} />
);
const number = getByLabelText("Number input label");
const increment = getAllByRole("button")[1];
userEvent.click(increment);
expect(number.value).toBe("1");
userEvent.click(increment);
expect(number.value).toBe("2");
});

test("Start incrementing from 0 when the min value is less than 0 and the max is 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={0} step={1} />
);
const number = getByLabelText("Number input label");
const increment = getAllByRole("button")[1];
userEvent.click(increment);
expect(number.value).toBe("0");
userEvent.click(increment);
expect(number.value).toBe("0");
});

test("Start incrementing from the min value when it is bigger than 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={2} max={10} step={0.5} />
);
const number = getByLabelText("Number input label");
const increment = getAllByRole("button")[1];
userEvent.click(increment);
expect(number.value).toBe("2");
userEvent.click(increment);
expect(number.value).toBe("2.5");
});

test("Start incrementing from the max value when it is less than 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={-1} step={0.5} />
);
const number = getByLabelText("Number input label");
const increment = getAllByRole("button")[1];
userEvent.click(increment);
expect(number.value).toBe("-1");
userEvent.click(increment);
expect(number.value).toBe("-1");
});

test("Start decrementing from 0 when the min value is less than 0 and the max value is bigger than 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={10} step={1} />
);
const number = getByLabelText("Number input label");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
expect(number.value).toBe("-1");
});

test("Start decrementing from 0 when the min value is 0 and the max value is bigger than 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={0} max={10} step={1} />
);
const number = getByLabelText("Number input label");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
expect(number.value).toBe("0");
});

test("Start decrementing from the min value when it is bigger than 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={2} max={10} step={0.5} />
);
const number = getByLabelText("Number input label");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
expect(number.value).toBe("2");
userEvent.click(decrement);
expect(number.value).toBe("2");
});

test("Start decrementing from the max value when it is less than 0", () => {
const { getByLabelText, getAllByRole } = render(
<DxcNumberInput label="Number input label" min={-10} max={-1} step={0.5} />
);
const number = getByLabelText("Number input label");
const decrement = getAllByRole("button")[0];
userEvent.click(decrement);
expect(number.value).toBe("-1");
userEvent.click(decrement);
expect(number.value).toBe("-1.5");
});

test("Increment and decrement the value with min, max and step using the arrows in keyboard", () => {
Expand All @@ -247,9 +348,10 @@ describe("Number input component tests", () => {
expect(number.value).toBe("5");
});

test("Number has correct accesibility attributes", () => {
test("Number has correct accessibility attributes", () => {
const { getByLabelText, getAllByRole } = render(<DxcNumberInput label="Number input label" />);
const number = getByLabelText("Number input label");
expect(number.getAttribute("type")).toBe("number");
expect(number.getAttribute("aria-autocomplete")).toBeNull();
expect(number.getAttribute("aria-controls")).toBeNull();
expect(number.getAttribute("aria-expanded")).toBeNull();
Expand All @@ -259,7 +361,7 @@ describe("Number input component tests", () => {
expect(increment.getAttribute("aria-label")).toBe("Increment value");
});

test("Number input submits correct values in a form", () => {
test("Number input submits correct values inside a form and actions don't trigger the submit event", () => {
const handlerOnSubmit = jest.fn((e) => {
e.preventDefault();
const formData = new FormData(e.target);
Expand Down
64 changes: 35 additions & 29 deletions lib/src/number-input/NumberInput.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from "react";
import styled from "styled-components";
import DxcTextInput from "../text-input/TextInput";
import NumberInputContext from "./NumberInputContext";
import NumberInputPropsType, { RefType } from "./types";

type NumberInputContextProps = {
typeNumber?: string;
minNumber?: number;
maxNumber?: number;
stepNumber?: number;
};

export const NumberInputContext = React.createContext<NumberInputContextProps | null>(null);

const DxcNumberInput = React.forwardRef<RefType, NumberInputPropsType>(
(
{
Expand All @@ -29,34 +37,32 @@ const DxcNumberInput = React.forwardRef<RefType, NumberInputPropsType>(
tabIndex,
},
ref
) => {
return (
<NumberInputContext.Provider value={{ typeNumber: "number", minNumber: min, maxNumber: max, stepNumber: step }}>
<NumberInputContainer>
<DxcTextInput
label={label}
name={name}
defaultValue={defaultValue}
value={value}
helperText={helperText}
placeholder={placeholder}
disabled={disabled}
optional={optional}
prefix={prefix}
suffix={suffix}
error={error}
onChange={onChange}
onBlur={onBlur}
autocomplete={autocomplete}
margin={margin}
size={size}
tabIndex={tabIndex}
ref={ref}
/>
</NumberInputContainer>
</NumberInputContext.Provider>
);
}
) => (
<NumberInputContext.Provider value={{ typeNumber: "number", minNumber: min, maxNumber: max, stepNumber: step }}>
<NumberInputContainer>
<DxcTextInput
label={label}
name={name}
defaultValue={defaultValue}
value={value}
helperText={helperText}
placeholder={placeholder}
disabled={disabled}
optional={optional}
prefix={prefix}
suffix={suffix}
error={error}
onChange={onChange}
onBlur={onBlur}
autocomplete={autocomplete}
margin={margin}
size={size}
tabIndex={tabIndex}
ref={ref}
/>
</NumberInputContainer>
</NumberInputContext.Provider>
)
);

const NumberInputContainer = styled.div`
Expand Down
11 changes: 0 additions & 11 deletions lib/src/number-input/NumberInputContext.tsx

This file was deleted.

20 changes: 0 additions & 20 deletions lib/src/number-input/numberInputContextTypes.ts

This file was deleted.

Loading