/**
* Presence is what stops Leo's hero star from animating over an idle panel, so
* the rules worth pinning are the ones a regression would quietly undo: hover in
* and out, typing keeping it awake, the settle after the last keystroke, and
* working overriding all of it.
*/
import { act, fireEvent, render, screen } from "@testing-library/react"
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
import { LEO_TYPING_SETTLE_MS, useLeoPresence } from "./use-leo-presence"
function Panel({ working = false }: { working?: boolean }) {
const { present, presenceHandlers } = useLeoPresence(working)
return (
{present ? "alive" : "still"}
)
}
const present = () => screen.getByTestId("present").textContent
const panel = () => screen.getByTestId("panel")
describe("useLeoPresence", () => {
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it("starts still, so an untouched panel animates nothing", () => {
render()
expect(present()).toBe("still")
})
it("wakes while the pointer is over the panel and settles when it leaves", () => {
render()
// React derives enter and leave from pointerover / pointerout, so those are
// the events a real pointer would deliver.
fireEvent.pointerOver(panel())
expect(present()).toBe("alive")
fireEvent.pointerOut(panel(), { relatedTarget: document.body })
expect(present()).toBe("still")
})
it("stays awake through a typing pause, then settles", () => {
render()
const field = screen.getByLabelText("Ask Leo")
act(() => {
field.dispatchEvent(new KeyboardEvent("keydown", { key: "a", bubbles: true }))
})
expect(present()).toBe("alive")
act(() => {
vi.advanceTimersByTime(LEO_TYPING_SETTLE_MS - 500)
})
expect(present()).toBe("alive")
act(() => {
field.dispatchEvent(new KeyboardEvent("keydown", { key: "b", bubbles: true }))
vi.advanceTimersByTime(LEO_TYPING_SETTLE_MS - 500)
})
expect(present()).toBe("alive")
act(() => {
vi.advanceTimersByTime(600)
})
expect(present()).toBe("still")
})
it("is alive whenever Leo is working, untouched", () => {
render()
expect(present()).toBe("alive")
})
})