https://bugs.webkit.org/show_bug.cgi?id=174670
Reviewed by Brian Burg.
Source/WebDriver:
We are already waiting for navigation to complete after navigation commands (go, back, forward, refresh), but
the spec says we should always wait before executing a new command and also after a click. This is causing test
testShouldBeAbleToNavigateBackInTheBrowserHistoryInPresenceOfIframes to sometimes fail, because it does .click()
+ .title and expects the title to tbe the one of the page loaded by the click. Since the load happens very fast,
the test usually passes, but in a real case with a slower load, the title of the previous page will be returned
most of the times.
6.3 Processing Model. Step 7. Wait for navigation to complete. If this returns an error return its value and
jump to step 1 in this overall algorithm, otherwise continue.
https://www.w3.org/TR/webdriver/#processing-model
14.1 Element Click. Step 10. If the click causes navigation: 1. Run the post-navigation checks and return its
value if it is an error. 2. Try to wait for navigation to complete.
https://www.w3.org/TR/webdriver/#element-click
* Session.cpp:
(WebDriver::Session::waitForNavigationToComplete): Send waitForNavigationToComplete message to the browser to
wait for any pending navigation of current browsing context to complete.
(WebDriver::Session::elementClick): Call waitForNavigationToComplete() after the click.
* Session.h:
* WebDriverService.cpp:
(WebDriver::WebDriverService::go): Wait for navigations to complete before running the command.
(WebDriver::WebDriverService::getCurrentURL): Ditto.
(WebDriver::WebDriverService::back): Ditto.
(WebDriver::WebDriverService::forward): Ditto.
(WebDriver::WebDriverService::refresh): Ditto.
(WebDriver::WebDriverService::getTitle): Ditto.
(WebDriver::WebDriverService::switchToFrame): Ditto.
(WebDriver::WebDriverService::switchToParentFrame): Ditto.
(WebDriver::WebDriverService::findElement): Ditto.
(WebDriver::WebDriverService::findElements): Ditto.
(WebDriver::WebDriverService::executeScript): Ditto.
(WebDriver::WebDriverService::executeAsyncScript): Ditto.
Source/WebKit:
Add waitForNavigationToComplete method to Automation to allow WebDriver to wait for pending navigations to
complete. The new method already receives page load strategy and timeout, but they are not implemented yet.
* UIProcess/Automation/Automation.json: Add waitForNavigationToComplete method and PageLoadStrategy new type.
* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::waitForNavigationToComplete): Call waitForNavigationToCompleteOnPage or
waitForNavigationToCompleteOnFrame depending on whether the current borwsing context is the main frame or not.
(WebKit::WebAutomationSession::waitForNavigationToCompleteOnPage): Check if there's an ongoing load for the page,
and wait for it to complete if needed.
(WebKit::WebAutomationSession::waitForNavigationToCompleteOnFrame): Check if there's an ongoing load for the frame,
and wait for it to complete if needed.
(WebKit::WebAutomationSession::navigateBrowsingContext): Use waitForNavigationToCompleteOnPage() now.
(WebKit::WebAutomationSession::goBackInBrowsingContext): Ditto.
(WebKit::WebAutomationSession::goForwardInBrowsingContext): Ditto.
(WebKit::WebAutomationSession::reloadBrowsingContext): Ditto.
(WebKit::WebAutomationSession::navigationOccurredForFrame): Renamed since it now receives the notification for
all the frames. Complete page operations if it's a main frame, or frame operations otherwise.
* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didFinishLoadForFrame): Notify about all frames, not only the main one.
(WebKit::WebPageProxy::didFailLoadForFrame): Ditto.
(WebKit::WebPageProxy::didSameDocumentNavigationForFrame): Ditto.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219722
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-07-21 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ WebDriver: wait until navigation is complete before running new commands and after a click
+ https://bugs.webkit.org/show_bug.cgi?id=174670
+
+ Reviewed by Brian Burg.
+
+ We are already waiting for navigation to complete after navigation commands (go, back, forward, refresh), but
+ the spec says we should always wait before executing a new command and also after a click. This is causing test
+ testShouldBeAbleToNavigateBackInTheBrowserHistoryInPresenceOfIframes to sometimes fail, because it does .click()
+ + .title and expects the title to tbe the one of the page loaded by the click. Since the load happens very fast,
+ the test usually passes, but in a real case with a slower load, the title of the previous page will be returned
+ most of the times.
+
+ 6.3 Processing Model. Step 7. Wait for navigation to complete. If this returns an error return its value and
+ jump to step 1 in this overall algorithm, otherwise continue.
+ https://www.w3.org/TR/webdriver/#processing-model
+
+ 14.1 Element Click. Step 10. If the click causes navigation: 1. Run the post-navigation checks and return its
+ value if it is an error. 2. Try to wait for navigation to complete.
+ https://www.w3.org/TR/webdriver/#element-click
+
+ * Session.cpp:
+ (WebDriver::Session::waitForNavigationToComplete): Send waitForNavigationToComplete message to the browser to
+ wait for any pending navigation of current browsing context to complete.
+ (WebDriver::Session::elementClick): Call waitForNavigationToComplete() after the click.
+ * Session.h:
+ * WebDriverService.cpp:
+ (WebDriver::WebDriverService::go): Wait for navigations to complete before running the command.
+ (WebDriver::WebDriverService::getCurrentURL): Ditto.
+ (WebDriver::WebDriverService::back): Ditto.
+ (WebDriver::WebDriverService::forward): Ditto.
+ (WebDriver::WebDriverService::refresh): Ditto.
+ (WebDriver::WebDriverService::getTitle): Ditto.
+ (WebDriver::WebDriverService::switchToFrame): Ditto.
+ (WebDriver::WebDriverService::switchToParentFrame): Ditto.
+ (WebDriver::WebDriverService::findElement): Ditto.
+ (WebDriver::WebDriverService::findElements): Ditto.
+ (WebDriver::WebDriverService::executeScript): Ditto.
+ (WebDriver::WebDriverService::executeAsyncScript): Ditto.
+
2017-07-21 Carlos Garcia Campos <cgarcia@igalia.com>
WebDriver: correctly handle main frame handles
});
}
+void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& completionHandler)
+{
+ if (!m_toplevelBrowsingContext) {
+ completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
+ return;
+ }
+
+ RefPtr<InspectorObject> parameters = InspectorObject::create();
+ parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
+ if (m_browsingContext)
+ parameters->setString(ASCIILiteral("frameHandle"), m_browsingContext.value());
+ m_host->sendCommandToBackend(ASCIILiteral("waitForNavigationToComplete"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
+ if (response.isError) {
+ auto result = CommandResult::fail(WTFMove(response.responseObject));
+ if (result.errorCode() == CommandResult::ErrorCode::NoSuchFrame) {
+ // Navigation destroyed the current frame, switch to top level browsing context and ignore the error.
+ switchToBrowsingContext(std::nullopt);
+ } else {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ }
+ completionHandler(CommandResult::success());
+ });
+}
+
void Session::elementClick(const String& elementID, Function<void (CommandResult&&)>&& completionHandler)
{
if (!m_toplevelBrowsingContext) {
// FIXME: the center of the bounding box is not always part of the element.
performMouseInteraction(rect.value().origin.x + rect.value().size.width / 2, rect.value().origin.y + rect.value().size.height / 2,
MouseButton::Left, MouseInteraction::SingleClick, WTFMove(completionHandler));
+
+ waitForNavigationToComplete(WTFMove(completionHandler));
});
}
std::optional<Seconds> implicit;
};
+ void waitForNavigationToComplete(Function<void (CommandResult&&)>&&);
void createTopLevelBrowsingContext(Function<void (CommandResult&&)>&&);
void close(Function<void (CommandResult&&)>&&);
void getTimeouts(Function<void (CommandResult&&)>&&);
return;
}
- session->go(url, WTFMove(completionHandler));
+ session->waitForNavigationToComplete([session, url = WTFMove(url), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ session->go(url, WTFMove(completionHandler));
+ });
}
void WebDriverService::getCurrentURL(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §9.2 Get Current URL.
// https://www.w3.org/TR/webdriver/#get-current-url
- if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
+ auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
+ if (!session)
+ return;
+
+ session->waitForNavigationToComplete([session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
session->getCurrentURL(WTFMove(completionHandler));
+ });
}
void WebDriverService::back(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §9.3 Back.
// https://www.w3.org/TR/webdriver/#back
- if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
+ auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
+ if (!session)
+ return;
+
+ session->waitForNavigationToComplete([session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
session->back(WTFMove(completionHandler));
+ });
}
void WebDriverService::forward(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §9.4 Forward.
// https://www.w3.org/TR/webdriver/#forward
- if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
+ auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
+ if (!session)
+ return;
+
+ session->waitForNavigationToComplete([session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
session->forward(WTFMove(completionHandler));
+ });
}
void WebDriverService::refresh(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §9.5 Refresh.
// https://www.w3.org/TR/webdriver/#refresh
- if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
+ auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
+ if (!session)
+ return;
+
+ session->waitForNavigationToComplete([session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
session->refresh(WTFMove(completionHandler));
+ });
}
void WebDriverService::getTitle(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §9.6 Get Title.
// https://www.w3.org/TR/webdriver/#get-title
- if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
+ auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
+ if (!session)
+ return;
+
+ session->waitForNavigationToComplete([session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
session->getTitle(WTFMove(completionHandler));
+ });
}
void WebDriverService::getWindowHandle(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
return;
}
- session->switchToFrame(WTFMove(frameID), WTFMove(completionHandler));
+ session->waitForNavigationToComplete([session, frameID, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ session->switchToFrame(WTFMove(frameID), WTFMove(completionHandler));
+ });
}
void WebDriverService::switchToParentFrame(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §10.6 Switch To Parent Frame.
// https://www.w3.org/TR/webdriver/#switch-to-parent-frame
- if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
+ auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
+ if (!session)
+ return;
+
+ session->waitForNavigationToComplete([session, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
session->switchToParentFrame(WTFMove(completionHandler));
+ });
}
static std::optional<String> findElementOrCompleteWithError(InspectorObject& parameters, Function<void (CommandResult&&)>& completionHandler)
if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, strategy, selector))
return;
- session->findElements(strategy, selector, Session::FindElementsMode::Single, emptyString(), WTFMove(completionHandler));
+ session->waitForNavigationToComplete([session, strategy = WTFMove(strategy), selector = WTFMove(selector), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ session->findElements(strategy, selector, Session::FindElementsMode::Single, emptyString(), WTFMove(completionHandler));
+ });
}
void WebDriverService::findElements(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
if (!findStrategyAndSelectorOrCompleteWithError(*parameters, completionHandler, strategy, selector))
return;
- session->findElements(strategy, selector, Session::FindElementsMode::Multiple, emptyString(), WTFMove(completionHandler));
+ session->waitForNavigationToComplete([session, strategy = WTFMove(strategy), selector = WTFMove(selector), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ session->findElements(strategy, selector, Session::FindElementsMode::Multiple, emptyString(), WTFMove(completionHandler));
+ });
}
void WebDriverService::findElementFromElement(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
if (!findScriptAndArgumentsOrCompleteWithError(*parameters, completionHandler, script, arguments))
return;
- session->executeScript(script, WTFMove(arguments), Session::ExecuteScriptMode::Sync, WTFMove(completionHandler));
+ session->waitForNavigationToComplete([session, script = WTFMove(script), arguments = WTFMove(arguments), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ session->executeScript(script, WTFMove(arguments), Session::ExecuteScriptMode::Sync, WTFMove(completionHandler));
+ });
}
void WebDriverService::executeAsyncScript(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
if (!findScriptAndArgumentsOrCompleteWithError(*parameters, completionHandler, script, arguments))
return;
- session->executeScript(script, WTFMove(arguments), Session::ExecuteScriptMode::Async, WTFMove(completionHandler));
+ session->waitForNavigationToComplete([session, script = WTFMove(script), arguments = WTFMove(arguments), completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+ if (result.isError()) {
+ completionHandler(WTFMove(result));
+ return;
+ }
+ session->executeScript(script, WTFMove(arguments), Session::ExecuteScriptMode::Async, WTFMove(completionHandler));
+ });
}
} // namespace WebDriver
+2017-07-21 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ WebDriver: wait until navigation is complete before running new commands and after a click
+ https://bugs.webkit.org/show_bug.cgi?id=174670
+
+ Reviewed by Brian Burg.
+
+ Add waitForNavigationToComplete method to Automation to allow WebDriver to wait for pending navigations to
+ complete. The new method already receives page load strategy and timeout, but they are not implemented yet.
+
+ * UIProcess/Automation/Automation.json: Add waitForNavigationToComplete method and PageLoadStrategy new type.
+ * UIProcess/Automation/WebAutomationSession.cpp:
+ (WebKit::WebAutomationSession::waitForNavigationToComplete): Call waitForNavigationToCompleteOnPage or
+ waitForNavigationToCompleteOnFrame depending on whether the current borwsing context is the main frame or not.
+ (WebKit::WebAutomationSession::waitForNavigationToCompleteOnPage): Check if there's an ongoing load for the page,
+ and wait for it to complete if needed.
+ (WebKit::WebAutomationSession::waitForNavigationToCompleteOnFrame): Check if there's an ongoing load for the frame,
+ and wait for it to complete if needed.
+ (WebKit::WebAutomationSession::navigateBrowsingContext): Use waitForNavigationToCompleteOnPage() now.
+ (WebKit::WebAutomationSession::goBackInBrowsingContext): Ditto.
+ (WebKit::WebAutomationSession::goForwardInBrowsingContext): Ditto.
+ (WebKit::WebAutomationSession::reloadBrowsingContext): Ditto.
+ (WebKit::WebAutomationSession::navigationOccurredForFrame): Renamed since it now receives the notification for
+ all the frames. Complete page operations if it's a main frame, or frame operations otherwise.
+ * UIProcess/Automation/WebAutomationSession.h:
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::didFinishLoadForFrame): Notify about all frames, not only the main one.
+ (WebKit::WebPageProxy::didFailLoadForFrame): Ditto.
+ (WebKit::WebPageProxy::didSameDocumentNavigationForFrame): Ditto.
+
2017-07-20 Carlos Garcia Campos <cgarcia@igalia.com>
Unreviewed. Remove WKIconDatabaseCairo.
"InvalidSelector"
]
},
+ {
+ "id": "PageLoadStrategy",
+ "type": "string",
+ "description": "Enumerates different page load strategies.",
+ "enum": [
+ "None",
+ "Eager",
+ "Normal"
+ ]
+ },
{
"id": "BrowsingContext",
"type": "object",
],
"async": true
},
+ {
+ "name": "waitForNavigationToComplete",
+ "description": "Wait for pending navigation to complete.",
+ "parameters": [
+ { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context in which wait for pending navigation to complete." },
+ { "name": "frameHandle", "$ref": "FrameHandle", "optional": true, "description": "The handle for the frame in which wait for pending navigation to complete. The main frame is used if this parameter empty string or excluded." },
+ { "name": "pageLoadStrategy", "$ref": "PageLoadStrategy", "optional": true, "description": "The page load strategy to use when determining when navigation is complete." },
+ { "name": "pageLoadTimeout", "type": "integer", "optional": true, "description": "The timeout in milliseconds that the navigation is expected to be completed in, otherwise a <code>Timeout</code> error is returned." }
+ ],
+ "async": true
+ },
{
"name": "inspectBrowsingContext",
"description": "Inspect the specified browsing context using Web Inspector.",
#endif
}
-void WebAutomationSession::navigateBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String& url, Ref<NavigateBrowsingContextCallback>&& callback)
+void WebAutomationSession::waitForNavigationToComplete(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String* optionalFrameHandle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<WaitForNavigationToCompleteCallback>&& callback)
{
- WebPageProxy* page = webPageProxyForHandle(handle);
+ WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
if (!page)
FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
- if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(page->pageID()))
+ // FIXME: Implement page load strategy and timeout.
+
+ if (optionalFrameHandle && !optionalFrameHandle->isEmpty()) {
+ std::optional<uint64_t> frameID = webFrameIDForHandle(*optionalFrameHandle);
+ if (!frameID)
+ FAIL_WITH_PREDEFINED_ERROR(FrameNotFound);
+ WebFrameProxy* frame = page->process().webFrame(frameID.value());
+ if (!frame)
+ FAIL_WITH_PREDEFINED_ERROR(FrameNotFound);
+ waitForNavigationToCompleteOnFrame(*frame, WTFMove(callback));
+ } else
+ waitForNavigationToCompleteOnPage(*page, WTFMove(callback));
+}
+
+void WebAutomationSession::waitForNavigationToCompleteOnPage(WebPageProxy& page, Ref<Inspector::BackendDispatcher::CallbackBase>&& callback)
+{
+ if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(page.pageID()))
+ callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
+
+ if (!page.pageLoadState().isLoading()) {
+ callback->sendSuccess(InspectorObject::create());
+ return;
+ }
+
+ m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page.pageID(), WTFMove(callback));
+}
+
+void WebAutomationSession::waitForNavigationToCompleteOnFrame(WebFrameProxy& frame, Ref<Inspector::BackendDispatcher::CallbackBase>&& callback)
+{
+ if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerFrame.take(frame.frameID()))
callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
- m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page->pageID(), WTFMove(callback));
+
+ if (frame.frameLoadState().state() == FrameLoadState::State::Finished) {
+ callback->sendSuccess(InspectorObject::create());
+ return;
+ }
+
+ m_pendingNavigationInBrowsingContextCallbacksPerFrame.set(frame.frameID(), WTFMove(callback));
+}
+
+void WebAutomationSession::navigateBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String& url, Ref<NavigateBrowsingContextCallback>&& callback)
+{
+ WebPageProxy* page = webPageProxyForHandle(handle);
+ if (!page)
+ FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
page->loadRequest(WebCore::URL(WebCore::URL(), url));
+ waitForNavigationToCompleteOnPage(*page, WTFMove(callback));
}
void WebAutomationSession::goBackInBrowsingContext(Inspector::ErrorString& errorString, const String& handle, Ref<GoBackInBrowsingContextCallback>&& callback)
if (!page)
FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
- if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(page->pageID()))
- callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
-
- if (page->goBack())
- m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page->pageID(), WTFMove(callback));
- else
- callback->sendSuccess();
+ page->goBack();
+ waitForNavigationToCompleteOnPage(*page, WTFMove(callback));
}
void WebAutomationSession::goForwardInBrowsingContext(Inspector::ErrorString& errorString, const String& handle, Ref<GoForwardInBrowsingContextCallback>&& callback)
if (!page)
FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
- if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(page->pageID()))
- callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
-
- if (page->goForward())
- m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page->pageID(), WTFMove(callback));
- else
- callback->sendSuccess();
+ page->goForward();
+ waitForNavigationToCompleteOnPage(*page, WTFMove(callback));
}
void WebAutomationSession::reloadBrowsingContext(Inspector::ErrorString& errorString, const String& handle, Ref<ReloadBrowsingContextCallback>&& callback)
if (!page)
FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
- if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(page->pageID()))
- callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
- m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page->pageID(), WTFMove(callback));
-
page->reload({ });
+ waitForNavigationToCompleteOnPage(*page, WTFMove(callback));
}
-void WebAutomationSession::navigationOccurredForPage(const WebPageProxy& page)
+void WebAutomationSession::navigationOccurredForFrame(const WebFrameProxy& frame)
{
- if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(page.pageID()))
- callback->sendSuccess(InspectorObject::create());
+ if (frame.isMainFrame()) {
+ if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(frame.page()->pageID()))
+ callback->sendSuccess(InspectorObject::create());
+ } else {
+ if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerFrame.take(frame.frameID()))
+ callback->sendSuccess(InspectorObject::create());
+ }
}
void WebAutomationSession::inspectorFrontendLoaded(const WebPageProxy& page)
WebProcessPool* processPool() const { return m_processPool; }
void setProcessPool(WebProcessPool*);
- void navigationOccurredForPage(const WebPageProxy&);
+ void navigationOccurredForFrame(const WebFrameProxy&);
void inspectorFrontendLoaded(const WebPageProxy&);
void keyboardEventsFlushedForPage(const WebPageProxy&);
void goBackInBrowsingContext(Inspector::ErrorString&, const String&, Ref<GoBackInBrowsingContextCallback>&&) override;
void goForwardInBrowsingContext(Inspector::ErrorString&, const String&, Ref<GoForwardInBrowsingContextCallback>&&) override;
void reloadBrowsingContext(Inspector::ErrorString&, const String&, Ref<ReloadBrowsingContextCallback>&&) override;
+ void waitForNavigationToComplete(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<WaitForNavigationToCompleteCallback>&&) 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, Ref<PerformKeyboardInteractionsCallback>&&) override;
String handleForWebFrameID(uint64_t frameID);
String handleForWebFrameProxy(const WebFrameProxy&);
+ void waitForNavigationToCompleteOnPage(WebPageProxy&, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
+ void waitForNavigationToCompleteOnFrame(WebFrameProxy&, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
+
// Implemented in generated WebAutomationSessionMessageReceiver.cpp.
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
HashMap<String, uint64_t> m_handleWebFrameMap;
HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNavigationInBrowsingContextCallbacksPerPage;
+ HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNavigationInBrowsingContextCallbacksPerFrame;
HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingInspectorCallbacksPerPage;
HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingKeyboardEventsFlushedCallbacksPerPage;
if (isMainFrame)
m_pageLoadState.didFinishLoad(transaction);
- if (isMainFrame && m_controlledByAutomation) {
+ if (m_controlledByAutomation) {
if (auto* automationSession = process().processPool().automationSession())
- automationSession->navigationOccurredForPage(*this);
+ automationSession->navigationOccurredForFrame(*frame);
}
frame->didFinishLoad();
if (isMainFrame)
m_pageLoadState.didFailLoad(transaction);
- if (isMainFrame && m_controlledByAutomation) {
+ if (m_controlledByAutomation) {
if (auto* automationSession = process().processPool().automationSession())
- automationSession->navigationOccurredForPage(*this);
+ automationSession->navigationOccurredForFrame(*frame);
}
frame->didFailLoad();
if (isMainFrame)
m_pageLoadState.didSameDocumentNavigation(transaction, url);
- if (isMainFrame && m_controlledByAutomation) {
+ if (m_controlledByAutomation) {
if (auto* automationSession = process().processPool().automationSession())
- automationSession->navigationOccurredForPage(*this);
+ automationSession->navigationOccurredForFrame(*frame);
}
m_pageLoadState.clearPendingAPIRequestURL(transaction);