diff options
author | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-20 01:20:17 +0000 |
---|---|---|
committer | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-20 01:20:17 +0000 |
commit | d898053263f96faf49c8367d12ff64a3ee2f76dd (patch) | |
tree | a84ada02f679c4fdc38479e79b2c88235ef2aab7 /chrome | |
parent | 33e73aa2d4e9be16871985f3a6433a5bdb6e44c6 (diff) | |
download | chromium_src-d898053263f96faf49c8367d12ff64a3ee2f76dd.zip chromium_src-d898053263f96faf49c8367d12ff64a3ee2f76dd.tar.gz chromium_src-d898053263f96faf49c8367d12ff64a3ee2f76dd.tar.bz2 |
Implement several ChromeDriver commands based on the javascript atoms.
Added a "501 Not Implemented" callback to mongoose for the WebDriver
commands that have not been implemented yet. This ensures tests that
fail from unimplemented commands fail with a meaningful message.
Patch by jleyba@chromium.org.
Original review at http://codereview.chromium.org/6542032
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/6542036
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75511 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/test/webdriver/WEBDRIVER_TESTS | 59 | ||||
-rw-r--r-- | chrome/test/webdriver/commands/target_locator_commands.cc | 20 | ||||
-rw-r--r-- | chrome/test/webdriver/commands/target_locator_commands.h | 14 | ||||
-rw-r--r-- | chrome/test/webdriver/commands/webelement_commands.cc | 389 | ||||
-rw-r--r-- | chrome/test/webdriver/commands/webelement_commands.h | 199 | ||||
-rw-r--r-- | chrome/test/webdriver/server.cc | 56 |
6 files changed, 715 insertions, 22 deletions
diff --git a/chrome/test/webdriver/WEBDRIVER_TESTS b/chrome/test/webdriver/WEBDRIVER_TESTS index 2580d67..02d8574 100644 --- a/chrome/test/webdriver/WEBDRIVER_TESTS +++ b/chrome/test/webdriver/WEBDRIVER_TESTS @@ -24,29 +24,33 @@ { 'all': [ 'children_finding_tests', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementByClassName', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementById', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementByIdWhenMultipleMatchesExist', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementByLinkText', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementByName', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementByTagName', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementByXPath', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementsByTagName', - '-children_finding_tests.ChildrenFindingTests.testShouldFindElementsByXpath', # 'cookie_tests', # 'correct_event_firing_tests', 'driver_element_finding_test', -# 'element_attribute_tests', + 'element_attribute_tests', # 'executing_async_javascript_test', 'executing_javascript_test', - # This test needs the tagname command. - '-executing_javascript_test.ExecutingJavaScriptTests.testShouldBeAbleToExecuteSimpleJavascriptAndReturnAWebElement', -# 'form_handling_tests', + 'form_handling_tests', + # The following require the click command. + '-form_handling_tests.FormHandlingTests.testClickingOnUnclickableElementsDoesNothing', + '-form_handling_tests.FormHandlingTests.testShouldBeAbleToClickImageButtons', + '-form_handling_tests.FormHandlingTests.testShouldBeAbleToSelectARadioButtonByClickingOnIt', + '-form_handling_tests.FormHandlingTests.testShouldClickOnSubmitInputElements', + # The following are all suppressed because the submit command currently does + # not wait for post-submit navigation events to complete. + '-form_handling_tests.FormHandlingTests.testShouldBeAbleToSubmitForms', + '-form_handling_tests.FormHandlingTests.testShouldSubmitAFormWhenAnyElementWihinThatFormIsSubmitted', + '-form_handling_tests.FormHandlingTests.testShouldSubmitAFormWhenAnyInputElementWithinThatFormIsSubmitted', + # Test fails from a bug in the WebDriver python bindings. This bug has been + # fixed in the WebDriver tree: + # http://code.google.com/p/selenium/source/detail?r=11480 + '-form_handling_tests.FormHandlingTests.testShouldThrowAnExceptionWhenSelectingAnUnselectableElement', 'frame_switching_tests', - # Next two frame switching tests are disabled because they depend on toggle. - '-frame_switching_tests.FrameSwitchingTest.testThatWeCanSwitchFrameByName', - '-frame_switching_tests.FrameSwitchingTest.testThatWeCanSwitchToFrameByIndex', -# 'implicit_waits_tests', + 'implicit_waits_tests', + # Depends on click. + '-implicit_waits_tests.ImplicitWaitTest.testShouldImplicitlyWaitForASingleElement', + '-implicit_waits_tests.ImplicitWaitTest.testShouldImplicitlyWaitUntilAtLeastOneElementIsFoundWhenSearchingForMany', + '-implicit_waits_tests.ImplicitWaitTest.testShouldReturnAfterFirstAttemptToFindManyAfterDisablingImplicitWaits', 'page_loading_tests', # testShouldReturnWhenGettingAUrlThatDoesNotResolve causes the test after # to fail when run in xvfb: crbug.com/72027. @@ -56,12 +60,25 @@ '-page_loading_tests.PageLoadingTests.testShouldBeAbleToNavigateForwardsInTheBrowserHistory', # This test is flaky. '-page_loading_tests.PageLoadingTests.testShouldWaitForDocumentToBeLoaded', -# 'rendered_webelement_tests' -# 'select_element_handling_tests', -# 'stale_reference_tests', + 'rendered_webelement_tests', + # Test is flaky. Sometimes can't find an element. + '-rendered_webelement_tests.RenderedWebElementTests.testShouldCorrectlyIdentifyThatAnElementHasWidth', + # Test expects a color keyword, but a rgba tuple is returned. + '-rendered_webelement_tests.RenderedWebElementTests.testShouldAllowInheritedStylesToBeUsed', + # Test expects hex color, but a rgb tuple is returned. + '-rendered_webelement_tests.RenderedWebElementTests.testShouldPickUpStyleOfAnElement', + 'select_element_handling_tests', + 'stale_reference_tests', + # Test requires click command. + '-stale_reference_tests.StaleReferenceTests.testOldPage', # 'text_handling_tests', # 'typing_tests', -# 'visibility_tests', + 'visibility_tests', + # Depends on click. + '-visibility_tests.VisibilityTests.testShouldModifyTheVisibilityOfAnElementDynamically', + '-visibility_tests.VisibilityTests.testShouldNotBeAbleToClickOnAnElementThatIsNotDisplayed', + # Bug in typing: element is not verified before typing. + '-visibility_tests.VisibilityTests.testShouldNotBeAbleToTypeAnElementThatIsNotDisplayed', ], 'win': [ diff --git a/chrome/test/webdriver/commands/target_locator_commands.cc b/chrome/test/webdriver/commands/target_locator_commands.cc index 841173c..0dd3684 100644 --- a/chrome/test/webdriver/commands/target_locator_commands.cc +++ b/chrome/test/webdriver/commands/target_locator_commands.cc @@ -130,4 +130,24 @@ void SwitchFrameCommand::ExecutePost(Response* const response) { response->SetStatus(kSuccess); } +ActiveElementCommand::ActiveElementCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebDriverCommand(path_segments, parameters) {} + +ActiveElementCommand::~ActiveElementCommand() {} + +bool ActiveElementCommand::DoesPost() { + return true; +} + +void ActiveElementCommand::ExecutePost(Response* const response) { + ListValue args; + Value* result = NULL; + ErrorCode status = session_->ExecuteScript( + "return document.activeElement || document.body", &args, &result); + response->SetStatus(status); + response->SetValue(result); +} + } // namespace webdriver diff --git a/chrome/test/webdriver/commands/target_locator_commands.h b/chrome/test/webdriver/commands/target_locator_commands.h index d9093cc..9294ab8 100644 --- a/chrome/test/webdriver/commands/target_locator_commands.h +++ b/chrome/test/webdriver/commands/target_locator_commands.h @@ -79,6 +79,20 @@ class SwitchFrameCommand : public WebDriverCommand { DISALLOW_COPY_AND_ASSIGN(SwitchFrameCommand); }; +// Retrieves the active element on the current page. +class ActiveElementCommand : public WebDriverCommand { + public: + ActiveElementCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ActiveElementCommand(); + + virtual bool DoesPost(); + virtual void ExecutePost(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ActiveElementCommand); +}; + } // namespace webdriver #endif // CHROME_TEST_WEBDRIVER_COMMANDS_TARGET_LOCATOR_COMMANDS_H_ diff --git a/chrome/test/webdriver/commands/webelement_commands.cc b/chrome/test/webdriver/commands/webelement_commands.cc index f240326..052ac39 100644 --- a/chrome/test/webdriver/commands/webelement_commands.cc +++ b/chrome/test/webdriver/commands/webelement_commands.cc @@ -15,6 +15,8 @@ namespace webdriver { +///////////////////// WebElementCommand //////////////////// + WebElementCommand::WebElementCommand( const std::vector<std::string>& path_segments, const DictionaryValue* const parameters) @@ -96,6 +98,391 @@ bool WebElementCommand::RequiresValidTab() { return true; } +///////////////////// ElementAttributeCommand //////////////////// + +ElementAttributeCommand::ElementAttributeCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementAttributeCommand::~ElementAttributeCommand() {} + +bool ElementAttributeCommand::DoesGet() { + return true; +} + +void ElementAttributeCommand::ExecuteGet(Response* const response) { + // There should be at least 7 segments to match + // "/session/$session/element/$id/attribute/$name" + if (path_segments_.size() < 7) { + SET_WEBDRIVER_ERROR(response, "Path segments is less than 7", + kBadRequest); + return; + } + + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::GET_ATTRIBUTE); + + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + args->Append(Value::CreateStringValue(path_segments_.at(6))); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementClearCommand //////////////////// + +ElementClearCommand::ElementClearCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementClearCommand::~ElementClearCommand() {} + +bool ElementClearCommand::DoesPost() { + return true; +} + +void ElementClearCommand::ExecutePost(Response* const response) { + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + + std::string script = base::StringPrintf( + "(%s).apply(null, arguments);", atoms::CLEAR); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementCssCommand //////////////////// + +ElementCssCommand::ElementCssCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementCssCommand::~ElementCssCommand() {} + +bool ElementCssCommand::DoesGet() { + return true; +} + +void ElementCssCommand::ExecuteGet(Response* const response) { + // There should be at least 7 segments to match + // "/session/$session/element/$id/css/$propertyName" + if (path_segments_.size() < 7) { + SET_WEBDRIVER_ERROR(response, "Path segments is less than 7", + kBadRequest); + return; + } + + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::GET_EFFECTIVE_STYLE); + + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + args->Append(Value::CreateStringValue(path_segments_.at(6))); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementDisplayedCommand //////////////////// + +ElementDisplayedCommand::ElementDisplayedCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementDisplayedCommand::~ElementDisplayedCommand() {} + +bool ElementDisplayedCommand::DoesGet() { + return true; +} + +void ElementDisplayedCommand::ExecuteGet(Response* const response) { + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::IS_DISPLAYED); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementEnabledCommand //////////////////// + +ElementEnabledCommand::ElementEnabledCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementEnabledCommand::~ElementEnabledCommand() {} + +bool ElementEnabledCommand::DoesGet() { + return true; +} + +void ElementEnabledCommand::ExecuteGet(Response* const response) { + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::IS_ENABLED); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementEqualsCommand //////////////////// + +ElementEqualsCommand::ElementEqualsCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementEqualsCommand::~ElementEqualsCommand() {} + +bool ElementEqualsCommand::DoesGet() { + return true; +} + +void ElementEqualsCommand::ExecuteGet(Response* const response) { + // There should be at least 7 segments to match + // "/session/$session/element/$id/equals/$other" + if (path_segments_.size() < 7) { + SET_WEBDRIVER_ERROR(response, "Path segments is less than 7", + kBadRequest); + return; + } + + std::string script = "return arguments[0] == arguments[1];"; + + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + args->Append(Value::CreateStringValue(path_segments_.at(6))); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementLocationCommand //////////////////// + +ElementLocationCommand::ElementLocationCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementLocationCommand::~ElementLocationCommand() {} + +bool ElementLocationCommand::DoesGet() { + return true; +} + +void ElementLocationCommand::ExecuteGet(Response* const response) { + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::GET_LOCATION); + + ListValue args; + args.Append(GetElementIdAsDictionaryValue(element_id)); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, &args, &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementLocationInViewCommand //////////////////// + +ElementLocationInViewCommand::ElementLocationInViewCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementLocationInViewCommand::~ElementLocationInViewCommand() {} + +bool ElementLocationInViewCommand::DoesGet() { + return true; +} + +void ElementLocationInViewCommand::ExecuteGet(Response* const response) { + std::string script = base::StringPrintf("arguments[0].scrollIntoView();" + "return (%s).apply(null, arguments);", + atoms::GET_LOCATION); + ListValue args; + args.Append(GetElementIdAsDictionaryValue(element_id)); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, &args, &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementNameCommand //////////////////// + +ElementNameCommand::ElementNameCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementNameCommand::~ElementNameCommand() {} + +bool ElementNameCommand::DoesGet() { + return true; +} + +void ElementNameCommand::ExecuteGet(Response* const response) { + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + + std::string script = "return arguments[0].tagName;"; + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementSelectedCommand //////////////////// + +ElementSelectedCommand::ElementSelectedCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementSelectedCommand::~ElementSelectedCommand() {} + +bool ElementSelectedCommand::DoesGet() { + return true; +} + +bool ElementSelectedCommand::DoesPost() { + return true; +} + +void ElementSelectedCommand::ExecuteGet(Response* const response) { + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::IS_SELECTED); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +void ElementSelectedCommand::ExecutePost(Response* const response) { + scoped_ptr<ListValue> args(new ListValue); + args->Append(GetElementIdAsDictionaryValue(element_id)); + args->Append(Value::CreateBooleanValue(true)); + + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::SET_SELECTED); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, args.get(), &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementSizeCommand //////////////////// + +ElementSizeCommand::ElementSizeCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementSizeCommand::~ElementSizeCommand() {} + +bool ElementSizeCommand::DoesGet() { + return true; +} + +void ElementSizeCommand::ExecuteGet(Response* const response) { + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::GET_SIZE); + + ListValue args; + args.Append(GetElementIdAsDictionaryValue(element_id)); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, &args, &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementSubmitCommand //////////////////// + +ElementSubmitCommand::ElementSubmitCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementSubmitCommand::~ElementSubmitCommand() {} + +bool ElementSubmitCommand::DoesPost() { + return true; +} + +void ElementSubmitCommand::ExecutePost(Response* const response) { + // TODO(jleyba): We need to wait for any post-submit navigation events to + // complete before responding to the client. + std::string script = base::StringPrintf( + "(%s).apply(null, arguments);", atoms::SUBMIT); + + ListValue args; + args.Append(GetElementIdAsDictionaryValue(element_id)); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, &args, &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementToggleCommand //////////////////// + +ElementToggleCommand::ElementToggleCommand( + const std::vector<std::string>& path_segments, + DictionaryValue* parameters) + : WebElementCommand(path_segments, parameters) {} + +ElementToggleCommand::~ElementToggleCommand() {} + +bool ElementToggleCommand::DoesPost() { + return true; +} + +void ElementToggleCommand::ExecutePost(Response* const response) { + std::string script = base::StringPrintf( + "return (%s).apply(null, arguments);", atoms::TOGGLE); + + ListValue args; + args.Append(GetElementIdAsDictionaryValue(element_id)); + + Value* result = NULL; + ErrorCode status = session_->ExecuteScript(script, &args, &result); + response->SetStatus(status); + response->SetValue(result); +} + +///////////////////// ElementValueCommand //////////////////// + ElementValueCommand::ElementValueCommand( const std::vector<std::string>& path_segments, DictionaryValue* parameters) @@ -170,6 +557,8 @@ void ElementValueCommand::ExecutePost(Response* const response) { response->SetStatus(kSuccess); } +///////////////////// ElementTextCommand //////////////////// + ElementTextCommand::ElementTextCommand( const std::vector<std::string>& path_segments, DictionaryValue* parameters) diff --git a/chrome/test/webdriver/commands/webelement_commands.h b/chrome/test/webdriver/commands/webelement_commands.h index 0484742..8d1ce9f 100644 --- a/chrome/test/webdriver/commands/webelement_commands.h +++ b/chrome/test/webdriver/commands/webelement_commands.h @@ -39,6 +39,205 @@ class WebElementCommand : public WebDriverCommand { DISALLOW_COPY_AND_ASSIGN(WebElementCommand); }; +// Retrieves element attributes. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/attribute/:name +class ElementAttributeCommand : public WebElementCommand { + public: + ElementAttributeCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementAttributeCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementAttributeCommand); +}; + +// Clears test input elements. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/clear +class ElementClearCommand : public WebElementCommand { + public: + ElementClearCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementClearCommand(); + + virtual bool DoesPost(); + virtual void ExecutePost(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementClearCommand); +}; + +// Retrieves element style properties. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/css/:propertyName +class ElementCssCommand : public WebElementCommand { + public: + ElementCssCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementCssCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementCssCommand); +}; + +// Queries whether an element is currently displayed ot the user. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/displayed +class ElementDisplayedCommand : public WebElementCommand { + public: + ElementDisplayedCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementDisplayedCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementDisplayedCommand); +}; + +// Queries whether an element is currently enabled. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/enabled +class ElementEnabledCommand : public WebElementCommand { + public: + ElementEnabledCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementEnabledCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementEnabledCommand); +}; + +// Queries whether two elements are equal. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/equals/:other +class ElementEqualsCommand : public WebElementCommand { + public: + ElementEqualsCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementEqualsCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementEqualsCommand); +}; + +// Retrieves the element's location on the page. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/location +class ElementLocationCommand : public WebElementCommand { + public: + ElementLocationCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementLocationCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementLocationCommand); +}; + +// Retrieves the element's location on the page after ensuring it is visible in +// the current viewport. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/location_in_view +class ElementLocationInViewCommand : public WebElementCommand { + public: + ElementLocationInViewCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementLocationInViewCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementLocationInViewCommand); +}; + +// Queries for an element's tag name. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/name +class ElementNameCommand : public WebElementCommand { + public: + ElementNameCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementNameCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementNameCommand); +}; + +// Handles selecting elements and querying whether they are currently selected. +// Queries whether an element is currently enabled. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/selected +class ElementSelectedCommand : public WebElementCommand { + public: + ElementSelectedCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementSelectedCommand(); + + virtual bool DoesGet(); + virtual bool DoesPost(); + virtual void ExecuteGet(Response* const response); + virtual void ExecutePost(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementSelectedCommand); +}; + +// Queries for an element's size. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/size +class ElementSizeCommand : public WebElementCommand { + public: + ElementSizeCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementSizeCommand(); + + virtual bool DoesGet(); + virtual void ExecuteGet(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementSizeCommand); +}; + +// Submit's the form containing the target element. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/submit +class ElementSubmitCommand : public WebElementCommand { + public: + ElementSubmitCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementSubmitCommand(); + + virtual bool DoesPost(); + virtual void ExecutePost(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementSubmitCommand); +}; + +// Toggle's whether an element is selected. +// http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/toggle +class ElementToggleCommand : public WebElementCommand { + public: + ElementToggleCommand(const std::vector<std::string>& path_segments, + DictionaryValue* parameters); + virtual ~ElementToggleCommand(); + + virtual bool DoesPost(); + virtual void ExecutePost(Response* const response); + + private: + DISALLOW_COPY_AND_ASSIGN(ElementToggleCommand); +}; + // Sends keys to the specified web element. Also gets the value property of an // element. // http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value diff --git a/chrome/test/webdriver/server.cc b/chrome/test/webdriver/server.cc index 274820a..9ec37be 100644 --- a/chrome/test/webdriver/server.cc +++ b/chrome/test/webdriver/server.cc @@ -16,17 +16,20 @@ #include "base/at_exit.h" #include "base/command_line.h" +#include "base/format_macros.h" #include "base/logging.h" #include "base/string_number_conversions.h" #include "base/scoped_ptr.h" #include "base/string_split.h" #include "base/string_util.h" +#include "base/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" #include "base/utf_string_conversions.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/webdriver/dispatch.h" +#include "chrome/test/webdriver/error_codes.h" #include "chrome/test/webdriver/session_manager.h" #include "chrome/test/webdriver/utility_functions.h" #include "chrome/test/webdriver/commands/cookie_commands.h" @@ -71,11 +74,37 @@ void Shutdown(struct mg_connection* connection, shutdown_event->Signal(); } +void SendNotImplementedError(struct mg_connection* connection, + const struct mg_request_info* request_info, + void* user_data) { + // Send a well-formed WebDriver JSON error response to ensure clients + // handle it correctly. + std::string body = base::StringPrintf( + "{\"status\":%d,\"value\":{\"message\":" + "\"Command has not been implemented yet: %s %s\"}}", + kUnknownCommand, request_info->request_method, request_info->uri); + + std::string header = base::StringPrintf( + "HTTP/1.1 501 Not Implemented\r\n" + "Content-Type:application/json\r\n" + "Content-Length:%" PRIuS "\r\n" + "\r\n", body.length()); + + LOG(ERROR) << header << body; + mg_write(connection, header.data(), header.length()); + mg_write(connection, body.data(), body.length()); +} + + template <typename CommandType> void SetCallback(struct mg_context* ctx, const char* pattern) { mg_set_uri_callback(ctx, pattern, &Dispatch<CommandType>, NULL); } +void SetNotImplemented(struct mg_context* ctx, const char* pattern) { + mg_set_uri_callback(ctx, pattern, &SendNotImplementedError, NULL); +} + void InitCallbacks(struct mg_context* ctx, base::WaitableEvent* shutdown_event) { mg_set_uri_callback(ctx, "/shutdown", &Shutdown, shutdown_event); @@ -102,10 +131,35 @@ void InitCallbacks(struct mg_context* ctx, // WebElement commands SetCallback<FindOneElementCommand>(ctx, "/session/*/element"); SetCallback<FindManyElementsCommand>(ctx, "/session/*/elements"); + SetCallback<ActiveElementCommand>(ctx, "/session/*/element/active"); SetCallback<FindOneElementCommand>(ctx, "/session/*/element/*/element"); SetCallback<FindManyElementsCommand>(ctx, "/session/*/elements/*/elements"); - SetCallback<ElementValueCommand>(ctx, "/session/*/element/*/value"); + SetCallback<ElementAttributeCommand>(ctx, + "/session/*/element/*/attribute/*"); + SetCallback<ElementCssCommand>(ctx, "/session/*/element/*/css/*"); + SetCallback<ElementClearCommand>(ctx, "/session/*/element/*/clear"); + SetCallback<ElementDisplayedCommand>(ctx, "/session/*/element/*/displayed"); + SetCallback<ElementEnabledCommand>(ctx, "/session/*/element/*/enabled"); + SetCallback<ElementEqualsCommand>(ctx, "/session/*/element/*/equals/*"); + SetCallback<ElementLocationCommand>(ctx, "/session/*/element/*/location"); + SetCallback<ElementLocationInViewCommand>(ctx, + "/session/*/element/*/location_in_view"); + SetCallback<ElementNameCommand>(ctx, "/session/*/element/*/name"); + SetCallback<ElementSelectedCommand>(ctx, "/session/*/element/*/selected"); + SetCallback<ElementSizeCommand>(ctx, "/session/*/element/*/size"); + SetCallback<ElementSubmitCommand>(ctx, "/session/*/element/*/submit"); SetCallback<ElementTextCommand>(ctx, "/session/*/element/*/text"); + SetCallback<ElementToggleCommand>(ctx, "/session/*/element/*/toggle"); + SetCallback<ElementValueCommand>(ctx, "/session/*/element/*/value"); + + // Commands that have not been implemented yet. We list these out explicitly + // so that tests that attempt to use them fail with a meaningful error. + SetNotImplemented(ctx, "/session/*/element/*/click"); + SetNotImplemented(ctx, "/session/*/element/*/drag"); + SetNotImplemented(ctx, "/session/*/element/*/hover"); + SetNotImplemented(ctx, "/session/*/execute_async"); + SetNotImplemented(ctx, "/session/*/timeouts/async_script"); + SetNotImplemented(ctx, "/session/*/screenshot"); // Since the /session/* is a wild card that would match the above URIs, this // line MUST be the last registered URI with the server. |