import React from "react"; import { fireEvent, render, waitFor } from "@testing-library/react-native"; import { InputNumber } from "."; type OS = "ios" | "android"; let Platform: { OS: OS }; beforeEach(() => { Platform = require("react-native").Platform; }); const platforms: OS[] = ["ios", "android"]; it.each(platforms)("renders an InputNumber on %s", platform => { Platform.OS = platform; const label = "My Accessible label"; const { getByLabelText } = render(); expect(getByLabelText(label)).toBeTruthy(); }); it.each(platforms)( "renders an InputNumber with defaultValue on %s", platform => { Platform.OS = platform; const value = 200; const { getByDisplayValue } = render(); expect(getByDisplayValue(value.toString())).toBeTruthy(); }, ); const notANumberErrorMessage = "Enter a number"; it("Displays a validation message when the value is not a number", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { getByText, getByLabelText } = render( , ); const inputValue = "this"; fireEvent.changeText(getByLabelText(a11yLabel), inputValue); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect( getByText(notANumberErrorMessage, { includeHiddenElements: true, }), ).toBeDefined(); expect(onChange).toHaveBeenCalledWith(inputValue); }); it("When onChange is called it returns a number", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { getByLabelText } = render( , ); fireEvent.changeText(getByLabelText(a11yLabel), "100"); expect(onChange).toHaveBeenCalledWith(100); }); it("doesn't change the value when the input is controlled without an onChange", async () => { const a11yLabel = "InputNumberTest"; const initialValue = 12; const changeValue = 100; const { queryByText, getByLabelText, getByDisplayValue } = render( , ); fireEvent.changeText(getByLabelText(a11yLabel), changeValue.toString()); expect(queryByText(changeValue.toString())).toBeNull(); expect(getByDisplayValue(initialValue.toString())).toBeDefined(); }); it("passes validation when decimal value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "13.5"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseFloat(numInput)); }); it("passes validation when negative value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "-15"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseInt(numInput, 10)); }); it("passes validation when negative decimal value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "-15.123"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseFloat(numInput)); }); it("passes validation when explicit positive value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "+15"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseInt(numInput, 10)); }); it("passes validation when e notation value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "6e10"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseFloat(numInput)); }); it("passes validation when e notation decimal value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "6.456e10"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseFloat(numInput)); }); it("passes validation when e notation for representing decimal value is entered", async () => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { queryByText, getByLabelText } = render( , ); const numInput = "6e-10"; fireEvent.changeText(getByLabelText(a11yLabel), numInput); await waitFor(() => { fireEvent(getByLabelText(a11yLabel), "blur"); }); expect(queryByText(notANumberErrorMessage)).toBeNull(); expect(onChange).toHaveBeenCalledWith(parseFloat(numInput)); }); describe("when the value ends with period", () => { const values = [".", "0.", "12.", "+1.", "-0."]; it.each(values)("doesn't convert the value %s", value => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { getByLabelText, getByDisplayValue } = render( , ); fireEvent.changeText(getByLabelText(a11yLabel), value); expect(getByDisplayValue(value)).toBeDefined(); }); }); describe("when the value ends with scientific notation", () => { const values = ["1e", "+2e", "1.2e", "-3e"]; it.each(values)("doesn't convert the value %s", value => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { getByLabelText, getByDisplayValue } = render( , ); fireEvent.changeText(getByLabelText(a11yLabel), value); expect(getByDisplayValue(value)).toBeDefined(); }); }); describe("when the value ends with + or -", () => { const values = ["+", "-"]; it.each(values)("doesn't convert the value %s", value => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { getByLabelText, getByDisplayValue } = render( , ); fireEvent.changeText(getByLabelText(a11yLabel), value); expect(getByDisplayValue(value)).toBeDefined(); }); }); describe("when the value ends with zero decimal", () => { const values = ["0.0", "+0.00000", "-3.00000", "2.100", ".0", ".00000"]; it.each(values)("doesn't convert the value %s", value => { const a11yLabel = "InputNumberTest"; const onChange = jest.fn(); const { getByLabelText, getByDisplayValue } = render( , ); fireEvent.changeText(getByLabelText(a11yLabel), value); expect(getByDisplayValue(value)).toBeDefined(); }); }); describe("when the OS is iOS", () => { const a11yLabel = "InputNumberTest"; beforeEach(() => { Platform.OS = "ios"; }); it("uses the decimal-pad keyboard when keyboard is 'decimal-pad'", () => { const { getByLabelText } = render( , ); expect(getByLabelText(a11yLabel).props.keyboardType).toEqual("decimal-pad"); }); it("uses the default numbers-and-punctuation keyboard when missing keyboard prop", () => { const { getByLabelText } = render( , ); expect(getByLabelText(a11yLabel).props.keyboardType).toEqual( "numbers-and-punctuation", ); }); it("uses the numbers-and-punctuation keyboard when keyboard is 'numbers-and-punctuation'", () => { const { getByLabelText } = render( , ); expect(getByLabelText(a11yLabel).props.keyboardType).toEqual( "numbers-and-punctuation", ); }); }); describe("when the OS is android", () => { const a11yLabel = "InputNumberTest"; beforeEach(() => { Platform.OS = "android"; }); it("uses the numeric keyboard when missing keyboard prop", () => { const { getByLabelText } = render( , ); expect(getByLabelText(a11yLabel).props.keyboardType).toEqual("numeric"); }); it("uses the numeric keyboard when keyboard is 'decimal-pad'", () => { const { getByLabelText } = render( , ); expect(getByLabelText(a11yLabel).props.keyboardType).toEqual("numeric"); }); it("uses the numeric keyboard when keyboard is 'numbers-and-punctuation'", () => { const { getByLabelText } = render( , ); expect(getByLabelText(a11yLabel).props.keyboardType).toEqual("numeric"); }); });