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