Skip to content

Commit

Permalink
Updated IE driver to better support W3C WebDriver Specification
Browse files Browse the repository at this point in the history
This is a large update that includes implementation of the following
things that are part of the WebDriver spec:

 * Implement the "get element property" command
 * Implement the "get named cookie" command
 * Implement the "minimize window" command
 * Implement the "fullscreen window" command
 * Update "set window rect" command to correctly recognize and restore
   from minimized or full screen state
 * Fix the "release actions" command to properly roll back all
   pending actions
 * Update the "perform actions" command to be more robust for pointer
   actions
 * Fix alert handling to handle dialogs with the "Do not show any more
   dialogs" check box
 * Added handling for the "dismiss and notify" and "accept and notify"
   user prompt handler states
  • Loading branch information
jimevans committed Aug 31, 2017
1 parent d4d8433 commit 08a118b
Show file tree
Hide file tree
Showing 44 changed files with 1,274 additions and 306 deletions.
29 changes: 25 additions & 4 deletions cpp/iedriver/Alert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,18 @@ Alert::Alert(std::tr1::shared_ptr<DocumentHost> browser, HWND handle) {
this->browser_ = browser;
this->alert_handle_ = handle;

this->is_standard_alert_ = true;
this->is_standard_control_alert_ = true;
HWND direct_ui_child = this->GetDirectUIChild();
this->is_standard_alert_ = direct_ui_child == NULL;
if (direct_ui_child) {
this->is_standard_control_alert_ = false;
DialogButtonInfo cancel_button_info = this->GetDialogButton(CANCEL);
if (cancel_button_info.button_exists) {
this->is_standard_alert_ = !IsLinkButton(cancel_button_info.button_handle);
} else {
this->is_standard_alert_ = false;
}
}

std::vector<HWND> text_boxes;
::EnumChildWindows(this->alert_handle_,
Expand Down Expand Up @@ -138,7 +148,7 @@ int Alert::SendKeysInternal(const std::string& keys,
std::string Alert::GetText() {
LOG(TRACE) << "Entering Alert::GetText";
std::string alert_text_value = "";
if (this->is_standard_alert_) {
if (this->is_standard_control_alert_) {
alert_text_value = this->GetStandardDialogText();
} else {
std::string alert_text = this->GetDirectUIDialogText();
Expand Down Expand Up @@ -325,7 +335,7 @@ HWND Alert::GetDirectUIChild() {
int Alert::ClickAlertButton(DialogButtonInfo button_info) {
LOG(TRACE) << "Entering Alert::ClickAlertButton";
// Click on the appropriate button of the Alert
if (this->is_standard_alert_) {
if (this->is_standard_control_alert_) {
::SendMessage(this->alert_handle_,
WM_COMMAND,
button_info.button_control_id,
Expand Down Expand Up @@ -432,6 +442,17 @@ bool Alert::IsCancelButton(HWND button_handle) {
return false;
}

bool Alert::IsLinkButton(HWND button_handle) {
std::vector<wchar_t> button_window_class(100);
::GetClassName(button_handle, &button_window_class[0], static_cast<int>(button_window_class.size()));
if (wcscmp(&button_window_class[0], L"Button") == 0) {
long window_long = ::GetWindowLong(button_handle, GWL_STYLE);
long button_style = window_long & BS_TYPEMASK;
return button_style == BS_COMMANDLINK;
}
return false;
}

bool Alert::IsSimpleEdit(HWND edit_handle) {
std::vector<wchar_t> child_window_class(100);
::GetClassName(edit_handle, &child_window_class[0], 100);
Expand Down Expand Up @@ -522,4 +543,4 @@ BOOL CALLBACK Alert::FindTextBoxes(HWND hwnd, LPARAM arg) {
return TRUE;
}

} // namespace webdriver
} // namespace webdriver
2 changes: 2 additions & 0 deletions cpp/iedriver/Alert.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class Alert {

static bool IsOKButton(HWND button_handle);
static bool IsCancelButton(HWND button_handle);
static bool IsLinkButton(HWND button_handle);
static bool IsSimpleEdit(HWND edit_handle);
static bool IsPasswordEdit(HWND edit_handle);
static BOOL CALLBACK FindDialogButton(HWND hwnd, LPARAM arg);
Expand All @@ -99,6 +100,7 @@ class Alert {
std::tr1::shared_ptr<DocumentHost> browser_;
bool is_standard_alert_;
bool is_security_alert_;
bool is_standard_control_alert_;
};


Expand Down
43 changes: 15 additions & 28 deletions cpp/iedriver/Browser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,33 +681,20 @@ HWND Browser::GetBrowserWindowHandle() {
return hwnd;
}

//HWND Browser::GetTabWindowHandle() {
// LOG(TRACE) << "Entering Browser::GetTabWindowHandle";
//
// HWND hwnd = NULL;
// CComPtr<IServiceProvider> service_provider;
// HRESULT hr = this->browser_->QueryInterface(IID_IServiceProvider,
// reinterpret_cast<void**>(&service_provider));
// if (SUCCEEDED(hr)) {
// CComPtr<IOleWindow> window;
// hr = service_provider->QueryService(SID_SShellBrowser,
// IID_IOleWindow,
// reinterpret_cast<void**>(&window));
// if (SUCCEEDED(hr)) {
// // This gets the TabWindowClass window in IE 7 and 8,
// // and the top-level window frame in IE 6. The window
// // we need is the InternetExplorer_Server window.
// window->GetWindow(&hwnd);
// hwnd = this->FindContentWindowHandle(hwnd);
// } else {
// LOGHR(WARN, hr) << "Unable to get window, call to IOleWindow::QueryService for SID_SShellBrowser failed";
// }
// } else {
// LOGHR(WARN, hr) << "Unable to get service, call to IWebBrowser2::QueryInterface for IID_IServiceProvider failed";
// }
//
// return hwnd;
//}
bool Browser::SetFullScreen(bool is_full_screen) {
if (is_full_screen) {
this->browser_->put_FullScreen(VARIANT_TRUE);
} else {
this->browser_->put_FullScreen(VARIANT_FALSE);
}
return true;
}

bool Browser::IsFullScreen() {
VARIANT_BOOL is_full_screen = VARIANT_FALSE;
this->browser_->get_FullScreen(&is_full_screen);
return is_full_screen == VARIANT_TRUE;
}

HWND Browser::GetActiveDialogWindowHandle() {
LOG(TRACE) << "Entering Browser::GetActiveDialogWindowHandle";
Expand Down Expand Up @@ -746,4 +733,4 @@ void Browser::CheckDialogType(HWND dialog_window_handle) {
}
}

} // namespace webdriver
} // namespace webdriver
3 changes: 3 additions & 0 deletions cpp/iedriver/Browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class Browser : public DocumentHost, public IDispEventSimpleImpl<1, Browser, &DI

bool IsValidWindow(void);

bool IsFullScreen(void);
bool SetFullScreen(bool is_full_screen);

IWebBrowser2* browser(void) { return this->browser_; }

private:
Expand Down
8 changes: 8 additions & 0 deletions cpp/iedriver/CommandHandlerRepository.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,20 @@
#include "CommandHandlers/FindChildElementsCommandHandler.h"
#include "CommandHandlers/FindElementCommandHandler.h"
#include "CommandHandlers/FindElementsCommandHandler.h"
#include "CommandHandlers/FullScreenWindowCommandHandler.h"
#include "CommandHandlers/GetActiveElementCommandHandler.h"
#include "CommandHandlers/GetAlertTextCommandHandler.h"
#include "CommandHandlers/GetAllCookiesCommandHandler.h"
#include "CommandHandlers/GetAllWindowHandlesCommandHandler.h"
#include "CommandHandlers/GetCurrentUrlCommandHandler.h"
#include "CommandHandlers/GetCurrentWindowHandleCommandHandler.h"
#include "CommandHandlers/GetElementAttributeCommandHandler.h"
#include "CommandHandlers/GetElementPropertyCommandHandler.h"
#include "CommandHandlers/GetElementRectCommandHandler.h"
#include "CommandHandlers/GetElementTagNameCommandHandler.h"
#include "CommandHandlers/GetElementTextCommandHandler.h"
#include "CommandHandlers/GetElementValueOfCssPropertyCommandHandler.h"
#include "CommandHandlers/GetNamedCookieCommandHandler.h"
#include "CommandHandlers/GetSessionCapabilitiesCommandHandler.h"
#include "CommandHandlers/GetPageSourceCommandHandler.h"
#include "CommandHandlers/GetTimeoutsCommandHandler.h"
Expand All @@ -57,6 +60,7 @@
#include "CommandHandlers/IsElementDisplayedCommandHandler.h"
#include "CommandHandlers/IsElementEnabledCommandHandler.h"
#include "CommandHandlers/IsElementSelectedCommandHandler.h"
#include "CommandHandlers/MinimizeWindowCommandHandler.h"
#include "CommandHandlers/MaximizeWindowCommandHandler.h"
#include "CommandHandlers/NewSessionCommandHandler.h"
#include "CommandHandlers/QuitCommandHandler.h"
Expand Down Expand Up @@ -124,13 +128,16 @@ void CommandHandlerRepository::PopulateCommandHandlers() {
this->command_handlers_[webdriver::CommandType::GetWindowRect] = CommandHandlerHandle(new GetWindowRectCommandHandler);
this->command_handlers_[webdriver::CommandType::SetWindowRect] = CommandHandlerHandle(new SetWindowRectCommandHandler);
this->command_handlers_[webdriver::CommandType::MaximizeWindow] = CommandHandlerHandle(new MaximizeWindowCommandHandler);
this->command_handlers_[webdriver::CommandType::MinimizeWindow] = CommandHandlerHandle(new MinimizeWindowCommandHandler);
this->command_handlers_[webdriver::CommandType::FullscreenWindow] = CommandHandlerHandle(new FullScreenWindowCommandHandler);
this->command_handlers_[webdriver::CommandType::GetActiveElement] = CommandHandlerHandle(new GetActiveElementCommandHandler);
this->command_handlers_[webdriver::CommandType::FindElement] = CommandHandlerHandle(new FindElementCommandHandler);
this->command_handlers_[webdriver::CommandType::FindElements] = CommandHandlerHandle(new FindElementsCommandHandler);
this->command_handlers_[webdriver::CommandType::FindChildElement] = CommandHandlerHandle(new FindChildElementCommandHandler);
this->command_handlers_[webdriver::CommandType::FindChildElements] = CommandHandlerHandle(new FindChildElementsCommandHandler);
this->command_handlers_[webdriver::CommandType::IsElementSelected] = CommandHandlerHandle(new IsElementSelectedCommandHandler);
this->command_handlers_[webdriver::CommandType::GetElementAttribute] = CommandHandlerHandle(new GetElementAttributeCommandHandler);
this->command_handlers_[webdriver::CommandType::GetElementProperty] = CommandHandlerHandle(new GetElementPropertyCommandHandler);
this->command_handlers_[webdriver::CommandType::GetElementValueOfCssProperty] = CommandHandlerHandle(new GetElementValueOfCssPropertyCommandHandler);
this->command_handlers_[webdriver::CommandType::GetElementText] = CommandHandlerHandle(new GetElementTextCommandHandler);
this->command_handlers_[webdriver::CommandType::GetElementTagName] = CommandHandlerHandle(new GetElementTagNameCommandHandler);
Expand All @@ -143,6 +150,7 @@ void CommandHandlerRepository::PopulateCommandHandlers() {
this->command_handlers_[webdriver::CommandType::ExecuteScript] = CommandHandlerHandle(new ExecuteScriptCommandHandler);
this->command_handlers_[webdriver::CommandType::ExecuteAsyncScript] = CommandHandlerHandle(new ExecuteAsyncScriptCommandHandler);
this->command_handlers_[webdriver::CommandType::GetAllCookies] = CommandHandlerHandle(new GetAllCookiesCommandHandler);
this->command_handlers_[webdriver::CommandType::GetNamedCookie] = CommandHandlerHandle(new GetNamedCookieCommandHandler);
this->command_handlers_[webdriver::CommandType::AddCookie] = CommandHandlerHandle(new AddCookieCommandHandler);
this->command_handlers_[webdriver::CommandType::DeleteNamedCookie] = CommandHandlerHandle(new DeleteCookieCommandHandler);
this->command_handlers_[webdriver::CommandType::DeleteAllCookies] = CommandHandlerHandle(new DeleteAllCookiesCommandHandler);
Expand Down
3 changes: 3 additions & 0 deletions cpp/iedriver/CommandHandlers/ActionsCommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ void ActionsCommandHandler::ExecuteInternal(
return;
}
status_code = executor.input_manager()->PerformInputSequence(browser_wrapper, actions_parameter_iterator->second);
if (status_code != WD_SUCCESS) {
response->SetErrorResponse(status_code, "Unexpected error performing action sequence.");
}
response->SetSuccessResponse(Json::Value::null);
}

Expand Down
62 changes: 62 additions & 0 deletions cpp/iedriver/CommandHandlers/FullScreenWindowCommandHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "FullScreenWindowCommandHandler.h"
#include "errorcodes.h"
#include "logging.h"
#include "../Browser.h"
#include "../IECommandExecutor.h"
#include "../Script.h"

namespace webdriver {

FullScreenWindowCommandHandler::FullScreenWindowCommandHandler(void) {
}

FullScreenWindowCommandHandler::~FullScreenWindowCommandHandler(void) {
}

void FullScreenWindowCommandHandler::ExecuteInternal(
const IECommandExecutor& executor,
const ParametersMap& command_parameters,
Response* response) {
int status_code = WD_SUCCESS;

BrowserHandle browser_wrapper;
status_code = executor.GetCurrentBrowser(&browser_wrapper);
if (status_code != WD_SUCCESS) {
response->SetErrorResponse(ERROR_NO_SUCH_WINDOW, "Error retrieving window");
return;
}

bool supports_full_screen = browser_wrapper->SetFullScreen(true);
if (!supports_full_screen) {
response->SetErrorResponse(ERROR_UNSUPPORTED_OPERATION,
"This version of Internet Explorer does not support setting to full screen");
}

HWND window_handle = browser_wrapper->GetTopLevelWindowHandle();
RECT window_rect;
::GetWindowRect(window_handle, &window_rect);
Json::Value response_value;
response_value["width"] = window_rect.right - window_rect.left;
response_value["height"] = window_rect.bottom - window_rect.top;
response_value["x"] = window_rect.left;
response_value["y"] = window_rect.top;
response->SetSuccessResponse(response_value);
}

} // namespace webdriver
36 changes: 36 additions & 0 deletions cpp/iedriver/CommandHandlers/FullScreenWindowCommandHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef WEBDRIVER_IE_FULLSCREENWINDOWCOMMANDHANDLER_H_
#define WEBDRIVER_IE_FULLSCREENWINDOWCOMMANDHANDLER_H_

#include "../IECommandHandler.h"

namespace webdriver {

class FullScreenWindowCommandHandler : public IECommandHandler {
public:
FullScreenWindowCommandHandler(void);
virtual ~FullScreenWindowCommandHandler(void);

protected:
void ExecuteInternal(const IECommandExecutor& executor,
const ParametersMap& command_parameters,
Response* response);
};

} // namespace webdriver

#endif // WEBDRIVER_IE_FULLSCREENWINDOWCOMMANDHANDLER_H_
81 changes: 81 additions & 0 deletions cpp/iedriver/CommandHandlers/GetElementPropertyCommandHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "GetElementPropertyCommandHandler.h"
#include "errorcodes.h"
#include "../Browser.h"
#include "../Element.h"
#include "../IECommandExecutor.h"

namespace webdriver {

GetElementPropertyCommandHandler::GetElementPropertyCommandHandler(void) {
}

GetElementPropertyCommandHandler::~GetElementPropertyCommandHandler(void) {
}

void GetElementPropertyCommandHandler::ExecuteInternal(
const IECommandExecutor& executor,
const ParametersMap& command_parameters,
Response* response) {
ParametersMap::const_iterator id_parameter_iterator = command_parameters.find("id");
ParametersMap::const_iterator name_parameter_iterator = command_parameters.find("name");
if (id_parameter_iterator == command_parameters.end()) {
response->SetErrorResponse(ERROR_INVALID_ARGUMENT, "Missing parameter in URL: id");
return;
} else if (name_parameter_iterator == command_parameters.end()) {
response->SetErrorResponse(ERROR_INVALID_ARGUMENT, "Missing parameter in URL: name");
return;
} else {
std::string element_id = id_parameter_iterator->second.asString();
std::string name = name_parameter_iterator->second.asString();

BrowserHandle browser_wrapper;
int status_code = executor.GetCurrentBrowser(&browser_wrapper);
if (status_code != WD_SUCCESS) {
response->SetErrorResponse(ERROR_NO_SUCH_WINDOW, "Unable to get browser");
return;
}

ElementHandle element_wrapper;
status_code = this->GetElement(executor, element_id, &element_wrapper);
if (status_code == WD_SUCCESS) {
std::string value = "";
bool is_null;
status_code = element_wrapper->GetPropertyValue(name,
&value,
&is_null);
if (status_code != WD_SUCCESS) {
response->SetErrorResponse(status_code, "Unable to get property");
return;
} else {
if (is_null) {
response->SetSuccessResponse(Json::Value::null);
return;
} else {
response->SetSuccessResponse(value);
return;
}
}
} else {
response->SetErrorResponse(ERROR_STALE_ELEMENT_REFERENCE, "Element is no longer valid");
return;
}
}
}

} // namespace webdriver
Loading

0 comments on commit 08a118b

Please sign in to comment.