[iOS] Can't select text after dismissing the keyboard when changing focus
[WebKit-https.git] / LayoutTests / resources / ui-helper.js
1
2 window.UIHelper = class UIHelper {
3     static isIOS()
4     {
5         return navigator.userAgent.includes('iPhone') || navigator.userAgent.includes('iPad');
6     }
7
8     static isWebKit2()
9     {
10         return window.testRunner.isWebKit2;
11     }
12
13     static tapAt(x, y)
14     {
15         console.assert(this.isIOS());
16
17         if (!this.isWebKit2()) {
18             eventSender.addTouchPoint(x, y);
19             eventSender.touchStart();
20             eventSender.releaseTouchPoint(0);
21             eventSender.touchEnd();
22             return Promise.resolve();
23         }
24
25         return new Promise((resolve) => {
26             testRunner.runUIScript(`
27                 uiController.singleTapAtPoint(${x}, ${y}, function() {
28                     uiController.uiScriptComplete('Done');
29                 });`, resolve);
30         });
31     }
32
33     static activateAt(x, y)
34     {
35         if (!this.isWebKit2() || !this.isIOS()) {
36             eventSender.mouseMoveTo(x, y);
37             eventSender.mouseDown();
38             eventSender.mouseUp();
39             return Promise.resolve();
40         }
41
42         return new Promise((resolve) => {
43             testRunner.runUIScript(`
44                 uiController.singleTapAtPoint(${x}, ${y}, function() {
45                     uiController.uiScriptComplete('Done');
46                 });`, resolve);
47         });
48     }
49
50     static activateElement(element)
51     {
52         const x = element.offsetLeft + element.offsetWidth / 2;
53         const y = element.offsetTop + element.offsetHeight / 2;
54         return UIHelper.activateAt(x, y);
55     }
56
57     static keyDown(key)
58     {
59         if (!this.isWebKit2() || !this.isIOS()) {
60             eventSender.keyDown(key);
61             return Promise.resolve();
62         }
63
64         return new Promise((resolve) => {
65             testRunner.runUIScript(`
66                 uiController.keyDownUsingHardwareKeyboard("downArrow", function() {
67                     uiController.uiScriptComplete("Done");
68                 });`, resolve);
69         });
70     }
71
72     static ensurePresentationUpdate()
73     {
74         if (!this.isWebKit2()) {
75             testRunner.display();
76             return Promise.resolve();
77         }
78
79         return new Promise(resolve => {
80             testRunner.runUIScript(`
81                 uiController.doAfterPresentationUpdate(function() {
82                     uiController.uiScriptComplete('Done');
83                 });`, resolve);
84         });
85     }
86
87     static ensureVisibleContentRectUpdate()
88     {
89         if (!this.isWebKit2())
90             return Promise.resolve();
91
92         return new Promise(resolve => {
93             const visibleContentRectUpdateScript = "uiController.doAfterVisibleContentRectUpdate(() => uiController.uiScriptComplete())";
94             testRunner.runUIScript(visibleContentRectUpdateScript, resolve);
95         });
96     }
97
98     static activateAndWaitForInputSessionAt(x, y)
99     {
100         if (!this.isWebKit2() || !this.isIOS())
101             return this.activateAt(x, y);
102
103         return new Promise(resolve => {
104             testRunner.runUIScript(`
105                 (function() {
106                     uiController.didShowKeyboardCallback = function() {
107                         uiController.uiScriptComplete("Done");
108                     };
109                     uiController.singleTapAtPoint(${x}, ${y}, function() { });
110                 })()`, resolve);
111         });
112     }
113
114     static activateFormControl(element)
115     {
116         if (!this.isWebKit2() || !this.isIOS())
117             return this.activateElement(element);
118
119         const x = element.offsetLeft + element.offsetWidth / 2;
120         const y = element.offsetTop + element.offsetHeight / 2;
121
122         return new Promise(resolve => {
123             testRunner.runUIScript(`
124                 (function() {
125                     uiController.didStartFormControlInteractionCallback = function() {
126                         uiController.uiScriptComplete("Done");
127                     };
128                     uiController.singleTapAtPoint(${x}, ${y}, function() { });
129                 })()`, resolve);
130         });
131     }
132
133     static waitForKeyboardToHide()
134     {
135         return new Promise(resolve => {
136             testRunner.runUIScript(`
137                 (function() {
138                     if (uiController.isShowingKeyboard)
139                         uiController.didHideKeyboardCallback = () => uiController.uiScriptComplete();
140                     else
141                         uiController.uiScriptComplete();
142                 })()`, resolve);
143         });
144     }
145
146     static getUICaretRect()
147     {
148         if (!this.isWebKit2() || !this.isIOS())
149             return Promise.resolve();
150
151         return new Promise(resolve => {
152             testRunner.runUIScript(`(function() {
153                 uiController.doAfterNextStablePresentationUpdate(function() {
154                     uiController.uiScriptComplete(JSON.stringify(uiController.textSelectionCaretRect));
155                 });
156             })()`, jsonString => {
157                 resolve(JSON.parse(jsonString));
158             });
159         });
160     }
161
162     static getUISelectionRects()
163     {
164         if (!this.isWebKit2() || !this.isIOS())
165             return Promise.resolve();
166
167         return new Promise(resolve => {
168             testRunner.runUIScript(`(function() {
169                 uiController.doAfterNextStablePresentationUpdate(function() {
170                     uiController.uiScriptComplete(JSON.stringify(uiController.selectionRangeViewRects));
171                 });
172             })()`, jsonString => {
173                 resolve(JSON.parse(jsonString));
174             });
175         });
176     }
177
178     static getSelectionStartGrabberViewRect()
179     {
180         if (!this.isWebKit2() || !this.isIOS())
181             return Promise.resolve();
182
183         return new Promise(resolve => {
184             testRunner.runUIScript(`(function() {
185                 uiController.doAfterNextStablePresentationUpdate(function() {
186                     uiController.uiScriptComplete(JSON.stringify(uiController.selectionStartGrabberViewRect));
187                 });
188             })()`, jsonString => {
189                 resolve(JSON.parse(jsonString));
190             });
191         });
192     }
193
194     static getSelectionEndGrabberViewRect()
195     {
196         if (!this.isWebKit2() || !this.isIOS())
197             return Promise.resolve();
198
199         return new Promise(resolve => {
200             testRunner.runUIScript(`(function() {
201                 uiController.doAfterNextStablePresentationUpdate(function() {
202                     uiController.uiScriptComplete(JSON.stringify(uiController.selectionEndGrabberViewRect));
203                 });
204             })()`, jsonString => {
205                 resolve(JSON.parse(jsonString));
206             });
207         });
208     }
209
210     static replaceTextAtRange(text, location, length) {
211         return new Promise(resolve => {
212             testRunner.runUIScript(`(() => {
213                 uiController.replaceTextAtRange("${text}", ${location}, ${length});
214                 uiController.uiScriptComplete('Done');
215             })()`, resolve);
216         });
217     }
218
219     static wait(promise)
220     {
221         testRunner.waitUntilDone();
222         if (window.finishJSTest)
223             window.jsTestIsAsync = true;
224
225         let finish = () => {
226             if (window.finishJSTest)
227                 finishJSTest();
228             else
229                 testRunner.notifyDone();
230         }
231
232         return promise.then(finish, finish);
233     }
234
235     static withUserGesture(callback)
236     {
237         internals.withUserGesture(callback);
238     }
239
240     static selectFormAccessoryPickerRow(rowIndex)
241     {
242         const selectRowScript = `(() => uiController.selectFormAccessoryPickerRow(${rowIndex}))()`;
243         return new Promise(resolve => testRunner.runUIScript(selectRowScript, resolve));
244     }
245
246     static selectFormPopoverTitle()
247     {
248         return new Promise(resolve => {
249             testRunner.runUIScript(`(() => {
250                 uiController.uiScriptComplete(uiController.selectFormPopoverTitle);
251             })()`, resolve);
252         });
253     }
254
255     static enterText(text)
256     {
257         const escapedText = text.replace(/`/g, "\\`");
258         const enterTextScript = `(() => uiController.enterText(\`${escapedText}\`))()`;
259         return new Promise(resolve => testRunner.runUIScript(enterTextScript, resolve));
260     }
261
262     static setTimePickerValue(hours, minutes)
263     {
264         const setValueScript = `(() => uiController.setTimePickerValue(${hours}, ${minutes}))()`;
265         return new Promise(resolve => testRunner.runUIScript(setValueScript, resolve));
266     }
267
268     static setShareSheetCompletesImmediatelyWithResolution(resolved)
269     {
270         const resolveShareSheet = `(() => uiController.setShareSheetCompletesImmediatelyWithResolution(${resolved}))()`;
271         return new Promise(resolve => testRunner.runUIScript(resolveShareSheet, resolve));
272     }
273
274     static textContentType()
275     {
276         return new Promise(resolve => {
277             testRunner.runUIScript(`(() => {
278                 uiController.uiScriptComplete(uiController.textContentType);
279             })()`, resolve);
280         });
281     }
282
283     static formInputLabel()
284     {
285         return new Promise(resolve => {
286             testRunner.runUIScript(`(() => {
287                 uiController.uiScriptComplete(uiController.formInputLabel);
288             })()`, resolve);
289         });
290     }
291
292     static isShowingDataListSuggestions()
293     {
294         return new Promise(resolve => {
295             testRunner.runUIScript(`(() => {
296                 uiController.uiScriptComplete(uiController.isShowingDataListSuggestions);
297             })()`, resolve);
298         });
299     }
300
301     static zoomScale()
302     {
303         return new Promise(resolve => {
304             testRunner.runUIScript(`(() => {
305                 uiController.uiScriptComplete(uiController.zoomScale);
306             })()`, resolve);
307         });
308     }
309
310     static typeCharacter(characterString)
311     {
312         if (!this.isWebKit2() || !this.isIOS()) {
313             eventSender.keyDown(characterString);
314             return;
315         }
316
317         const escapedString = characterString.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
318         const uiScript = `uiController.typeCharacterUsingHardwareKeyboard(\`${escapedString}\`, () => uiController.uiScriptComplete())`;
319         return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
320     }
321
322     static applyAutocorrection(newText, oldText)
323     {
324         if (!this.isWebKit2())
325             return;
326
327         const [escapedNewText, escapedOldText] = [newText.replace(/`/g, "\\`"), oldText.replace(/`/g, "\\`")];
328         const uiScript = `uiController.applyAutocorrection(\`${escapedNewText}\`, \`${escapedOldText}\`, () => uiController.uiScriptComplete())`;
329         return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
330     }
331
332     static inputViewBounds()
333     {
334         if (!this.isWebKit2() || !this.isIOS())
335             return Promise.resolve();
336
337         return new Promise(resolve => {
338             testRunner.runUIScript(`(() => {
339                 uiController.uiScriptComplete(JSON.stringify(uiController.inputViewBounds));
340             })()`, jsonString => {
341                 resolve(JSON.parse(jsonString));
342             });
343         });
344     }
345
346     static setViewScale(scale)
347     {
348         if (!this.isWebKit2())
349             return Promise.resolve();
350
351         return new Promise(resolve => testRunner.runUIScript(`uiController.setViewScale(${scale})`, resolve));
352     }
353 }