diff --git a/Source/WebDriver/ChangeLog b/Source/WebDriver/ChangeLog index ee13f4accb77..81e96d31a9e5 100644 --- a/Source/WebDriver/ChangeLog +++ b/Source/WebDriver/ChangeLog @@ -1,3 +1,30 @@ +2017-09-19 Carlos Garcia Campos + + WebDriver: Implement commands to get and set the window rect + https://bugs.webkit.org/show_bug.cgi?id=177134 + + Reviewed by Brian Burg. + + We are currently implementing the selenium legacy ones, we should implement the w3c ones instead. + + https://w3c.github.io/webdriver/webdriver-spec.html#resizing-and-positioning-windows + + * Session.cpp: + (WebDriver::Session::getToplevelBrowsingContextRect): Helper to get the window rect. This is used by both get + and set window rect commands. + (WebDriver::Session::moveToplevelBrowsingContextwindow): Helper to ask automation to move the window. + (WebDriver::Session::resizeToplevelBrowsingContextwindow): Helper to ask automation to resize the window. + (WebDriver::Session::getWindowRect): Handle prompts and then call getToplevelBrowsingContextRect(). + (WebDriver::Session::setWindowRect): Handle prompts and then move and resize the window according to the given + parameters and finish the operation calling getToplevelBrowsingContextRect(). + * Session.h: + * WebDriverService.cpp: + (WebDriver::WebDriverService::getWindowRect): Ask the session to get the window rect. + (WebDriver::valueAsNumberInRange): Helper to check a value is a valid number in the given range. + (WebDriver::WebDriverService::setWindowRect): Get and check size and position from parameters and then ask the + session to set the window rect. + * WebDriverService.h: + 2017-09-19 Carlos Garcia Campos WebDriver: wrong response in case of errors diff --git a/Source/WebDriver/Session.cpp b/Source/WebDriver/Session.cpp index 5eceb9c5c415..44c7e93afbc2 100644 --- a/Source/WebDriver/Session.cpp +++ b/Source/WebDriver/Session.cpp @@ -636,13 +636,8 @@ void Session::switchToParentFrame(Function&& completionH }); } -void Session::getWindowPosition(Function&& completionHandler) +void Session::getToplevelBrowsingContextRect(Function&& completionHandler) { - if (!m_toplevelBrowsingContext) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow)); - return; - } - RefPtr parameters = InspectorObject::create(); parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value()); m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) { @@ -656,26 +651,37 @@ void Session::getWindowPosition(Function&& completionHan return; } RefPtr windowOrigin; - if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)) { + double x, y; + if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin) + || !windowOrigin->getDouble(ASCIILiteral("x"), x) + || !windowOrigin->getDouble(ASCIILiteral("y"), y)) { completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError)); return; } - completionHandler(CommandResult::success(WTFMove(windowOrigin))); + RefPtr windowSize; + double width, height; + if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize) + || !windowSize->getDouble(ASCIILiteral("width"), width) + || !windowSize->getDouble(ASCIILiteral("height"), width)) { + completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError)); + return; + } + auto windowRect = InspectorObject::create(); + windowRect->setDouble(ASCIILiteral("x"), x); + windowRect->setDouble(ASCIILiteral("y"), y); + windowRect->setDouble(ASCIILiteral("width"), width); + windowRect->setDouble(ASCIILiteral("height"), height); + completionHandler(CommandResult::success(WTFMove(windowRect))); }); } -void Session::setWindowPosition(int windowX, int windowY, Function&& completionHandler) +void Session::moveToplevelBrowsingContextWindow(double x, double y, Function&& completionHandler) { - if (!m_toplevelBrowsingContext) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow)); - return; - } - RefPtr parameters = InspectorObject::create(); parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value()); RefPtr windowOrigin = InspectorObject::create(); - windowOrigin->setInteger("x", windowX); - windowOrigin->setInteger("y", windowY); + windowOrigin->setDouble("x", x); + windowOrigin->setDouble("y", y); parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin)); m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) { if (response.isError) { @@ -686,53 +692,86 @@ void Session::setWindowPosition(int windowX, int windowY, Function&& completionHandler) +void Session::resizeToplevelBrowsingContextWindow(double width, double height, Function&& completionHandler) { - if (!m_toplevelBrowsingContext) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow)); - return; - } - RefPtr parameters = InspectorObject::create(); parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value()); - m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) { - if (response.isError || !response.responseObject) { + RefPtr windowSize = InspectorObject::create(); + windowSize->setDouble("width", width); + windowSize->setDouble("height", height); + parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize)); + m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) { + if (response.isError) { completionHandler(CommandResult::fail(WTFMove(response.responseObject))); return; } - RefPtr browsingContext; - if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError)); - return; - } - RefPtr windowSize; - if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError)); + completionHandler(CommandResult::success()); + }); +} + +void Session::getWindowRect(Function&& completionHandler) +{ + if (!m_toplevelBrowsingContext) { + completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow)); + return; + } + + handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { + if (result.isError()) { + completionHandler(WTFMove(result)); return; } - completionHandler(CommandResult::success(WTFMove(windowSize))); + getToplevelBrowsingContextRect(WTFMove(completionHandler)); }); } -void Session::setWindowSize(int windowWidth, int windowHeight, Function&& completionHandler) +void Session::setWindowRect(std::optional x, std::optional y, std::optional width, std::optional height, Function&& completionHandler) { if (!m_toplevelBrowsingContext) { completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow)); return; } - RefPtr parameters = InspectorObject::create(); - parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value()); - RefPtr windowSize = InspectorObject::create(); - windowSize->setInteger("width", windowWidth); - windowSize->setInteger("height", windowHeight); - parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize)); - m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) { - if (response.isError) { - completionHandler(CommandResult::fail(WTFMove(response.responseObject))); + handleUserPrompts([this, x, y, width, height, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { + if (result.isError()) { + completionHandler(WTFMove(result)); return; } - completionHandler(CommandResult::success()); + + if (width && height) { + resizeToplevelBrowsingContextWindow(width.value(), height.value(), [this, x, y, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { + if (result.isError()) { + completionHandler(WTFMove(result)); + return; + } + if (!x || !y) { + getToplevelBrowsingContextRect(WTFMove(completionHandler)); + return; + } + + moveToplevelBrowsingContextWindow(x.value(), y.value(), [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { + if (result.isError()) { + completionHandler(WTFMove(result)); + return; + } + getToplevelBrowsingContextRect(WTFMove(completionHandler)); + }); + }); + return; + } + + if (x && y) { + moveToplevelBrowsingContextWindow(x.value(), y.value(), [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable { + if (result.isError()) { + completionHandler(WTFMove(result)); + return; + } + getToplevelBrowsingContextRect(WTFMove(completionHandler)); + }); + return; + } + + getToplevelBrowsingContextRect(WTFMove(completionHandler)); }); } diff --git a/Source/WebDriver/Session.h b/Source/WebDriver/Session.h index 68cae7eb97c6..e5c3e47abf74 100644 --- a/Source/WebDriver/Session.h +++ b/Source/WebDriver/Session.h @@ -87,10 +87,8 @@ class Session : public RefCounted { void getWindowHandles(Function&&); void switchToFrame(RefPtr&&, Function&&); void switchToParentFrame(Function&&); - void getWindowPosition(Function&&); - void setWindowPosition(int windowX, int windowY, Function&&); - void getWindowSize(Function&&); - void setWindowSize(int windowWidth, int windowHeight, Function&&); + void getWindowRect(Function&&); + void setWindowRect(std::optional x, std::optional y, std::optional width, std::optional height, Function&&); void findElements(const String& strategy, const String& selector, FindElementsMode, const String& rootElementID, Function&&); void isElementSelected(const String& elementID, Function&&); void getElementText(const String& elementID, Function&&); @@ -123,6 +121,10 @@ class Session : public RefCounted { void closeTopLevelBrowsingContext(const String& toplevelBrowsingContext, Function&&); void closeAllToplevelBrowsingContexts(const String& toplevelBrowsingContext, Function&&); + void getToplevelBrowsingContextRect(Function&&); + void moveToplevelBrowsingContextWindow(double x, double y, Function&&); + void resizeToplevelBrowsingContextWindow(double width, double height, Function&&); + std::optional pageLoadStrategyString() const; void handleUserPrompts(Function&&); diff --git a/Source/WebDriver/WebDriverService.cpp b/Source/WebDriver/WebDriverService.cpp index cb745c55e95e..5eec2f0e0e74 100644 --- a/Source/WebDriver/WebDriverService.cpp +++ b/Source/WebDriver/WebDriverService.cpp @@ -118,12 +118,8 @@ const WebDriverService::Command WebDriverService::s_commands[] = { { HTTPMethod::Get, "/session/$sessionId/window/handles", &WebDriverService::getWindowHandles }, { HTTPMethod::Post, "/session/$sessionId/frame", &WebDriverService::switchToFrame }, { HTTPMethod::Post, "/session/$sessionId/frame/parent", &WebDriverService::switchToParentFrame }, - - // FIXME: Not in the spec, but still used by Selenium. - { HTTPMethod::Get, "/session/$sessionId/window/position", &WebDriverService::getWindowPosition }, - { HTTPMethod::Post, "/session/$sessionId/window/position", &WebDriverService::setWindowPosition }, - { HTTPMethod::Get, "/session/$sessionId/window/size", &WebDriverService::getWindowSize }, - { HTTPMethod::Post, "/session/$sessionId/window/size", &WebDriverService::setWindowSize }, + { HTTPMethod::Get, "/session/$sessionId/window/rect", &WebDriverService::getWindowRect }, + { HTTPMethod::Post, "/session/$sessionId/window/rect", &WebDriverService::setWindowRect }, { HTTPMethod::Post, "/session/$sessionId/element", &WebDriverService::findElement }, { HTTPMethod::Post, "/session/$sessionId/elements", &WebDriverService::findElements }, @@ -799,58 +795,76 @@ void WebDriverService::getWindowHandle(RefPtr&& parameters, Fun session->getWindowHandle(WTFMove(completionHandler)); } -void WebDriverService::getWindowPosition(RefPtr&& parameters, Function&& completionHandler) +void WebDriverService::getWindowRect(RefPtr&& parameters, Function&& completionHandler) { + // §10.7.1 Get Window Rect. + // https://w3c.github.io/webdriver/webdriver-spec.html#get-window-rect if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler)) - session->getWindowPosition(WTFMove(completionHandler)); + session->getWindowRect(WTFMove(completionHandler)); } -void WebDriverService::setWindowPosition(RefPtr&& parameters, Function&& completionHandler) +static std::optional valueAsNumberInRange(const InspectorValue& value, double minAllowed = 0, double maxAllowed = INT_MAX) { - auto session = findSessionOrCompleteWithError(*parameters, completionHandler); - if (!session) - return; - - int windowX; - if (!parameters->getInteger(ASCIILiteral("x"), windowX)) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); - return; - } + double number; + if (!value.asDouble(number)) + return std::nullopt; - int windowY; - if (!parameters->getInteger(ASCIILiteral("y"), windowY)) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); - return; - } + if (std::isnan(number) || std::isinf(number)) + return std::nullopt; - session->setWindowPosition(windowX, windowY, WTFMove(completionHandler)); -} + if (number < minAllowed || number > maxAllowed) + return std::nullopt; -void WebDriverService::getWindowSize(RefPtr&& parameters, Function&& completionHandler) -{ - if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler)) - session->getWindowSize(WTFMove(completionHandler)); + return number; } -void WebDriverService::setWindowSize(RefPtr&& parameters, Function&& completionHandler) +void WebDriverService::setWindowRect(RefPtr&& parameters, Function&& completionHandler) { - auto session = findSessionOrCompleteWithError(*parameters, completionHandler); - if (!session) - return; - - int windowWidth; - if (!parameters->getInteger(ASCIILiteral("width"), windowWidth)) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); - return; + // §10.7.2 Set Window Rect. + // https://w3c.github.io/webdriver/webdriver-spec.html#set-window-rect + RefPtr value; + std::optional width; + if (parameters->getValue(ASCIILiteral("width"), value)) { + if (auto number = valueAsNumberInRange(*value)) + width = number; + else if (!value->isNull()) { + completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); + return; + } } - - int windowHeight; - if (!parameters->getInteger(ASCIILiteral("height"), windowHeight)) { - completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); - return; + std::optional height; + if (parameters->getValue(ASCIILiteral("height"), value)) { + if (auto number = valueAsNumberInRange(*value)) + height = number; + else if (!value->isNull()) { + completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); + return; + } + } + std::optional x; + if (parameters->getValue(ASCIILiteral("x"), value)) { + if (auto number = valueAsNumberInRange(*value, INT_MIN)) + x = number; + else if (!value->isNull()) { + completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); + return; + } + } + std::optional y; + if (parameters->getValue(ASCIILiteral("y"), value)) { + if (auto number = valueAsNumberInRange(*value, INT_MIN)) + y = number; + else if (!value->isNull()) { + completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument)); + return; + } } - session->setWindowSize(windowWidth, windowHeight, WTFMove(completionHandler)); + // FIXME: If the remote end does not support the Set Window Rect command for the current + // top-level browsing context for any reason, return error with error code unsupported operation. + + if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler)) + session->setWindowRect(x, y, width, height, WTFMove(completionHandler)); } void WebDriverService::closeWindow(RefPtr&& parameters, Function&& completionHandler) diff --git a/Source/WebDriver/WebDriverService.h b/Source/WebDriver/WebDriverService.h index 0e02cf2a75e2..fe8735805357 100644 --- a/Source/WebDriver/WebDriverService.h +++ b/Source/WebDriver/WebDriverService.h @@ -79,10 +79,8 @@ class WebDriverService final : public HTTPRequestHandler { void getWindowHandles(RefPtr&&, Function&&); void switchToFrame(RefPtr&&, Function&&); void switchToParentFrame(RefPtr&&, Function&&); - void getWindowPosition(RefPtr&&, Function&&); - void setWindowPosition(RefPtr&&, Function&&); - void getWindowSize(RefPtr&&, Function&&); - void setWindowSize(RefPtr&&, Function&&); + void getWindowRect(RefPtr&&, Function&&); + void setWindowRect(RefPtr&&, Function&&); void findElement(RefPtr&&, Function&&); void findElements(RefPtr&&, Function&&); void findElementFromElement(RefPtr&&, Function&&);