// @vitest-environment jsdom // // docs/DESIGN.md "Text stays selectable": a button whose text is a title or a name is `selectable` — // its text selects (Chrome selects none inside a button without `user-select: text`), and the click // that ends selecting it, or a press dragged past the slop, does nothing. Held here, on the primitive every button family is built on. import { describe, it, expect, vi, afterEach } from "vitest"; import { render, screen, cleanup, fireEvent } from "@testing-library/react"; import { Pressable } from "./Pressable"; import { Button } from "./Button"; afterEach(() => { window.getSelection()!.removeAllRanges(); cleanup(); }); function selectText(el: Element) { const range = document.createRange(); range.selectNodeContents(el); window.getSelection()!.removeAllRanges(); window.getSelection()!.addRange(range); } describe("a selectable button", () => { it("lets its text select, and ignores the click that ends a selection", () => { const onClick = vi.fn(); render( Andor , ); const btn = screen.getByRole("button"); expect(btn.classList.contains("select-text")).toBe(true); selectText(screen.getByText("Andor")); fireEvent.click(btn, { detail: 1 }); // the mouseup that ended the drag-select expect(onClick).not.toHaveBeenCalled(); window.getSelection()!.removeAllRanges(); fireEvent.click(btn, { detail: 1 }); expect(onClick).toHaveBeenCalledTimes(1); }); // E28 review H2: Enter / Space on a focused title with its words still selected (selected, then // tabbed to) did nothing — a keyboard click ends no selection; it carries no pointer at all. it("a keyboard click opens even with the title's words selected", () => { const onClick = vi.fn(); render( Andor , ); selectText(screen.getByText("Andor")); fireEvent.click(screen.getByRole("button"), { detail: 0 }); expect(onClick).toHaveBeenCalledTimes(1); }); it("ignores a press dragged past the slop, keeps a steady one and a keyboard click", () => { const onClick = vi.fn(); render( Andor , ); const btn = screen.getByRole("button"); fireEvent.mouseDown(btn, { clientX: 10, clientY: 10 }); fireEvent.click(btn, { detail: 1, clientX: 40, clientY: 10 }); expect(onClick).not.toHaveBeenCalled(); fireEvent.mouseDown(btn, { clientX: 10, clientY: 10 }); fireEvent.click(btn, { detail: 1, clientX: 13, clientY: 12 }); expect(onClick).toHaveBeenCalledTimes(1); // Enter / Space: a click with no pointer, wherever the last press was. fireEvent.mouseDown(btn, { clientX: 10, clientY: 10 }); fireEvent.click(btn, { detail: 0, clientX: 0, clientY: 0 }); expect(onClick).toHaveBeenCalledTimes(2); }); it("still clicks when the selection is somewhere else on the page", () => { const onClick = vi.fn(); render( <>

elsewhere

, ); selectText(screen.getByText("elsewhere")); screen.getByRole("button").click(); expect(onClick).toHaveBeenCalledTimes(1); }); it("is off unless asked: a plain button neither selects nor guards", () => { const onClick = vi.fn(); render(Save); const btn = screen.getByRole("button"); expect(btn.classList.contains("select-text")).toBe(false); selectText(btn); btn.click(); expect(onClick).toHaveBeenCalledTimes(1); }); });