Web Automation: All key events should be processed before sending response
https://bugs.webkit.org/show_bug.cgi?id=160114
<rdar://problem/27505943>
Reviewed by Darin Adler.
When evaluating performKeyboardInteractions, we were sending all
NSEvents synchronously, but because WebPageProxy was doing its
own queueing and asynchronous processing of those key events, we
would receive and respond to the next Automation command before
having completed all of the key events.
This change makes performKeyboardInteractions asynchronous. It
will be notified only after WebPageProxy has exhausted its queue
of key events.
* UIProcess/Automation/Automation.json:
* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::keyboardEventsFlushedForPage):
(WebKit::WebAutomationSession::evaluateJavaScriptFunction):
(WebKit::WebAutomationSession::performKeyboardInteractions):
* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didReceiveEvent):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@203635 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebKit2/UIProcess/Automation/Automation.json b/Source/WebKit2/UIProcess/Automation/Automation.json
index e8fad27..46ccea8 100644
--- a/Source/WebKit2/UIProcess/Automation/Automation.json
+++ b/Source/WebKit2/UIProcess/Automation/Automation.json
@@ -339,7 +339,8 @@
"parameters": [
{ "name": "handle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context which should receive key." },
{ "name": "interactions", "type": "array", "items": { "$ref": "KeyboardInteraction" }, "description": "An ordered list of key sequences to be delivered using native key events." }
- ]
+ ],
+ "async": true
},
{
"name": "takeScreenshot",
diff --git a/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp b/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp
index 27291ff..27b1f16 100644
--- a/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp
+++ b/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp
@@ -464,6 +464,12 @@
callback->sendSuccess(InspectorObject::create());
}
+void WebAutomationSession::keyboardEventsFlushedForPage(const WebPageProxy& page)
+{
+ if (auto callback = m_pendingKeyboardEventsFlushedCallbacksPerPage.take(page.pageID()))
+ callback->sendSuccess(InspectorObject::create());
+}
+
void WebAutomationSession::evaluateJavaScriptFunction(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String* optionalFrameHandle, const String& function, const Inspector::InspectorArray& arguments, const bool* optionalExpectsImplicitCallbackArgument, const int* optionalCallbackTimeout, Ref<EvaluateJavaScriptFunctionCallback>&& callback)
{
WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
@@ -923,7 +929,7 @@
#endif // USE(APPKIT)
}
-void WebAutomationSession::performKeyboardInteractions(ErrorString& errorString, const String& handle, const Inspector::InspectorArray& interactions)
+void WebAutomationSession::performKeyboardInteractions(ErrorString& errorString, const String& handle, const Inspector::InspectorArray& interactions, Ref<PerformKeyboardInteractionsCallback>&& callback)
{
#if !USE(APPKIT)
FAIL_WITH_PREDEFINED_ERROR(NotImplemented);
@@ -985,9 +991,16 @@
}
ASSERT(actionsToPerform.size());
+ if (!actionsToPerform.size())
+ FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InternalError, "No actions to perform.");
+
+ auto& callbackInMap = m_pendingKeyboardEventsFlushedCallbacksPerPage.add(page->pageID(), nullptr).iterator->value;
+ if (callbackInMap)
+ callbackInMap->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
+ callbackInMap = WTFMove(callback);
+
for (auto& action : actionsToPerform)
action();
-
#endif // USE(APPKIT)
}
diff --git a/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h b/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h
index b612f56..384af65 100644
--- a/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h
+++ b/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h
@@ -84,6 +84,7 @@
void navigationOccurredForPage(const WebPageProxy&);
void inspectorFrontendLoaded(const WebPageProxy&);
+ void keyboardEventsFlushedForPage(const WebPageProxy&);
#if ENABLE(REMOTE_INSPECTOR)
// Inspector::RemoteAutomationTarget API
@@ -108,7 +109,7 @@
void inspectBrowsingContext(Inspector::ErrorString&, const String&, const bool* optionalEnableAutoCapturing, Ref<InspectBrowsingContextCallback>&&) override;
void evaluateJavaScriptFunction(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle, const String& function, const Inspector::InspectorArray& arguments, const bool* optionalExpectsImplicitCallbackArgument, const int* optionalCallbackTimeout, Ref<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>&&) override;
void performMouseInteraction(Inspector::ErrorString&, const String& handle, const Inspector::InspectorObject& requestedPosition, const String& mouseButton, const String& mouseInteraction, const Inspector::InspectorArray& keyModifiers, RefPtr<Inspector::Protocol::Automation::Point>& updatedPosition) override;
- void performKeyboardInteractions(Inspector::ErrorString&, const String& handle, const Inspector::InspectorArray& interactions) override;
+ void performKeyboardInteractions(Inspector::ErrorString&, const String& handle, const Inspector::InspectorArray& interactions, Ref<PerformKeyboardInteractionsCallback>&&) override;
void takeScreenshot(Inspector::ErrorString&, const String& handle, Ref<Inspector::AutomationBackendDispatcherHandler::TakeScreenshotCallback>&&) override;
void resolveChildFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle, const int* optionalOrdinal, const String* optionalName, const String* optionalNodeHandle, Ref<ResolveChildFrameHandleCallback>&&) override;
void resolveParentFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&&) override;
@@ -177,8 +178,8 @@
HashMap<String, uint64_t> m_handleWebFrameMap;
HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNavigationInBrowsingContextCallbacksPerPage;
-
HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingInspectorCallbacksPerPage;
+ HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingKeyboardEventsFlushedCallbacksPerPage;
uint64_t m_nextEvaluateJavaScriptCallbackID { 1 };
HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>> m_evaluateJavaScriptFunctionCallbacks;
diff --git a/Source/WebKit2/UIProcess/WebPageProxy.cpp b/Source/WebKit2/UIProcess/WebPageProxy.cpp
index dcc0e38..1c967cb 100644
--- a/Source/WebKit2/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit2/UIProcess/WebPageProxy.cpp
@@ -4857,6 +4857,10 @@
if (!m_keyEventQueue.isEmpty())
m_process->send(Messages::WebPage::KeyEvent(m_keyEventQueue.first()), m_pageID);
+ else {
+ if (auto* automationSession = process().processPool().automationSession())
+ automationSession->keyboardEventsFlushedForPage(*this);
+ }
// The call to doneWithKeyEvent may close this WebPage.
// Protect against this being destroyed.