/*
* 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");
});
});
});