WebDriver: Implement page load strategy
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Aug 2017 11:14:34 +0000 (11:14 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 5 Aug 2017 11:14:34 +0000 (11:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175183

Reviewed by Brian Burg.

Source/WebDriver:

Validate and parse page load strategy when processing capabilities.

* Capabilities.h:
* Session.cpp:
(WebDriver::Session::pageLoadStrategyString const): Helper to get the page load strategy as a String to be
passed to Automation.
(WebDriver::Session::go): Pass page load strategy if present.
(WebDriver::Session::back): Ditto.
(WebDriver::Session::forward): Ditto.
(WebDriver::Session::refresh): Ditto.
(WebDriver::Session::waitForNavigationToComplete): Ditto.
* Session.h:
* WebDriverService.cpp:
(WebDriver::deserializePageLoadStrategy):
(WebDriver::WebDriverService::parseCapabilities const):
(WebDriver::WebDriverService::validatedCapabilities const):
(WebDriver::WebDriverService::newSession):

Source/WebKit:

Split pending navigation maps into normal and eager, and use one or the other depending on the received page
load strategy. We need to keep different maps for every page load strategy because every command could use a
different strategy.

* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::waitForNavigationToComplete): Extract page load strategy from parameter and pass
it to waitForNavigationToCompleteOnPage() and waitForNavigationToCompleteOnFrame().
(WebKit::WebAutomationSession::waitForNavigationToCompleteOnPage): Return early if page load strategy is
none. Otherwise at the pening callback to the normal or eager map depeding on the page load straegy.
(WebKit::WebAutomationSession::waitForNavigationToCompleteOnFrame): Ditto.
(WebKit::respondToPendingNavigationCallbacksWithTimeout): Helper to send pening navigation callback in case of
timeout failure.
(WebKit::WebAutomationSession::loadTimerFired): Call finishPendingNavigationsWithTimeoutFailure() with all the maps.
(WebKit::WebAutomationSession::navigateBrowsingContext): Extract page load strategy from parameter and pass it
to waitForNavigationToCompleteOnPage().
(WebKit::WebAutomationSession::goBackInBrowsingContext): Ditto.
(WebKit::WebAutomationSession::goForwardInBrowsingContext): Ditto.
(WebKit::WebAutomationSession::reloadBrowsingContext): Ditto.
(WebKit::WebAutomationSession::navigationOccurredForFrame): Use the normal maps.
(WebKit::WebAutomationSession::documentLoadedForFrame): Stop timeout timer and dispatch eager pending navigations.
* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didFinishDocumentLoadForFrame): Notify the automation session.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@220317 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebDriver/Capabilities.h
Source/WebDriver/ChangeLog
Source/WebDriver/Session.cpp
Source/WebDriver/Session.h
Source/WebDriver/WebDriverService.cpp
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp
Source/WebKit/UIProcess/Automation/WebAutomationSession.h
Source/WebKit/UIProcess/WebPageProxy.cpp

index 17552d4..e11573d 100644 (file)
@@ -38,12 +38,19 @@ struct Timeouts {
     std::optional<Seconds> implicit;
 };
 
+enum class PageLoadStrategy {
+    None,
+    Normal,
+    Eager
+};
+
 struct Capabilities {
     std::optional<String> browserName;
     std::optional<String> browserVersion;
     std::optional<String> platformName;
     std::optional<bool> acceptInsecureCerts;
     std::optional<Timeouts> timeouts;
+    std::optional<PageLoadStrategy> pageLoadStrategy;
 #if PLATFORM(GTK)
     std::optional<String> browserBinary;
     std::optional<Vector<String>> browserArguments;
index 55e04fa..5f49170 100644 (file)
@@ -1,5 +1,30 @@
 2017-08-05  Carlos Garcia Campos  <cgarcia@igalia.com>
 
+        WebDriver: Implement page load strategy
+        https://bugs.webkit.org/show_bug.cgi?id=175183
+
+        Reviewed by Brian Burg.
+
+        Validate and parse page load strategy when processing capabilities.
+
+        * Capabilities.h:
+        * Session.cpp:
+        (WebDriver::Session::pageLoadStrategyString const): Helper to get the page load strategy as a String to be
+        passed to Automation.
+        (WebDriver::Session::go): Pass page load strategy if present.
+        (WebDriver::Session::back): Ditto.
+        (WebDriver::Session::forward): Ditto.
+        (WebDriver::Session::refresh): Ditto.
+        (WebDriver::Session::waitForNavigationToComplete): Ditto.
+        * Session.h:
+        * WebDriverService.cpp:
+        (WebDriver::deserializePageLoadStrategy):
+        (WebDriver::WebDriverService::parseCapabilities const):
+        (WebDriver::WebDriverService::validatedCapabilities const):
+        (WebDriver::WebDriverService::newSession):
+
+2017-08-05  Carlos Garcia Campos  <cgarcia@igalia.com>
+
         Unreviewed. Try to fix build with clang after r220315.
 
         * WebDriverService.cpp:
index 8a8f105..52b4227 100644 (file)
@@ -102,6 +102,23 @@ void Session::switchToBrowsingContext(std::optional<String> browsingContext)
         m_currentBrowsingContext = browsingContext;
 }
 
+std::optional<String> Session::pageLoadStrategyString() const
+{
+    if (!capabilities().pageLoadStrategy)
+        return std::nullopt;
+
+    switch (capabilities().pageLoadStrategy.value()) {
+    case PageLoadStrategy::None:
+        return String("None");
+    case PageLoadStrategy::Normal:
+        return String("Normal");
+    case PageLoadStrategy::Eager:
+        return String("Eager");
+    }
+
+    return std::nullopt;
+}
+
 void Session::createTopLevelBrowsingContext(Function<void (CommandResult&&)>&& completionHandler)
 {
     ASSERT(!m_toplevelBrowsingContext.value());
@@ -134,6 +151,8 @@ void Session::go(const String& url, Function<void (CommandResult&&)>&& completio
     parameters->setString(ASCIILiteral("url"), url);
     if (m_timeouts.pageLoad)
         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
+    if (auto pageLoadStrategy = pageLoadStrategyString())
+        parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
     m_host->sendCommandToBackend(ASCIILiteral("navigateBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
         if (response.isError) {
             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
@@ -183,6 +202,8 @@ void Session::back(Function<void (CommandResult&&)>&& completionHandler)
     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
     if (m_timeouts.pageLoad)
         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
+    if (auto pageLoadStrategy = pageLoadStrategyString())
+        parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
     m_host->sendCommandToBackend(ASCIILiteral("goBackInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
         if (response.isError) {
             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
@@ -204,6 +225,8 @@ void Session::forward(Function<void (CommandResult&&)>&& completionHandler)
     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
     if (m_timeouts.pageLoad)
         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
+    if (auto pageLoadStrategy = pageLoadStrategyString())
+        parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
     m_host->sendCommandToBackend(ASCIILiteral("goForwardInBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
         if (response.isError) {
             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
@@ -225,6 +248,8 @@ void Session::refresh(Function<void (CommandResult&&)>&& completionHandler)
     parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
     if (m_timeouts.pageLoad)
         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
+    if (auto pageLoadStrategy = pageLoadStrategyString())
+        parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.value());
     m_host->sendCommandToBackend(ASCIILiteral("reloadBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
         if (response.isError) {
             completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
@@ -981,6 +1006,8 @@ void Session::waitForNavigationToComplete(Function<void (CommandResult&&)>&& com
         parameters->setString(ASCIILiteral("frameHandle"), m_currentBrowsingContext.value());
     if (m_timeouts.pageLoad)
         parameters->setInteger(ASCIILiteral("pageLoadTimeout"), m_timeouts.pageLoad.value().millisecondsAs<int>());
+    if (auto pageLoadStrategy = pageLoadStrategyString())
+        parameters->setString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy.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));
index fad861a..9e0d7cf 100644 (file)
@@ -101,6 +101,8 @@ private:
     void switchToTopLevelBrowsingContext(std::optional<String>);
     void switchToBrowsingContext(std::optional<String>);
 
+    std::optional<String> pageLoadStrategyString() const;
+
     RefPtr<Inspector::InspectorObject> createElement(RefPtr<Inspector::InspectorValue>&&);
     RefPtr<Inspector::InspectorObject> createElement(const String& elementID);
     RefPtr<Inspector::InspectorObject> extractElement(Inspector::InspectorValue&);
index 40d2453..c08803e 100644 (file)
@@ -277,6 +277,17 @@ static std::optional<Timeouts> deserializeTimeouts(InspectorObject& timeoutsObje
     return timeouts;
 }
 
+static std::optional<PageLoadStrategy> deserializePageLoadStrategy(const String& pageLoadStrategy)
+{
+    if (pageLoadStrategy == "none")
+        return PageLoadStrategy::None;
+    if (pageLoadStrategy == "normal")
+        return PageLoadStrategy::Normal;
+    if (pageLoadStrategy == "eager")
+        return PageLoadStrategy::Eager;
+    return std::nullopt;
+}
+
 void WebDriverService::parseCapabilities(const InspectorObject& matchedCapabilities, Capabilities& capabilities) const
 {
     // Matched capabilities have already been validated.
@@ -295,6 +306,9 @@ void WebDriverService::parseCapabilities(const InspectorObject& matchedCapabilit
     RefPtr<InspectorObject> timeouts;
     if (matchedCapabilities.getObject(ASCIILiteral("timeouts"), timeouts))
         capabilities.timeouts = deserializeTimeouts(*timeouts);
+    String pageLoadStrategy;
+    if (matchedCapabilities.getString(ASCIILiteral("pageLoadStrategy"), pageLoadStrategy))
+        capabilities.pageLoadStrategy = deserializePageLoadStrategy(pageLoadStrategy);
     platformParseCapabilities(matchedCapabilities, capabilities);
 }
 
@@ -336,9 +350,8 @@ RefPtr<InspectorObject> WebDriverService::validatedCapabilities(const InspectorO
             result->setString(it->key, stringValue);
         } else if (it->key == "pageLoadStrategy") {
             String pageLoadStrategy;
-            if (!it->value->asString(pageLoadStrategy))
+            if (!it->value->asString(pageLoadStrategy) || !deserializePageLoadStrategy(pageLoadStrategy))
                 return nullptr;
-            // FIXME: implement pageLoadStrategy.
             result->setString(it->key, pageLoadStrategy);
         } else if (it->key == "proxy") {
             // FIXME: implement proxy support.
@@ -560,6 +573,19 @@ void WebDriverService::newSession(RefPtr<InspectorObject>&& parameters, Function
                     timeoutsObject->setInteger(ASCIILiteral("implicit"), capabilities.timeouts.value().implicit.value().millisecondsAs<int>());
                 capabilitiesObject->setObject(ASCIILiteral("timeouts"), WTFMove(timeoutsObject));
             }
+            if (capabilities.pageLoadStrategy) {
+                switch (capabilities.pageLoadStrategy.value()) {
+                case PageLoadStrategy::None:
+                    capabilitiesObject->setString(ASCIILiteral("pageLoadStrategy"), "none");
+                    break;
+                case PageLoadStrategy::Normal:
+                    capabilitiesObject->setString(ASCIILiteral("pageLoadStrategy"), "normal");
+                    break;
+                case PageLoadStrategy::Eager:
+                    capabilitiesObject->setString(ASCIILiteral("pageLoadStrategy"), "eager");
+                    break;
+                }
+            }
             resultObject->setObject(ASCIILiteral("value"), WTFMove(capabilitiesObject));
             completionHandler(CommandResult::success(WTFMove(resultObject)));
         });
index fa0098f..549038e 100644 (file)
@@ -1,5 +1,36 @@
 2017-08-05  Carlos Garcia Campos  <cgarcia@igalia.com>
 
+        WebDriver: Implement page load strategy
+        https://bugs.webkit.org/show_bug.cgi?id=175183
+
+        Reviewed by Brian Burg.
+
+        Split pending navigation maps into normal and eager, and use one or the other depending on the received page
+        load strategy. We need to keep different maps for every page load strategy because every command could use a
+        different strategy.
+
+        * UIProcess/Automation/WebAutomationSession.cpp:
+        (WebKit::WebAutomationSession::waitForNavigationToComplete): Extract page load strategy from parameter and pass
+        it to waitForNavigationToCompleteOnPage() and waitForNavigationToCompleteOnFrame().
+        (WebKit::WebAutomationSession::waitForNavigationToCompleteOnPage): Return early if page load strategy is
+        none. Otherwise at the pening callback to the normal or eager map depeding on the page load straegy.
+        (WebKit::WebAutomationSession::waitForNavigationToCompleteOnFrame): Ditto.
+        (WebKit::respondToPendingNavigationCallbacksWithTimeout): Helper to send pening navigation callback in case of
+        timeout failure.
+        (WebKit::WebAutomationSession::loadTimerFired): Call finishPendingNavigationsWithTimeoutFailure() with all the maps.
+        (WebKit::WebAutomationSession::navigateBrowsingContext): Extract page load strategy from parameter and pass it
+        to waitForNavigationToCompleteOnPage().
+        (WebKit::WebAutomationSession::goBackInBrowsingContext): Ditto.
+        (WebKit::WebAutomationSession::goForwardInBrowsingContext): Ditto.
+        (WebKit::WebAutomationSession::reloadBrowsingContext): Ditto.
+        (WebKit::WebAutomationSession::navigationOccurredForFrame): Use the normal maps.
+        (WebKit::WebAutomationSession::documentLoadedForFrame): Stop timeout timer and dispatch eager pending navigations.
+        * UIProcess/Automation/WebAutomationSession.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didFinishDocumentLoadForFrame): Notify the automation session.
+
+2017-08-05  Carlos Garcia Campos  <cgarcia@igalia.com>
+
         WebDriver: use in-view center point for clicks instead of bounding box center point
         https://bugs.webkit.org/show_bug.cgi?id=174863
 
index 7f6d6cd..41a50f7 100644 (file)
@@ -54,6 +54,8 @@ namespace WebKit {
 // ยง8. Sessions
 // https://www.w3.org/TR/webdriver/#dfn-session-page-load-timeout
 static const Seconds defaultPageLoadTimeout = 300_s;
+// https://www.w3.org/TR/webdriver/#dfn-page-loading-strategy
+static const Inspector::Protocol::Automation::PageLoadStrategy defaultPageLoadStrategy = Inspector::Protocol::Automation::PageLoadStrategy::Normal;
 
 WebAutomationSession::WebAutomationSession()
     : m_client(std::make_unique<API::AutomationSessionClient>())
@@ -385,15 +387,27 @@ void WebAutomationSession::moveWindowOfBrowsingContext(Inspector::ErrorString& e
 #endif
 }
 
+static std::optional<Inspector::Protocol::Automation::PageLoadStrategy> pageLoadStrategyFromStringParameter(const String* optionalPageLoadStrategyString)
+{
+    if (!optionalPageLoadStrategyString)
+        return defaultPageLoadStrategy;
+
+    auto parsedPageLoadStrategy = Inspector::Protocol::AutomationHelpers::parseEnumValueFromString<Inspector::Protocol::Automation::PageLoadStrategy>(*optionalPageLoadStrategyString);
+    if (!parsedPageLoadStrategy)
+        return std::nullopt;
+    return parsedPageLoadStrategy;
+}
+
 void WebAutomationSession::waitForNavigationToComplete(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String* optionalFrameHandle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<WaitForNavigationToCompleteCallback>&& callback)
 {
     WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
 
-    // FIXME: Implement page load strategy.
-
-    Seconds pageLoadTimeout = optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout;
+    auto pageLoadStrategy = pageLoadStrategyFromStringParameter(optionalPageLoadStrategyString);
+    if (!pageLoadStrategy)
+        FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "The parameter 'pageLoadStrategy' is invalid.");
+    auto pageLoadTimeout = optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout;
 
     if (optionalFrameHandle && !optionalFrameHandle->isEmpty()) {
         std::optional<uint64_t> frameID = webFrameIDForHandle(*optionalFrameHandle);
@@ -402,57 +416,82 @@ void WebAutomationSession::waitForNavigationToComplete(Inspector::ErrorString& e
         WebFrameProxy* frame = page->process().webFrame(frameID.value());
         if (!frame)
             FAIL_WITH_PREDEFINED_ERROR(FrameNotFound);
-        waitForNavigationToCompleteOnFrame(*frame, pageLoadTimeout, WTFMove(callback));
+        waitForNavigationToCompleteOnFrame(*frame, pageLoadStrategy.value(), pageLoadTimeout, WTFMove(callback));
     } else
-        waitForNavigationToCompleteOnPage(*page, pageLoadTimeout, WTFMove(callback));
+        waitForNavigationToCompleteOnPage(*page, pageLoadStrategy.value(), pageLoadTimeout, WTFMove(callback));
 }
 
-void WebAutomationSession::waitForNavigationToCompleteOnPage(WebPageProxy& page, Seconds timeout, Ref<Inspector::BackendDispatcher::CallbackBase>&& callback)
+void WebAutomationSession::waitForNavigationToCompleteOnPage(WebPageProxy& page, Inspector::Protocol::Automation::PageLoadStrategy loadStrategy, Seconds timeout, Ref<Inspector::BackendDispatcher::CallbackBase>&& callback)
 {
     ASSERT(!m_loadTimer.isActive());
-    if (!page.pageLoadState().isLoading()) {
+    if (loadStrategy == Inspector::Protocol::Automation::PageLoadStrategy::None || !page.pageLoadState().isLoading()) {
         callback->sendSuccess(InspectorObject::create());
         return;
     }
 
     m_loadTimer.startOneShot(timeout);
-    m_pendingNavigationInBrowsingContextCallbacksPerPage.set(page.pageID(), WTFMove(callback));
+    switch (loadStrategy) {
+    case Inspector::Protocol::Automation::PageLoadStrategy::Normal:
+        m_pendingNormalNavigationInBrowsingContextCallbacksPerPage.set(page.pageID(), WTFMove(callback));
+        break;
+    case Inspector::Protocol::Automation::PageLoadStrategy::Eager:
+        m_pendingEagerNavigationInBrowsingContextCallbacksPerPage.set(page.pageID(), WTFMove(callback));
+        break;
+    case Inspector::Protocol::Automation::PageLoadStrategy::None:
+        ASSERT_NOT_REACHED();
+    }
 }
 
-void WebAutomationSession::waitForNavigationToCompleteOnFrame(WebFrameProxy& frame, Seconds timeout, Ref<Inspector::BackendDispatcher::CallbackBase>&& callback)
+void WebAutomationSession::waitForNavigationToCompleteOnFrame(WebFrameProxy& frame, Inspector::Protocol::Automation::PageLoadStrategy loadStrategy, Seconds timeout, Ref<Inspector::BackendDispatcher::CallbackBase>&& callback)
 {
     ASSERT(!m_loadTimer.isActive());
-    if (frame.frameLoadState().state() == FrameLoadState::State::Finished) {
+    if (loadStrategy == Inspector::Protocol::Automation::PageLoadStrategy::None || frame.frameLoadState().state() == FrameLoadState::State::Finished) {
         callback->sendSuccess(InspectorObject::create());
         return;
     }
 
     m_loadTimer.startOneShot(timeout);
-    m_pendingNavigationInBrowsingContextCallbacksPerFrame.set(frame.frameID(), WTFMove(callback));
+    switch (loadStrategy) {
+    case Inspector::Protocol::Automation::PageLoadStrategy::Normal:
+        m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame.set(frame.frameID(), WTFMove(callback));
+        break;
+    case Inspector::Protocol::Automation::PageLoadStrategy::Eager:
+        m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame.set(frame.frameID(), WTFMove(callback));
+        break;
+    case Inspector::Protocol::Automation::PageLoadStrategy::None:
+        ASSERT_NOT_REACHED();
+    }
 }
 
-void WebAutomationSession::loadTimerFired()
+static void respondToPendingNavigationCallbacksWithTimeout(HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>>& map)
 {
-    for (auto frameID : m_pendingNavigationInBrowsingContextCallbacksPerFrame.keys()) {
-        auto callback = m_pendingNavigationInBrowsingContextCallbacksPerFrame.take(frameID);
-        callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
-    }
-    for (auto pageID : m_pendingNavigationInBrowsingContextCallbacksPerPage.keys()) {
-        auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(pageID);
+    for (auto id : map.keys()) {
+        auto callback = map.take(id);
         callback->sendFailure(STRING_FOR_PREDEFINED_ERROR_NAME(Timeout));
     }
 }
 
+void WebAutomationSession::loadTimerFired()
+{
+    respondToPendingNavigationCallbacksWithTimeout(m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame);
+    respondToPendingNavigationCallbacksWithTimeout(m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame);
+    respondToPendingNavigationCallbacksWithTimeout(m_pendingNormalNavigationInBrowsingContextCallbacksPerPage);
+    respondToPendingNavigationCallbacksWithTimeout(m_pendingEagerNavigationInBrowsingContextCallbacksPerPage);
+}
+
 void WebAutomationSession::navigateBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String& url, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<NavigateBrowsingContextCallback>&& callback)
 {
     WebPageProxy* page = webPageProxyForHandle(handle);
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
 
-    // FIXME: Implement page load strategy.
+    auto pageLoadStrategy = pageLoadStrategyFromStringParameter(optionalPageLoadStrategyString);
+    if (!pageLoadStrategy)
+        FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "The parameter 'pageLoadStrategy' is invalid.");
+    auto pageLoadTimeout = optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout;
 
     page->loadRequest(WebCore::URL(WebCore::URL(), url));
-    waitForNavigationToCompleteOnPage(*page, optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout, WTFMove(callback));
+    waitForNavigationToCompleteOnPage(*page, pageLoadStrategy.value(), pageLoadTimeout, WTFMove(callback));
 }
 
 void WebAutomationSession::goBackInBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoBackInBrowsingContextCallback>&& callback)
@@ -461,10 +500,13 @@ void WebAutomationSession::goBackInBrowsingContext(Inspector::ErrorString& error
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
 
-    // FIXME: Implement page load strategy.
+    auto pageLoadStrategy = pageLoadStrategyFromStringParameter(optionalPageLoadStrategyString);
+    if (!pageLoadStrategy)
+        FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "The parameter 'pageLoadStrategy' is invalid.");
+    auto pageLoadTimeout = optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout;
 
     page->goBack();
-    waitForNavigationToCompleteOnPage(*page, optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout, WTFMove(callback));
+    waitForNavigationToCompleteOnPage(*page, pageLoadStrategy.value(), pageLoadTimeout, WTFMove(callback));
 }
 
 void WebAutomationSession::goForwardInBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoForwardInBrowsingContextCallback>&& callback)
@@ -473,10 +515,13 @@ void WebAutomationSession::goForwardInBrowsingContext(Inspector::ErrorString& er
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
 
-    // FIXME: Implement page load strategy.
+    auto pageLoadStrategy = pageLoadStrategyFromStringParameter(optionalPageLoadStrategyString);
+    if (!pageLoadStrategy)
+        FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "The parameter 'pageLoadStrategy' is invalid.");
+    auto pageLoadTimeout = optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout;
 
     page->goForward();
-    waitForNavigationToCompleteOnPage(*page, optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout, WTFMove(callback));
+    waitForNavigationToCompleteOnPage(*page, pageLoadStrategy.value(), pageLoadTimeout, WTFMove(callback));
 }
 
 void WebAutomationSession::reloadBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<ReloadBrowsingContextCallback>&& callback)
@@ -485,10 +530,13 @@ void WebAutomationSession::reloadBrowsingContext(Inspector::ErrorString& errorSt
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
 
-    // FIXME: Implement page load strategy.
+    auto pageLoadStrategy = pageLoadStrategyFromStringParameter(optionalPageLoadStrategyString);
+    if (!pageLoadStrategy)
+        FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "The parameter 'pageLoadStrategy' is invalid.");
+    auto pageLoadTimeout = optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout;
 
     page->reload({ });
-    waitForNavigationToCompleteOnPage(*page, optionalPageLoadTimeout ? Seconds::fromMilliseconds(*optionalPageLoadTimeout) : defaultPageLoadTimeout, WTFMove(callback));
+    waitForNavigationToCompleteOnPage(*page, pageLoadStrategy.value(), pageLoadTimeout, WTFMove(callback));
 }
 
 void WebAutomationSession::navigationOccurredForFrame(const WebFrameProxy& frame)
@@ -497,13 +545,28 @@ void WebAutomationSession::navigationOccurredForFrame(const WebFrameProxy& frame
         // New page loaded, clear frame handles previously cached.
         m_handleWebFrameMap.clear();
         m_webFrameHandleMap.clear();
-        if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerPage.take(frame.page()->pageID())) {
+        if (auto callback = m_pendingNormalNavigationInBrowsingContextCallbacksPerPage.take(frame.page()->pageID())) {
             m_loadTimer.stop();
             callback->sendSuccess(InspectorObject::create());
         }
         m_domainNotifier->browsingContextCleared(handleForWebPageProxy(*frame.page()));
     } else {
-        if (auto callback = m_pendingNavigationInBrowsingContextCallbacksPerFrame.take(frame.frameID())) {
+        if (auto callback = m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame.take(frame.frameID())) {
+            m_loadTimer.stop();
+            callback->sendSuccess(InspectorObject::create());
+        }
+    }
+}
+
+void WebAutomationSession::documentLoadedForFrame(const WebFrameProxy& frame)
+{
+    if (frame.isMainFrame()) {
+        if (auto callback = m_pendingEagerNavigationInBrowsingContextCallbacksPerPage.take(frame.page()->pageID())) {
+            m_loadTimer.stop();
+            callback->sendSuccess(InspectorObject::create());
+        }
+    } else {
+        if (auto callback = m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame.take(frame.frameID())) {
             m_loadTimer.stop();
             callback->sendSuccess(InspectorObject::create());
         }
index c9ce901..95275c6 100644 (file)
@@ -94,6 +94,7 @@ public:
     void setProcessPool(WebProcessPool*);
 
     void navigationOccurredForFrame(const WebFrameProxy&);
+    void documentLoadedForFrame(const WebFrameProxy&);
     void inspectorFrontendLoaded(const WebPageProxy&);
     void keyboardEventsFlushedForPage(const WebPageProxy&);
     void willClosePage(const WebPageProxy&);
@@ -163,8 +164,8 @@ private:
     String handleForWebFrameID(uint64_t frameID);
     String handleForWebFrameProxy(const WebFrameProxy&);
 
-    void waitForNavigationToCompleteOnPage(WebPageProxy&, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
-    void waitForNavigationToCompleteOnFrame(WebFrameProxy&, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
+    void waitForNavigationToCompleteOnPage(WebPageProxy&, Inspector::Protocol::Automation::PageLoadStrategy, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
+    void waitForNavigationToCompleteOnFrame(WebFrameProxy&, Inspector::Protocol::Automation::PageLoadStrategy, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
     void loadTimerFired();
 
     // Implemented in generated WebAutomationSessionMessageReceiver.cpp.
@@ -212,8 +213,10 @@ private:
     HashMap<uint64_t, String> m_webFrameHandleMap;
     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_pendingNormalNavigationInBrowsingContextCallbacksPerPage;
+    HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerPage;
+    HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame;
+    HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame;
     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingInspectorCallbacksPerPage;
     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingKeyboardEventsFlushedCallbacksPerPage;
 
index 5a2a633..8b03472 100644 (file)
@@ -3369,6 +3369,11 @@ void WebPageProxy::didFinishDocumentLoadForFrame(uint64_t frameID, uint64_t navi
     WebFrameProxy* frame = m_process->webFrame(frameID);
     MESSAGE_CHECK(frame);
 
+    if (m_controlledByAutomation) {
+        if (auto* automationSession = process().processPool().automationSession())
+            automationSession->documentLoadedForFrame(*frame);
+    }
+
     // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
     RefPtr<API::Navigation> navigation;
     if (frame->isMainFrame() && navigationID)