Repository navigation
Expand file tree
/
Copy pathsoftwareKeyboard.test.ts
More file actions
136 lines (122 loc) · 4.78 KB
/
Copy pathsoftwareKeyboard.test.ts
File metadata and controls
136 lines (122 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { describe, expect, it, vi } from "vite-plus/test";
import { createSoftwareKeyboardStore } from "./softwareKeyboard";
function fixture(options: { native?: boolean; overlay?: boolean; desktop?: boolean } = {}) {
const viewport = Object.assign(new EventTarget(), { width: 390, height: 844, scale: 1 });
const keyboard = Object.assign(new EventTarget(), {
boundingRect: { height: 0 },
overlaysContent: options.overlay ?? false,
});
const win = {
innerHeight: 844,
visualViewport: viewport,
navigator: options.native ? { virtualKeyboard: keyboard } : {},
};
const store = createSoftwareKeyboardStore(win as unknown as Window, options.desktop ?? false);
const resize = (height: number, width = viewport.width, scale = viewport.scale) => {
Object.assign(viewport, { height, width, scale });
viewport.dispatchEvent(new Event("resize"));
};
const geometry = (height: number) => {
keyboard.boundingRect.height = height;
keyboard.dispatchEvent(new Event("geometrychange"));
};
return { store, viewport, keyboard, win, resize, geometry };
}
describe("software keyboard detection", () => {
it("follows native keyboard geometry even when the viewport does not resize", () => {
const { store, geometry } = fixture({ native: true, overlay: true });
const observed: boolean[] = [];
const unsubscribe = store.subscribe(() => observed.push(store.getSnapshot()));
expect(store.getSnapshot()).toBe(false);
geometry(300);
expect(store.getSnapshot()).toBe(true);
geometry(0);
expect(store.getSnapshot()).toBe(false);
expect(observed).toEqual([true, false]);
unsubscribe();
geometry(300);
expect(observed).toEqual([true, false]);
});
// regression: #21763 composer Enter sent instead of inserting a newline on software keyboards
it("prefers overlay geometry over a misleading viewport height", () => {
const { store, resize, geometry } = fixture({ native: true, overlay: true });
const unsubscribe = store.subscribe(() => {});
resize(500);
expect(store.getSnapshot()).toBe(false);
geometry(300);
expect(store.getSnapshot()).toBe(true);
geometry(0);
expect(store.getSnapshot()).toBe(false);
unsubscribe();
});
it.each([false, true])("falls back to viewport changes with native API present: %s", (native) => {
const { store, resize, keyboard } = fixture({ native });
const unsubscribe = store.subscribe(() => {});
resize(500);
expect(store.getSnapshot()).toBe(true);
resize(550);
expect(store.getSnapshot()).toBe(true);
resize(844);
expect(store.getSnapshot()).toBe(false);
expect(keyboard.overlaysContent).toBe(false);
unsubscribe();
});
// regression: #21763 composer Enter sent instead of inserting a newline on software keyboards
it("detects a docked keyboard when subscribing after it has opened", () => {
const { store, resize } = fixture();
resize(500);
const unsubscribe = store.subscribe(() => {});
expect(store.getSnapshot()).toBe(true);
resize(844);
expect(store.getSnapshot()).toBe(false);
unsubscribe();
});
it("ignores small height changes such as the browser toolbar", () => {
const { store, resize } = fixture();
const unsubscribe = store.subscribe(() => {});
resize(750);
expect(store.getSnapshot()).toBe(false);
resize(700);
expect(store.getSnapshot()).toBe(false);
unsubscribe();
});
it("ignores pinch zoom and recognizes keyboard changes at the new scale", () => {
const { store, resize } = fixture();
const unsubscribe = store.subscribe(() => {});
resize(422, 195, 2);
expect(store.getSnapshot()).toBe(false);
resize(300);
expect(store.getSnapshot()).toBe(true);
resize(422);
expect(store.getSnapshot()).toBe(false);
unsubscribe();
});
it("does not mistake rotation for an open keyboard", () => {
const { store, resize, win } = fixture();
const unsubscribe = store.subscribe(() => {});
win.innerHeight = 390;
resize(390, 844);
expect(store.getSnapshot()).toBe(false);
unsubscribe();
});
it("recognizes keyboard closure despite viewport rounding at high zoom", () => {
const { store, resize } = fixture();
resize(211, 98, 4);
const unsubscribe = store.subscribe(() => {});
resize(150);
expect(store.getSnapshot()).toBe(true);
resize(210.6);
expect(store.getSnapshot()).toBe(false);
unsubscribe();
});
it("bypasses both native geometry and viewport detection on desktop", () => {
const { store, geometry, resize } = fixture({ native: true, overlay: true, desktop: true });
const listener = vi.fn();
const unsubscribe = store.subscribe(listener);
geometry(300);
resize(500);
expect(store.getSnapshot()).toBe(false);
expect(listener).not.toHaveBeenCalled();
unsubscribe();
});
});