WebDriver: handle click events on option elements
[WebKit-https.git] / Source / WebDriver / Session.cpp
1 /*
2  * Copyright (C) 2017 Igalia S.L.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Session.h"
28
29 #include "CommandResult.h"
30 #include "SessionHost.h"
31 #include "WebDriverAtoms.h"
32 #include <inspector/InspectorValues.h>
33 #include <wtf/CryptographicallyRandomNumber.h>
34 #include <wtf/HexNumber.h>
35 #include <wtf/UUID.h>
36
37 using namespace Inspector;
38
39 namespace WebDriver {
40
41 // The web element identifier is a constant defined by the spec in Section 11 Elements.
42 // https://www.w3.org/TR/webdriver/#elements
43 static const String webElementIdentifier = ASCIILiteral("element-6066-11e4-a52e-4f735466cecf");
44
45 Session::Session(std::unique_ptr<SessionHost>&& host)
46     : m_host(WTFMove(host))
47     , m_id(createCanonicalUUIDString())
48 {
49 }
50
51 Session::~Session()
52 {
53 }
54
55 const Capabilities& Session::capabilities() const
56 {
57     return m_host->capabilities();
58 }
59
60 void Session::close(Function<void (CommandResult&&)>&& completionHandler)
61 {
62     if (!m_toplevelBrowsingContext) {
63         completionHandler(CommandResult::success());
64         return;
65     }
66
67     RefPtr<InspectorObject> parameters = InspectorObject::create();
68     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
69     m_host->sendCommandToBackend(ASCIILiteral("closeBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
70         if (response.isError) {
71             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
72             return;
73         }
74         switchToTopLevelBrowsingContext(std::nullopt);
75         completionHandler(CommandResult::success());
76     });
77 }
78
79 void Session::setTimeouts(const Timeouts& timeouts, Function<void (CommandResult&&)>&& completionHandler)
80 {
81     if (timeouts.script)
82         m_timeouts.script = timeouts.script;
83     if (timeouts.pageLoad)
84         m_timeouts.pageLoad = timeouts.pageLoad;
85     if (timeouts.implicit)
86         m_timeouts.implicit = timeouts.implicit;
87     completionHandler(CommandResult::success());
88 }
89
90 void Session::switchToTopLevelBrowsingContext(std::optional<String> toplevelBrowsingContext)
91 {
92     m_toplevelBrowsingContext = toplevelBrowsingContext;
93     m_currentBrowsingContext = std::nullopt;
94 }
95
96 void Session::switchToBrowsingContext(std::optional<String> browsingContext)
97 {
98     // Automation sends empty strings for main frame.
99     if (!browsingContext || browsingContext.value().isEmpty())
100         m_currentBrowsingContext = std::nullopt;
101     else
102         m_currentBrowsingContext = browsingContext;
103 }
104
105 std::optional<String> Session::pageLoadStrategyString() const
106 {
107     if (!capabilities().pageLoadStrategy)
108         return std::nullopt;
109
110     switch (capabilities().pageLoadStrategy.value()) {
111     case PageLoadStrategy::None:
112         return String("None");
113     case PageLoadStrategy::Normal:
114         return String("Normal");
115     case PageLoadStrategy::Eager:
116         return String("Eager");
117     }
118
119     return std::nullopt;
120 }
121
122 void Session::createTopLevelBrowsingContext(Function<void (CommandResult&&)>&& completionHandler)
123 {
124     ASSERT(!m_toplevelBrowsingContext.value());
125     m_host->startAutomationSession(m_id, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<String> errorMessage) mutable {
126         if (errorMessage) {
127             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError, errorMessage.value()));
128             return;
129         }
130         m_host->sendCommandToBackend(ASCIILiteral("createBrowsingContext"), nullptr, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
131             if (response.isError || !response.responseObject) {
132                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
133                 return;
134             }
135             String handle;
136             if (!response.responseObject->getString(ASCIILiteral("handle"), handle)) {
137                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
138                 return;
139             }
140             switchToTopLevelBrowsingContext(handle);
141             completionHandler(CommandResult::success());
142         });
143     });
144 }
145
146 void Session::handleUserPrompts(Function<void (CommandResult&&)>&& completionHandler)
147 {
148     RefPtr<InspectorObject> parameters = InspectorObject::create();
149     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
150     m_host->sendCommandToBackend(ASCIILiteral("isShowingJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
151         if (response.isError || !response.responseObject) {
152             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
153             return;
154         }
155         bool isShowingJavaScriptDialog;
156         if (!response.responseObject->getBoolean("result", isShowingJavaScriptDialog)) {
157             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
158             return;
159         }
160
161         if (!isShowingJavaScriptDialog) {
162             completionHandler(CommandResult::success());
163             return;
164         }
165
166         if (!capabilities().unhandledPromptBehavior) {
167             reportUnexpectedAlertOpen([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
168                 dismissAlert([this, errorResult = WTFMove(result), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
169                     if (result.isError()) {
170                         completionHandler(WTFMove(result));
171                         return;
172                     }
173                     completionHandler(WTFMove(errorResult));
174                 });
175             });
176             return;
177         }
178
179         switch (capabilities().unhandledPromptBehavior.value()) {
180         case UnhandledPromptBehavior::Dismiss:
181             dismissAlert(WTFMove(completionHandler));
182             break;
183         case UnhandledPromptBehavior::Accept:
184             acceptAlert(WTFMove(completionHandler));
185             break;
186         case UnhandledPromptBehavior::Ignore:
187             reportUnexpectedAlertOpen(WTFMove(completionHandler));
188             break;
189         }
190     });
191 }
192
193 void Session::reportUnexpectedAlertOpen(Function<void (CommandResult&&)>&& completionHandler)
194 {
195     getAlertText([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) {
196         std::optional<String> alertText;
197         if (!result.isError()) {
198             String valueString;
199             if (result.result()->asString(valueString))
200                 alertText = valueString;
201         }
202         auto errorResult = CommandResult::fail(CommandResult::ErrorCode::UnexpectedAlertOpen);
203         if (alertText) {
204             RefPtr<InspectorObject> additonalData = InspectorObject::create();
205             additonalData->setString(ASCIILiteral("text"), alertText.value());
206             errorResult.setAdditionalErrorData(WTFMove(additonalData));
207         }
208         completionHandler(WTFMove(errorResult));
209     });
210 }
211
212 void Session::go(const String& url, Function<void (CommandResult&&)>&& completionHandler)
213 {
214     if (!m_toplevelBrowsingContext) {
215         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
216         return;
217     }
218
219     handleUserPrompts([this, url, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
220         if (result.isError()) {
221             completionHandler(WTFMove(result));
222             return;
223         }
224
225         RefPtr<InspectorObject> parameters = InspectorObject::create();
226         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
227         parameters->setString(ASCIILiteral("url"), url);
228         if (m_timeouts.pageLoad)
229             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
230         if (auto pageLoadStrategy = pageLoadStrategyString())
231             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
232         m_host->sendCommandToBackend(ASCIILiteral("navigateBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
233             if (response.isError) {
234                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
235                 return;
236             }
237             switchToBrowsingContext(std::nullopt);
238             completionHandler(CommandResult::success());
239         });
240     });
241 }
242
243 void Session::getCurrentURL(Function<void (CommandResult&&)>&& completionHandler)
244 {
245     if (!m_toplevelBrowsingContext) {
246         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
247         return;
248     }
249
250     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
251         if (result.isError()) {
252             completionHandler(WTFMove(result));
253             return;
254         }
255
256         RefPtr<InspectorObject> parameters = InspectorObject::create();
257         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
258         m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
259             if (response.isError || !response.responseObject) {
260                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
261                 return;
262             }
263             RefPtr<InspectorObject> browsingContext;
264             if (!response.responseObject->getObject("context", browsingContext)) {
265                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
266                 return;
267             }
268             String url;
269             if (!browsingContext->getString("url", url)) {
270                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
271                 return;
272             }
273             completionHandler(CommandResult::success(InspectorValue::create(url)));
274         });
275     });
276 }
277
278 void Session::back(Function<void (CommandResult&&)>&& completionHandler)
279 {
280     if (!m_toplevelBrowsingContext) {
281         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
282         return;
283     }
284
285     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
286         if (result.isError()) {
287             completionHandler(WTFMove(result));
288             return;
289         }
290         RefPtr<InspectorObject> parameters = InspectorObject::create();
291         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
292         if (m_timeouts.pageLoad)
293             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
294         if (auto pageLoadStrategy = pageLoadStrategyString())
295             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
296         m_host->sendCommandToBackend(ASCIILiteral("goBackInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
297             if (response.isError) {
298                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
299                 return;
300             }
301             switchToBrowsingContext(std::nullopt);
302             completionHandler(CommandResult::success());
303         });
304     });
305 }
306
307 void Session::forward(Function<void (CommandResult&&)>&& completionHandler)
308 {
309     if (!m_toplevelBrowsingContext) {
310         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
311         return;
312     }
313
314     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
315         if (result.isError()) {
316             completionHandler(WTFMove(result));
317             return;
318         }
319         RefPtr<InspectorObject> parameters = InspectorObject::create();
320         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
321         if (m_timeouts.pageLoad)
322             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
323         if (auto pageLoadStrategy = pageLoadStrategyString())
324             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
325         m_host->sendCommandToBackend(ASCIILiteral("goForwardInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
326             if (response.isError) {
327                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
328                 return;
329             }
330             switchToBrowsingContext(std::nullopt);
331             completionHandler(CommandResult::success());
332         });
333     });
334 }
335
336 void Session::refresh(Function<void (CommandResult&&)>&& completionHandler)
337 {
338     if (!m_toplevelBrowsingContext) {
339         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
340         return;
341     }
342
343     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
344         if (result.isError()) {
345             completionHandler(WTFMove(result));
346             return;
347         }
348         RefPtr<InspectorObject> parameters = InspectorObject::create();
349         parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
350         if (m_timeouts.pageLoad)
351             parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
352         if (auto pageLoadStrategy = pageLoadStrategyString())
353             parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
354         m_host->sendCommandToBackend(ASCIILiteral("reloadBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
355             if (response.isError) {
356                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
357                 return;
358             }
359             switchToBrowsingContext(std::nullopt);
360             completionHandler(CommandResult::success());
361         });
362     });
363 }
364
365 void Session::getTitle(Function<void (CommandResult&&)>&& completionHandler)
366 {
367     if (!m_toplevelBrowsingContext) {
368         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
369         return;
370     }
371
372     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
373         if (result.isError()) {
374             completionHandler(WTFMove(result));
375             return;
376         }
377         RefPtr<InspectorObject> parameters = InspectorObject::create();
378         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
379         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function() { return document.title; }"));
380         parameters->setArray(ASCIILiteral("arguments"), InspectorArray::create());
381         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
382             if (response.isError || !response.responseObject) {
383                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
384                 return;
385             }
386             String valueString;
387             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
388                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
389                 return;
390             }
391             RefPtr<InspectorValue> resultValue;
392             if (!InspectorValue::parseJSON(valueString, resultValue)) {
393                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
394                 return;
395             }
396             completionHandler(CommandResult::success(WTFMove(resultValue)));
397         });
398     });
399 }
400
401 void Session::getWindowHandle(Function<void (CommandResult&&)>&& completionHandler)
402 {
403     if (!m_toplevelBrowsingContext) {
404         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
405         return;
406     }
407
408     RefPtr<InspectorObject> parameters = InspectorObject::create();
409     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
410     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
411         if (response.isError || !response.responseObject) {
412             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
413             return;
414         }
415         RefPtr<InspectorObject> browsingContext;
416         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
417             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
418             return;
419         }
420         String handle;
421         if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
422             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
423             return;
424         }
425         completionHandler(CommandResult::success(InspectorValue::create(handle)));
426     });
427 }
428
429 void Session::closeWindow(Function<void (CommandResult&&)>&& completionHandler)
430 {
431     if (!m_toplevelBrowsingContext) {
432         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
433         return;
434     }
435
436     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
437         if (result.isError()) {
438             completionHandler(WTFMove(result));
439             return;
440         }
441         close(WTFMove(completionHandler));
442     });
443 }
444
445 void Session::switchToWindow(const String& windowHandle, Function<void (CommandResult&&)>&& completionHandler)
446 {
447     RefPtr<InspectorObject> parameters = InspectorObject::create();
448     parameters->setString(ASCIILiteral("browsingContextHandle"), windowHandle);
449     m_host->sendCommandToBackend(ASCIILiteral("switchToBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), windowHandle, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
450         if (response.isError) {
451             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
452             return;
453         }
454         switchToTopLevelBrowsingContext(windowHandle);
455         completionHandler(CommandResult::success());
456     });
457 }
458
459 void Session::getWindowHandles(Function<void (CommandResult&&)>&& completionHandler)
460 {
461     if (!m_toplevelBrowsingContext) {
462         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
463         return;
464     }
465
466     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContexts"), InspectorObject::create(), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
467         if (response.isError || !response.responseObject) {
468             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
469             return;
470         }
471         RefPtr<InspectorArray> browsingContextArray;
472         if (!response.responseObject->getArray(ASCIILiteral("contexts"), browsingContextArray)) {
473             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
474             return;
475         }
476         RefPtr<InspectorArray> windowHandles = InspectorArray::create();
477         for (unsigned i = 0; i < browsingContextArray->length(); ++i) {
478             RefPtr<InspectorValue> browsingContextValue = browsingContextArray->get(i);
479             RefPtr<InspectorObject> browsingContext;
480             if (!browsingContextValue->asObject(browsingContext)) {
481                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
482                 return;
483             }
484
485             String handle;
486             if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
487                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
488                 return;
489             }
490
491             windowHandles->pushString(handle);
492         }
493         completionHandler(CommandResult::success(WTFMove(windowHandles)));
494     });
495 }
496
497 void Session::switchToFrame(RefPtr<InspectorValue>&& frameID, Function<void (CommandResult&&)>&& completionHandler)
498 {
499     if (!m_toplevelBrowsingContext) {
500         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
501         return;
502     }
503
504     if (frameID->isNull()) {
505         switchToBrowsingContext(std::nullopt);
506         completionHandler(CommandResult::success());
507         return;
508     }
509
510     handleUserPrompts([this, frameID = WTFMove(frameID), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
511         if (result.isError()) {
512             completionHandler(WTFMove(result));
513             return;
514         }
515         RefPtr<InspectorObject> parameters = InspectorObject::create();
516         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
517         if (m_currentBrowsingContext)
518             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
519
520         int frameIndex;
521         if (frameID->asInteger(frameIndex)) {
522             if (frameIndex < 0 || frameIndex > USHRT_MAX) {
523                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
524                 return;
525             }
526             parameters->setInteger(ASCIILiteral("ordinal"), frameIndex);
527         } else {
528             String frameElementID = extractElementID(*frameID);
529             if (!frameElementID.isEmpty())
530                 parameters->setString(ASCIILiteral("nodeHandle"), frameElementID);
531             else {
532                 String frameName;
533                 if (!frameID->asString(frameName)) {
534                     completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
535                     return;
536                 }
537                 parameters->setString(ASCIILiteral("name"), frameName);
538             }
539         }
540
541         m_host->sendCommandToBackend(ASCIILiteral("resolveChildFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
542             if (response.isError || !response.responseObject) {
543                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
544                 return;
545             }
546             String frameHandle;
547             if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
548                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
549                 return;
550             }
551             switchToBrowsingContext(frameHandle);
552             completionHandler(CommandResult::success());
553         });
554     });
555 }
556
557 void Session::switchToParentFrame(Function<void (CommandResult&&)>&& completionHandler)
558 {
559     if (!m_toplevelBrowsingContext) {
560         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
561         return;
562     }
563
564     if (!m_currentBrowsingContext) {
565         completionHandler(CommandResult::success());
566         return;
567     }
568
569     handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
570         if (result.isError()) {
571             completionHandler(WTFMove(result));
572             return;
573         }
574         RefPtr<InspectorObject> parameters = InspectorObject::create();
575         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
576         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
577         m_host->sendCommandToBackend(ASCIILiteral("resolveParentFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
578             if (response.isError || !response.responseObject) {
579                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
580                 return;
581             }
582             String frameHandle;
583             if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
584                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
585                 return;
586             }
587             switchToBrowsingContext(frameHandle);
588             completionHandler(CommandResult::success());
589         });
590     });
591 }
592
593 void Session::getWindowPosition(Function<void (CommandResult&&)>&& completionHandler)
594 {
595     if (!m_toplevelBrowsingContext) {
596         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
597         return;
598     }
599
600     RefPtr<InspectorObject> parameters = InspectorObject::create();
601     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
602     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
603         if (response.isError || !response.responseObject) {
604             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
605             return;
606         }
607         RefPtr<InspectorObject> browsingContext;
608         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
609             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
610             return;
611         }
612         RefPtr<InspectorObject> windowOrigin;
613         if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)) {
614             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
615             return;
616         }
617         completionHandler(CommandResult::success(WTFMove(windowOrigin)));
618     });
619 }
620
621 void Session::setWindowPosition(int windowX, int windowY, Function<void (CommandResult&&)>&& completionHandler)
622 {
623     if (!m_toplevelBrowsingContext) {
624         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
625         return;
626     }
627
628     RefPtr<InspectorObject> parameters = InspectorObject::create();
629     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
630     RefPtr<InspectorObject> windowOrigin = InspectorObject::create();
631     windowOrigin->setInteger("x", windowX);
632     windowOrigin->setInteger("y", windowY);
633     parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin));
634     m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
635         if (response.isError) {
636             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
637             return;
638         }
639         completionHandler(CommandResult::success());
640     });
641 }
642
643 void Session::getWindowSize(Function<void (CommandResult&&)>&& completionHandler)
644 {
645     if (!m_toplevelBrowsingContext) {
646         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
647         return;
648     }
649
650     RefPtr<InspectorObject> parameters = InspectorObject::create();
651     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
652     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
653         if (response.isError || !response.responseObject) {
654             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
655             return;
656         }
657         RefPtr<InspectorObject> browsingContext;
658         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
659             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
660             return;
661         }
662         RefPtr<InspectorObject> windowSize;
663         if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)) {
664             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
665             return;
666         }
667         completionHandler(CommandResult::success(WTFMove(windowSize)));
668     });
669 }
670
671 void Session::setWindowSize(int windowWidth, int windowHeight, Function<void (CommandResult&&)>&& completionHandler)
672 {
673     if (!m_toplevelBrowsingContext) {
674         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
675         return;
676     }
677
678     RefPtr<InspectorObject> parameters = InspectorObject::create();
679     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
680     RefPtr<InspectorObject> windowSize = InspectorObject::create();
681     windowSize->setInteger("width", windowWidth);
682     windowSize->setInteger("height", windowHeight);
683     parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
684     m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
685         if (response.isError) {
686             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
687             return;
688         }
689         completionHandler(CommandResult::success());
690     });
691 }
692
693 RefPtr<InspectorObject> Session::createElement(RefPtr<InspectorValue>&& value)
694 {
695     RefPtr<InspectorObject> valueObject;
696     if (!value->asObject(valueObject))
697         return nullptr;
698
699     String elementID;
700     if (!valueObject->getString("session-node-" + m_id, elementID))
701         return nullptr;
702
703     RefPtr<InspectorObject> elementObject = InspectorObject::create();
704     elementObject->setString(webElementIdentifier, elementID);
705     return elementObject;
706 }
707
708 RefPtr<InspectorObject> Session::createElement(const String& elementID)
709 {
710     RefPtr<InspectorObject> elementObject = InspectorObject::create();
711     elementObject->setString("session-node-" + m_id, elementID);
712     return elementObject;
713 }
714
715 RefPtr<InspectorObject> Session::extractElement(InspectorValue& value)
716 {
717     String elementID = extractElementID(value);
718     return !elementID.isEmpty() ? createElement(elementID) : nullptr;
719 }
720
721 String Session::extractElementID(InspectorValue& value)
722 {
723     RefPtr<InspectorObject> valueObject;
724     if (!value.asObject(valueObject))
725         return emptyString();
726
727     String elementID;
728     if (!valueObject->getString(webElementIdentifier, elementID))
729         return emptyString();
730
731     return elementID;
732 }
733
734 void Session::computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption> options, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<InspectorObject>&&)>&& completionHandler)
735 {
736     ASSERT(m_toplevelBrowsingContext.value());
737
738     RefPtr<InspectorObject> parameters = InspectorObject::create();
739     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
740     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
741     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
742     parameters->setBoolean(ASCIILiteral("scrollIntoViewIfNeeded"), options.contains(ElementLayoutOption::ScrollIntoViewIfNeeded));
743     parameters->setBoolean(ASCIILiteral("useViewportCoordinates"), options.contains(ElementLayoutOption::UseViewportCoordinates));
744     m_host->sendCommandToBackend(ASCIILiteral("computeElementLayout"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
745         if (response.isError || !response.responseObject) {
746             completionHandler(std::nullopt, std::nullopt, false, WTFMove(response.responseObject));
747             return;
748         }
749         RefPtr<InspectorObject> rectObject;
750         if (!response.responseObject->getObject(ASCIILiteral("rect"), rectObject)) {
751             completionHandler(std::nullopt, std::nullopt, false, nullptr);
752             return;
753         }
754         std::optional<int> elementX;
755         std::optional<int> elementY;
756         RefPtr<InspectorObject> elementPosition;
757         if (rectObject->getObject(ASCIILiteral("origin"), elementPosition)) {
758             int x, y;
759             if (elementPosition->getInteger(ASCIILiteral("x"), x) && elementPosition->getInteger(ASCIILiteral("y"), y)) {
760                 elementX = x;
761                 elementY = y;
762             }
763         }
764         if (!elementX || !elementY) {
765             completionHandler(std::nullopt, std::nullopt, false, nullptr);
766             return;
767         }
768         std::optional<int> elementWidth;
769         std::optional<int> elementHeight;
770         RefPtr<InspectorObject> elementSize;
771         if (rectObject->getObject(ASCIILiteral("size"), elementSize)) {
772             int width, height;
773             if (elementSize->getInteger(ASCIILiteral("width"), width) && elementSize->getInteger(ASCIILiteral("height"), height)) {
774                 elementWidth = width;
775                 elementHeight = height;
776             }
777         }
778         if (!elementWidth || !elementHeight) {
779             completionHandler(std::nullopt, std::nullopt, false, nullptr);
780             return;
781         }
782         Rect rect = { { elementX.value(), elementY.value() }, { elementWidth.value(), elementHeight.value() } };
783
784         bool isObscured;
785         if (!response.responseObject->getBoolean(ASCIILiteral("isObscured"), isObscured)) {
786             completionHandler(std::nullopt, std::nullopt, false, nullptr);
787             return;
788         }
789         RefPtr<InspectorObject> inViewCenterPointObject;
790         if (!response.responseObject->getObject(ASCIILiteral("inViewCenterPoint"), inViewCenterPointObject)) {
791             completionHandler(rect, std::nullopt, isObscured, nullptr);
792             return;
793         }
794         int inViewCenterPointX, inViewCenterPointY;
795         if (!inViewCenterPointObject->getInteger(ASCIILiteral("x"), inViewCenterPointX)
796             || !inViewCenterPointObject->getInteger(ASCIILiteral("y"), inViewCenterPointY)) {
797             completionHandler(std::nullopt, std::nullopt, isObscured, nullptr);
798             return;
799         }
800         Point inViewCenterPoint = { inViewCenterPointX, inViewCenterPointY };
801         completionHandler(rect, inViewCenterPoint, isObscured, nullptr);
802     });
803 }
804
805 void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, Function<void (CommandResult&&)>&& completionHandler)
806 {
807     if (!m_toplevelBrowsingContext) {
808         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
809         return;
810     }
811
812     auto implicitWait = m_timeouts.implicit.value_or(0_s);
813     RefPtr<InspectorArray> arguments = InspectorArray::create();
814     arguments->pushString(InspectorValue::create(strategy)->toJSONString());
815     if (rootElementID.isEmpty())
816         arguments->pushString(InspectorValue::null()->toJSONString());
817     else
818         arguments->pushString(createElement(rootElementID)->toJSONString());
819     arguments->pushString(InspectorValue::create(selector)->toJSONString());
820     arguments->pushString(InspectorValue::create(mode == FindElementsMode::Single)->toJSONString());
821     arguments->pushString(InspectorValue::create(implicitWait.milliseconds())->toJSONString());
822
823     RefPtr<InspectorObject> parameters = InspectorObject::create();
824     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
825     if (m_currentBrowsingContext)
826         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
827     parameters->setString(ASCIILiteral("function"), FindNodesJavaScript);
828     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
829     parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
830     // If there's an implicit wait, use one second more as callback timeout.
831     if (implicitWait)
832         parameters->setInteger(ASCIILiteral("callbackTimeout"), Seconds(implicitWait + 1_s).millisecondsAs<int>());
833
834     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), mode, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
835         if (response.isError || !response.responseObject) {
836             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
837             return;
838         }
839         String valueString;
840         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
841             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
842             return;
843         }
844         RefPtr<InspectorValue> resultValue;
845         if (!InspectorValue::parseJSON(valueString, resultValue)) {
846             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
847             return;
848         }
849
850         switch (mode) {
851         case FindElementsMode::Single: {
852             RefPtr<InspectorObject> elementObject = createElement(WTFMove(resultValue));
853             if (!elementObject) {
854                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
855                 return;
856             }
857             completionHandler(CommandResult::success(WTFMove(elementObject)));
858             break;
859         }
860         case FindElementsMode::Multiple: {
861             RefPtr<InspectorArray> elementsArray;
862             if (!resultValue->asArray(elementsArray)) {
863                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
864                 return;
865             }
866             RefPtr<InspectorArray> elementObjectsArray = InspectorArray::create();
867             unsigned elementsArrayLength = elementsArray->length();
868             for (unsigned i = 0; i < elementsArrayLength; ++i) {
869                 if (auto elementObject = createElement(elementsArray->get(i)))
870                     elementObjectsArray->pushObject(WTFMove(elementObject));
871             }
872             completionHandler(CommandResult::success(WTFMove(elementObjectsArray)));
873             break;
874         }
875         }
876     });
877 }
878
879 void Session::isElementSelected(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
880 {
881     if (!m_toplevelBrowsingContext) {
882         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
883         return;
884     }
885
886     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
887         if (result.isError()) {
888             completionHandler(WTFMove(result));
889             return;
890         }
891         RefPtr<InspectorArray> arguments = InspectorArray::create();
892         arguments->pushString(createElement(elementID)->toJSONString());
893         arguments->pushString(InspectorValue::create("selected")->toJSONString());
894
895         RefPtr<InspectorObject> parameters = InspectorObject::create();
896         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
897         if (m_currentBrowsingContext)
898             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
899         parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
900         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
901         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
902             if (response.isError || !response.responseObject) {
903                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
904                 return;
905             }
906             String valueString;
907             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
908                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
909                 return;
910             }
911             RefPtr<InspectorValue> resultValue;
912             if (!InspectorValue::parseJSON(valueString, resultValue)) {
913                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
914                 return;
915             }
916             if (resultValue->isNull()) {
917                 completionHandler(CommandResult::success(InspectorValue::create(false)));
918                 return;
919             }
920             String booleanResult;
921             if (!resultValue->asString(booleanResult) || booleanResult != "true") {
922                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
923                 return;
924             }
925             completionHandler(CommandResult::success(InspectorValue::create(true)));
926         });
927     });
928 }
929
930 void Session::getElementText(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
931 {
932     if (!m_toplevelBrowsingContext) {
933         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
934         return;
935     }
936
937     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
938         if (result.isError()) {
939             completionHandler(WTFMove(result));
940             return;
941         }
942         RefPtr<InspectorArray> arguments = InspectorArray::create();
943         arguments->pushString(createElement(elementID)->toJSONString());
944
945         RefPtr<InspectorObject> parameters = InspectorObject::create();
946         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
947         if (m_currentBrowsingContext)
948             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
949         // FIXME: Add an atom to properly implement this instead of just using innerText.
950         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, '') }"));
951         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
952         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
953             if (response.isError || !response.responseObject) {
954                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
955                 return;
956             }
957             String valueString;
958             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
959                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
960                 return;
961             }
962             RefPtr<InspectorValue> resultValue;
963             if (!InspectorValue::parseJSON(valueString, resultValue)) {
964                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
965                 return;
966             }
967             completionHandler(CommandResult::success(WTFMove(resultValue)));
968         });
969     });
970 }
971
972 void Session::getElementTagName(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
973 {
974     if (!m_toplevelBrowsingContext) {
975         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
976         return;
977     }
978
979     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
980         if (result.isError()) {
981             completionHandler(WTFMove(result));
982             return;
983         }
984         RefPtr<InspectorArray> arguments = InspectorArray::create();
985         arguments->pushString(createElement(elementID)->toJSONString());
986
987         RefPtr<InspectorObject> parameters = InspectorObject::create();
988         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
989         if (m_currentBrowsingContext)
990             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
991         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.tagName.toLowerCase() }"));
992         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
993         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
994             if (response.isError || !response.responseObject) {
995                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
996                 return;
997             }
998             String valueString;
999             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1000                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1001                 return;
1002             }
1003             RefPtr<InspectorValue> resultValue;
1004             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1005                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1006                 return;
1007             }
1008             completionHandler(CommandResult::success(WTFMove(resultValue)));
1009         });
1010     });
1011 }
1012
1013 void Session::getElementRect(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1014 {
1015     if (!m_toplevelBrowsingContext) {
1016         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1017         return;
1018     }
1019
1020     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1021         if (result.isError()) {
1022             completionHandler(WTFMove(result));
1023             return;
1024         }
1025         computeElementLayout(elementID, { }, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&&, bool, RefPtr<InspectorObject>&& error) {
1026             if (!rect || error) {
1027                 completionHandler(CommandResult::fail(WTFMove(error)));
1028                 return;
1029             }
1030             RefPtr<InspectorObject> rectObject = InspectorObject::create();
1031             rectObject->setInteger(ASCIILiteral("x"), rect.value().origin.x);
1032             rectObject->setInteger(ASCIILiteral("y"), rect.value().origin.y);
1033             rectObject->setInteger(ASCIILiteral("width"), rect.value().size.width);
1034             rectObject->setInteger(ASCIILiteral("height"), rect.value().size.height);
1035             completionHandler(CommandResult::success(WTFMove(rectObject)));
1036         });
1037     });
1038 }
1039
1040 void Session::isElementEnabled(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1041 {
1042     if (!m_toplevelBrowsingContext) {
1043         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1044         return;
1045     }
1046
1047     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1048         if (result.isError()) {
1049             completionHandler(WTFMove(result));
1050             return;
1051         }
1052         RefPtr<InspectorArray> arguments = InspectorArray::create();
1053         arguments->pushString(createElement(elementID)->toJSONString());
1054
1055         RefPtr<InspectorObject> parameters = InspectorObject::create();
1056         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1057         if (m_currentBrowsingContext)
1058             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1059         parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.disabled === undefined ? true : !element.disabled }"));
1060         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1061         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1062             if (response.isError || !response.responseObject) {
1063                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1064                 return;
1065             }
1066             String valueString;
1067             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1068                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1069                 return;
1070             }
1071             RefPtr<InspectorValue> resultValue;
1072             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1073                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1074                 return;
1075             }
1076             completionHandler(CommandResult::success(WTFMove(resultValue)));
1077         });
1078     });
1079 }
1080
1081 void Session::isElementDisplayed(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1082 {
1083     if (!m_toplevelBrowsingContext) {
1084         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1085         return;
1086     }
1087
1088     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1089         if (result.isError()) {
1090             completionHandler(WTFMove(result));
1091             return;
1092         }
1093         RefPtr<InspectorArray> arguments = InspectorArray::create();
1094         arguments->pushString(createElement(elementID)->toJSONString());
1095
1096         RefPtr<InspectorObject> parameters = InspectorObject::create();
1097         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1098         if (m_currentBrowsingContext)
1099             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1100         parameters->setString(ASCIILiteral("function"), ElementDisplayedJavaScript);
1101         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1102         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1103             if (response.isError || !response.responseObject) {
1104                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1105                 return;
1106             }
1107             String valueString;
1108             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1109                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1110                 return;
1111             }
1112             RefPtr<InspectorValue> resultValue;
1113             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1114                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1115                 return;
1116             }
1117             completionHandler(CommandResult::success(WTFMove(resultValue)));
1118         });
1119     });
1120 }
1121
1122 void Session::getElementAttribute(const String& elementID, const String& attribute, Function<void (CommandResult&&)>&& completionHandler)
1123 {
1124     if (!m_toplevelBrowsingContext) {
1125         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1126         return;
1127     }
1128
1129     handleUserPrompts([this, elementID, attribute, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1130         if (result.isError()) {
1131             completionHandler(WTFMove(result));
1132             return;
1133         }
1134         RefPtr<InspectorArray> arguments = InspectorArray::create();
1135         arguments->pushString(createElement(elementID)->toJSONString());
1136         arguments->pushString(InspectorValue::create(attribute)->toJSONString());
1137
1138         RefPtr<InspectorObject> parameters = InspectorObject::create();
1139         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1140         if (m_currentBrowsingContext)
1141             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1142         parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
1143         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1144         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1145             if (response.isError || !response.responseObject) {
1146                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1147                 return;
1148             }
1149             String valueString;
1150             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1151                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1152                 return;
1153             }
1154             RefPtr<InspectorValue> resultValue;
1155             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1156                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1157                 return;
1158             }
1159             completionHandler(CommandResult::success(WTFMove(resultValue)));
1160         });
1161     });
1162 }
1163
1164 void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& completionHandler)
1165 {
1166     if (!m_toplevelBrowsingContext) {
1167         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1168         return;
1169     }
1170
1171     RefPtr<InspectorObject> parameters = InspectorObject::create();
1172     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1173     if (m_currentBrowsingContext)
1174         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1175     if (m_timeouts.pageLoad)
1176         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
1177     if (auto pageLoadStrategy = pageLoadStrategyString())
1178         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
1179     m_host->sendCommandToBackend(ASCIILiteral("waitForNavigationToComplete"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1180         if (response.isError) {
1181             auto result = CommandResult::fail(WTFMove(response.responseObject));
1182             if (result.errorCode() == CommandResult::ErrorCode::NoSuchFrame) {
1183                 // Navigation destroyed the current frame, switch to top level browsing context and ignore the error.
1184                 switchToBrowsingContext(std::nullopt);
1185             } else {
1186                 completionHandler(WTFMove(result));
1187                 return;
1188             }
1189         }
1190         completionHandler(CommandResult::success());
1191     });
1192 }
1193
1194 void Session::selectOptionElement(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1195 {
1196     RefPtr<InspectorObject> parameters = InspectorObject::create();
1197     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1198     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1199     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
1200     m_host->sendCommandToBackend(ASCIILiteral("selectOptionElement"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1201         if (response.isError) {
1202             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1203             return;
1204         }
1205         completionHandler(CommandResult::success());
1206     });
1207 }
1208
1209 void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1210 {
1211     if (!m_toplevelBrowsingContext) {
1212         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1213         return;
1214     }
1215
1216     OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
1217     options |= ElementLayoutOption::UseViewportCoordinates;
1218     computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), elementID, completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
1219         if (!rect || error) {
1220             completionHandler(CommandResult::fail(WTFMove(error)));
1221             return;
1222         }
1223         if (isObscured) {
1224             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementClickIntercepted));
1225             return;
1226         }
1227         if (!inViewCenter) {
1228             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementNotInteractable));
1229             return;
1230         }
1231
1232         getElementTagName(elementID, [this, elementID, inViewCenter = WTFMove(inViewCenter), isObscured, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1233             bool isOptionElement = false;
1234             if (!result.isError()) {
1235                 String tagName;
1236                 if (result.result()->asString(tagName))
1237                     isOptionElement = tagName == "option";
1238             }
1239
1240             Function<void (CommandResult&&)> continueAfterClickFunction = [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1241                 if (result.isError()) {
1242                     completionHandler(WTFMove(result));
1243                     return;
1244                 }
1245
1246                 waitForNavigationToComplete(WTFMove(completionHandler));
1247             };
1248             if (isOptionElement)
1249                 selectOptionElement(elementID, WTFMove(continueAfterClickFunction));
1250             else
1251                 performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(continueAfterClickFunction));
1252         });
1253     });
1254 }
1255
1256 void Session::elementClear(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1257 {
1258     if (!m_toplevelBrowsingContext) {
1259         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1260         return;
1261     }
1262
1263     RefPtr<InspectorArray> arguments = InspectorArray::create();
1264     arguments->pushString(createElement(elementID)->toJSONString());
1265
1266     RefPtr<InspectorObject> parameters = InspectorObject::create();
1267     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1268     if (m_currentBrowsingContext)
1269         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1270     parameters->setString(ASCIILiteral("function"), FormElementClearJavaScript);
1271     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1272     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1273         if (response.isError) {
1274             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1275             return;
1276         }
1277         completionHandler(CommandResult::success());
1278     });
1279 }
1280
1281 String Session::virtualKeyForKeySequence(const String& keySequence, KeyModifier& modifier)
1282 {
1283     // ยง17.4.2 Keyboard Actions.
1284     // https://www.w3.org/TR/webdriver/#keyboard-actions
1285     modifier = KeyModifier::None;
1286     switch (keySequence[0]) {
1287     case 0xE001U:
1288         return ASCIILiteral("Cancel");
1289     case 0xE002U:
1290         return ASCIILiteral("Help");
1291     case 0xE003U:
1292         return ASCIILiteral("Backspace");
1293     case 0xE004U:
1294         return ASCIILiteral("Tab");
1295     case 0xE005U:
1296         return ASCIILiteral("Clear");
1297     case 0xE006U:
1298         return ASCIILiteral("Return");
1299     case 0xE007U:
1300         return ASCIILiteral("Enter");
1301     case 0xE008U:
1302         modifier = KeyModifier::Shift;
1303         return ASCIILiteral("Shift");
1304     case 0xE009U:
1305         modifier = KeyModifier::Control;
1306         return ASCIILiteral("Control");
1307     case 0xE00AU:
1308         modifier = KeyModifier::Alternate;
1309         return ASCIILiteral("Alternate");
1310     case 0xE00BU:
1311         return ASCIILiteral("Pause");
1312     case 0xE00CU:
1313         return ASCIILiteral("Escape");
1314     case 0xE00DU:
1315         return ASCIILiteral("Space");
1316     case 0xE00EU:
1317         return ASCIILiteral("PageUp");
1318     case 0xE00FU:
1319         return ASCIILiteral("PageDown");
1320     case 0xE010U:
1321         return ASCIILiteral("End");
1322     case 0xE011U:
1323         return ASCIILiteral("Home");
1324     case 0xE012U:
1325         return ASCIILiteral("LeftArrow");
1326     case 0xE013U:
1327         return ASCIILiteral("UpArrow");
1328     case 0xE014U:
1329         return ASCIILiteral("RightArrow");
1330     case 0xE015U:
1331         return ASCIILiteral("DownArrow");
1332     case 0xE016U:
1333         return ASCIILiteral("Insert");
1334     case 0xE017U:
1335         return ASCIILiteral("Delete");
1336     case 0xE018U:
1337         return ASCIILiteral("Semicolon");
1338     case 0xE019U:
1339         return ASCIILiteral("Equals");
1340     case 0xE01AU:
1341         return ASCIILiteral("NumberPad0");
1342     case 0xE01BU:
1343         return ASCIILiteral("NumberPad1");
1344     case 0xE01CU:
1345         return ASCIILiteral("NumberPad2");
1346     case 0xE01DU:
1347         return ASCIILiteral("NumberPad3");
1348     case 0xE01EU:
1349         return ASCIILiteral("NumberPad4");
1350     case 0xE01FU:
1351         return ASCIILiteral("NumberPad5");
1352     case 0xE020U:
1353         return ASCIILiteral("NumberPad6");
1354     case 0xE021U:
1355         return ASCIILiteral("NumberPad7");
1356     case 0xE022U:
1357         return ASCIILiteral("NumberPad8");
1358     case 0xE023U:
1359         return ASCIILiteral("NumberPad9");
1360     case 0xE024U:
1361         return ASCIILiteral("NumberPadMultiply");
1362     case 0xE025U:
1363         return ASCIILiteral("NumberPadAdd");
1364     case 0xE026U:
1365         return ASCIILiteral("NumberPadSeparator");
1366     case 0xE027U:
1367         return ASCIILiteral("NumberPadSubtract");
1368     case 0xE028U:
1369         return ASCIILiteral("NumberPadDecimal");
1370     case 0xE029U:
1371         return ASCIILiteral("NumberPadDivide");
1372     case 0xE031U:
1373         return ASCIILiteral("Function1");
1374     case 0xE032U:
1375         return ASCIILiteral("Function2");
1376     case 0xE033U:
1377         return ASCIILiteral("Function3");
1378     case 0xE034U:
1379         return ASCIILiteral("Function4");
1380     case 0xE035U:
1381         return ASCIILiteral("Function5");
1382     case 0xE036U:
1383         return ASCIILiteral("Function6");
1384     case 0xE037U:
1385         return ASCIILiteral("Function7");
1386     case 0xE038U:
1387         return ASCIILiteral("Function8");
1388     case 0xE039U:
1389         return ASCIILiteral("Function9");
1390     case 0xE03AU:
1391         return ASCIILiteral("Function10");
1392     case 0xE03BU:
1393         return ASCIILiteral("Function11");
1394     case 0xE03CU:
1395         return ASCIILiteral("Function12");
1396     case 0xE03DU:
1397         modifier = KeyModifier::Meta;
1398         return ASCIILiteral("Meta");
1399     default:
1400         break;
1401     }
1402     return String();
1403 }
1404
1405 void Session::elementSendKeys(const String& elementID, Vector<String>&& keys, Function<void (CommandResult&&)>&& completionHandler)
1406 {
1407     if (!m_toplevelBrowsingContext) {
1408         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1409         return;
1410     }
1411
1412     handleUserPrompts([this, elementID, keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1413         if (result.isError()) {
1414             completionHandler(WTFMove(result));
1415             return;
1416         }
1417         // FIXME: move this to an atom.
1418         static const char focusScript[] =
1419             "function focus(element) {"
1420             "    var doc = element.ownerDocument || element;"
1421             "    var prevActiveElement = doc.activeElement;"
1422             "    if (element != prevActiveElement && prevActiveElement)"
1423             "        prevActiveElement.blur();"
1424             "    element.focus();"
1425             "    if (element != prevActiveElement && element.value && element.value.length && element.setSelectionRange)"
1426             "        element.setSelectionRange(element.value.length, element.value.length);"
1427             "    if (element != doc.activeElement)"
1428             "        throw new Error('cannot focus element');"
1429             "}";
1430
1431         RefPtr<InspectorArray> arguments = InspectorArray::create();
1432         arguments->pushString(createElement(elementID)->toJSONString());
1433         RefPtr<InspectorObject> parameters = InspectorObject::create();
1434         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1435         if (m_currentBrowsingContext)
1436             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1437         parameters->setString(ASCIILiteral("function"), focusScript);
1438         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1439         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1440             if (response.isError || !response.responseObject) {
1441                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1442                 return;
1443             }
1444
1445             unsigned stickyModifiers = 0;
1446             Vector<KeyboardInteraction> interactions;
1447             interactions.reserveInitialCapacity(keys.size());
1448             for (const auto& key : keys) {
1449                 KeyboardInteraction interaction;
1450                 KeyModifier modifier;
1451                 auto virtualKey = virtualKeyForKeySequence(key, modifier);
1452                 if (!virtualKey.isNull()) {
1453                     interaction.key = virtualKey;
1454                     if (modifier != KeyModifier::None) {
1455                         stickyModifiers ^= modifier;
1456                         if (stickyModifiers & modifier)
1457                             interaction.type = KeyboardInteractionType::KeyPress;
1458                         else
1459                             interaction.type = KeyboardInteractionType::KeyRelease;
1460                     }
1461                 } else
1462                     interaction.text = key;
1463                 interactions.uncheckedAppend(WTFMove(interaction));
1464             }
1465
1466             // Reset sticky modifiers if needed.
1467             if (stickyModifiers) {
1468                 if (stickyModifiers & KeyModifier::Shift)
1469                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Shift")) });
1470                 if (stickyModifiers & KeyModifier::Control)
1471                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Control")) });
1472                 if (stickyModifiers & KeyModifier::Alternate)
1473                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Alternate")) });
1474                 if (stickyModifiers & KeyModifier::Meta)
1475                     interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Meta")) });
1476             }
1477
1478             performKeyboardInteractions(WTFMove(interactions), WTFMove(completionHandler));
1479         });
1480     });
1481 }
1482
1483 void Session::elementSubmit(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1484 {
1485     if (!m_toplevelBrowsingContext) {
1486         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1487         return;
1488     }
1489
1490     handleUserPrompts([this, elementID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1491         if (result.isError()) {
1492             completionHandler(WTFMove(result));
1493             return;
1494         }
1495         RefPtr<InspectorArray> arguments = InspectorArray::create();
1496         arguments->pushString(createElement(elementID)->toJSONString());
1497
1498         RefPtr<InspectorObject> parameters = InspectorObject::create();
1499         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1500         if (m_currentBrowsingContext)
1501             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1502         parameters->setString(ASCIILiteral("function"), FormSubmitJavaScript);
1503         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1504         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1505             if (response.isError) {
1506                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1507                 return;
1508             }
1509             completionHandler(CommandResult::success());
1510         });
1511     });
1512 }
1513
1514 RefPtr<InspectorValue> Session::handleScriptResult(RefPtr<InspectorValue>&& resultValue)
1515 {
1516     RefPtr<InspectorArray> resultArray;
1517     if (resultValue->asArray(resultArray)) {
1518         RefPtr<InspectorArray> returnValueArray = InspectorArray::create();
1519         unsigned resultArrayLength = resultArray->length();
1520         for (unsigned i = 0; i < resultArrayLength; ++i)
1521             returnValueArray->pushValue(handleScriptResult(resultArray->get(i)));
1522         return returnValueArray;
1523     }
1524
1525     if (auto element = createElement(RefPtr<InspectorValue>(resultValue)))
1526         return element;
1527
1528     RefPtr<InspectorObject> resultObject;
1529     if (resultValue->asObject(resultObject)) {
1530         RefPtr<InspectorObject> returnValueObject = InspectorObject::create();
1531         auto end = resultObject->end();
1532         for (auto it = resultObject->begin(); it != end; ++it)
1533             returnValueObject->setValue(it->key, handleScriptResult(WTFMove(it->value)));
1534         return returnValueObject;
1535     }
1536
1537     return resultValue;
1538 }
1539
1540 void Session::executeScript(const String& script, RefPtr<InspectorArray>&& argumentsArray, ExecuteScriptMode mode, Function<void (CommandResult&&)>&& completionHandler)
1541 {
1542     if (!m_toplevelBrowsingContext) {
1543         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1544         return;
1545     }
1546
1547     handleUserPrompts([this, script, argumentsArray = WTFMove(argumentsArray), mode, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
1548         if (result.isError()) {
1549             completionHandler(WTFMove(result));
1550             return;
1551         }
1552         RefPtr<InspectorArray> arguments = InspectorArray::create();
1553         unsigned argumentsLength = argumentsArray->length();
1554         for (unsigned i = 0; i < argumentsLength; ++i) {
1555             if (auto argument = argumentsArray->get(i)) {
1556                 if (auto element = extractElement(*argument))
1557                     arguments->pushString(element->toJSONString());
1558                 else
1559                     arguments->pushString(argument->toJSONString());
1560             }
1561         }
1562
1563         RefPtr<InspectorObject> parameters = InspectorObject::create();
1564         parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1565         if (m_currentBrowsingContext)
1566             parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1567         parameters->setString(ASCIILiteral("function"), "function(){" + script + '}');
1568         parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1569         if (mode == ExecuteScriptMode::Async) {
1570             parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
1571             if (m_timeouts.script)
1572                 parameters->setInteger(ASCIILiteral("callbackTimeout"), m_timeouts.script.value().millisecondsAs<int>());
1573         }
1574         m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1575             if (response.isError || !response.responseObject) {
1576                 completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1577                 return;
1578             }
1579             String valueString;
1580             if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1581                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1582                 return;
1583             }
1584             if (valueString.isEmpty()) {
1585                 completionHandler(CommandResult::success());
1586                 return;
1587             }
1588             RefPtr<InspectorValue> resultValue;
1589             if (!InspectorValue::parseJSON(valueString, resultValue)) {
1590                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1591                 return;
1592             }
1593             completionHandler(CommandResult::success(handleScriptResult(WTFMove(resultValue))));
1594         });
1595     });
1596 }
1597
1598 void Session::performMouseInteraction(int x, int y, MouseButton button, MouseInteraction interaction, Function<void (CommandResult&&)>&& completionHandler)
1599 {
1600     RefPtr<InspectorObject> parameters = InspectorObject::create();
1601     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1602     RefPtr<InspectorObject> position = InspectorObject::create();
1603     position->setInteger(ASCIILiteral("x"), x);
1604     position->setInteger(ASCIILiteral("y"), y);
1605     parameters->setObject(ASCIILiteral("position"), WTFMove(position));
1606     switch (button) {
1607     case MouseButton::None:
1608         parameters->setString(ASCIILiteral("button"), ASCIILiteral("None"));
1609         break;
1610     case MouseButton::Left:
1611         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Left"));
1612         break;
1613     case MouseButton::Middle:
1614         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Middle"));
1615         break;
1616     case MouseButton::Right:
1617         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Right"));
1618         break;
1619     }
1620     switch (interaction) {
1621     case MouseInteraction::Move:
1622         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Move"));
1623         break;
1624     case MouseInteraction::Down:
1625         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Down"));
1626         break;
1627     case MouseInteraction::Up:
1628         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Up"));
1629         break;
1630     case MouseInteraction::SingleClick:
1631         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("SingleClick"));
1632         break;
1633     case MouseInteraction::DoubleClick:
1634         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("DoubleClick"));
1635         break;
1636     }
1637     parameters->setArray(ASCIILiteral("modifiers"), InspectorArray::create());
1638     m_host->sendCommandToBackend(ASCIILiteral("performMouseInteraction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1639         if (response.isError) {
1640             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1641             return;
1642         }
1643         completionHandler(CommandResult::success());
1644     });
1645 }
1646
1647 void Session::performKeyboardInteractions(Vector<KeyboardInteraction>&& interactions, Function<void (CommandResult&&)>&& completionHandler)
1648 {
1649     RefPtr<InspectorObject> parameters = InspectorObject::create();
1650     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1651     RefPtr<InspectorArray> interactionsArray = InspectorArray::create();
1652     for (const auto& interaction : interactions) {
1653         RefPtr<InspectorObject> interactionObject = InspectorObject::create();
1654         switch (interaction.type) {
1655         case KeyboardInteractionType::KeyPress:
1656             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyPress"));
1657             break;
1658         case KeyboardInteractionType::KeyRelease:
1659             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyRelease"));
1660             break;
1661         case KeyboardInteractionType::InsertByKey:
1662             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("InsertByKey"));
1663             break;
1664         }
1665         if (interaction.key)
1666             interactionObject->setString(ASCIILiteral("key"), interaction.key.value());
1667         if (interaction.text)
1668             interactionObject->setString(ASCIILiteral("text"), interaction.text.value());
1669         interactionsArray->pushObject(WTFMove(interactionObject));
1670     }
1671     parameters->setArray(ASCIILiteral("interactions"), WTFMove(interactionsArray));
1672     m_host->sendCommandToBackend(ASCIILiteral("performKeyboardInteractions"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1673         if (response.isError) {
1674             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1675             return;
1676         }
1677         completionHandler(CommandResult::success());
1678     });
1679 }
1680
1681 void Session::dismissAlert(Function<void (CommandResult&&)>&& completionHandler)
1682 {
1683     if (!m_toplevelBrowsingContext) {
1684         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1685         return;
1686     }
1687
1688     RefPtr<InspectorObject> parameters = InspectorObject::create();
1689     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1690     m_host->sendCommandToBackend(ASCIILiteral("dismissCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1691         if (response.isError) {
1692             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1693             return;
1694         }
1695         completionHandler(CommandResult::success());
1696     });
1697 }
1698
1699 void Session::acceptAlert(Function<void (CommandResult&&)>&& completionHandler)
1700 {
1701     if (!m_toplevelBrowsingContext) {
1702         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1703         return;
1704     }
1705
1706     RefPtr<InspectorObject> parameters = InspectorObject::create();
1707     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1708     m_host->sendCommandToBackend(ASCIILiteral("acceptCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1709         if (response.isError) {
1710             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1711             return;
1712         }
1713         completionHandler(CommandResult::success());
1714     });
1715 }
1716
1717 void Session::getAlertText(Function<void (CommandResult&&)>&& completionHandler)
1718 {
1719     if (!m_toplevelBrowsingContext) {
1720         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1721         return;
1722     }
1723
1724     RefPtr<InspectorObject> parameters = InspectorObject::create();
1725     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1726     m_host->sendCommandToBackend(ASCIILiteral("messageOfCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1727         if (response.isError || !response.responseObject) {
1728             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1729             return;
1730         }
1731         String valueString;
1732         if (!response.responseObject->getString(ASCIILiteral("message"), valueString)) {
1733             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1734             return;
1735         }
1736         completionHandler(CommandResult::success(InspectorValue::create(valueString)));
1737     });
1738 }
1739
1740 void Session::sendAlertText(const String& text, Function<void (CommandResult&&)>&& completionHandler)
1741 {
1742     if (!m_toplevelBrowsingContext) {
1743         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1744         return;
1745     }
1746
1747     RefPtr<InspectorObject> parameters = InspectorObject::create();
1748     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1749     parameters->setString(ASCIILiteral("userInput"), text);
1750     m_host->sendCommandToBackend(ASCIILiteral("setUserInputForCurrentJavaScriptPrompt"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1751         if (response.isError) {
1752             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1753             return;
1754         }
1755         completionHandler(CommandResult::success());
1756     });
1757 }
1758
1759 } // namespace WebDriver