import React from "react"; import { fireEvent, render, cleanup, screen, waitFor } from "@testing-library/react"; import EditableText from "../EditableText"; import { within } from "@storybook/testing-library"; describe("EditableText", () => { afterEach(() => { cleanup(); }); it("should render an input in edit mode", () => { render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.queryByRole("input"); expect(input).toBeInTheDocument(); }); it("should not render an input when 'readOnly' is false when clicked", () => { render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.queryByRole("input"); expect(input).not.toBeInTheDocument(); }); describe("rendered value", () => { it("should render original value when value of an editable component is cleared", async () => { const value = "Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); fireEvent.change(input, { target: { value: "" } }); expect(input).toHaveValue(""); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(within(screen.getByRole("button")).getByText(value)).toBeInTheDocument(); }); }); describe("event handling", () => { describe("onClick", () => { const onClick = jest.fn(); it("should call onClick when clicking on an editable component", () => { render(); const component = screen.getByRole("button"); fireEvent.click(component); expect(onClick).toHaveBeenCalledTimes(1); }); it("should call onClick when clicking on 'readOnly' component", () => { render(); const component = screen.getByRole("button"); fireEvent.click(component); expect(onClick).toHaveBeenCalledTimes(1); }); }); describe("onChange", () => { const onChange = jest.fn(); it("should call onChange with new value when changed in an editable component", async () => { const value = "Editable test"; const newValue = "New Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); fireEvent.change(input, { target: { value: newValue } }); expect(input).toHaveValue(newValue); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(within(await screen.findByRole("button")).getByText(newValue)).toBeInTheDocument(); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(newValue); }); it("should not call onChange when value isn't changed in an editable component", async () => { const value = "Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); expect(input).toHaveValue(value); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(within(screen.getByRole("button")).getByText(value)).toBeInTheDocument(); expect(onChange).not.toBeCalled(); }); it("should not call onChange when value of an editable component is cleared", async () => { const value = "Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); fireEvent.change(input, { target: { value: "" } }); expect(input).toHaveValue(""); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(within(screen.getByRole("button")).getByText(value)).toBeInTheDocument(); expect(onChange).not.toBeCalled(); }); }); describe("onEditModeChange", () => { const onEditModeChange = jest.fn(); it("should call onEditModeChange with true when enter edit mode", async () => { const value = "Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); expect(onEditModeChange).toHaveBeenCalledTimes(1); expect(onEditModeChange).toHaveBeenCalledWith(true); }); it("should call onEditModeChange with false when exit edit mode", async () => { const value = "Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(onEditModeChange).toHaveBeenCalledTimes(2); expect(onEditModeChange).toHaveBeenLastCalledWith(false); }); }); }); describe("with placeholder", () => { it("should show a placeholder if provided and input is empty", async () => { const onChange = jest.fn(); const placeholderText = "Placeholder text"; const value = "Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); fireEvent.change(input, { target: { value: "" } }); expect(input).toHaveValue(""); expect(screen.getByPlaceholderText(placeholderText)).toBeInTheDocument(); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(within(await screen.findByRole("button")).getByText(placeholderText)).toBeInTheDocument(); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith(""); }); it("should not show a placeholder if provided and input is not empty", async () => { const placeholderText = "Placeholder text"; const value = "Editable test"; const newValue = "New Editable test"; render(); const component = screen.getByRole("button"); fireEvent.click(component); const input = screen.getByRole("input"); fireEvent.change(input, { target: { value: newValue } }); expect(input).toHaveValue(newValue); expect(screen.getByPlaceholderText(placeholderText)).toBeInTheDocument(); await waitFor(() => { fireEvent.keyDown(input, { key: "Enter" }); }); expect(within(await screen.findByRole("button")).getByText(newValue)).toBeInTheDocument(); }); }); });