import userEvent from "@testing-library/user-event"; import { render, screen, waitFor } from "@testing-library/react"; import { expect } from "vitest"; import React, { FormEvent, useState } from "react"; import { Select, Option } from ":/components/Forms/Select/index"; import { Button } from ":/components/Button"; import { CunninghamProvider } from ":/components/Provider"; import { expectMenuToBeClosed, expectMenuToBeOpen, expectNoOptions, expectOptions, expectOptionToBeDisabled, expectOptionToBeSelected, expectOptionToBeUnselected, } from ":/components/Forms/Select/test-utils"; import { Input } from ":/components/Forms/Input"; describe(" , ); const input = screen.getByRole("combobox", { name: "City", }); // It returns the input. expect(input.tagName).toEqual("INPUT"); const menu: HTMLDivElement = screen.getByRole("listbox", { name: "City", }); expectMenuToBeClosed(menu); // Click on the input. await user.click(input); expectMenuToBeOpen(menu); expectOptions(["Paris", "Panama", "London", "New York", "Tokyo"]); // Select an option. const option: HTMLLIElement = screen.getByRole("option", { name: "New York", }); await user.click(option); // The menu should be closed. expectMenuToBeClosed(menu); // The input should have the selected value. expect(input).toHaveValue("New York"); }); it("filters options when typing", async () => { const user = userEvent.setup(); render( setValue(e.target.value as any)} /> ); }; render(); const user = userEvent.setup(); const input = screen.getByRole("combobox", { name: "City", }); screen.getByText("Value = |"); // It returns the input. expect(input.tagName).toEqual("INPUT"); const menu: HTMLDivElement = screen.getByRole("listbox", { name: "City", }); expectMenuToBeClosed(menu); // Click on the input. await user.click(input); expectMenuToBeOpen(menu); expectOptions(["Paris", "Panama", "London", "New York", "Tokyo"]); // Verify that filtering works. await user.type(input, "Pa"); expectMenuToBeOpen(menu); expectOptions(["Paris", "Panama"]); await user.type(input, "rr"); expectNoOptions(); expect(input).toHaveValue("Parr"); // This is a way to blur the combobox. await user.click(screen.getByRole("textbox")); expect(input).toHaveValue(""); screen.getByText("Value = |"); }); it("clears the added text to the existing value input on blur if no other item is selected", async () => { const Wrapper = () => { const [value, setValue] = useState( "london", ); return (
Value = {value}|
); }; render(); const user = userEvent.setup(); const input = screen.getByRole("combobox", { name: "City", }); screen.getByText("Value = london|"); // It returns the input. expect(input.tagName).toEqual("INPUT"); expect(input).toHaveValue("London"); await user.type(input, "rr"); expect(input).toHaveValue("Londonrr"); // This is a way to blur the combobox. await user.click(screen.getByRole("textbox")); expect(input).toHaveValue("London"); screen.getByText("Value = london|"); }); it("clears value", async () => { render( , ); const input = screen.getByRole("combobox", { name: "City", }); expect(input).toHaveValue("New York"); }); it("should select with defaultValue using value", async () => { render( , ); const input = screen.getByRole("combobox", { name: "City", }); expect(input).toHaveValue(""); }); it("works controlled", async () => { const Wrapper = () => { const [value, setValue] = useState( "london", ); const [onChangeCounts, setOnChangeCounts] = useState(0); return (
Value = {value}|
onChangeCounts = {onChangeCounts}|
, ); const input = screen.getByRole("combobox", { name: "City", }); expect(input).toHaveAttribute("disabled"); const button: HTMLButtonElement = document.querySelector( ".c__select__inner__actions__open", )!; expect(button).toBeDisabled(); const menu: HTMLDivElement = screen.getByRole("listbox", { name: "City", }); expectMenuToBeClosed(menu); const user = userEvent.setup(); // Try to open the menu. await user.click(input); // Make sure menu is still closed. expectMenuToBeClosed(menu); // Make sure no value is rendered const valueRendered = document.querySelector(".c__select__inner__value"); expect(valueRendered).toHaveTextContent(""); // Try to type await user.type(input, "Pa"); expectMenuToBeClosed(menu); }); it("submits form data", async () => { let formData: any; const Wrapper = () => { const onSubmit = (e: FormEvent) => { e.preventDefault(); const data = new FormData(e.currentTarget); formData = { city: data.get("city"), }; }; return (
); }; const { rerender } = render(, { wrapper: CunninghamProvider, }); const user = userEvent.setup(); const input = screen.getByRole("combobox", { name: "City", }); const menu: HTMLDivElement = screen.getByRole("listbox", { name: "City", }); // Check init value (defaultValue / value / nothing) expect(input).toHaveValue(expected); // Add filter await user.clear(input); await user.type(input, "Pa"); expectMenuToBeOpen(menu); expectOptions(["Paris", "Panama"]); myOptions.shift(); // Rerender the select with the options mutated rerender(); expectMenuToBeOpen(menu); // Options is refreshed expectOptions(["Panama"]); // Filter is still active expect(input).toHaveValue("Pa"); myOptions.shift(); // Rerender the select with the options mutated (only london left) rerender(); // Filter is still active expect(input).toHaveValue("Pa"); expect(screen.getByText("No options available")).toBeInTheDocument(); await user.clear(input); expectOptions(["London"]); await user.click( screen.getByRole("option", { name: "London", }), ); expect(input).toHaveValue("London"); }); }); }); describe("Simple", () => { it("should select an option and unselect it", async () => { const user = userEvent.setup(); render( , ); const menu: HTMLDivElement = screen.getByRole("listbox", { name: "City", }); const label = screen.getByText("City"); const valueRendered = document.querySelector(".c__select__inner__value"); // Make sure option is selected. expect(valueRendered).toHaveTextContent("Tokyo"); expect(Array.from(label.classList)).not.toContain("placeholder"); // Make sure menu is automatically closed. expectMenuToBeClosed(menu); }); it("should select with defaultValue using value", () => { render( setValue(e.target.value as string)} />
); }; render(); const input = screen.getByRole("combobox", { name: "City", }); // Make sure value is selected. screen.getByText("Value = london|"); // Change value. const user = userEvent.setup(); await user.click(input); // Make sure the option is selected. const option: HTMLLIElement = screen.getByRole("option", { name: "London", }); expectOptionToBeSelected(option); // Select an option. await user.click( screen.getByRole("option", { name: "New York", }), ); // Make sure value is selected. screen.getByText("Value = new_york|"); // clear value. const button = screen.getByRole("button", { name: "Clear", }); await user.click(button); // Make sure value is cleared. screen.getByText("Value = |"); }); it("renders disabled", async () => { render( , ); screen.getByText("This is a text"); }); it("renders with state=error", async () => { render( , ); expect( document.querySelector(".c__select.c__select--success"), ).toBeInTheDocument(); }); it("submits form data", async () => { let formData: any; const Wrapper = () => { const onSubmit = (e: FormEvent) => { e.preventDefault(); const data = new FormData(e.currentTarget); formData = { city: data.get("city"), }; }; return (
, ); screen.getByRole("combobox", { name: "City", }); const valueRendered = document.querySelector(".c__select__inner__value"); // Make sure default value is rendered. expect(valueRendered).toHaveTextContent("Paris"); // Make sure the clear button is not rendered. expect( screen.queryByRole("button", { name: "Clear selection", }), ).not.toBeInTheDocument(); }); it("is not possible to select disabled options", async () => { render( , ); // Make sure the input is accessible. screen.getByRole("combobox", { name: "City", }); const label = screen.getByText("City"); expect(Array.from(label.classList)).toContain("offscreen"); }); it("renders menu empty placeholder when there are no options to display", async () => { render(