fix(SW-3691): Setup one prettier config for whole repo * Setup prettierrc in root and remove other configs Approved-by: Joakim Jäderberg Approved-by: Linus Flood
198 lines
6.0 KiB
TypeScript
198 lines
6.0 KiB
TypeScript
import { describe, expect, it, vi, afterEach } from "vitest"
|
|
import { render, screen, fireEvent, cleanup } from "@testing-library/react"
|
|
import userEvent from "@testing-library/user-event"
|
|
import { Input } from "./Input"
|
|
import { TextField } from "react-aria-components"
|
|
|
|
afterEach(() => {
|
|
cleanup()
|
|
})
|
|
|
|
// Wrap Input in TextField for proper React Aria context
|
|
const renderInput = (props: React.ComponentProps<typeof Input>) => {
|
|
return render(
|
|
<TextField>
|
|
<Input {...props} />
|
|
</TextField>
|
|
)
|
|
}
|
|
|
|
// Render Input standalone (without TextField) for testing Input's own behavior
|
|
const renderInputStandalone = (props: React.ComponentProps<typeof Input>) => {
|
|
return render(<Input {...props} />)
|
|
}
|
|
|
|
describe("Input", () => {
|
|
describe("props", () => {
|
|
it("applies required attribute", () => {
|
|
renderInput({ label: "Email", required: true })
|
|
expect(screen.getByRole("textbox")).toHaveProperty("required", true)
|
|
})
|
|
|
|
it("applies readOnly attribute", () => {
|
|
renderInput({ label: "Email", readOnly: true })
|
|
expect(screen.getByRole("textbox")).toHaveProperty("readOnly", true)
|
|
})
|
|
|
|
it("applies placeholder for floating label when provided", () => {
|
|
renderInput({ label: "Email", placeholder: "Enter email" })
|
|
expect(screen.getByRole("textbox").getAttribute("placeholder")).toBe(
|
|
"Enter email"
|
|
)
|
|
})
|
|
|
|
it("applies empty placeholder for top label by default", () => {
|
|
renderInput({ label: "Email", labelPosition: "top" })
|
|
expect(screen.getByRole("textbox").getAttribute("placeholder")).toBe("")
|
|
})
|
|
|
|
it("applies custom id", () => {
|
|
// Use standalone render since TextField overrides id via context
|
|
renderInputStandalone({ label: "Email", id: "custom-id" })
|
|
expect(screen.getByRole("textbox").getAttribute("id")).toBe("custom-id")
|
|
})
|
|
|
|
it("applies aria-describedby", () => {
|
|
renderInput({ label: "Email", "aria-describedby": "error-message" })
|
|
expect(screen.getByRole("textbox").getAttribute("aria-describedby")).toBe(
|
|
"error-message"
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("clear content button", () => {
|
|
it("does not show clear button when showClearContentIcon is false", () => {
|
|
renderInput({
|
|
label: "Email",
|
|
value: "test",
|
|
onChange: vi.fn(),
|
|
showClearContentIcon: false,
|
|
})
|
|
expect(screen.queryByLabelText("Clear content")).toBeNull()
|
|
})
|
|
|
|
it("does not show clear button when input is empty", () => {
|
|
renderInput({
|
|
label: "Email",
|
|
value: "",
|
|
onChange: vi.fn(),
|
|
showClearContentIcon: true,
|
|
})
|
|
expect(screen.queryByLabelText("Clear content")).toBeNull()
|
|
})
|
|
|
|
it("shows clear button when input has value and showClearContentIcon is true", () => {
|
|
renderInput({
|
|
label: "Email",
|
|
value: "test",
|
|
onChange: vi.fn(),
|
|
showClearContentIcon: true,
|
|
})
|
|
expect(screen.getByLabelText("Clear content")).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe("icons", () => {
|
|
it("renders left icon when provided", () => {
|
|
renderInput({
|
|
label: "Search",
|
|
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
|
leftIcon: <span data-testid="left-icon">🔍</span>,
|
|
})
|
|
expect(screen.getByTestId("left-icon")).toBeTruthy()
|
|
})
|
|
|
|
it("renders right icon when provided", () => {
|
|
renderInput({
|
|
label: "Password",
|
|
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
|
rightIcon: <span data-testid="right-icon">👁</span>,
|
|
})
|
|
expect(screen.getByTestId("right-icon")).toBeTruthy()
|
|
})
|
|
|
|
it("hides right icon when clear button is shown", () => {
|
|
renderInput({
|
|
label: "Email",
|
|
value: "test",
|
|
onChange: vi.fn(),
|
|
showClearContentIcon: true,
|
|
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
|
rightIcon: <span data-testid="right-icon">👁</span>,
|
|
})
|
|
expect(screen.queryByTestId("right-icon")).toBeNull()
|
|
expect(screen.getByLabelText("Clear content")).toBeTruthy()
|
|
})
|
|
|
|
it("shows right icon when clear button condition not met", () => {
|
|
renderInput({
|
|
label: "Email",
|
|
value: "",
|
|
onChange: vi.fn(),
|
|
showClearContentIcon: true,
|
|
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
|
rightIcon: <span data-testid="right-icon">👁</span>,
|
|
})
|
|
expect(screen.getByTestId("right-icon")).toBeTruthy()
|
|
})
|
|
})
|
|
|
|
describe("controlled input", () => {
|
|
it("displays the controlled value", () => {
|
|
renderInput({
|
|
label: "Email",
|
|
value: "test@example.com",
|
|
onChange: vi.fn(),
|
|
})
|
|
expect(screen.getByRole("textbox")).toHaveProperty(
|
|
"value",
|
|
"test@example.com"
|
|
)
|
|
})
|
|
|
|
it("calls onChange when typing", async () => {
|
|
const onChange = vi.fn()
|
|
renderInput({ label: "Email", value: "", onChange })
|
|
|
|
const input = screen.getByRole("textbox")
|
|
await userEvent.type(input, "a")
|
|
|
|
expect(onChange).toHaveBeenCalled()
|
|
})
|
|
|
|
it("does not change value without onChange updating it", () => {
|
|
const onChange = vi.fn()
|
|
renderInput({ label: "Email", value: "initial", onChange })
|
|
|
|
const input = screen.getByRole("textbox")
|
|
fireEvent.change(input, { target: { value: "changed" } })
|
|
|
|
// Value stays the same because it's controlled
|
|
expect(input).toHaveProperty("value", "initial")
|
|
})
|
|
})
|
|
|
|
describe("ref forwarding", () => {
|
|
it("forwards ref to the input element", () => {
|
|
const ref = { current: null as HTMLInputElement | null }
|
|
render(
|
|
<TextField>
|
|
<Input label="Email" ref={ref} />
|
|
</TextField>
|
|
)
|
|
expect(ref.current).toBeInstanceOf(HTMLInputElement)
|
|
})
|
|
|
|
it("allows focusing via ref", () => {
|
|
const ref = { current: null as HTMLInputElement | null }
|
|
render(
|
|
<TextField>
|
|
<Input label="Email" ref={ref} />
|
|
</TextField>
|
|
)
|
|
ref.current?.focus()
|
|
expect(document.activeElement).toBe(ref.current)
|
|
})
|
|
})
|
|
})
|