/* * Copyright 2021-2024 Avaiga Private Limited * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ import React from "react"; import { render, waitFor, fireEvent, createEvent } from "@testing-library/react"; import "@testing-library/jest-dom"; import userEvent from "@testing-library/user-event"; import Input from "./Input"; import { TaipyContext } from "../../context/taipyContext"; import { TaipyState, INITIAL_STATE } from "../../context/taipyReducers"; describe("Input Component", () => { it("renders", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("toto"); expect(elt.tagName).toBe("INPUT"); }); it("displays the right info for string", async () => { const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("toto"); expect(elt.parentElement?.parentElement).toHaveClass("taipy-input"); }); it("displays the default value", async () => { const { getByDisplayValue } = render( , ); getByDisplayValue("titi"); }); it("displays with width=70%", async () => { const { getByDisplayValue, getByTestId } = render( ); const element = getByDisplayValue("toto"); expect(element.parentElement?.parentElement).toHaveStyle('max-width: 70%'); }); it("displays with width=500", async () => { const { getByDisplayValue, getByTestId } = render( ); const element = getByDisplayValue("toto"); expect(element.parentElement?.parentElement).toHaveStyle('max-width: 500px'); }); it("is disabled", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("val"); expect(elt).toBeDisabled(); }); it("is enabled by default", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("val"); expect(elt).not.toBeDisabled(); }); it("is enabled by active", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("val"); expect(elt).not.toBeDisabled(); }); it("dispatch a well formed message", async () => { const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("Val"); await userEvent.clear(elt); await waitFor(() => expect(dispatch).toHaveBeenCalled()); expect(dispatch).toHaveBeenLastCalledWith({ name: "varname", payload: { value: "" }, propagate: true, type: "SEND_UPDATE_ACTION", }); }); it("dispatch a well formed message on enter", async () => { const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("Val"); await userEvent.click(elt); await userEvent.keyboard("data{Enter}"); await waitFor(() => expect(dispatch).toHaveBeenCalled()); expect(dispatch).toHaveBeenLastCalledWith({ name: "", payload: { action: "on_action", args: ["Enter", "varname", "Valdata"] }, type: "SEND_ACTION_ACTION", }); }); it("dispatch a well formed update message with change_delay=-1", async () => { const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("Val"); await userEvent.click(elt); await userEvent.keyboard("data{Enter}"); await waitFor(() => expect(dispatch).toHaveBeenCalled()); expect(dispatch).toHaveBeenLastCalledWith({ name: "varname", payload: { value: "Valdata" }, propagate: true, type: "SEND_UPDATE_ACTION", }); }); it("dispatch a well formed update message with change_delay=0", async () => { const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("Val"); await userEvent.click(elt); await userEvent.keyboard("data{Enter}"); await waitFor(() => expect(dispatch).toHaveBeenCalled()); expect(dispatch).toHaveBeenLastCalledWith({ name: "varname", payload: { value: "Valdata" }, propagate: true, type: "SEND_UPDATE_ACTION", }); }); it("dispatch a no action message on unsupported key", async () => { const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("Val"); await userEvent.click(elt); await userEvent.keyboard("data{Escape}"); await waitFor(() => expect(dispatch).toHaveBeenCalled()); expect(dispatch).toHaveBeenLastCalledWith({ name: "varname", payload: { value: "Valdata" }, propagate: true, type: "SEND_UPDATE_ACTION", }); }); it("should display visibility off icon when password is visible", async () => { const { getByLabelText } = render(); const visibilityButton = getByLabelText("toggle password visibility"); fireEvent.click(visibilityButton); const visibilityIcon = document.querySelector('svg[data-testid="VisibilityOffIcon"]'); expect(visibilityIcon).toBeInTheDocument(); }); it("should display visibility icon when password is hidden", async () => { const { getByLabelText } = render(); const visibilityButton = getByLabelText("toggle password visibility"); expect(visibilityButton).toBeInTheDocument(); }); it("should prevent default action when mouse down event occurs on password visibility button", async () => { const { getByLabelText } = render(); const visibilityButton = getByLabelText("toggle password visibility"); const keyDown = createEvent.mouseDown(visibilityButton); fireEvent(visibilityButton, keyDown); expect(keyDown.defaultPrevented).toBe(true); }); it("parses actionKeys correctly", () => { const { rerender } = render(); rerender(); rerender(); rerender(); }); }); describe("Number Component", () => { it("renders", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("12"); expect(elt.tagName).toBe("INPUT"); }); it("displays the right info for string", async () => { const { getByDisplayValue } = render( , ); const elt = getByDisplayValue(12); expect(elt.parentElement?.parentElement).toHaveClass("taipy-number"); }); it("displays the default value", async () => { const { getByDisplayValue } = render( , ); getByDisplayValue("1"); }); it("is disabled", async () => { const { getByDisplayValue, getByLabelText } = render(); const elt = getByDisplayValue("33"); expect(elt).toBeDisabled(); const upSpinner = getByLabelText("Increment value"); expect(upSpinner).toBeDisabled(); }); it("is enabled by default", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("33"); expect(elt).not.toBeDisabled(); }); it("is enabled by active", async () => { const { getByDisplayValue } = render(); const elt = getByDisplayValue("33"); expect(elt).not.toBeDisabled(); }); it("dispatch a well formed message", async () => { const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByDisplayValue } = render( , ); const elt = getByDisplayValue("33"); await userEvent.clear(elt); await userEvent.type(elt, "666"); await waitFor(() => expect(dispatch).toHaveBeenCalled()); expect(dispatch).toHaveBeenLastCalledWith({ name: "varname", payload: { value: "666" }, propagate: true, type: "SEND_UPDATE_ACTION", }); }); xit("shows 0", async () => { //not working cf. https://github.com/testing-library/user-event/issues/1066 const { getByDisplayValue } = render(); const elt = getByDisplayValue("0") as HTMLInputElement; expect(elt).toBeInTheDocument(); await userEvent.type(elt, "{ArrowUp}"); expect(elt.value).toBe("1"); await userEvent.type(elt, "{ArrowDown}"); expect(elt.value).toBe("0"); }); it("Validates increment by step value on up click", async () => { const { getByDisplayValue, getByLabelText } = render( , ); const upSpinner = getByLabelText("Increment value"); const elt = getByDisplayValue("0") as HTMLInputElement; await userEvent.click(upSpinner); expect(elt.value).toBe("2"); }); it("Validates decrement by step value on down click", async () => { const { getByDisplayValue, getByLabelText } = render( , ); const downSpinner = getByLabelText("Decrement value"); const elt = getByDisplayValue("0") as HTMLInputElement; await userEvent.click(downSpinner); expect(elt.value).toBe("-2"); }); it("Validates increment when holding shift key and clicking up", async () => { const user = userEvent.setup(); const { getByDisplayValue, getByLabelText } = render( , ); const upSpinner = getByLabelText("Increment value"); const elt = getByDisplayValue("0") as HTMLInputElement; await user.keyboard("[ShiftLeft>]"); await user.click(upSpinner); expect(elt.value).toBe("20"); }); it("Validates decrement when holding shift key and clicking down", async () => { const user = userEvent.setup(); const { getByDisplayValue, getByLabelText } = render( , ); const downSpinner = getByLabelText("Decrement value"); const elt = getByDisplayValue("0") as HTMLInputElement; await user.keyboard("[ShiftLeft>]"); await user.click(downSpinner); expect(elt.value).toBe("-20"); }); it("Validate increment when holding shift key and arrow up", async () => { const user = userEvent.setup(); const { getByDisplayValue } = render(); const elt = getByDisplayValue("0") as HTMLInputElement; await user.click(elt); await user.keyboard("[ShiftLeft>]"); await user.keyboard("[ArrowUp]"); expect(elt.value).toBe("20"); }); it("Validate value when reaching max value", async () => { const user = userEvent.setup(); const { getByDisplayValue } = render(); const elt = getByDisplayValue("0") as HTMLInputElement; await user.click(elt); await user.keyboard("[ShiftLeft>]"); // Press the arrow up twice to validate that the value will not exceed the maximum value when reached await user.keyboard("[ArrowUp]"); await user.keyboard("[ArrowUp]"); expect(elt.value).toBe("20"); }); it("Validate value when reaching min value", async () => { const user = userEvent.setup(); const { getByDisplayValue } = render(); const elt = getByDisplayValue("20") as HTMLInputElement; await user.click(elt); await user.keyboard("[ShiftLeft>]"); // Press the arrow down twice to validate that the value will not exceed the minimum value when reached await user.keyboard("[ArrowDown]"); await user.keyboard("[ArrowDown]"); expect(elt.value).toBe("0"); }); it("it should not decrement below the min value", () => { const { getByLabelText } = render(); const downSpinner = getByLabelText("Decrement value"); fireEvent.mouseDown(downSpinner); const inputElement = document.getElementById("Test Input") as HTMLInputElement; expect(inputElement.value).toBe("0"); }); it("should not exceed max value when incrementing", async () => { const { getByLabelText } = render( , ); const upSpinner = getByLabelText("Increment value"); fireEvent.mouseDown(upSpinner, { shiftKey: true }); const inputElement = document.getElementById("Test Input") as HTMLInputElement; await waitFor(() => { expect(inputElement.value).toBe("20"); }); }); });