WebDriver: implement user prompt commands
[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::go(const String& url, Function<void (CommandResult&&)>&& completionHandler)
147 {
148     if (!m_toplevelBrowsingContext) {
149         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
150         return;
151     }
152
153     RefPtr<InspectorObject> parameters = InspectorObject::create();
154     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
155     parameters->setString(ASCIILiteral("url"), url);
156     if (m_timeouts.pageLoad)
157         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
158     if (auto pageLoadStrategy = pageLoadStrategyString())
159         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
160     m_host->sendCommandToBackend(ASCIILiteral("navigateBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
161         if (response.isError) {
162             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
163             return;
164         }
165         switchToBrowsingContext(std::nullopt);
166         completionHandler(CommandResult::success());
167     });
168 }
169
170 void Session::getCurrentURL(Function<void (CommandResult&&)>&& completionHandler)
171 {
172     if (!m_toplevelBrowsingContext) {
173         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
174         return;
175     }
176
177     RefPtr<InspectorObject> parameters = InspectorObject::create();
178     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
179     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
180         if (response.isError || !response.responseObject) {
181             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
182             return;
183         }
184         RefPtr<InspectorObject> browsingContext;
185         if (!response.responseObject->getObject("context", browsingContext)) {
186             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
187             return;
188         }
189         String url;
190         if (!browsingContext->getString("url", url)) {
191             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
192             return;
193         }
194         completionHandler(CommandResult::success(InspectorValue::create(url)));
195     });
196 }
197
198 void Session::back(Function<void (CommandResult&&)>&& completionHandler)
199 {
200     if (!m_toplevelBrowsingContext) {
201         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
202         return;
203     }
204
205     RefPtr<InspectorObject> parameters = InspectorObject::create();
206     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
207     if (m_timeouts.pageLoad)
208         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
209     if (auto pageLoadStrategy = pageLoadStrategyString())
210         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
211     m_host->sendCommandToBackend(ASCIILiteral("goBackInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
212         if (response.isError) {
213             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
214             return;
215         }
216         switchToBrowsingContext(std::nullopt);
217         completionHandler(CommandResult::success());
218     });
219 }
220
221 void Session::forward(Function<void (CommandResult&&)>&& completionHandler)
222 {
223     if (!m_toplevelBrowsingContext) {
224         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
225         return;
226     }
227
228     RefPtr<InspectorObject> parameters = InspectorObject::create();
229     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
230     if (m_timeouts.pageLoad)
231         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
232     if (auto pageLoadStrategy = pageLoadStrategyString())
233         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
234     m_host->sendCommandToBackend(ASCIILiteral("goForwardInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
235         if (response.isError) {
236             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
237             return;
238         }
239         switchToBrowsingContext(std::nullopt);
240         completionHandler(CommandResult::success());
241     });
242 }
243
244 void Session::refresh(Function<void (CommandResult&&)>&& completionHandler)
245 {
246     if (!m_toplevelBrowsingContext) {
247         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
248         return;
249     }
250
251     RefPtr<InspectorObject> parameters = InspectorObject::create();
252     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
253     if (m_timeouts.pageLoad)
254         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
255     if (auto pageLoadStrategy = pageLoadStrategyString())
256         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
257     m_host->sendCommandToBackend(ASCIILiteral("reloadBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
258         if (response.isError) {
259             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
260             return;
261         }
262         switchToBrowsingContext(std::nullopt);
263         completionHandler(CommandResult::success());
264     });
265 }
266
267 void Session::getTitle(Function<void (CommandResult&&)>&& completionHandler)
268 {
269     if (!m_toplevelBrowsingContext) {
270         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
271         return;
272     }
273
274     RefPtr<InspectorObject> parameters = InspectorObject::create();
275     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
276     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function() { return document.title; }"));
277     parameters->setArray(ASCIILiteral("arguments"), InspectorArray::create());
278     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
279         if (response.isError || !response.responseObject) {
280             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
281             return;
282         }
283         String valueString;
284         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
285             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
286             return;
287         }
288         RefPtr<InspectorValue> resultValue;
289         if (!InspectorValue::parseJSON(valueString, resultValue)) {
290             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
291             return;
292         }
293         completionHandler(CommandResult::success(WTFMove(resultValue)));
294     });
295 }
296
297 void Session::getWindowHandle(Function<void (CommandResult&&)>&& completionHandler)
298 {
299     if (!m_toplevelBrowsingContext) {
300         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
301         return;
302     }
303
304     RefPtr<InspectorObject> parameters = InspectorObject::create();
305     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
306     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
307         if (response.isError || !response.responseObject) {
308             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
309             return;
310         }
311         RefPtr<InspectorObject> browsingContext;
312         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
313             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
314             return;
315         }
316         String handle;
317         if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
318             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
319             return;
320         }
321         completionHandler(CommandResult::success(InspectorValue::create(handle)));
322     });
323 }
324
325 void Session::closeWindow(Function<void (CommandResult&&)>&& completionHandler)
326 {
327     if (!m_toplevelBrowsingContext) {
328         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
329         return;
330     }
331
332     close(WTFMove(completionHandler));
333 }
334
335 void Session::switchToWindow(const String& windowHandle, Function<void (CommandResult&&)>&& completionHandler)
336 {
337     RefPtr<InspectorObject> parameters = InspectorObject::create();
338     parameters->setString(ASCIILiteral("browsingContextHandle"), windowHandle);
339     m_host->sendCommandToBackend(ASCIILiteral("switchToBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), windowHandle, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
340         if (response.isError) {
341             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
342             return;
343         }
344         switchToTopLevelBrowsingContext(windowHandle);
345         completionHandler(CommandResult::success());
346     });
347 }
348
349 void Session::getWindowHandles(Function<void (CommandResult&&)>&& completionHandler)
350 {
351     if (!m_toplevelBrowsingContext) {
352         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
353         return;
354     }
355
356     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContexts"), InspectorObject::create(), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
357         if (response.isError || !response.responseObject) {
358             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
359             return;
360         }
361         RefPtr<InspectorArray> browsingContextArray;
362         if (!response.responseObject->getArray(ASCIILiteral("contexts"), browsingContextArray)) {
363             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
364             return;
365         }
366         RefPtr<InspectorArray> windowHandles = InspectorArray::create();
367         for (unsigned i = 0; i < browsingContextArray->length(); ++i) {
368             RefPtr<InspectorValue> browsingContextValue = browsingContextArray->get(i);
369             RefPtr<InspectorObject> browsingContext;
370             if (!browsingContextValue->asObject(browsingContext)) {
371                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
372                 return;
373             }
374
375             String handle;
376             if (!browsingContext->getString(ASCIILiteral("handle"), handle)) {
377                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
378                 return;
379             }
380
381             windowHandles->pushString(handle);
382         }
383         completionHandler(CommandResult::success(WTFMove(windowHandles)));
384     });
385 }
386
387 void Session::switchToFrame(RefPtr<InspectorValue>&& frameID, Function<void (CommandResult&&)>&& completionHandler)
388 {
389     if (!m_toplevelBrowsingContext) {
390         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
391         return;
392     }
393
394     if (frameID->isNull()) {
395         switchToBrowsingContext(std::nullopt);
396         completionHandler(CommandResult::success());
397         return;
398     }
399
400     RefPtr<InspectorObject> parameters = InspectorObject::create();
401     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
402     if (m_currentBrowsingContext)
403         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
404
405     int frameIndex;
406     if (frameID->asInteger(frameIndex)) {
407         if (frameIndex < 0 || frameIndex > USHRT_MAX) {
408             completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
409             return;
410         }
411         parameters->setInteger(ASCIILiteral("ordinal"), frameIndex);
412     } else {
413         String frameElementID = extractElementID(*frameID);
414         if (!frameElementID.isEmpty())
415             parameters->setString(ASCIILiteral("nodeHandle"), frameElementID);
416         else {
417             String frameName;
418             if (!frameID->asString(frameName)) {
419                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchFrame));
420                 return;
421             }
422             parameters->setString(ASCIILiteral("name"), frameName);
423         }
424     }
425
426     m_host->sendCommandToBackend(ASCIILiteral("resolveChildFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
427         if (response.isError || !response.responseObject) {
428             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
429             return;
430         }
431         String frameHandle;
432         if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
433             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
434             return;
435         }
436         switchToBrowsingContext(frameHandle);
437         completionHandler(CommandResult::success());
438     });
439 }
440
441 void Session::switchToParentFrame(Function<void (CommandResult&&)>&& completionHandler)
442 {
443     if (!m_toplevelBrowsingContext) {
444         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
445         return;
446     }
447
448     if (!m_currentBrowsingContext) {
449         completionHandler(CommandResult::success());
450         return;
451     }
452
453     RefPtr<InspectorObject> parameters = InspectorObject::create();
454     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
455     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
456     m_host->sendCommandToBackend(ASCIILiteral("resolveParentFrameHandle"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
457         if (response.isError || !response.responseObject) {
458             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
459             return;
460         }
461         String frameHandle;
462         if (!response.responseObject->getString(ASCIILiteral("result"), frameHandle)) {
463             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
464             return;
465         }
466         switchToBrowsingContext(frameHandle);
467         completionHandler(CommandResult::success());
468     });
469 }
470
471 void Session::getWindowPosition(Function<void (CommandResult&&)>&& completionHandler)
472 {
473     if (!m_toplevelBrowsingContext) {
474         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
475         return;
476     }
477
478     RefPtr<InspectorObject> parameters = InspectorObject::create();
479     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
480     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
481         if (response.isError || !response.responseObject) {
482             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
483             return;
484         }
485         RefPtr<InspectorObject> browsingContext;
486         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
487             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
488             return;
489         }
490         RefPtr<InspectorObject> windowOrigin;
491         if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)) {
492             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
493             return;
494         }
495         completionHandler(CommandResult::success(WTFMove(windowOrigin)));
496     });
497 }
498
499 void Session::setWindowPosition(int windowX, int windowY, Function<void (CommandResult&&)>&& completionHandler)
500 {
501     if (!m_toplevelBrowsingContext) {
502         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
503         return;
504     }
505
506     RefPtr<InspectorObject> parameters = InspectorObject::create();
507     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
508     RefPtr<InspectorObject> windowOrigin = InspectorObject::create();
509     windowOrigin->setInteger("x", windowX);
510     windowOrigin->setInteger("y", windowY);
511     parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin));
512     m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
513         if (response.isError) {
514             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
515             return;
516         }
517         completionHandler(CommandResult::success());
518     });
519 }
520
521 void Session::getWindowSize(Function<void (CommandResult&&)>&& completionHandler)
522 {
523     if (!m_toplevelBrowsingContext) {
524         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
525         return;
526     }
527
528     RefPtr<InspectorObject> parameters = InspectorObject::create();
529     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
530     m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
531         if (response.isError || !response.responseObject) {
532             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
533             return;
534         }
535         RefPtr<InspectorObject> browsingContext;
536         if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
537             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
538             return;
539         }
540         RefPtr<InspectorObject> windowSize;
541         if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)) {
542             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
543             return;
544         }
545         completionHandler(CommandResult::success(WTFMove(windowSize)));
546     });
547 }
548
549 void Session::setWindowSize(int windowWidth, int windowHeight, Function<void (CommandResult&&)>&& completionHandler)
550 {
551     if (!m_toplevelBrowsingContext) {
552         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
553         return;
554     }
555
556     RefPtr<InspectorObject> parameters = InspectorObject::create();
557     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
558     RefPtr<InspectorObject> windowSize = InspectorObject::create();
559     windowSize->setInteger("width", windowWidth);
560     windowSize->setInteger("height", windowHeight);
561     parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
562     m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
563         if (response.isError) {
564             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
565             return;
566         }
567         completionHandler(CommandResult::success());
568     });
569 }
570
571 RefPtr<InspectorObject> Session::createElement(RefPtr<InspectorValue>&& value)
572 {
573     RefPtr<InspectorObject> valueObject;
574     if (!value->asObject(valueObject))
575         return nullptr;
576
577     String elementID;
578     if (!valueObject->getString("session-node-" + m_id, elementID))
579         return nullptr;
580
581     RefPtr<InspectorObject> elementObject = InspectorObject::create();
582     elementObject->setString(webElementIdentifier, elementID);
583     return elementObject;
584 }
585
586 RefPtr<InspectorObject> Session::createElement(const String& elementID)
587 {
588     RefPtr<InspectorObject> elementObject = InspectorObject::create();
589     elementObject->setString("session-node-" + m_id, elementID);
590     return elementObject;
591 }
592
593 RefPtr<InspectorObject> Session::extractElement(InspectorValue& value)
594 {
595     String elementID = extractElementID(value);
596     return !elementID.isEmpty() ? createElement(elementID) : nullptr;
597 }
598
599 String Session::extractElementID(InspectorValue& value)
600 {
601     RefPtr<InspectorObject> valueObject;
602     if (!value.asObject(valueObject))
603         return emptyString();
604
605     String elementID;
606     if (!valueObject->getString(webElementIdentifier, elementID))
607         return emptyString();
608
609     return elementID;
610 }
611
612 void Session::computeElementLayout(const String& elementID, OptionSet<ElementLayoutOption> options, Function<void (std::optional<Rect>&&, std::optional<Point>&&, bool, RefPtr<InspectorObject>&&)>&& completionHandler)
613 {
614     ASSERT(m_toplevelBrowsingContext.value());
615
616     RefPtr<InspectorObject> parameters = InspectorObject::create();
617     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
618     parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
619     parameters->setString(ASCIILiteral("nodeHandle"), elementID);
620     parameters->setBoolean(ASCIILiteral("scrollIntoViewIfNeeded"), options.contains(ElementLayoutOption::ScrollIntoViewIfNeeded));
621     parameters->setBoolean(ASCIILiteral("useViewportCoordinates"), options.contains(ElementLayoutOption::UseViewportCoordinates));
622     m_host->sendCommandToBackend(ASCIILiteral("computeElementLayout"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
623         if (response.isError || !response.responseObject) {
624             completionHandler(std::nullopt, std::nullopt, false, WTFMove(response.responseObject));
625             return;
626         }
627         RefPtr<InspectorObject> rectObject;
628         if (!response.responseObject->getObject(ASCIILiteral("rect"), rectObject)) {
629             completionHandler(std::nullopt, std::nullopt, false, nullptr);
630             return;
631         }
632         std::optional<int> elementX;
633         std::optional<int> elementY;
634         RefPtr<InspectorObject> elementPosition;
635         if (rectObject->getObject(ASCIILiteral("origin"), elementPosition)) {
636             int x, y;
637             if (elementPosition->getInteger(ASCIILiteral("x"), x) && elementPosition->getInteger(ASCIILiteral("y"), y)) {
638                 elementX = x;
639                 elementY = y;
640             }
641         }
642         if (!elementX || !elementY) {
643             completionHandler(std::nullopt, std::nullopt, false, nullptr);
644             return;
645         }
646         std::optional<int> elementWidth;
647         std::optional<int> elementHeight;
648         RefPtr<InspectorObject> elementSize;
649         if (rectObject->getObject(ASCIILiteral("size"), elementSize)) {
650             int width, height;
651             if (elementSize->getInteger(ASCIILiteral("width"), width) && elementSize->getInteger(ASCIILiteral("height"), height)) {
652                 elementWidth = width;
653                 elementHeight = height;
654             }
655         }
656         if (!elementWidth || !elementHeight) {
657             completionHandler(std::nullopt, std::nullopt, false, nullptr);
658             return;
659         }
660         Rect rect = { { elementX.value(), elementY.value() }, { elementWidth.value(), elementHeight.value() } };
661
662         bool isObscured;
663         if (!response.responseObject->getBoolean(ASCIILiteral("isObscured"), isObscured)) {
664             completionHandler(std::nullopt, std::nullopt, false, nullptr);
665             return;
666         }
667         RefPtr<InspectorObject> inViewCenterPointObject;
668         if (!response.responseObject->getObject(ASCIILiteral("inViewCenterPoint"), inViewCenterPointObject)) {
669             completionHandler(rect, std::nullopt, isObscured, nullptr);
670             return;
671         }
672         int inViewCenterPointX, inViewCenterPointY;
673         if (!inViewCenterPointObject->getInteger(ASCIILiteral("x"), inViewCenterPointX)
674             || !inViewCenterPointObject->getInteger(ASCIILiteral("y"), inViewCenterPointY)) {
675             completionHandler(std::nullopt, std::nullopt, isObscured, nullptr);
676             return;
677         }
678         Point inViewCenterPoint = { inViewCenterPointX, inViewCenterPointY };
679         completionHandler(rect, inViewCenterPoint, isObscured, nullptr);
680     });
681 }
682
683 void Session::findElements(const String& strategy, const String& selector, FindElementsMode mode, const String& rootElementID, Function<void (CommandResult&&)>&& completionHandler)
684 {
685     if (!m_toplevelBrowsingContext) {
686         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
687         return;
688     }
689
690     auto implicitWait = m_timeouts.implicit.value_or(0_s);
691     RefPtr<InspectorArray> arguments = InspectorArray::create();
692     arguments->pushString(InspectorValue::create(strategy)->toJSONString());
693     if (rootElementID.isEmpty())
694         arguments->pushString(InspectorValue::null()->toJSONString());
695     else
696         arguments->pushString(createElement(rootElementID)->toJSONString());
697     arguments->pushString(InspectorValue::create(selector)->toJSONString());
698     arguments->pushString(InspectorValue::create(mode == FindElementsMode::Single)->toJSONString());
699     arguments->pushString(InspectorValue::create(implicitWait.milliseconds())->toJSONString());
700
701     RefPtr<InspectorObject> parameters = InspectorObject::create();
702     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
703     if (m_currentBrowsingContext)
704         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
705     parameters->setString(ASCIILiteral("function"), FindNodesJavaScript);
706     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
707     parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
708     // If there's an implicit wait, use one second more as callback timeout.
709     if (implicitWait)
710         parameters->setInteger(ASCIILiteral("callbackTimeout"), Seconds(implicitWait + 1_s).millisecondsAs<int>());
711
712     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), mode, completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
713         if (response.isError || !response.responseObject) {
714             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
715             return;
716         }
717         String valueString;
718         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
719             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
720             return;
721         }
722         RefPtr<InspectorValue> resultValue;
723         if (!InspectorValue::parseJSON(valueString, resultValue)) {
724             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
725             return;
726         }
727
728         switch (mode) {
729         case FindElementsMode::Single: {
730             RefPtr<InspectorObject> elementObject = createElement(WTFMove(resultValue));
731             if (!elementObject) {
732                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
733                 return;
734             }
735             completionHandler(CommandResult::success(WTFMove(elementObject)));
736             break;
737         }
738         case FindElementsMode::Multiple: {
739             RefPtr<InspectorArray> elementsArray;
740             if (!resultValue->asArray(elementsArray)) {
741                 completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchElement));
742                 return;
743             }
744             RefPtr<InspectorArray> elementObjectsArray = InspectorArray::create();
745             unsigned elementsArrayLength = elementsArray->length();
746             for (unsigned i = 0; i < elementsArrayLength; ++i) {
747                 if (auto elementObject = createElement(elementsArray->get(i)))
748                     elementObjectsArray->pushObject(WTFMove(elementObject));
749             }
750             completionHandler(CommandResult::success(WTFMove(elementObjectsArray)));
751             break;
752         }
753         }
754     });
755 }
756
757 void Session::isElementSelected(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
758 {
759     if (!m_toplevelBrowsingContext) {
760         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
761         return;
762     }
763
764     RefPtr<InspectorArray> arguments = InspectorArray::create();
765     arguments->pushString(createElement(elementID)->toJSONString());
766     arguments->pushString(InspectorValue::create("selected")->toJSONString());
767
768     RefPtr<InspectorObject> parameters = InspectorObject::create();
769     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
770     if (m_currentBrowsingContext)
771         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
772     parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
773     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
774     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
775         if (response.isError || !response.responseObject) {
776             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
777             return;
778         }
779         String valueString;
780         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
781             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
782             return;
783         }
784         RefPtr<InspectorValue> resultValue;
785         if (!InspectorValue::parseJSON(valueString, resultValue)) {
786             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
787             return;
788         }
789         if (resultValue->isNull()) {
790             completionHandler(CommandResult::success(InspectorValue::create(false)));
791             return;
792         }
793         String booleanResult;
794         if (!resultValue->asString(booleanResult) || booleanResult != "true") {
795             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
796             return;
797         }
798         completionHandler(CommandResult::success(InspectorValue::create(true)));
799     });
800 }
801
802 void Session::getElementText(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
803 {
804     if (!m_toplevelBrowsingContext) {
805         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
806         return;
807     }
808
809     RefPtr<InspectorArray> arguments = InspectorArray::create();
810     arguments->pushString(createElement(elementID)->toJSONString());
811
812     RefPtr<InspectorObject> parameters = InspectorObject::create();
813     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
814     if (m_currentBrowsingContext)
815         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
816     // FIXME: Add an atom to properly implement this instead of just using innerText.
817     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, '') }"));
818     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
819     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
820         if (response.isError || !response.responseObject) {
821             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
822             return;
823         }
824         String valueString;
825         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
826             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
827             return;
828         }
829         RefPtr<InspectorValue> resultValue;
830         if (!InspectorValue::parseJSON(valueString, resultValue)) {
831             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
832             return;
833         }
834         completionHandler(CommandResult::success(WTFMove(resultValue)));
835     });
836 }
837
838 void Session::getElementTagName(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
839 {
840     if (!m_toplevelBrowsingContext) {
841         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
842         return;
843     }
844
845     RefPtr<InspectorArray> arguments = InspectorArray::create();
846     arguments->pushString(createElement(elementID)->toJSONString());
847
848     RefPtr<InspectorObject> parameters = InspectorObject::create();
849     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
850     if (m_currentBrowsingContext)
851         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
852     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.tagName.toLowerCase() }"));
853     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
854     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
855         if (response.isError || !response.responseObject) {
856             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
857             return;
858         }
859         String valueString;
860         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
861             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
862             return;
863         }
864         RefPtr<InspectorValue> resultValue;
865         if (!InspectorValue::parseJSON(valueString, resultValue)) {
866             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
867             return;
868         }
869         completionHandler(CommandResult::success(WTFMove(resultValue)));
870     });
871 }
872
873 void Session::getElementRect(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
874 {
875     if (!m_toplevelBrowsingContext) {
876         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
877         return;
878     }
879
880     computeElementLayout(elementID, { }, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&&, bool, RefPtr<InspectorObject>&& error) {
881         if (!rect || error) {
882             completionHandler(CommandResult::fail(WTFMove(error)));
883             return;
884         }
885         RefPtr<InspectorObject> rectObject = InspectorObject::create();
886         rectObject->setInteger(ASCIILiteral("x"), rect.value().origin.x);
887         rectObject->setInteger(ASCIILiteral("y"), rect.value().origin.y);
888         rectObject->setInteger(ASCIILiteral("width"), rect.value().size.width);
889         rectObject->setInteger(ASCIILiteral("height"), rect.value().size.height);
890         completionHandler(CommandResult::success(WTFMove(rectObject)));
891     });
892 }
893
894 void Session::isElementEnabled(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
895 {
896     if (!m_toplevelBrowsingContext) {
897         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
898         return;
899     }
900
901     RefPtr<InspectorArray> arguments = InspectorArray::create();
902     arguments->pushString(createElement(elementID)->toJSONString());
903
904     RefPtr<InspectorObject> parameters = InspectorObject::create();
905     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
906     if (m_currentBrowsingContext)
907         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
908     parameters->setString(ASCIILiteral("function"), ASCIILiteral("function(element) { return element.disabled === undefined ? true : !element.disabled }"));
909     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
910     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
911         if (response.isError || !response.responseObject) {
912             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
913             return;
914         }
915         String valueString;
916         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
917             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
918             return;
919         }
920         RefPtr<InspectorValue> resultValue;
921         if (!InspectorValue::parseJSON(valueString, resultValue)) {
922             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
923             return;
924         }
925         completionHandler(CommandResult::success(WTFMove(resultValue)));
926     });
927 }
928
929 void Session::isElementDisplayed(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
930 {
931     if (!m_toplevelBrowsingContext) {
932         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
933         return;
934     }
935
936     RefPtr<InspectorArray> arguments = InspectorArray::create();
937     arguments->pushString(createElement(elementID)->toJSONString());
938
939     RefPtr<InspectorObject> parameters = InspectorObject::create();
940     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
941     if (m_currentBrowsingContext)
942         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
943     parameters->setString(ASCIILiteral("function"), ElementDisplayedJavaScript);
944     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
945     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
946         if (response.isError || !response.responseObject) {
947             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
948             return;
949         }
950         String valueString;
951         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
952             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
953             return;
954         }
955         RefPtr<InspectorValue> resultValue;
956         if (!InspectorValue::parseJSON(valueString, resultValue)) {
957             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
958             return;
959         }
960         completionHandler(CommandResult::success(WTFMove(resultValue)));
961     });
962 }
963
964 void Session::getElementAttribute(const String& elementID, const String& attribute, Function<void (CommandResult&&)>&& completionHandler)
965 {
966     if (!m_toplevelBrowsingContext) {
967         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
968         return;
969     }
970
971     RefPtr<InspectorArray> arguments = InspectorArray::create();
972     arguments->pushString(createElement(elementID)->toJSONString());
973     arguments->pushString(InspectorValue::create(attribute)->toJSONString());
974
975     RefPtr<InspectorObject> parameters = InspectorObject::create();
976     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
977     if (m_currentBrowsingContext)
978         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
979     parameters->setString(ASCIILiteral("function"), ElementAttributeJavaScript);
980     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
981     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
982         if (response.isError || !response.responseObject) {
983             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
984             return;
985         }
986         String valueString;
987         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
988             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
989             return;
990         }
991         RefPtr<InspectorValue> resultValue;
992         if (!InspectorValue::parseJSON(valueString, resultValue)) {
993             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
994             return;
995         }
996         completionHandler(CommandResult::success(WTFMove(resultValue)));
997     });
998 }
999
1000 void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& completionHandler)
1001 {
1002     if (!m_toplevelBrowsingContext) {
1003         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1004         return;
1005     }
1006
1007     RefPtr<InspectorObject> parameters = InspectorObject::create();
1008     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1009     if (m_currentBrowsingContext)
1010         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1011     if (m_timeouts.pageLoad)
1012         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
1013     if (auto pageLoadStrategy = pageLoadStrategyString())
1014         parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
1015     m_host->sendCommandToBackend(ASCIILiteral("waitForNavigationToComplete"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1016         if (response.isError) {
1017             auto result = CommandResult::fail(WTFMove(response.responseObject));
1018             if (result.errorCode() == CommandResult::ErrorCode::NoSuchFrame) {
1019                 // Navigation destroyed the current frame, switch to top level browsing context and ignore the error.
1020                 switchToBrowsingContext(std::nullopt);
1021             } else {
1022                 completionHandler(WTFMove(result));
1023                 return;
1024             }
1025         }
1026         completionHandler(CommandResult::success());
1027     });
1028 }
1029
1030 void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1031 {
1032     if (!m_toplevelBrowsingContext) {
1033         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1034         return;
1035     }
1036
1037     OptionSet<ElementLayoutOption> options = ElementLayoutOption::ScrollIntoViewIfNeeded;
1038     options |= ElementLayoutOption::UseViewportCoordinates;
1039     computeElementLayout(elementID, options, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](std::optional<Rect>&& rect, std::optional<Point>&& inViewCenter, bool isObscured, RefPtr<InspectorObject>&& error) mutable {
1040         if (!rect || error) {
1041             completionHandler(CommandResult::fail(WTFMove(error)));
1042             return;
1043         }
1044         if (isObscured) {
1045             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementClickIntercepted));
1046             return;
1047         }
1048         if (!inViewCenter) {
1049             completionHandler(CommandResult::fail(CommandResult::ErrorCode::ElementNotInteractable));
1050             return;
1051         }
1052
1053         performMouseInteraction(inViewCenter.value().x, inViewCenter.value().y, MouseButton::Left, MouseInteraction::SingleClick, WTFMove(completionHandler));
1054
1055         waitForNavigationToComplete(WTFMove(completionHandler));
1056     });
1057 }
1058
1059 void Session::elementClear(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1060 {
1061     if (!m_toplevelBrowsingContext) {
1062         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1063         return;
1064     }
1065
1066     RefPtr<InspectorArray> arguments = InspectorArray::create();
1067     arguments->pushString(createElement(elementID)->toJSONString());
1068
1069     RefPtr<InspectorObject> parameters = InspectorObject::create();
1070     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1071     if (m_currentBrowsingContext)
1072         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1073     parameters->setString(ASCIILiteral("function"), FormElementClearJavaScript);
1074     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1075     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1076         if (response.isError) {
1077             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1078             return;
1079         }
1080         completionHandler(CommandResult::success());
1081     });
1082 }
1083
1084 String Session::virtualKeyForKeySequence(const String& keySequence, KeyModifier& modifier)
1085 {
1086     // ยง17.4.2 Keyboard Actions.
1087     // https://www.w3.org/TR/webdriver/#keyboard-actions
1088     modifier = KeyModifier::None;
1089     switch (keySequence[0]) {
1090     case 0xE001U:
1091         return ASCIILiteral("Cancel");
1092     case 0xE002U:
1093         return ASCIILiteral("Help");
1094     case 0xE003U:
1095         return ASCIILiteral("Backspace");
1096     case 0xE004U:
1097         return ASCIILiteral("Tab");
1098     case 0xE005U:
1099         return ASCIILiteral("Clear");
1100     case 0xE006U:
1101         return ASCIILiteral("Return");
1102     case 0xE007U:
1103         return ASCIILiteral("Enter");
1104     case 0xE008U:
1105         modifier = KeyModifier::Shift;
1106         return ASCIILiteral("Shift");
1107     case 0xE009U:
1108         modifier = KeyModifier::Control;
1109         return ASCIILiteral("Control");
1110     case 0xE00AU:
1111         modifier = KeyModifier::Alternate;
1112         return ASCIILiteral("Alternate");
1113     case 0xE00BU:
1114         return ASCIILiteral("Pause");
1115     case 0xE00CU:
1116         return ASCIILiteral("Escape");
1117     case 0xE00DU:
1118         return ASCIILiteral("Space");
1119     case 0xE00EU:
1120         return ASCIILiteral("PageUp");
1121     case 0xE00FU:
1122         return ASCIILiteral("PageDown");
1123     case 0xE010U:
1124         return ASCIILiteral("End");
1125     case 0xE011U:
1126         return ASCIILiteral("Home");
1127     case 0xE012U:
1128         return ASCIILiteral("LeftArrow");
1129     case 0xE013U:
1130         return ASCIILiteral("UpArrow");
1131     case 0xE014U:
1132         return ASCIILiteral("RightArrow");
1133     case 0xE015U:
1134         return ASCIILiteral("DownArrow");
1135     case 0xE016U:
1136         return ASCIILiteral("Insert");
1137     case 0xE017U:
1138         return ASCIILiteral("Delete");
1139     case 0xE018U:
1140         return ASCIILiteral("Semicolon");
1141     case 0xE019U:
1142         return ASCIILiteral("Equals");
1143     case 0xE01AU:
1144         return ASCIILiteral("NumberPad0");
1145     case 0xE01BU:
1146         return ASCIILiteral("NumberPad1");
1147     case 0xE01CU:
1148         return ASCIILiteral("NumberPad2");
1149     case 0xE01DU:
1150         return ASCIILiteral("NumberPad3");
1151     case 0xE01EU:
1152         return ASCIILiteral("NumberPad4");
1153     case 0xE01FU:
1154         return ASCIILiteral("NumberPad5");
1155     case 0xE020U:
1156         return ASCIILiteral("NumberPad6");
1157     case 0xE021U:
1158         return ASCIILiteral("NumberPad7");
1159     case 0xE022U:
1160         return ASCIILiteral("NumberPad8");
1161     case 0xE023U:
1162         return ASCIILiteral("NumberPad9");
1163     case 0xE024U:
1164         return ASCIILiteral("NumberPadMultiply");
1165     case 0xE025U:
1166         return ASCIILiteral("NumberPadAdd");
1167     case 0xE026U:
1168         return ASCIILiteral("NumberPadSeparator");
1169     case 0xE027U:
1170         return ASCIILiteral("NumberPadSubtract");
1171     case 0xE028U:
1172         return ASCIILiteral("NumberPadDecimal");
1173     case 0xE029U:
1174         return ASCIILiteral("NumberPadDivide");
1175     case 0xE031U:
1176         return ASCIILiteral("Function1");
1177     case 0xE032U:
1178         return ASCIILiteral("Function2");
1179     case 0xE033U:
1180         return ASCIILiteral("Function3");
1181     case 0xE034U:
1182         return ASCIILiteral("Function4");
1183     case 0xE035U:
1184         return ASCIILiteral("Function5");
1185     case 0xE036U:
1186         return ASCIILiteral("Function6");
1187     case 0xE037U:
1188         return ASCIILiteral("Function7");
1189     case 0xE038U:
1190         return ASCIILiteral("Function8");
1191     case 0xE039U:
1192         return ASCIILiteral("Function9");
1193     case 0xE03AU:
1194         return ASCIILiteral("Function10");
1195     case 0xE03BU:
1196         return ASCIILiteral("Function11");
1197     case 0xE03CU:
1198         return ASCIILiteral("Function12");
1199     case 0xE03DU:
1200         modifier = KeyModifier::Meta;
1201         return ASCIILiteral("Meta");
1202     default:
1203         break;
1204     }
1205     return String();
1206 }
1207
1208 void Session::elementSendKeys(const String& elementID, Vector<String>&& keys, Function<void (CommandResult&&)>&& completionHandler)
1209 {
1210     if (!m_toplevelBrowsingContext) {
1211         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1212         return;
1213     }
1214
1215     // FIXME: move this to an atom.
1216     static const char focusScript[] =
1217         "function focus(element) {"
1218         "    var doc = element.ownerDocument || element;"
1219         "    var prevActiveElement = doc.activeElement;"
1220         "    if (element != prevActiveElement && prevActiveElement)"
1221         "        prevActiveElement.blur();"
1222         "    element.focus();"
1223         "    if (element != prevActiveElement && element.value && element.value.length && element.setSelectionRange)"
1224         "        element.setSelectionRange(element.value.length, element.value.length);"
1225         "    if (element != doc.activeElement)"
1226         "        throw new Error('cannot focus element');"
1227         "}";
1228
1229     RefPtr<InspectorArray> arguments = InspectorArray::create();
1230     arguments->pushString(createElement(elementID)->toJSONString());
1231     RefPtr<InspectorObject> parameters = InspectorObject::create();
1232     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1233     if (m_currentBrowsingContext)
1234         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1235     parameters->setString(ASCIILiteral("function"), focusScript);
1236     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1237     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), keys = WTFMove(keys), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
1238         if (response.isError || !response.responseObject) {
1239             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1240             return;
1241         }
1242
1243         unsigned stickyModifiers = 0;
1244         Vector<KeyboardInteraction> interactions;
1245         interactions.reserveInitialCapacity(keys.size());
1246         for (const auto& key : keys) {
1247             KeyboardInteraction interaction;
1248             KeyModifier modifier;
1249             auto virtualKey = virtualKeyForKeySequence(key, modifier);
1250             if (!virtualKey.isNull()) {
1251                 interaction.key = virtualKey;
1252                 if (modifier != KeyModifier::None) {
1253                     stickyModifiers ^= modifier;
1254                     if (stickyModifiers & modifier)
1255                         interaction.type = KeyboardInteractionType::KeyPress;
1256                     else
1257                         interaction.type = KeyboardInteractionType::KeyRelease;
1258                 }
1259             } else
1260                 interaction.text = key;
1261             interactions.uncheckedAppend(WTFMove(interaction));
1262         }
1263
1264         // Reset sticky modifiers if needed.
1265         if (stickyModifiers) {
1266             if (stickyModifiers & KeyModifier::Shift)
1267                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Shift")) });
1268             if (stickyModifiers & KeyModifier::Control)
1269                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Control")) });
1270             if (stickyModifiers & KeyModifier::Alternate)
1271                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Alternate")) });
1272             if (stickyModifiers & KeyModifier::Meta)
1273                 interactions.append({ KeyboardInteractionType::KeyRelease, std::nullopt, std::optional<String>(ASCIILiteral("Meta")) });
1274         }
1275
1276         performKeyboardInteractions(WTFMove(interactions), WTFMove(completionHandler));
1277     });
1278 }
1279
1280 void Session::elementSubmit(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
1281 {
1282     if (!m_toplevelBrowsingContext) {
1283         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1284         return;
1285     }
1286
1287     RefPtr<InspectorArray> arguments = InspectorArray::create();
1288     arguments->pushString(createElement(elementID)->toJSONString());
1289
1290     RefPtr<InspectorObject> parameters = InspectorObject::create();
1291     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1292     if (m_currentBrowsingContext)
1293         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1294     parameters->setString(ASCIILiteral("function"), FormSubmitJavaScript);
1295     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1296     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1297         if (response.isError) {
1298             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1299             return;
1300         }
1301         completionHandler(CommandResult::success());
1302     });
1303 }
1304
1305 RefPtr<InspectorValue> Session::handleScriptResult(RefPtr<InspectorValue>&& resultValue)
1306 {
1307     RefPtr<InspectorArray> resultArray;
1308     if (resultValue->asArray(resultArray)) {
1309         RefPtr<InspectorArray> returnValueArray = InspectorArray::create();
1310         unsigned resultArrayLength = resultArray->length();
1311         for (unsigned i = 0; i < resultArrayLength; ++i)
1312             returnValueArray->pushValue(handleScriptResult(resultArray->get(i)));
1313         return returnValueArray;
1314     }
1315
1316     if (auto element = createElement(RefPtr<InspectorValue>(resultValue)))
1317         return element;
1318
1319     RefPtr<InspectorObject> resultObject;
1320     if (resultValue->asObject(resultObject)) {
1321         RefPtr<InspectorObject> returnValueObject = InspectorObject::create();
1322         auto end = resultObject->end();
1323         for (auto it = resultObject->begin(); it != end; ++it)
1324             returnValueObject->setValue(it->key, handleScriptResult(WTFMove(it->value)));
1325         return returnValueObject;
1326     }
1327
1328     return resultValue;
1329 }
1330
1331 void Session::executeScript(const String& script, RefPtr<InspectorArray>&& argumentsArray, ExecuteScriptMode mode, Function<void (CommandResult&&)>&& completionHandler)
1332 {
1333     if (!m_toplevelBrowsingContext) {
1334         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1335         return;
1336     }
1337
1338     RefPtr<InspectorArray> arguments = InspectorArray::create();
1339     unsigned argumentsLength = argumentsArray->length();
1340     for (unsigned i = 0; i < argumentsLength; ++i) {
1341         if (auto argument = argumentsArray->get(i)) {
1342             if (auto element = extractElement(*argument))
1343                 arguments->pushString(element->toJSONString());
1344             else
1345                 arguments->pushString(argument->toJSONString());
1346         }
1347     }
1348
1349     RefPtr<InspectorObject> parameters = InspectorObject::create();
1350     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1351     if (m_currentBrowsingContext)
1352         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
1353     parameters->setString(ASCIILiteral("function"), "function(){" + script + '}');
1354     parameters->setArray(ASCIILiteral("arguments"), WTFMove(arguments));
1355     if (mode == ExecuteScriptMode::Async) {
1356         parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
1357         if (m_timeouts.script)
1358             parameters->setInteger(ASCIILiteral("callbackTimeout"), m_timeouts.script.value().millisecondsAs<int>());
1359     }
1360     m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1361         if (response.isError || !response.responseObject) {
1362             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1363             return;
1364         }
1365         String valueString;
1366         if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
1367             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1368             return;
1369         }
1370         if (valueString.isEmpty()) {
1371             completionHandler(CommandResult::success());
1372             return;
1373         }
1374         RefPtr<InspectorValue> resultValue;
1375         if (!InspectorValue::parseJSON(valueString, resultValue)) {
1376             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1377             return;
1378         }
1379         completionHandler(CommandResult::success(handleScriptResult(WTFMove(resultValue))));
1380     });
1381 }
1382
1383 void Session::performMouseInteraction(int x, int y, MouseButton button, MouseInteraction interaction, Function<void (CommandResult&&)>&& completionHandler)
1384 {
1385     RefPtr<InspectorObject> parameters = InspectorObject::create();
1386     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1387     RefPtr<InspectorObject> position = InspectorObject::create();
1388     position->setInteger(ASCIILiteral("x"), x);
1389     position->setInteger(ASCIILiteral("y"), y);
1390     parameters->setObject(ASCIILiteral("position"), WTFMove(position));
1391     switch (button) {
1392     case MouseButton::None:
1393         parameters->setString(ASCIILiteral("button"), ASCIILiteral("None"));
1394         break;
1395     case MouseButton::Left:
1396         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Left"));
1397         break;
1398     case MouseButton::Middle:
1399         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Middle"));
1400         break;
1401     case MouseButton::Right:
1402         parameters->setString(ASCIILiteral("button"), ASCIILiteral("Right"));
1403         break;
1404     }
1405     switch (interaction) {
1406     case MouseInteraction::Move:
1407         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Move"));
1408         break;
1409     case MouseInteraction::Down:
1410         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Down"));
1411         break;
1412     case MouseInteraction::Up:
1413         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("Up"));
1414         break;
1415     case MouseInteraction::SingleClick:
1416         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("SingleClick"));
1417         break;
1418     case MouseInteraction::DoubleClick:
1419         parameters->setString(ASCIILiteral("interaction"), ASCIILiteral("DoubleClick"));
1420         break;
1421     }
1422     parameters->setArray(ASCIILiteral("modifiers"), InspectorArray::create());
1423     m_host->sendCommandToBackend(ASCIILiteral("performMouseInteraction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1424         if (response.isError) {
1425             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1426             return;
1427         }
1428         completionHandler(CommandResult::success());
1429     });
1430 }
1431
1432 void Session::performKeyboardInteractions(Vector<KeyboardInteraction>&& interactions, Function<void (CommandResult&&)>&& completionHandler)
1433 {
1434     RefPtr<InspectorObject> parameters = InspectorObject::create();
1435     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
1436     RefPtr<InspectorArray> interactionsArray = InspectorArray::create();
1437     for (const auto& interaction : interactions) {
1438         RefPtr<InspectorObject> interactionObject = InspectorObject::create();
1439         switch (interaction.type) {
1440         case KeyboardInteractionType::KeyPress:
1441             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyPress"));
1442             break;
1443         case KeyboardInteractionType::KeyRelease:
1444             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("KeyRelease"));
1445             break;
1446         case KeyboardInteractionType::InsertByKey:
1447             interactionObject->setString(ASCIILiteral("type"), ASCIILiteral("InsertByKey"));
1448             break;
1449         }
1450         if (interaction.key)
1451             interactionObject->setString(ASCIILiteral("key"), interaction.key.value());
1452         if (interaction.text)
1453             interactionObject->setString(ASCIILiteral("text"), interaction.text.value());
1454         interactionsArray->pushObject(WTFMove(interactionObject));
1455     }
1456     parameters->setArray(ASCIILiteral("interactions"), WTFMove(interactionsArray));
1457     m_host->sendCommandToBackend(ASCIILiteral("performKeyboardInteractions"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1458         if (response.isError) {
1459             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1460             return;
1461         }
1462         completionHandler(CommandResult::success());
1463     });
1464 }
1465
1466 void Session::dismissAlert(Function<void (CommandResult&&)>&& completionHandler)
1467 {
1468     if (!m_toplevelBrowsingContext) {
1469         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1470         return;
1471     }
1472
1473     RefPtr<InspectorObject> parameters = InspectorObject::create();
1474     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1475     m_host->sendCommandToBackend(ASCIILiteral("dismissCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1476         if (response.isError) {
1477             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1478             return;
1479         }
1480         completionHandler(CommandResult::success());
1481     });
1482 }
1483
1484 void Session::acceptAlert(Function<void (CommandResult&&)>&& completionHandler)
1485 {
1486     if (!m_toplevelBrowsingContext) {
1487         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1488         return;
1489     }
1490
1491     RefPtr<InspectorObject> parameters = InspectorObject::create();
1492     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1493     m_host->sendCommandToBackend(ASCIILiteral("acceptCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1494         if (response.isError) {
1495             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1496             return;
1497         }
1498         completionHandler(CommandResult::success());
1499     });
1500 }
1501
1502 void Session::getAlertText(Function<void (CommandResult&&)>&& completionHandler)
1503 {
1504     if (!m_toplevelBrowsingContext) {
1505         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1506         return;
1507     }
1508
1509     RefPtr<InspectorObject> parameters = InspectorObject::create();
1510     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1511     m_host->sendCommandToBackend(ASCIILiteral("messageOfCurrentJavaScriptDialog"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1512         if (response.isError || !response.responseObject) {
1513             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1514             return;
1515         }
1516         String valueString;
1517         if (!response.responseObject->getString(ASCIILiteral("message"), valueString)) {
1518             completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
1519             return;
1520         }
1521         completionHandler(CommandResult::success(InspectorValue::create(valueString)));
1522     });
1523 }
1524
1525 void Session::sendAlertText(const String& text, Function<void (CommandResult&&)>&& completionHandler)
1526 {
1527     if (!m_toplevelBrowsingContext) {
1528         completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
1529         return;
1530     }
1531
1532     RefPtr<InspectorObject> parameters = InspectorObject::create();
1533     parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
1534     parameters->setString(ASCIILiteral("userInput"), text);
1535     m_host->sendCommandToBackend(ASCIILiteral("setUserInputForCurrentJavaScriptPrompt"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
1536         if (response.isError) {
1537             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
1538             return;
1539         }
1540         completionHandler(CommandResult::success());
1541     });
1542 }
1543
1544 } // namespace WebDriver