import { describe, expect, it } from "vitest";
import { render } from "@testing-library/react";
import { page } from "vitest/browser";
import { DiveFormActions } from "./dive-form-actions";
// The stylesheet holds the pin itself, and its release on a short viewport.
import "@/app/globals.css";
// A form that runs on past the screen, ending in the row: pinned to the foot of
// the screen while there is room, and in its place at the form's end while the
// visible height is under 30rem, which is what the keyboard leaves.
function renderLongForm() {
const { container } = render(
<>
{/* The page's footer, which the form never ends flush against. */}
>,
);
return container.querySelector("[data-dive-form-actions]")!;
}
const scrollPaddingBottom = () =>
getComputedStyle(document.documentElement).scrollPaddingBottom;
describe("DiveFormActions", () => {
it("pins to the foot of the screen, and lets go while the viewport is short", async () => {
await page.viewport(390, 800);
const row = renderLongForm();
await expect.poll(() => row.hasAttribute("data-stuck")).toBe(true);
expect(getComputedStyle(row).position).toBe("sticky");
expect(row.getBoundingClientRect().bottom).toBeCloseTo(innerHeight, 0);
expect(scrollPaddingBottom()).toBe("64px");
// The keyboard coming up: the row goes back to the form's end, which is
// off screen below, and the padding it reserved goes with it - although
// its observer still reads a row below the fold as stuck.
await page.viewport(390, 400);
await expect.poll(() => getComputedStyle(row).position).toBe("static");
expect(row.getBoundingClientRect().top).toBeGreaterThan(innerHeight);
expect(scrollPaddingBottom()).toBe("auto");
// And its surface, which fades out rather than vanishing.
await expect
.poll(() => getComputedStyle(row).backgroundColor)
.toBe("rgba(0, 0, 0, 0)");
await page.viewport(390, 800);
await expect.poll(() => getComputedStyle(row).position).toBe("sticky");
await expect.poll(() => row.hasAttribute("data-stuck")).toBe(true);
expect(row.getBoundingClientRect().bottom).toBeCloseTo(innerHeight, 0);
});
it("rests at the form's end once scrolled there", async () => {
await page.viewport(390, 800);
const row = renderLongForm();
await expect.poll(() => row.hasAttribute("data-stuck")).toBe(true);
scrollTo(0, document.documentElement.scrollHeight);
await expect.poll(() => row.hasAttribute("data-stuck")).toBe(false);
expect(scrollPaddingBottom()).toBe("auto");
scrollTo(0, 0);
});
});