Files
cunningham/packages/react/src/components/Forms/Input/index.spec.tsx
Anthony Le Courric e251bbb438 🚨(eslint-config-custom) prob order with windows
With Windows the order of the imports was not the same as with Linux,
this was causing the linter to fail with CI.
We force the import starting with ":" to the internal group to fix this
issue.
2023-09-11 16:15:13 +02:00

239 lines
7.4 KiB
TypeScript

import { render, screen, waitFor } from "@testing-library/react";
import React, { useRef } from "react";
import userEvent from "@testing-library/user-event";
import { expect } from "vitest";
import { Input, InputOnlyProps } from ":/components/Forms/Input/index";
import { Button } from ":/components/Button";
import { FieldProps } from "../Field";
const spyError = vi.spyOn(global.console, "error");
describe("<Input/>", () => {
afterAll(() => {
spyError.mockRestore();
});
it("renders and can type", async () => {
const user = userEvent.setup();
render(<Input label="First name" />);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
expect(input.value).toEqual("");
await user.type(input, "John");
expect(input.value).toEqual("John");
});
it("renders with default value and can type", async () => {
const user = userEvent.setup();
render(<Input label="First name" defaultValue="John" />);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
expect(input.value).toEqual("John");
await user.clear(input);
expect(input.value).toEqual("");
await user.type(input, "Paul");
expect(input.value).toEqual("Paul");
});
it("renders with moving label", async () => {
const user = userEvent.setup();
render(
<div>
<Input label="First name" />
<Input label="Second name" />
</div>,
);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
const input2: HTMLInputElement = screen.getByRole("textbox", {
name: "Second name",
});
const label = screen.getByText("First name");
expect(Array.from(label.classList)).toContain("placeholder");
// Clicking on the input should remove the placeholder class.
await user.click(input);
expect(Array.from(label.classList)).not.toContain("placeholder");
// Writing something should remove the placeholder class too.
await user.type(input, "John");
expect(Array.from(label.classList)).not.toContain("placeholder");
// Clearing the input and focus out should add the placeholder class
await user.clear(input);
await user.click(input2);
expect(Array.from(label.classList)).toContain("placeholder");
});
it("renders with state=success", async () => {
render(<Input label="First name" state="success" />);
expect(document.querySelector(".c__field--success")).toBeInTheDocument();
expect(
document.querySelector(".c__input__wrapper--success"),
).toBeInTheDocument();
});
it("renders with state=error", async () => {
render(<Input label="First name" state="error" />);
expect(document.querySelector(".c__field--error")).toBeInTheDocument();
expect(
document.querySelector(".c__input__wrapper--error"),
).toBeInTheDocument();
});
it("renders disabled", async () => {
const user = userEvent.setup();
render(<Input label="First name" disabled={true} />);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
expect(
document.querySelector(".c__input__wrapper--disabled"),
).toBeInTheDocument();
expect(input.value).toEqual("");
// Disabled inputs should not be able to type.
await user.type(input, "John");
expect(input.value).toEqual("");
});
it("renders with left icon", async () => {
render(
<Input
label="First name"
icon={<span className="material-icons">apartment</span>}
/>,
);
expect(document.querySelector(".material-icons")).toBeInTheDocument();
});
it("renders with right icon", async () => {
render(
<Input
label="First name"
rightIcon={<span className="material-icons">apartment</span>}
/>,
);
expect(document.querySelector(".material-icons")).toBeInTheDocument();
});
it("renders with text", async () => {
render(
<Input
label="First name"
rightIcon={<span className="material-icons">apartment</span>}
text="Some text"
/>,
);
screen.getByText("Some text");
});
it("renders with text items", async () => {
render(
<Input
label="First name"
rightIcon={<span className="material-icons">apartment</span>}
textItems={[
"Text too long",
"Wrong choice",
"Must contain at least 9 characters, uppercase and digits",
]}
/>,
);
expect(
screen.getAllByRole("listitem").map((item) => item.textContent),
).toEqual([
"Text too long",
"Wrong choice",
"Must contain at least 9 characters, uppercase and digits",
]);
});
it("renders with text and text right", async () => {
render(
<Input
label="First name"
rightIcon={<span className="material-icons">apartment</span>}
rightText="Some text right"
/>,
);
screen.getByText("Some text right");
});
it("renders with char counter", async () => {
const user = userEvent.setup();
render(<Input label="First name" charCounter={true} charCounterMax={15} />);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
screen.getByText("0/15");
await user.type(input, "Jo");
screen.getByText("2/15");
await user.type(input, "hn");
screen.getByText("4/15");
await user.clear(input);
screen.getByText("0/15");
});
it("forwards ref", async () => {
const user = userEvent.setup();
const Wrapper = () => {
const ref = useRef<HTMLInputElement>(null);
return (
<div>
<Input label="First name" ref={ref} />
<Button onClick={() => ref.current?.focus()}>Focus</Button>
</div>
);
};
render(<Wrapper />);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
expect(input).not.toHaveFocus();
await user.click(screen.getByRole("button", { name: "Focus" }));
waitFor(() => expect(input).toHaveFocus());
});
it("works controlled", async () => {
const Wrapper = () => {
const [value, setValue] = React.useState("I am controlled");
return (
<div>
<div>Value: {value}.</div>
<Input
label="First name"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<Button onClick={() => setValue("")}>Reset</Button>
</div>
);
};
const user = userEvent.setup();
render(<Wrapper />);
const input: HTMLInputElement = screen.getByRole("textbox", {
name: "First name",
});
screen.getByText("Value: I am controlled.");
await user.type(input, "John");
screen.getByText("Value: I am controlledJohn.");
await user.clear(input);
screen.getByText("Value: .");
});
it("checks the props doesn't create error warning", async () => {
const propsInput: Required<FieldProps & InputOnlyProps> = {
label: "First name",
fullWidth: true,
charCounter: true,
charCounterMax: 15,
className: "c__field--full-width",
compact: false,
state: "default",
icon: "my icon",
rightIcon: "my right icon",
text: "my text",
textItems: ["my text item 1", "my text item 2"],
rightText: "my right text",
};
render(<Input {...propsInput} />);
expect(spyError).not.toHaveBeenCalled();
});
});