Browse Source
refactor: improve mobile keyboard interaction sync by introducing strict input validation and explicit state resets
master
refactor: improve mobile keyboard interaction sync by introducing strict input validation and explicit state resets
master
3 changed files with 134 additions and 86 deletions
-
88src/components/Componentes/question-snap-list.test.tsx
-
71src/components/Componentes/question-snap-list.tsx
-
61src/components/Componentes/use-sheet-scroll-lock.ts
@ -0,0 +1,88 @@ |
|||
import { |
|||
cleanup, |
|||
fireEvent, |
|||
render, |
|||
screen, |
|||
waitFor, |
|||
} from "@testing-library/react"; |
|||
import { afterEach, describe, expect, it, vi } from "vitest"; |
|||
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-keyboard-shift"); |
|||
}); |
|||
|
|||
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 = screen.getByRole("textbox", { name: "Question two" }); |
|||
|
|||
fireEvent.focusIn(firstInput); |
|||
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-keyboard-shift", |
|||
), |
|||
).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> |
|||
</>, |
|||
); |
|||
|
|||
fireEvent.focusIn(screen.getByRole("textbox", { name: "Question input" })); |
|||
expect(document.body).toHaveClass("question-keyboard-open"); |
|||
|
|||
fireEvent.focusOut(screen.getByRole("textbox", { name: "Question input" })); |
|||
fireEvent.focusIn(screen.getByRole("textbox", { name: "Dialog search" })); |
|||
|
|||
await waitFor(() => { |
|||
expect(document.body).not.toHaveClass("question-keyboard-open"); |
|||
}); |
|||
}); |
|||
}); |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue