You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.5 KiB
164 lines
4.5 KiB
import {
|
|
cleanup,
|
|
fireEvent,
|
|
render,
|
|
screen,
|
|
waitFor,
|
|
} from "@testing-library/react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { updateQuestionKeyboardHeight } from "./question-viewport-coordinator";
|
|
import { QuestionSnapList } from "./question-snap-list";
|
|
|
|
vi.mock("@/translations/provider", () => ({
|
|
useI18n: () => ({ dictionary: {} }),
|
|
}));
|
|
|
|
describe("QuestionSnapList keyboard interaction", () => {
|
|
afterEach(() => {
|
|
cleanup();
|
|
document.body.classList.remove("question-keyboard-open");
|
|
document.documentElement.style.removeProperty("--question-lift-y");
|
|
});
|
|
|
|
it("does not treat pointer contact as input focus", () => {
|
|
render(
|
|
<QuestionSnapList>
|
|
<input aria-label="Question one" type="text" />
|
|
</QuestionSnapList>,
|
|
);
|
|
|
|
fireEvent.pointerDown(
|
|
screen.getByRole("textbox", { name: "Question one" }),
|
|
);
|
|
|
|
expect(document.body).not.toHaveClass("question-keyboard-open");
|
|
});
|
|
|
|
it("activates only on real focus and resets before changing questions", async () => {
|
|
render(
|
|
<QuestionSnapList>
|
|
<input aria-label="Question one" type="text" />
|
|
<input aria-label="Question two" type="text" />
|
|
</QuestionSnapList>,
|
|
);
|
|
|
|
const firstInput = screen.getByRole("textbox", { name: "Question one" });
|
|
const secondInput = document.querySelector<HTMLInputElement>(
|
|
'input[aria-label="Question two"]',
|
|
);
|
|
const content = firstInput.closest<HTMLElement>(".question-snap-content");
|
|
vi.spyOn(content as HTMLElement, "getBoundingClientRect").mockReturnValue({
|
|
top: 300,
|
|
bottom: 600,
|
|
left: 0,
|
|
right: 300,
|
|
width: 300,
|
|
height: 300,
|
|
x: 0,
|
|
y: 300,
|
|
toJSON: () => ({}),
|
|
});
|
|
|
|
firstInput.focus();
|
|
updateQuestionKeyboardHeight(300);
|
|
await waitFor(() => {
|
|
expect(document.body).toHaveClass("question-keyboard-open");
|
|
});
|
|
|
|
fireEvent.wheel(screen.getByRole("region", { name: "Questions" }), {
|
|
deltaY: 100,
|
|
});
|
|
|
|
await waitFor(() => {
|
|
expect(document.body).not.toHaveClass("question-keyboard-open");
|
|
expect(firstInput).not.toHaveFocus();
|
|
expect(secondInput).not.toHaveFocus();
|
|
expect(
|
|
document.documentElement.style.getPropertyValue(
|
|
"--question-lift-y",
|
|
),
|
|
).toBe("0px");
|
|
});
|
|
});
|
|
|
|
it("does not keep question keyboard state for a dialog input", async () => {
|
|
render(
|
|
<>
|
|
<QuestionSnapList>
|
|
<input aria-label="Question input" type="text" />
|
|
</QuestionSnapList>
|
|
<div role="dialog">
|
|
<input aria-label="Dialog search" type="text" />
|
|
</div>
|
|
</>,
|
|
);
|
|
|
|
const questionInput = screen.getByRole("textbox", {
|
|
name: "Question input",
|
|
});
|
|
const content = questionInput.closest<HTMLElement>(
|
|
".question-snap-content",
|
|
);
|
|
vi.spyOn(content as HTMLElement, "getBoundingClientRect").mockReturnValue({
|
|
top: 300,
|
|
bottom: 600,
|
|
left: 0,
|
|
right: 300,
|
|
width: 300,
|
|
height: 300,
|
|
x: 0,
|
|
y: 300,
|
|
toJSON: () => ({}),
|
|
});
|
|
|
|
questionInput.focus();
|
|
updateQuestionKeyboardHeight(300);
|
|
await waitFor(() => {
|
|
expect(document.body).toHaveClass("question-keyboard-open");
|
|
});
|
|
|
|
screen.getByRole("textbox", { name: "Dialog search" }).focus();
|
|
|
|
await waitFor(() => {
|
|
expect(document.body).not.toHaveClass("question-keyboard-open");
|
|
});
|
|
});
|
|
|
|
it("raises again when Flutter reopens the keyboard without another focusin", async () => {
|
|
render(
|
|
<QuestionSnapList>
|
|
<input aria-label="Persistent input" type="text" />
|
|
</QuestionSnapList>,
|
|
);
|
|
|
|
const input = screen.getByRole("textbox", { name: "Persistent input" });
|
|
const content = input.closest<HTMLElement>(".question-snap-content");
|
|
vi.spyOn(content as HTMLElement, "getBoundingClientRect").mockReturnValue({
|
|
top: 300,
|
|
bottom: 600,
|
|
left: 0,
|
|
right: 300,
|
|
width: 300,
|
|
height: 300,
|
|
x: 0,
|
|
y: 300,
|
|
toJSON: () => ({}),
|
|
});
|
|
|
|
input.focus();
|
|
updateQuestionKeyboardHeight(300);
|
|
await waitFor(() => expect(document.body).toHaveClass("question-keyboard-open"));
|
|
|
|
updateQuestionKeyboardHeight(0);
|
|
await waitFor(() => {
|
|
expect(document.body).not.toHaveClass("question-keyboard-open");
|
|
expect(input).toHaveFocus();
|
|
});
|
|
|
|
updateQuestionKeyboardHeight(300);
|
|
await waitFor(() => {
|
|
expect(document.body).toHaveClass("question-keyboard-open");
|
|
expect(input).toHaveFocus();
|
|
});
|
|
});
|
|
});
|