diff --git a/frontend/src/lib/useScrollFade.dom.test.tsx b/frontend/src/lib/useScrollFade.dom.test.tsx new file mode 100644 index 00000000..090eee25 --- /dev/null +++ b/frontend/src/lib/useScrollFade.dom.test.tsx @@ -0,0 +1,49 @@ +// @vitest-environment jsdom +import { describe, it, expect, beforeAll, afterEach } from "vitest"; +import { render, cleanup, fireEvent } from "@testing-library/react"; +import { useScrollFade } from "./useScrollFade"; + +beforeAll(() => { + class Stub { + observe() {} + unobserve() {} + disconnect() {} + } + globalThis.ResizeObserver ??= Stub as unknown as typeof ResizeObserver; +}); +afterEach(cleanup); + +function Scroller({ fadeTop = true }: { fadeTop?: boolean }) { + const fade = useScrollFade(20, fadeTop); + const { ref } = fade; + return
; +} + +/** A scroller 100 px tall over 300 px of content, scrolled to `top`. */ +function scrolledTo(el: HTMLElement, top: number) { + Object.defineProperties(el, { + clientHeight: { configurable: true, value: 100 }, + scrollHeight: { configurable: true, value: 300 }, + scrollTop: { configurable: true, value: top, writable: true }, + }); + fireEvent.scroll(el); +} + +// iPad WebKit kept a scrolled container's mask stuck to the content: at the bottom of a scrolled page +// the last strip (a table's pager) sat under a dark band. With no edge to fade there is no mask. +describe("useScrollFade", () => { + it("masks the edge that is clipped", () => { + const { getByTestId } = render(