summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-19 01:39:04 +0000
committerkkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-19 01:39:04 +0000
commitc3a44d60fb7d03edbb55dd49efb7a41041065833 (patch)
treed8bf6a690af05fc4bb4ecba932ce9531b4372918
parent44574ee7d6da72dd47d4d16187a6176e12863ab7 (diff)
downloadchromium_src-c3a44d60fb7d03edbb55dd49efb7a41041065833.zip
chromium_src-c3a44d60fb7d03edbb55dd49efb7a41041065833.tar.gz
chromium_src-c3a44d60fb7d03edbb55dd49efb7a41041065833.tar.bz2
Fix minor issues in chromedriver dealing with design mode, frame switching,
and opacity. Also, clean up some of the error messages. BUG=88685,88686,88810,88957 TEST=none Review URL: http://codereview.chromium.org/7347010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92946 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/test/webdriver/commands/execute_async_script_command.cc2
-rw-r--r--chrome/test/webdriver/commands/execute_command.cc2
-rw-r--r--chrome/test/webdriver/commands/response.cc2
-rw-r--r--chrome/test/webdriver/commands/webelement_commands.cc3
-rw-r--r--chrome/test/webdriver/session.cc62
-rw-r--r--chrome/test/webdriver/session.h1
-rw-r--r--chrome/test/webdriver/test/chromedriver_tests.py110
-rw-r--r--chrome/test/webdriver/test/content_editable.html11
-rw-r--r--chrome/test/webdriver/test/design_mode_doc.html9
-rw-r--r--chrome/test/webdriver/test/switch_to_frame_by_index.html10
-rw-r--r--chrome/test/webdriver/test/transparent.html12
-rw-r--r--chrome/test/webdriver/webdriver_error.cc49
-rw-r--r--chrome/test/webdriver/webdriver_error.h3
13 files changed, 213 insertions, 63 deletions
diff --git a/chrome/test/webdriver/commands/execute_async_script_command.cc b/chrome/test/webdriver/commands/execute_async_script_command.cc
index cf3ec1a..b0e9aaf 100644
--- a/chrome/test/webdriver/commands/execute_async_script_command.cc
+++ b/chrome/test/webdriver/commands/execute_async_script_command.cc
@@ -41,7 +41,7 @@ void ExecuteAsyncScriptCommand::ExecutePost(Response* const response) {
Error* error = session_->ExecuteAsyncScript(
session_->current_target(), script, args, &result);
if (error) {
- error->AddDetails("Original script: " + script);
+ error->AddDetails("Script execution failed. Script: " + script);
response->SetError(error);
return;
}
diff --git a/chrome/test/webdriver/commands/execute_command.cc b/chrome/test/webdriver/commands/execute_command.cc
index 044d0d0..65ec162 100644
--- a/chrome/test/webdriver/commands/execute_command.cc
+++ b/chrome/test/webdriver/commands/execute_command.cc
@@ -40,7 +40,7 @@ void ExecuteCommand::ExecutePost(Response* const response) {
Value* result = NULL;
Error* error = session_->ExecuteScript(script, args, &result);
if (error) {
- error->AddDetails("Original script: " + script);
+ error->AddDetails("Script execution failed. Script: " + script);
response->SetError(error);
return;
}
diff --git a/chrome/test/webdriver/commands/response.cc b/chrome/test/webdriver/commands/response.cc
index 0060fa0..6b96bae 100644
--- a/chrome/test/webdriver/commands/response.cc
+++ b/chrome/test/webdriver/commands/response.cc
@@ -59,7 +59,7 @@ void Response::SetValue(Value* value) {
void Response::SetError(Error* error) {
DictionaryValue* error_dict = new DictionaryValue();
- error_dict->SetString(kMessageKey, error->ToString());
+ error_dict->SetString(kMessageKey, error->GetMessage());
SetStatus(error->code());
SetValue(error_dict);
diff --git a/chrome/test/webdriver/commands/webelement_commands.cc b/chrome/test/webdriver/commands/webelement_commands.cc
index 0ea0c01..561bd53 100644
--- a/chrome/test/webdriver/commands/webelement_commands.cc
+++ b/chrome/test/webdriver/commands/webelement_commands.cc
@@ -161,7 +161,8 @@ bool ElementDisplayedCommand::DoesGet() {
void ElementDisplayedCommand::ExecuteGet(Response* const response) {
bool is_displayed;
Error* error = session_->IsElementDisplayed(
- session_->current_target(), element, &is_displayed);
+ session_->current_target(), element, false /* ignore_opacity */,
+ &is_displayed);
if (error) {
response->SetError(error);
return;
diff --git a/chrome/test/webdriver/session.cc b/chrome/test/webdriver/session.cc
index e59e7b8..e6c30a4 100644
--- a/chrome/test/webdriver/session.cc
+++ b/chrome/test/webdriver/session.cc
@@ -150,7 +150,8 @@ Error* Session::ExecuteAsyncScript(const FrameId& frame_id,
Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
bool is_displayed = false;
- Error* error = IsElementDisplayed(current_target_, element, &is_displayed);
+ Error* error = IsElementDisplayed(
+ current_target_, element, true /* ignore_opacity */, &is_displayed);
if (error)
return error;
if (!is_displayed)
@@ -165,28 +166,36 @@ Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
ListValue args;
args.Append(element.ToValue());
- // Focus the element if not focused already. If it is an editable element,
- // focus the editing host element instead. Descendants of an editing host
- // element cannot be focused in chrome.
- // See http://www.w3.org/TR/html5/editing.html#attr-contenteditable.
+ // Focus the target element in order to send keys to it.
+ // First, the currently active element is blurred, if it is different from
+ // the target element. We do not want to blur an element unnecessarily,
+ // because this may cause us to lose the current cursor position in the
+ // element.
+ // Secondly, we focus the target element.
+ // Thirdly, we check if the new active element is the target element. If not,
+ // we throw an error.
+ // Additional notes:
+ // - |document.activeElement| is the currently focused element, or body if
+ // no element is focused
+ // - Even if |document.hasFocus()| returns true and the active element is
+ // the body, sometimes we still need to focus the body element for send
+ // keys to work. Not sure why
+ // - You cannot focus a descendant of a content editable node
// TODO(jleyba): Update this to use the correct atom.
const char* kFocusScript =
"var elem = arguments[0];"
- "if (elem.isContentEditable) {"
- " while (elem.parentNode && elem.parentNode.isContentEditable)"
- " elem = elem.parentNode;"
- "}"
- "if (elem != document.activeElement) {"
- " if(document.activeElement)"
- " document.activeElement.blur();"
- " elem.focus();"
- "}";
+ "var doc = elem.ownerDocument || elem;"
+ "var prevActiveElem = doc.activeElement;"
+ "if (elem != prevActiveElem && prevActiveElem)"
+ " prevActiveElem.blur();"
+ "elem.focus();"
+ "if (elem != doc.activeElement)"
+ " throw new Error('Failed to send keys because cannot focus element.');";
Value* unscoped_result = NULL;
error = ExecuteScript(kFocusScript, &args, &unscoped_result);
- if (error) {
- error->AddDetails("Failed to focus element before sending keys");
+ if (error)
return error;
- }
+
error = NULL;
RunSessionTask(NewRunnableMethod(
this,
@@ -523,6 +532,7 @@ Error* Session::SwitchToWindow(const std::string& name) {
if (!switch_to_id)
return new Error(kNoSuchWindow);
+ frame_elements_.clear();
current_target_ = FrameId(switch_to_id, FramePath());
return NULL;
}
@@ -564,7 +574,7 @@ Error* Session::SwitchToFrameWithIndex(int index) {
"console.info(frame == null ? 'found nothing' : frame);"
"if (!frame) { return null; }"
"frame_xpath = ((frame.tagName == 'IFRAME' ? "
- " '/html/body//iframe' : '/html/frameset/frame') + index);"
+ " '(/html/body//iframe)' : '/html/frameset/frame') + index);"
"return [frame, frame_xpath];";
ListValue args;
args.Append(Value::CreateIntegerValue(index));
@@ -923,11 +933,13 @@ Error* Session::GetElementBorder(const FrameId& frame_id,
Error* Session::IsElementDisplayed(const FrameId& frame_id,
const WebElementId& element,
+ bool ignore_opacity,
bool* is_displayed) {
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::IS_DISPLAYED);
ListValue args;
args.Append(element.ToValue());
+ args.Append(Value::CreateBooleanValue(ignore_opacity));
Value* unscoped_result = NULL;
Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
@@ -996,7 +1008,8 @@ Error* Session::GetElementTagName(const FrameId& frame_id,
Error* Session::GetClickableLocation(const WebElementId& element,
gfx::Point* location) {
bool is_displayed = false;
- Error* error = IsElementDisplayed(current_target_, element, &is_displayed);
+ Error* error = IsElementDisplayed(
+ current_target_, element, true /* ignore_opacity */, &is_displayed);
if (error)
return error;
if (!is_displayed)
@@ -1163,12 +1176,11 @@ Error* Session::ExecuteScriptAndParseResponse(const FrameId& frame_id,
ErrorCode code = static_cast<ErrorCode>(status);
if (code != kSuccess) {
DictionaryValue* error_dict;
- std::string error_msg = "Script threw an exception";
- if (result_dict->GetDictionary("value", &error_dict)) {
- std::string exception;
- if (error_dict->GetString("message", &exception))
- error_msg += ": " + exception;
- }
+ std::string error_msg;
+ if (result_dict->GetDictionary("value", &error_dict))
+ error_dict->GetString("message", &error_msg);
+ if (error_msg.empty())
+ error_msg = "Script failed with error code: " + base::IntToString(code);
return new Error(code, error_msg);
}
diff --git a/chrome/test/webdriver/session.h b/chrome/test/webdriver/session.h
index 3842f00..9409029 100644
--- a/chrome/test/webdriver/session.h
+++ b/chrome/test/webdriver/session.h
@@ -243,6 +243,7 @@ class Session {
// Gets whether the element is currently displayed.
Error* IsElementDisplayed(const FrameId& frame_id,
const WebElementId& element,
+ bool ignore_opacity,
bool* is_visible);
// Gets whether the element is currently enabled.
diff --git a/chrome/test/webdriver/test/chromedriver_tests.py b/chrome/test/webdriver/test/chromedriver_tests.py
index c50ae9b..65a2887 100644
--- a/chrome/test/webdriver/test/chromedriver_tests.py
+++ b/chrome/test/webdriver/test/chromedriver_tests.py
@@ -385,6 +385,11 @@ class MouseTest(ChromeDriverTest):
super(MouseTest, self).setUp()
self._driver = self.GetNewDriver()
+ def testCanClickTransparentElement(self):
+ self._driver.get(GetTestDataUrl() + '/transparent.html')
+ self._driver.find_element_by_tag_name('a').click()
+ self.assertTrue(self._driver.execute_script('return window.success'))
+
def testClickElementThatNeedsContainerScrolling(self):
self._driver.get(GetTestDataUrl() + '/test_page.html')
self._driver.find_element_by_name('hidden_scroll').click()
@@ -420,13 +425,55 @@ class TypingTest(ChromeDriverTest):
def setUp(self):
super(TypingTest, self).setUp()
self._driver = self.GetNewDriver()
- self._driver.get(GetTestDataUrl() + '/test_page.html')
- # See http://crbug.com/85243.
- def testCanSendKeysToDescendantOfEditingHost(self):
- self._driver.find_element_by_name('editable_child').send_keys('moo')
- text = self._driver.find_element_by_name('editable').text
- self.assertEquals('mooeditable', text)
+ def testSendKeysToEditingHostDiv(self):
+ self._driver.get(GetTestDataUrl() + '/content_editable.html')
+ div = self._driver.find_element_by_name('editable')
+ # Break into two to ensure element doesn't lose focus.
+ div.send_keys('hi')
+ div.send_keys(' there')
+ self.assertEquals('hi there', div.text)
+
+ def testSendKeysToNonFocusableChildOfEditingHost(self):
+ self._driver.get(GetTestDataUrl() + '/content_editable.html')
+ child = self._driver.find_element_by_name('editable_child')
+ self.assertRaises(WebDriverException, child.send_keys, 'hi')
+
+ def testSendKeysToFocusableChildOfEditingHost(self):
+ self._driver.get(GetTestDataUrl() + '/content_editable.html')
+ child = self._driver.find_element_by_tag_name('input')
+ child.send_keys('hi')
+ child.send_keys(' there')
+ self.assertEquals('hi there', child.get_attribute('value'))
+
+ def testSendKeysToDesignModePage(self):
+ self._driver.get(GetTestDataUrl() + '/design_mode_doc.html')
+ body = self._driver.find_element_by_tag_name('body')
+ body.send_keys('hi')
+ body.send_keys(' there')
+ self.assertEquals('hi there', body.text)
+
+ def testSendKeysToDesignModeIframe(self):
+ self._driver.get(GetTestDataUrl() + '/content_editable.html')
+ self._driver.switch_to_frame(0)
+ body = self._driver.find_element_by_tag_name('body')
+ body.send_keys('hi')
+ body.send_keys(' there')
+ self.assertEquals('hi there', body.text)
+
+ def testSendKeysToTransparentElement(self):
+ self._driver.get(GetTestDataUrl() + '/transparent.html')
+ text_box = self._driver.find_element_by_tag_name('input')
+ text_box.send_keys('hi')
+ self.assertEquals('hi', text_box.get_attribute('value'))
+
+ def testSendKeysDesignModePageAfterNavigate(self):
+ self._driver.get(GetTestDataUrl() + '/test_page.html')
+ self._driver.get(GetTestDataUrl() + '/design_mode_doc.html')
+ body = self._driver.find_element_by_tag_name('body')
+ body.send_keys('hi')
+ body.send_keys(' there')
+ self.assertEquals('hi there', body.text)
class UrlBaseTest(unittest.TestCase):
@@ -579,6 +626,57 @@ class FileUploadControlTest(ChromeDriverTest):
self.assertTrue(f['name'] in filenames)
+class FrameSwitchingTest(ChromeDriverTest):
+
+ def testGetWindowHandles(self):
+ driver = self.GetNewDriver({'chrome.switches': ['disable-popup-blocking']})
+ driver.get(GetTestDataUrl() + '/test_page.html')
+ driver.execute_script('window.popup = window.open("about:blank")')
+ self.assertEquals(2, len(driver.window_handles))
+ driver.execute_script('window.popup.close()')
+ self.assertEquals(1, len(driver.window_handles))
+
+ def testSwitchToSameWindow(self):
+ driver = self.GetNewDriver({'chrome.switches': ['disable-popup-blocking']})
+ driver.get(GetTestDataUrl() + '/test_page.html')
+ driver.switch_to_window(driver.window_handles[0])
+ self.assertEquals('test_page.html', driver.current_url.split('/')[-1])
+
+ def testClosedWindowThrows(self):
+ driver = self.GetNewDriver({'chrome.switches': ['disable-popup-blocking']})
+ driver.get(GetTestDataUrl() + '/test_page.html')
+ driver.execute_script('window.open("about:blank")')
+ driver.close()
+ self.assertRaises(WebDriverException, driver.close)
+
+ def testSwitchFromClosedWindow(self):
+ driver = self.GetNewDriver({'chrome.switches': ['disable-popup-blocking']})
+ driver.get(GetTestDataUrl() + '/test_page.html')
+ driver.execute_script('window.open("about:blank")')
+ driver.close()
+ driver.switch_to_window(driver.window_handles[0])
+ self.assertEquals('about:blank', driver.current_url)
+
+ def testSwitchToWindowWhileInSubframe(self):
+ driver = self.GetNewDriver({'chrome.switches': ['disable-popup-blocking']})
+ driver.get(GetTestDataUrl() + '/test_page.html')
+ driver.execute_script('window.open("about:blank")')
+ driver.switch_to_frame(0)
+ driver.switch_to_window(driver.window_handles[1])
+ self.assertEquals('about:blank', driver.current_url)
+
+ # Tests that the indexing is absolute and not based on index of frame in its
+ # parent element.
+ # See crbug.com/88685.
+ def testSwitchToFrameByIndex(self):
+ driver = self.GetNewDriver({'chrome.switches': ['disable-popup-blocking']})
+ driver.get(GetTestDataUrl() + '/switch_to_frame_by_index.html')
+ for i in range(3):
+ driver.switch_to_frame(i)
+ self.assertEquals(str(i), driver.current_url.split('?')[-1])
+ driver.switch_to_default_content()
+
+
"""Chrome functional test section. All implementation tests of ChromeDriver
should go above.
diff --git a/chrome/test/webdriver/test/content_editable.html b/chrome/test/webdriver/test/content_editable.html
new file mode 100644
index 0000000..82b5c35
--- /dev/null
+++ b/chrome/test/webdriver/test/content_editable.html
@@ -0,0 +1,11 @@
+<html>
+ <body>
+ <div name='editable' contentEditable>
+ <input type='text'></input>
+ </div>
+ <div name='editable2' contentEditable>
+ <div name='editable_child'>editable</div>
+ </div>
+ <iframe src='design_mode_doc.html'></iframe>
+ </body>
+</html>
diff --git a/chrome/test/webdriver/test/design_mode_doc.html b/chrome/test/webdriver/test/design_mode_doc.html
new file mode 100644
index 0000000..3b92bb0
--- /dev/null
+++ b/chrome/test/webdriver/test/design_mode_doc.html
@@ -0,0 +1,9 @@
+<html>
+ <script>
+ window.onload = function() {
+ document.designMode = "on";
+ }
+ </script>
+ <body>
+ </body>
+</html>
diff --git a/chrome/test/webdriver/test/switch_to_frame_by_index.html b/chrome/test/webdriver/test/switch_to_frame_by_index.html
new file mode 100644
index 0000000..36b2dc1
--- /dev/null
+++ b/chrome/test/webdriver/test/switch_to_frame_by_index.html
@@ -0,0 +1,10 @@
+<html>
+ <body>
+ <iframe src='test_page.html?0'></iframe>
+ <div>
+ <div>Some text</div>
+ <iframe src='test_page.html?1'></iframe>
+ </div>
+ <iframe src='test_page.html?2'></iframe>
+ </body>
+</html>
diff --git a/chrome/test/webdriver/test/transparent.html b/chrome/test/webdriver/test/transparent.html
new file mode 100644
index 0000000..6739596
--- /dev/null
+++ b/chrome/test/webdriver/test/transparent.html
@@ -0,0 +1,12 @@
+<html>
+ <script>
+ var success = false;
+ function succeed() {
+ success = true;
+ }
+ </script>
+ <body>
+ <a style='opacity: 0' onclick='succeed()'>Click here</a>
+ <input style='opacity: 0' type='text'></input>
+ </body>
+</html>
diff --git a/chrome/test/webdriver/webdriver_error.cc b/chrome/test/webdriver/webdriver_error.cc
index 3db95d8..07098c0 100644
--- a/chrome/test/webdriver/webdriver_error.cc
+++ b/chrome/test/webdriver/webdriver_error.cc
@@ -11,34 +11,34 @@ namespace webdriver {
namespace {
// Returns the string equivalent of the given |ErrorCode|.
-const char* ErrorCodeToString(ErrorCode code) {
+const char* DefaultMessageForErrorCode(ErrorCode code) {
switch (code) {
case kSuccess:
- return "SUCCESS";
+ return "Success";
case kNoSuchElement:
- return "NO_SUCH_ELEMENT";
+ return "The element could not be found";
case kNoSuchFrame:
- return "NO_SUCH_FRAME";
+ return "The frame could not be found";
case kUnknownCommand:
- return "UNKNOWN_COMMAND";
+ return "Unknown command";
case kStaleElementReference:
- return "STALE_ELEMENT_REFERENCE";
+ return "Element reference is invalid";
case kElementNotVisible:
- return "ELEMENT_NOT_VISIBLE";
+ return "Element is not visible";
case kInvalidElementState:
- return "INVALID_ELEMENT_STATE";
+ return "Element is in an invalid state";
case kUnknownError:
- return "UNKNOWN_ERROR";
+ return "Unknown error";
case kElementNotSelectable:
- return "ELEMENT_NOT_SELECTABLE";
+ return "Element is not selectable";
case kXPathLookupError:
- return "XPATH_LOOKUP_ERROR";
+ return "XPath lookup error";
case kNoSuchWindow:
- return "NO_SUCH_WINDOW";
+ return "The window could not be found";
case kInvalidCookieDomain:
- return "INVALID_COOKIE_DOMAIN";
+ return "The cookie domain is invalid";
case kUnableToSetCookie:
- return "UNABLE_TO_SET_COOKIE";
+ return "Unable to set cookie";
default:
return "<unknown>";
}
@@ -63,15 +63,12 @@ void Error::AddDetails(const std::string& details) {
details_ = details + ";\n " + details_;
}
-std::string Error::ToString() const {
- std::string error;
- if (code_ != kUnknownError) {
- error += ErrorCodeToString(code_);
- error += ": ";
- }
- if (details_.length()) {
- error += details_;
- }
+std::string Error::GetMessage() const {
+ std::string msg;
+ if (details_.length())
+ msg = details_;
+ else
+ msg = DefaultMessageForErrorCode(code_);
// Only include a stacktrace on Linux. Windows and Mac have all symbols
// stripped in release builds.
@@ -81,11 +78,11 @@ std::string Error::ToString() const {
if (count > 0) {
std::ostringstream ostream;
trace_.OutputToStream(&ostream);
- error += "\n";
- error += ostream.str();
+ msg += "\n";
+ msg += ostream.str();
}
#endif
- return error;
+ return msg;
}
ErrorCode Error::code() const {
diff --git a/chrome/test/webdriver/webdriver_error.h b/chrome/test/webdriver/webdriver_error.h
index 0a232da..c0c094f 100644
--- a/chrome/test/webdriver/webdriver_error.h
+++ b/chrome/test/webdriver/webdriver_error.h
@@ -49,8 +49,7 @@ class Error {
void AddDetails(const std::string& details);
- // Returns a formatted string describing the error. For logging purposes.
- std::string ToString() const;
+ std::string GetMessage() const;
ErrorCode code() const;
const std::string& details() const;