├── test
├── pages
│ ├── alerts.html
│ ├── js.html
│ ├── webdriver.html
│ ├── navigation2.html
│ ├── navigation1.html
│ ├── frame1.html
│ ├── frame2.html
│ ├── frame3.html
│ ├── keyboard.html
│ ├── session.html
│ ├── redirect.html
│ ├── frameset.html
│ ├── frames.html
│ ├── element.html
│ ├── finder.html
│ └── mouse.html
├── http_connection_test.cpp
├── client_test.cpp
├── alerts_test.cpp
├── keyboard_test.cpp
├── main.cpp
├── browsers_test.cpp
├── frames_test.cpp
├── examples_test.cpp
├── capabilities_test.cpp
├── wait_test.cpp
├── webdriver_test.cpp
├── element_test.cpp
├── to_string_test.cpp
├── wait_match_test.cpp
├── environment.h
├── mouse_test.cpp
├── shared_test.cpp
├── finder_test.cpp
├── CMakeLists.txt
├── conversions_test.cpp
├── js_test.cpp
├── session_test.cpp
└── resource_test.cpp
├── .gitignore
├── include
├── webdriverxx.h
└── webdriverxx
│ ├── errors.h
│ ├── detail
│ ├── factories.h
│ ├── http_client.h
│ ├── finder.h
│ ├── keyboard.h
│ ├── factories_impl.h
│ ├── meta_tools.h
│ ├── time.h
│ ├── http_connection.h
│ ├── finder.inl
│ ├── error_handling.h
│ ├── types.h
│ ├── shared.h
│ ├── to_string.h
│ ├── http_request.h
│ └── resource.h
│ ├── browsers
│ ├── phantom.h
│ ├── firefox.h
│ ├── chrome.h
│ └── ie.h
│ ├── webdriver.h
│ ├── js_args.h
│ ├── client.h
│ ├── window.h
│ ├── by.h
│ ├── types.h
│ ├── element.h
│ ├── client.inl
│ ├── wait.h
│ ├── keys.h
│ ├── response_status_code.h
│ ├── element.inl
│ ├── wait_match.h
│ ├── session.h
│ ├── capabilities.h
│ ├── conversions.h
│ └── session.inl
├── .travis.yml
├── CMakeLists.txt
├── LICENSE
└── README.md
/test/pages/alerts.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/test/pages/js.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/webdriver.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/navigation2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Navigation 2
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/navigation1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Navigation 1
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/pages/frame1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/frame2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/frame3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/keyboard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/pages/session.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Test title
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/pages/redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/pages/frameset.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/test/pages/frames.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 | *.obj
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Compiled Dynamic libraries
12 | *.so
13 | *.dylib
14 | *.dll
15 |
16 | # Fortran module files
17 | *.mod
18 |
19 | # Compiled Static libraries
20 | *.lai
21 | *.la
22 | *.a
23 | *.lib
24 |
25 | # Executables
26 | *.exe
27 | *.out
28 | *.app
29 |
--------------------------------------------------------------------------------
/test/pages/element.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Some text
7 |
8 |
9 | visible text
10 | hidden text
11 |
12 |
--------------------------------------------------------------------------------
/test/pages/finder.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | test link text
8 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/include/webdriverxx.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_H
2 | #define WEBDRIVERXX_H
3 |
4 | #include "webdriverxx/webdriver.h"
5 | #include "webdriverxx/browsers/chrome.h"
6 | #include "webdriverxx/browsers/firefox.h"
7 | #include "webdriverxx/browsers/ie.h"
8 | #include "webdriverxx/browsers/phantom.h"
9 | #include "webdriverxx/wait.h"
10 | #include "webdriverxx/wait_match.h"
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/include/webdriverxx/errors.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_ERRORS_H
2 | #define WEBDRIVERXX_ERRORS_H
3 |
4 | #include
5 | #include
6 |
7 | namespace webdriverxx {
8 |
9 | struct WebDriverException : std::runtime_error {
10 | explicit WebDriverException(const std::string& message)
11 | : std::runtime_error(message) {}
12 | };
13 |
14 | } // namespace webdriverxx
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 |
3 | compiler:
4 | - gcc
5 | - clang
6 |
7 | branches:
8 | only:
9 | - master
10 | - dev
11 |
12 | before_script:
13 | - mkdir build
14 | - cd build
15 | - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
16 | - phantomjs --webdriver=7777 --webdriver-loglevel=WARN &
17 | - npm install http-server -g
18 | - http-server ./test/pages --silent &
19 |
20 | script:
21 | - cmake --build .
22 | - ctest -V
23 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/factories.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_FACTORIES_H
2 | #define WEBDRIVERXX_DETAIL_FACTORIES_H
3 |
4 | #include "shared.h"
5 | #include
6 |
7 | namespace webdriverxx {
8 |
9 | class Element;
10 |
11 | namespace detail {
12 |
13 | class Finder;
14 | class Resource;
15 |
16 | struct IFinderFactory {
17 | virtual Finder MakeFinder(const Shared& context) = 0;
18 | virtual ~IFinderFactory() {}
19 |
20 | };
21 |
22 | struct IElementFactory {
23 | virtual Element MakeElement(const std::string& id) = 0;
24 | virtual ~IElementFactory() {}
25 | };
26 |
27 | } // namespace detail
28 | } // namespace webdriverxx
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/include/webdriverxx/browsers/phantom.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_BROWSERS_PHANTOM_H
2 | #define WEBDRIVERXX_BROWSERS_PHANTOM_H
3 |
4 | #include "../capabilities.h"
5 |
6 | namespace webdriverxx {
7 |
8 | struct Phantom : Capabilities { // copyable
9 | Phantom(const Capabilities& defaults = Capabilities())
10 | : Capabilities(defaults) {
11 | SetBrowserName(browser::Phantom);
12 | SetVersion("");
13 | SetPlatform(platform::Any);
14 | }
15 |
16 | WEBDRIVERXX_PROPERTIES_BEGIN(Phantom)
17 | // Profile is a profile folder, zipped and base64 encoded.
18 | WEBDRIVERXX_PROPERTY(LoggingPrefs, "loggingPrefs", LoggingPrefs)
19 | WEBDRIVERXX_PROPERTIES_END()
20 | };
21 |
22 | } // namespace webdriverxx
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/http_client.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_HTTP_CLIENT_H
2 | #define WEBDRIVERXX_DETAIL_HTTP_CLIENT_H
3 |
4 | #include
5 |
6 | namespace webdriverxx {
7 | namespace detail {
8 |
9 | struct HttpResponse {
10 | long http_code;
11 | std::string body;
12 |
13 | HttpResponse()
14 | : http_code(0)
15 | {}
16 | };
17 |
18 | struct IHttpClient {
19 | virtual HttpResponse Get(const std::string& url) const = 0;
20 | virtual HttpResponse Delete(const std::string& url) const = 0;
21 | virtual HttpResponse Post(const std::string& url, const std::string& data) const = 0;
22 | virtual ~IHttpClient() {}
23 | };
24 |
25 | } // namespace detail
26 | } // namespace webdriverxx
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 | project(webdriverxx)
3 |
4 | if (NOT MSVC)
5 | include(CheckCXXCompilerFlag)
6 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
7 | CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
8 | if(COMPILER_SUPPORTS_CXX11)
9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
10 | elseif(COMPILER_SUPPORTS_CXX0X)
11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
12 | endif()
13 | endif()
14 |
15 | enable_testing()
16 |
17 | include_directories(include)
18 | add_subdirectory(test)
19 |
20 | install(DIRECTORY
21 | ${CMAKE_SOURCE_DIR}/include/
22 | DESTINATION /usr/local/include/${PROJECT_NAME}
23 | FILES_MATCHING PATTERN "*")
24 |
25 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/finder.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_FINDER_H
2 | #define WEBDRIVERXX_DETAIL_FINDER_H
3 |
4 | #include "shared.h"
5 | #include "resource.h"
6 | #include "factories.h"
7 | #include "../by.h"
8 | #include
9 |
10 | namespace webdriverxx {
11 |
12 | class Element;
13 |
14 | namespace detail {
15 |
16 | class Finder { // copyable
17 | public:
18 | Finder(
19 | const Shared& context,
20 | const Shared& factory
21 | );
22 |
23 | Element FindElement(const By& by) const;
24 | std::vector FindElements(const By& by) const;
25 |
26 | private:
27 | Shared context_;
28 | Shared factory_;
29 | };
30 |
31 | } // namespace detail
32 | } // namespace webdriverxx
33 |
34 | #include "finder.inl"
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/test/http_connection_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 | #include
5 |
6 | namespace test {
7 |
8 | using namespace webdriverxx;
9 | using namespace webdriverxx::detail;
10 |
11 | TEST(HttpConnection, CanBeCreated) {
12 | HttpConnection connection;
13 | }
14 |
15 | TEST(HttpConnection, GetsPage) {
16 | HttpConnection connection;
17 | HttpResponse response = connection.Get(GetWebDriverUrl() + "status");
18 | ASSERT_EQ(200, response.http_code);
19 | ASSERT_TRUE(!response.body.empty());
20 | }
21 |
22 | TEST(HttpConnection, ThrowsExceptionIfPortIsClosed) {
23 | HttpConnection connection;
24 | const char *const kUrlWithClosedPort = "http://127.0.0.1:7778/";
25 | ASSERT_THROW(connection.Get(kUrlWithClosedPort), WebDriverException);
26 | }
27 |
28 | } // namespace test
29 |
--------------------------------------------------------------------------------
/include/webdriverxx/browsers/firefox.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_BROWSERS_FIREFOX_H
2 | #define WEBDRIVERXX_BROWSERS_FIREFOX_H
3 |
4 | #include "../capabilities.h"
5 |
6 | namespace webdriverxx {
7 |
8 | struct Firefox : Capabilities { // copyable
9 | Firefox(const Capabilities& defaults = Capabilities())
10 | : Capabilities(defaults) {
11 | SetBrowserName(browser::Firefox);
12 | SetVersion("");
13 | SetPlatform(platform::Any);
14 | }
15 |
16 | WEBDRIVERXX_PROPERTIES_BEGIN(Firefox)
17 | // Profile is a profile folder, zipped and base64 encoded.
18 | // TODO: add FirefoxProfile
19 | WEBDRIVERXX_PROPERTY(Profile, "firefox_profile", std::string)
20 | WEBDRIVERXX_PROPERTY(LoggingPrefs, "loggingPrefs", LoggingPrefs)
21 | WEBDRIVERXX_PROPERTY(FirefoxBinary, "firefox_binary", std::string)
22 | WEBDRIVERXX_PROPERTIES_END()
23 | };
24 |
25 | } // namespace webdriverxx
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/keyboard.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_KEYBOARD_H
2 | #define WEBDRIVERXX_DETAIL_KEYBOARD_H
3 |
4 | #include "resource.h"
5 | #include "../conversions.h"
6 | #include "../keys.h"
7 |
8 | namespace webdriverxx {
9 | namespace detail {
10 |
11 | class Keyboard { // copyable
12 | public:
13 | Keyboard(const Shared& resource, const std::string& command)
14 | : resource_(resource)
15 | , command_(command)
16 | {}
17 |
18 | const Keyboard& SendKeys(const std::string& keys) const {
19 | return SendKeys(Shortcut() << keys);
20 | }
21 |
22 | const Keyboard& SendKeys(const Shortcut& shortcut) const {
23 | resource_->Post(command_, JsonObject()
24 | .Set("value", ToJson(shortcut.keys_)));
25 | return *this;
26 | }
27 |
28 | private:
29 | Shared resource_;
30 | std::string command_;
31 | };
32 |
33 | } // namespace detail
34 | } // namespace webdriverxx
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/test/client_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | class TestClient : public ::testing::Test {
10 | protected:
11 | static void SetUpTestCase() {
12 | client = new Client(GetWebDriverUrl());
13 | }
14 |
15 | static void TearDownTestCase() {
16 | delete client;
17 | client = 0;
18 | }
19 |
20 | static Client* client;
21 | };
22 |
23 | Client* TestClient::client = 0;
24 |
25 | TEST_F(TestClient, GetsStatus) {
26 | picojson::object status = client->GetStatus();
27 | ASSERT_TRUE(status["build"].is());
28 | ASSERT_TRUE(status["os"].is());
29 | }
30 |
31 | TEST_F(TestClient, GetsSessions) {
32 | client->GetSessions();
33 | }
34 |
35 | TEST_F(TestClient, CreatesSession) {
36 | Parameters params = GetParameters();
37 | client->CreateSession(params.desired, params.required);
38 | }
39 |
40 | } // namespace test
41 |
--------------------------------------------------------------------------------
/test/pages/mouse.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
20 |
21 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/factories_impl.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_FACTORIES_IMPL_H
2 | #define WEBDRIVERXX_DETAIL_FACTORIES_IMPL_H
3 |
4 | #include "factories.h"
5 | #include "resource.h"
6 | #include "finder.h"
7 | #include "shared.h"
8 | #include "../element.h"
9 |
10 | namespace webdriverxx {
11 | namespace detail {
12 |
13 | class SessionFactory // noncopyable
14 | : public IElementFactory
15 | , public IFinderFactory
16 | , public SharedObjectBase
17 | {
18 | public:
19 | explicit SessionFactory(const Shared& session_resource)
20 | : session_resource_(session_resource)
21 | {}
22 |
23 | virtual Element MakeElement(const std::string& id) {
24 | return Element(
25 | id,
26 | detail::MakeSubResource(session_resource_, "element", id),
27 | Shared(this)
28 | );
29 | }
30 |
31 | virtual Finder MakeFinder(const Shared& context) {
32 | return Finder(context, Shared(this));
33 | }
34 |
35 | private:
36 | const Shared session_resource_;
37 | };
38 |
39 | } // namespace detail
40 | } // namespace webdriverxx
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/meta_tools.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_META_TOOLS_H
2 | #define WEBDRIVERXX_DETAIL_META_TOOLS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace webdriverxx {
10 | namespace detail {
11 |
12 | template
13 | struct type_is { typedef T type; };
14 |
15 | template
16 | T& value_ref(); // MSVC2010 doesn't have std::declval
17 |
18 | template
19 | class is_iterable {
20 | template
21 | static std::false_type test(...);
22 | template
23 | static decltype(std::begin(value_ref()), std::end(value_ref()),
24 | std::true_type()) test(int);
25 |
26 | typedef decltype(test(0)) verdict;
27 |
28 | public:
29 | static const bool value = verdict::value;
30 | };
31 |
32 | template
33 | struct is_string : std::is_convertible {};
34 |
35 | template
36 | struct if_ : std::conditional {};
37 |
38 | } // namespace detail
39 | } // namespace webdriverxx
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Sergey Kogan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/include/webdriverxx/webdriver.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_WEBDRIVER_H
2 | #define WEBDRIVERXX_WEBDRIVER_H
3 |
4 | #include "client.h"
5 | #include "session.h"
6 |
7 | namespace webdriverxx {
8 |
9 | // The main class for interactions with a server. Automatically connects to a server,
10 | // creates and deletes a session and gives access to session's API.
11 | class WebDriver // copyable
12 | : public Client
13 | , public Session {
14 | public:
15 | explicit WebDriver(
16 | const Capabilities& desired = Capabilities(),
17 | const Capabilities& required = Capabilities(),
18 | const std::string& url = kDefaultWebDriverUrl
19 | )
20 | : Client(url)
21 | , Session(CreateSession(desired, required))
22 | {}
23 | };
24 |
25 | inline
26 | WebDriver Start(
27 | const Capabilities& desired,
28 | const Capabilities& required = Capabilities(),
29 | const std::string& url = kDefaultWebDriverUrl
30 | )
31 | {
32 | return WebDriver(desired, required, url);
33 | }
34 |
35 | inline
36 | WebDriver Start(const Capabilities& desired, const std::string& url)
37 | {
38 | return Start(desired, Capabilities(), url);
39 | }
40 |
41 | } // namespace webdriverxx
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/include/webdriverxx/js_args.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_JS_ARGS_H
2 | #define WEBDRIVERXX_JS_ARGS_H
3 |
4 | #include "conversions.h"
5 | #include "picojson.h"
6 |
7 | namespace webdriverxx {
8 |
9 | class Session;
10 |
11 | class JsArgs // copyable
12 | {
13 | public:
14 | JsArgs() : args_(picojson::array()) {}
15 |
16 | // This member works out of the box for scalar values, Elements and std::vector
17 | // with scalar values or Elements. Additional code is needed to use it
18 | // with custom objects and custom containers. Take a look
19 | // to the TestJsExecutor/CanPassArray, TestJsExecutor/CanPassCustomArray
20 | // and TestJsExecutor/CanPassCustomObjects tests to get details.
21 | template
22 | JsArgs& operator << (const T& arg) {
23 | args_.get().push_back(ToJson(arg));
24 | return *this;
25 | }
26 |
27 | // Alternative backdoor for passing custom data structures as arguments.
28 | JsArgs& operator << (const picojson::value& arg) {
29 | args_.get().push_back(arg);
30 | return *this;
31 | }
32 |
33 | private:
34 | friend class Session;
35 | picojson::value args_;
36 | };
37 |
38 | } // namespace webdriverxx
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/time.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_TIME_H
2 | #define WEBDRIVERXX_DETAIL_TIME_H
3 |
4 | #include "error_handling.h"
5 | #include "../types.h"
6 |
7 | #ifdef _WIN32
8 |
9 | #include
10 |
11 | #else
12 |
13 | #include
14 | #include
15 |
16 | #endif
17 |
18 | namespace webdriverxx {
19 | namespace detail {
20 |
21 | inline
22 | TimePoint Now() {
23 | #ifdef _WIN32
24 | FILETIME time;
25 | ::GetSystemTimeAsFileTime(&time);
26 | return ((static_cast(time.dwHighDateTime) << 32)
27 | + time.dwLowDateTime)/10000;
28 | #else
29 | timeval time = {};
30 | WEBDRIVERXX_CHECK(0 == gettimeofday(&time, nullptr), "gettimeofday failure");
31 | return static_cast(time.tv_sec)*1000 + time.tv_usec/1000;
32 | #endif
33 | }
34 |
35 | inline
36 | void Sleep(Duration milliseconds) {
37 | #ifdef _WIN32
38 | ::Sleep(static_cast(milliseconds));
39 | #else
40 | timespec time = { static_cast(milliseconds/1000),
41 | static_cast(milliseconds%1000)*1000000 };
42 | while (nanosleep(&time, &time)) {}
43 | #endif
44 | }
45 |
46 | } // namespace detail
47 | } // namespace webdriverxx
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/include/webdriverxx/client.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_CLIENT_H
2 | #define WEBDRIVERXX_CLIENT_H
3 |
4 | #include "session.h"
5 | #include "capabilities.h"
6 | #include "detail/resource.h"
7 | #include "detail/http_connection.h"
8 | #include "picojson.h"
9 | #include
10 | #include
11 |
12 | namespace webdriverxx {
13 |
14 | const char *const kDefaultWebDriverUrl = "http://localhost:4444/wd/hub/";
15 |
16 | // Gives low level access to server's resources. You normally should not use it.
17 | class Client { // copyable
18 | public:
19 | explicit Client(const std::string& url = kDefaultWebDriverUrl);
20 | virtual ~Client() {}
21 |
22 | picojson::object GetStatus() const;
23 |
24 | // Returns existing sessions.
25 | std::vector GetSessions() const;
26 |
27 | // Creates new session.
28 | Session CreateSession(
29 | const Capabilities& desired,
30 | const Capabilities& required
31 | ) const;
32 |
33 | private:
34 | Session MakeSession(
35 | const std::string& id,
36 | detail::Resource::Ownership mode
37 | ) const;
38 |
39 | private:
40 | detail::Shared resource_;
41 | };
42 |
43 | } // namespace webdriverxx
44 |
45 | #include "client.inl"
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/include/webdriverxx/window.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_WINDOW_H
2 | #define WEBDRIVERXX_WINDOW_H
3 |
4 | #include "types.h"
5 | #include "conversions.h"
6 | #include "detail/resource.h"
7 | #include
8 |
9 | namespace webdriverxx {
10 |
11 | class Window { // copyable
12 | public:
13 | Window(const std::string& handle, const detail::Shared& resource)
14 | : handle_(handle)
15 | , resource_(resource)
16 | {}
17 |
18 | std::string GetHandle() const {
19 | return handle_;
20 | }
21 |
22 | Size GetSize() const {
23 | return resource_->GetValue("size");
24 | }
25 |
26 | const Window& SetSize(const Size& size) const {
27 | resource_->PostValue("size", size);
28 | return *this;
29 | }
30 |
31 | Point GetPosition() const {
32 | return resource_->GetValue("position");
33 | }
34 |
35 | const Window& SetPosition(const Point& position) const {
36 | resource_->PostValue("position", position);
37 | return *this;
38 | }
39 |
40 | const Window& Maximize() const {
41 | resource_->Post("maximize");
42 | return *this;
43 | }
44 |
45 | private:
46 | std::string handle_;
47 | detail::Shared resource_;
48 | };
49 |
50 | } // namespace webdriverxx
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/http_connection.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_HTTP_CONNECTION_H
2 | #define WEBDRIVERXX_DETAIL_HTTP_CONNECTION_H
3 |
4 | #include "http_client.h"
5 | #include "http_request.h"
6 | #include "error_handling.h"
7 | #include "shared.h"
8 | #include
9 |
10 | namespace webdriverxx {
11 | namespace detail {
12 |
13 | class HttpConnection // noncopyable
14 | : public IHttpClient
15 | , public SharedObjectBase
16 | {
17 | public:
18 | HttpConnection()
19 | : connection_(InitCurl())
20 | {}
21 |
22 | ~HttpConnection() {
23 | curl_easy_cleanup(connection_);
24 | }
25 |
26 | HttpResponse Get(const std::string& url) const {
27 | return HttpGetRequest(connection_, url).Execute();
28 | }
29 |
30 | HttpResponse Delete(const std::string& url) const {
31 | return HttpDeleteRequest(connection_, url).Execute();
32 | }
33 |
34 | HttpResponse Post(
35 | const std::string& url,
36 | const std::string& upload_data
37 | ) const {
38 | return HttpPostRequest(connection_, url, upload_data).Execute();
39 | }
40 |
41 | private:
42 | static
43 | CURL* InitCurl() {
44 | CURL *const result = curl_easy_init();
45 | WEBDRIVERXX_CHECK(result, "Cannot initialize CURL");
46 | return result;
47 | }
48 |
49 | private:
50 | CURL *const connection_;
51 | };
52 |
53 | } // namespace detail
54 | } // namespace webdriverxx
55 |
56 | #endif
57 |
--------------------------------------------------------------------------------
/include/webdriverxx/by.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_BY_H
2 | #define WEBDRIVERXX_BY_H
3 |
4 | #include
5 |
6 | namespace webdriverxx {
7 |
8 | class By { // copyable
9 | public:
10 | By(const std::string& strategy, const std::string& value)
11 | : strategy_(strategy)
12 | , value_(value)
13 | {}
14 |
15 | const std::string& GetStrategy() const {
16 | return strategy_;
17 | }
18 |
19 | const std::string& GetValue() const {
20 | return value_;
21 | }
22 |
23 | private:
24 | std::string strategy_;
25 | std::string value_;
26 | };
27 |
28 | inline By ByClass(const std::string& value) {
29 | return By("class name", value);
30 | }
31 |
32 | inline By ByCss(const std::string& value) {
33 | return By("css selector", value);
34 | }
35 |
36 | inline By ById(const std::string& value) {
37 | return By("id", value);
38 | }
39 |
40 | inline By ByName(const std::string& value) {
41 | return By("name", value);
42 | }
43 |
44 | inline By ByLinkText(const std::string& value) {
45 | return By("link text", value);
46 | }
47 |
48 | inline By ByPartialLinkText(const std::string& value) {
49 | return By("partial link text", value);
50 | }
51 |
52 | inline By ByTag(const std::string& value) {
53 | return By("tag name", value);
54 | }
55 |
56 | inline By ByXPath(const std::string& value) {
57 | return By("xpath", value);
58 | }
59 |
60 | } // namespace webdriverxx
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/test/alerts_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | class TestAlerts : public ::testing::Test {
10 | protected:
11 | static void SetUpTestCase() {
12 | GetDriver().Navigate(GetTestPageUrl("alerts.html"));
13 | }
14 |
15 | TestAlerts() : driver(GetDriver()) {}
16 |
17 | WebDriver driver;
18 | };
19 |
20 | TEST_F(TestAlerts, AcceptsAlert) {
21 | if (IsPhantom()) return;
22 | driver.Execute("alert('abc')");
23 | driver.AcceptAlert();
24 | }
25 |
26 | TEST_F(TestAlerts, DismissesAlert) {
27 | if (IsPhantom()) return;
28 | driver.Execute("alert('abc')");
29 | driver.DismissAlert();
30 | }
31 |
32 | TEST_F(TestAlerts, GetsAlertText) {
33 | if (IsPhantom()) return;
34 | driver.Execute("alert('abc')");
35 | ASSERT_EQ("abc", driver.GetAlertText());
36 | driver.DismissAlert();
37 | }
38 |
39 | TEST_F(TestAlerts, SendsKeysToAlert) {
40 | if (IsPhantom()) return;
41 | driver.Execute("result = prompt('abc')");
42 | driver.SendKeysToAlert("def");
43 | driver.AcceptAlert();
44 | ASSERT_EQ("def", driver.Eval("return result"));
45 | }
46 |
47 | TEST_F(TestAlerts, DismissesSendedKeys) {
48 | if (IsPhantom()) return;
49 | driver.Execute("result = prompt('abc')");
50 | driver.SendKeysToAlert("def");
51 | driver.DismissAlert();
52 | ASSERT_FALSE(driver.Eval("return result"));
53 | }
54 |
55 | } // namespace test
56 |
--------------------------------------------------------------------------------
/test/keyboard_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 | #include
5 |
6 | namespace test {
7 |
8 | using namespace webdriverxx;
9 |
10 | class TestKeyboard : public ::testing::Test {
11 | protected:
12 | static void SetUpTestCase() {
13 | GetDriver().Navigate(GetTestPageUrl("keyboard.html"));
14 | }
15 |
16 | TestKeyboard() : driver(GetDriver()) {}
17 |
18 | WebDriver driver;
19 | };
20 |
21 | TEST_F(TestKeyboard, SendsKeysToElement) {
22 | Element e = driver.FindElement(ByName("first"));
23 | e.Clear()
24 | .SendKeys("abc")
25 | .SendKeys(keys::Left).SendKeys(keys::Left).SendKeys(keys::Left)
26 | .SendKeys("def")
27 | ;
28 | ASSERT_EQ("abcdef", e.GetAttribute("value"));
29 | }
30 |
31 | TEST_F(TestKeyboard, SendsShortcuts) {
32 | Element e = driver.FindElement(ByName("first"));
33 | e.Clear()
34 | .SendKeys(Shortcut() << keys::Shift << "a" << "bc")
35 | .SendKeys("def")
36 | ;
37 | ASSERT_EQ("ABCdef", e.GetAttribute("value"));
38 | }
39 |
40 | TEST_F(TestKeyboard, SendsKeysToActiveElement) {
41 | Element first = driver.FindElement(ByName("first"));
42 | Element second = driver.FindElement(ByName("second"));
43 | first.Click().Clear();
44 | driver.SendKeys("abc");
45 | second.Click().Clear();
46 | driver.SendKeys("def");
47 | ASSERT_EQ("abc", first.GetAttribute("value"));
48 | ASSERT_EQ("def", second.GetAttribute("value"));
49 | }
50 |
51 | } // namespace test
52 |
--------------------------------------------------------------------------------
/test/main.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | Environment* Environment::instance_ = 0;
8 |
9 | bool IsCommandLineArgument(const std::string& arg, const char* name) {
10 | return arg.find(std::string("--") + name) == 0;
11 | }
12 |
13 | std::string GetCommandLineArgumentValue(const std::string& arg) {
14 | const size_t pos = arg.find('=');
15 | return pos == std::string::npos ? std::string() : arg.substr(pos + 1);
16 | }
17 |
18 | Parameters ParseParameters(int argc, char **argv) {
19 | Parameters result;
20 | for(int i = 1; i < argc; ++i) {
21 | const std::string arg = argv[i];
22 | if (IsCommandLineArgument(arg, "browser")) {
23 | result.web_driver_url = webdriverxx::kDefaultWebDriverUrl;
24 | const std::string browser_name = GetCommandLineArgumentValue(arg);
25 | result.desired.Set("browserName", browser_name);
26 | } else if (IsCommandLineArgument(arg, "pages")) {
27 | result.test_pages_url = GetCommandLineArgumentValue(arg);
28 | } else if (IsCommandLineArgument(arg, "webdriver")) {
29 | result.web_driver_url = GetCommandLineArgumentValue(arg);
30 | } else if (IsCommandLineArgument(arg, "test_real_browsers")) {
31 | result.test_real_browsers = true;
32 | }
33 | }
34 | return result;
35 | }
36 |
37 | } // namespace test
38 |
39 | int main(int argc, char **argv) {
40 | ::testing::InitGoogleTest(&argc, argv);
41 | ::testing::AddGlobalTestEnvironment(
42 | new test::Environment(test::ParseParameters(argc, argv))
43 | );
44 | return RUN_ALL_TESTS();
45 | }
46 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/finder.inl:
--------------------------------------------------------------------------------
1 | #include "../conversions.h"
2 | #include "../element.h"
3 | #include "types.h"
4 | #include
5 |
6 | namespace webdriverxx {
7 | namespace detail {
8 |
9 | inline
10 | Finder::Finder(
11 | const Shared& context,
12 | const Shared& factory
13 | )
14 | : context_(context)
15 | , factory_(factory)
16 | {}
17 |
18 | inline
19 | Element Finder::FindElement(const By& by) const {
20 | WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()
21 | return factory_->MakeElement(FromJson(
22 | context_->Post("element", JsonObject()
23 | .Set("using", by.GetStrategy())
24 | .Set("value", by.GetValue())
25 | )).ref);
26 | WEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()
27 | << "context: " << context_->GetUrl()
28 | << ", strategy: " << by.GetStrategy()
29 | << ", value: " << by.GetValue()
30 | )
31 | }
32 |
33 | inline
34 | std::vector Finder::FindElements(const By& by) const {
35 | WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()
36 | const auto ids =
37 | FromJson>(
38 | context_->Post("elements", JsonObject()
39 | .Set("using", by.GetStrategy())
40 | .Set("value", by.GetValue())
41 | ));
42 | std::vector result;
43 | result.reserve(ids.size());
44 | std::transform(ids.begin(), ids.end(), std::back_inserter(result),
45 | [this](const ElementRef& element_ref) {
46 | return factory_->MakeElement(element_ref.ref);
47 | });
48 | return result;
49 | WEBDRIVERXX_FUNCTION_CONTEXT_END_EX(Fmt()
50 | << "context: " << context_->GetUrl()
51 | << ", strategy: " << by.GetStrategy()
52 | << ", value: " << by.GetValue()
53 | )
54 | }
55 |
56 | } // namespace detail
57 | } // namespace webdriverxx
58 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/error_handling.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_ERROR_HANDLING_H
2 | #define WEBDRIVERXX_DETAIL_ERROR_HANDLING_H
3 |
4 | #include "../errors.h"
5 | #include
6 | #include
7 |
8 | namespace webdriverxx {
9 | namespace detail {
10 |
11 | class Fmt {
12 | public:
13 | template
14 | Fmt& operator << (const T& value) {
15 | stream_ << value;
16 | return *this;
17 | }
18 |
19 | operator std::string() const {
20 | return stream_.str();
21 | }
22 |
23 | private:
24 | std::ostringstream stream_;
25 | };
26 |
27 | template
28 | bool BoolCast(T value) {
29 | return !!value;
30 | }
31 |
32 | } // namespace detail
33 | } // namespace webdriverxx
34 |
35 | #if __cplusplus >= 201103L
36 | #define WEBDRIVERXX_CURRENT_FUNCTION __func__
37 | #else
38 | #define WEBDRIVERXX_CURRENT_FUNCTION __FUNCTION__
39 | #endif
40 |
41 | #define WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN() \
42 | try {
43 |
44 | #define WEBDRIVERXX_FUNCTION_CONTEXT_END() \
45 | } catch (const std::exception& e) { \
46 | throw ::webdriverxx::WebDriverException(std::string(e.what()) \
47 | + " called from " + WEBDRIVERXX_CURRENT_FUNCTION); \
48 | }
49 |
50 | #define WEBDRIVERXX_FUNCTION_CONTEXT_END_EX(details) \
51 | } catch (const std::exception& e) { \
52 | throw ::webdriverxx::WebDriverException(std::string(e.what()) \
53 | + " called from " + WEBDRIVERXX_CURRENT_FUNCTION \
54 | + " (" + std::string(details) + ")"); \
55 | }
56 |
57 | #define WEBDRIVERXX_THROW(message) \
58 | throw ::webdriverxx::WebDriverException(::webdriverxx::detail::Fmt() \
59 | << std::string(message) \
60 | << " at line " << __LINE__ \
61 | << ", file " << __FILE__ \
62 | )
63 |
64 | #define WEBDRIVERXX_CHECK(pred, message) \
65 | for (;!detail::BoolCast(pred);) \
66 | WEBDRIVERXX_THROW(message)
67 |
68 | #endif
69 |
--------------------------------------------------------------------------------
/test/browsers_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace test {
9 |
10 | using namespace webdriverxx;
11 |
12 | TEST(Firefox, WithTheSimplestSyntax) {
13 | if (!TestRealBrowsers()) return;
14 | auto ff = Start(Firefox());
15 | }
16 |
17 | TEST(Firefox, WithCustomUrl) {
18 | if (!TestRealBrowsers()) return;
19 | auto ff = Start(Firefox(), kDefaultWebDriverUrl);
20 | }
21 |
22 | TEST(Firefox, WithDefaultCapabilities) {
23 | if (!TestRealBrowsers()) return;
24 | auto defaults = Capabilities().SetProxy(DirectConnection());
25 | auto ff = Start(Firefox(defaults));
26 | }
27 |
28 | TEST(Firefox, HasCapabilitiesProperties) {
29 | if (!TestRealBrowsers()) return;
30 | auto ff = Start(Firefox().SetProxy(DirectConnection()));
31 | }
32 |
33 | TEST(Firefox, ConvertsToJson) {
34 | auto ff = Firefox()
35 | .SetLoggingPrefs(LoggingPrefs().SetLevel(log_level::Warning))
36 | .SetFirefoxBinary("abc");
37 | const auto json = ToJson(ff);
38 | const auto c = FromJson(json);
39 | const auto logging = c.Get("loggingPrefs");
40 | ASSERT_EQ(browser::Firefox, c.GetBrowserName());
41 | ASSERT_EQ("WARNING", logging.Get("driver"));
42 | ASSERT_EQ("abc", c.Get("firefox_binary"));
43 | }
44 |
45 | TEST(InternetExplorer, ConvertsToJson) {
46 | auto ie = InternetExplorer();
47 | const auto json = ToJson(ie);
48 | const auto c = FromJson(json);
49 | ASSERT_EQ(browser::InternetExplorer, c.GetBrowserName());
50 | }
51 |
52 | TEST(Chrome, ConvertsToJson) {
53 | auto gc = Chrome();
54 | const auto json = ToJson(gc);
55 | const auto c = FromJson(json);
56 | ASSERT_EQ(browser::Chrome, c.GetBrowserName());
57 | }
58 |
59 | } // namespace test
60 |
--------------------------------------------------------------------------------
/include/webdriverxx/types.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_TYPES_H
2 | #define WEBDRIVERXX_TYPES_H
3 |
4 | #include
5 |
6 | namespace webdriverxx {
7 |
8 | typedef unsigned long long TimePoint;
9 | typedef unsigned Duration;
10 |
11 | struct Size {
12 | int width;
13 | int height;
14 | Size() : width(0), height(0) {}
15 | };
16 |
17 | struct Point {
18 | int x;
19 | int y;
20 | Point() : x(0), y(0) {}
21 | Point(int x, int y) : x(x), y(y) {}
22 | };
23 |
24 | typedef Point Offset;
25 |
26 | struct Cookie {
27 | enum {
28 | NoExpiry = 0
29 | };
30 |
31 | std::string name;
32 | std::string value;
33 | std::string path;
34 | std::string domain;
35 | bool secure;
36 | bool http_only;
37 | int expiry; // seconds since midnight, January 1, 1970 UTC
38 |
39 | Cookie() : secure(false), http_only(false), expiry(NoExpiry) {}
40 | Cookie(
41 | const std::string& name,
42 | const std::string& value,
43 | const std::string& path = std::string(),
44 | const std::string& domain = std::string(),
45 | bool secure = false,
46 | bool http_only = false,
47 | int expiry = NoExpiry
48 | )
49 | : name(name)
50 | , value(value)
51 | , path(path)
52 | , domain(domain)
53 | , secure(secure)
54 | , http_only(http_only)
55 | , expiry(expiry)
56 | {}
57 |
58 | bool operator == (const Cookie& c) const {
59 | return name == c.name
60 | && value == c.value
61 | && path == c.path
62 | && domain == c.domain
63 | && secure == c.secure
64 | && http_only == c.http_only
65 | && expiry == c.expiry
66 | ;
67 | }
68 | };
69 |
70 | namespace timeout {
71 |
72 | typedef const char* Type;
73 |
74 | Type const Implicit = "implicit";
75 | Type const PageLoad = "page load";
76 | Type const Script = "script";
77 |
78 | } // namespace timeout
79 |
80 | namespace mouse {
81 | enum Button {
82 | LeftButton = 0,
83 | MiddleButton = 1,
84 | RightButton = 2
85 | };
86 | } // namespace mouse
87 |
88 | } // namespace webdriverxx
89 |
90 | #endif
91 |
--------------------------------------------------------------------------------
/test/frames_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | class TestFrames : public ::testing::Test {
10 | protected:
11 | TestFrames()
12 | : driver(GetDriver())
13 | , url(GetTestPageUrl("frames.html"))
14 | {}
15 |
16 | void SetUp()
17 | {
18 | driver.Navigate(url);
19 | }
20 |
21 | WebDriver driver;
22 | std::string url;
23 | };
24 |
25 | TEST_F(TestFrames, OnTopFrameByDefault) {
26 | ASSERT_EQ("top_frame", driver.FindElement(ById("tag")).GetAttribute("value"));
27 | }
28 |
29 | TEST_F(TestFrames, CanSwitchToFrameByNumber) {
30 | driver.SetFocusToFrame(1);
31 | ASSERT_EQ("frame3", driver.FindElement(ById("tag")).GetAttribute("value"));
32 | }
33 |
34 | TEST_F(TestFrames, CanSwitchToFrameByName) {
35 | driver.SetFocusToFrame("frame3_name");
36 | ASSERT_EQ("frame3", driver.FindElement(ById("tag")).GetAttribute("value"));
37 | }
38 |
39 | TEST_F(TestFrames, CanSwitchToFrameByElement) {
40 | std::vector frames = driver.FindElements(ByTag("iframe"));
41 | ASSERT_EQ(2u, frames.size());
42 | driver.SetFocusToFrame(frames[1]);
43 | ASSERT_EQ("frame3", driver.FindElement(ById("tag")).GetAttribute("value"));
44 | }
45 |
46 | TEST_F(TestFrames, CanSwitchToDefaultFrame) {
47 | driver.SetFocusToFrame(1);
48 | driver.SetFocusToDefaultFrame();
49 | ASSERT_EQ("top_frame", driver.FindElement(ById("tag")).GetAttribute("value"));
50 | }
51 |
52 | TEST_F(TestFrames, CanSwitchToDeepFrames) {
53 | driver.SetFocusToFrame(0).SetFocusToFrame(1);
54 | ASSERT_EQ("frame2", driver.FindElement(ById("tag")).GetAttribute("value"));
55 | }
56 |
57 | TEST_F(TestFrames, CanSwitchToParentFrame) {
58 | if (IsPhantom()) return; // Not supported in PhantomJS 1.9.7
59 | driver.SetFocusToFrame(0).SetFocusToFrame(1)
60 | .SetFocusToParentFrame().SetFocusToParentFrame();
61 | ASSERT_EQ("top_frame", driver.FindElement(ById("tag")).GetAttribute("value"));
62 | }
63 |
64 | } // namespace test
65 |
--------------------------------------------------------------------------------
/include/webdriverxx/element.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_ELEMENT_H
2 | #define WEBDRIVERXX_ELEMENT_H
3 |
4 | #include "by.h"
5 | #include "types.h"
6 | #include "keys.h"
7 | #include "detail/shared.h"
8 | #include "detail/keyboard.h"
9 | #include "detail/resource.h"
10 | #include "detail/factories.h"
11 | #include
12 | #include
13 |
14 | namespace webdriverxx {
15 |
16 | // An element from DOM
17 | class Element { // copyable
18 | public:
19 | Element();
20 |
21 | Element(
22 | const std::string& ref,
23 | const detail::Shared& resource,
24 | const detail::Shared& factory
25 | );
26 |
27 | std::string GetRef() const; // Returns ID that is used by Webdriver to identify elements
28 |
29 | bool IsDisplayed() const;
30 | bool IsEnabled() const;
31 | bool IsSelected() const;
32 | Point GetLocation() const;
33 | Point GetLocationInView() const;
34 | Size GetSize() const;
35 | std::string GetAttribute(const std::string& name) const;
36 | std::string GetCssProperty(const std::string& name) const;
37 | std::string GetTagName() const;
38 | std::string GetText() const;
39 |
40 | Element FindElement(const By& by) const;
41 | std::vector FindElements(const By& by) const;
42 |
43 | const Element& Clear() const;
44 | const Element& Click() const;
45 | const Element& Submit() const;
46 |
47 | const Element& SendKeys(const std::string& keys) const;
48 | const Element& SendKeys(const Shortcut& shortcut) const;
49 |
50 | bool Equals(const Element& other) const;
51 | bool operator != (const Element& other) const;
52 | bool operator == (const Element& other) const;
53 | bool operator < (const Element& other) const;
54 |
55 | private:
56 | detail::Resource& GetResource() const;
57 | detail::Keyboard GetKeyboard() const;
58 |
59 | private:
60 | std::string ref_;
61 | detail::Shared resource_;
62 | detail::Shared factory_;
63 | };
64 |
65 | } // namespace webdriverxx
66 |
67 | #include "element.inl"
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/test/examples_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #ifndef WEBDRIVERXX_ENABLE_GMOCK_MATCHERS
4 | #define WEBDRIVERXX_ENABLE_GMOCK_MATCHERS
5 | #endif
6 | #include
7 | #include
8 |
9 | namespace test {
10 |
11 | using namespace webdriverxx;
12 |
13 | class TestExamples : public ::testing::Test {
14 | protected:
15 | TestExamples() : driver(GetDriver()) {}
16 |
17 | void StopNavigation() {
18 | WaitForMatch([this] {
19 | return driver.Navigate(GetTestPageUrl("non_existing.html")).GetUrl();
20 | }, ::testing::HasSubstr("non_existing"));
21 | }
22 |
23 | WebDriver driver;
24 | };
25 |
26 | TEST_F(TestExamples, QuickExample) {
27 | driver
28 | .Navigate("http://google.com")
29 | .FindElement(ByCss("input[name=q]"))
30 | .SendKeys("Hello, world!")
31 | .Submit();
32 |
33 | StopNavigation(); // Firefox doesn't perform navigation right after Submit.
34 | }
35 |
36 | TEST_F(TestExamples, ImplicitWait) {
37 | driver.SetImplicitTimeoutMs(0);
38 | try {
39 | Element element = driver.FindElement(ByName("akela"));
40 | FAIL();
41 | } catch (const std::exception&) {}
42 | }
43 |
44 | TEST_F(TestExamples, ExplicitWait1) {
45 | auto find_element = [&]{ return driver.FindElement(ById("async_loaded")); };
46 | try {
47 | int timeout = 0;
48 | Element element = WaitForValue(find_element, timeout);
49 | FAIL();
50 | } catch (const std::exception&) {}
51 | }
52 |
53 | TEST_F(TestExamples, ExplicitWait2) {
54 | auto element_is_selected = [&]{
55 | return driver.FindElement(ById("async_loaded")).IsSelected();
56 | };
57 | try {
58 | int timeout = 0;
59 | WaitUntil(element_is_selected, timeout);
60 | FAIL();
61 | } catch (const std::exception&) {}
62 | }
63 |
64 | TEST_F(TestExamples, UseGmockMatchers) {
65 | driver.Navigate(GetTestPageUrl("redirect.html"));
66 | auto url = [&]{ return driver.GetUrl(); };
67 | using namespace ::testing;
68 | WaitForMatch(url, HasSubstr("target"));
69 | StopNavigation();
70 | }
71 |
72 | } // namespace test
73 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/types.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_TYPES_H
2 | #define WEBDRIVERXX_DETAIL_TYPES_H
3 |
4 | #include "../conversions.h"
5 | #include "../capabilities.h"
6 | #include "../picojson.h"
7 | #include
8 |
9 | namespace webdriverxx {
10 | namespace detail {
11 |
12 | struct SessionRef {
13 | std::string id;
14 | Capabilities capabilities;
15 | };
16 |
17 | struct ElementRef {
18 | std::string ref;
19 | };
20 |
21 | inline
22 | picojson::value CustomToJson(const ElementRef& ref) {
23 | return JsonObject()
24 | .Set("ELEMENT", ref.ref)
25 | ;
26 | }
27 |
28 | inline
29 | void CustomFromJson(const picojson::value& value, ElementRef& result) {
30 | WEBDRIVERXX_CHECK(value.is(), "ElementRef is not an object");
31 | result.ref = FromJson(value.get("ELEMENT"));
32 | if (result.ref == "null") {
33 | std::stringstream element(value.serialize());
34 | std::string segment;
35 | std::vector strArr;
36 | while (std::getline(element, segment, ':')) {
37 | segment.erase(std::remove(segment.begin(), segment.end(), '{'), segment.end());
38 | segment.erase(std::remove(segment.begin(), segment.end(), '"'), segment.end());
39 | segment.erase(std::remove(segment.begin(), segment.end(), '}'), segment.end());
40 | strArr.push_back(segment);
41 | }
42 | if (strArr.size() >= 1) {
43 | std::stringstream ss;
44 | ss << "{\"ELEMENT\":" << "\"" << strArr[1] << "\"}";
45 | picojson::value jSon;
46 | picojson::parse(jSon, ss);
47 | result.ref = FromJson(jSon.get("ELEMENT"));
48 | }
49 | }
50 | }
51 |
52 | inline
53 | void CustomFromJson(const picojson::value& value, SessionRef& result) {
54 | WEBDRIVERXX_CHECK(value.is(), "Session information is not an object");
55 | result.id = value.get("sessionId").to_str();
56 | if (value.get("capabilities").is())
57 | result.capabilities = Capabilities(value.get("capabilities").get());
58 | }
59 |
60 | } // namespace detail
61 | } // namespace webdriverxx
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/include/webdriverxx/browsers/chrome.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_BROWSERS_CHROME_H
2 | #define WEBDRIVERXX_BROWSERS_CHROME_H
3 |
4 | #include "../capabilities.h"
5 |
6 | namespace webdriverxx {
7 | namespace chrome {
8 |
9 | struct PerfLoggingPrefs : JsonObject {
10 | WEBDRIVERXX_PROPERTIES_BEGIN(PerfLoggingPrefs)
11 | WEBDRIVERXX_PROPERTY(EnableNetwork, "enableNetwork", bool)
12 | WEBDRIVERXX_PROPERTY(enablePage, "enablePage", bool)
13 | WEBDRIVERXX_PROPERTY(enableTimeline, "enableTimeline", bool)
14 | WEBDRIVERXX_PROPERTY(tracingCategories, "tracingCategories", std::string)
15 | WEBDRIVERXX_PROPERTY(bufferUsageReportingInterval, "bufferUsageReportingInterval", int)
16 | WEBDRIVERXX_PROPERTIES_END()
17 | };
18 |
19 | } // namespace chrome
20 |
21 | struct Chrome : Capabilities { // copyable
22 | Chrome(const Capabilities& defaults = Capabilities())
23 | : Capabilities(defaults) {
24 | SetBrowserName(browser::Chrome);
25 | SetVersion("");
26 | SetPlatform(platform::Any);
27 | }
28 |
29 | // See https://sites.google.com/a/chromium.org/chromedriver/capabilities for details
30 | WEBDRIVERXX_PROPERTIES_BEGIN(Chrome)
31 | WEBDRIVERXX_PROPERTY(LoggingPrefs, "loggingPrefs", LoggingPrefs)
32 | WEBDRIVERXX_PROPERTY(Args, "args", std::vector)
33 | WEBDRIVERXX_PROPERTY(Binary, "binary", std::string)
34 | // Each extension is a base64-encoded .crx file
35 | WEBDRIVERXX_PROPERTY(Extensions, "extensions", std::vector)
36 | WEBDRIVERXX_PROPERTY(LocalState, "localState", JsonObject)
37 | WEBDRIVERXX_PROPERTY(Prefs, "prefs", JsonObject)
38 | WEBDRIVERXX_PROPERTY(Detach, "detach", bool)
39 | WEBDRIVERXX_PROPERTY(DebuggerAddress, "debuggerAddress", std::string)
40 | WEBDRIVERXX_PROPERTY(ExcludeSwitches, "excludeSwitches", std::vector)
41 | WEBDRIVERXX_PROPERTY(MinidumpPath, "minidumpPath", std::string)
42 | WEBDRIVERXX_PROPERTY(MobileEmulation, "mobileEmulation", JsonObject)
43 | WEBDRIVERXX_PROPERTY(PerfLoggingPrefs, "perfLoggingPrefs", chrome::PerfLoggingPrefs)
44 | WEBDRIVERXX_PROPERTIES_END()
45 | };
46 |
47 | } // namespace webdriverxx
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/shared.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_DETAIL_SHARED_H
2 | #define WEBDRIVERXX_DETAIL_SHARED_H
3 |
4 | #include
5 |
6 | namespace webdriverxx {
7 | namespace detail {
8 |
9 | class SharedObjectBase { // noncopyable
10 | public:
11 | SharedObjectBase() : ref_(0) {}
12 | virtual ~SharedObjectBase() {}
13 |
14 | virtual void AddRef() {
15 | ++ref_;
16 | }
17 |
18 | virtual void Release() {
19 | if (--ref_ == 0)
20 | delete this;
21 | }
22 |
23 | private:
24 | SharedObjectBase(SharedObjectBase&);
25 | SharedObjectBase& operator = (SharedObjectBase&);
26 |
27 | private:
28 | unsigned ref_;
29 | };
30 |
31 | // Copyable, not thread safe
32 | template
33 | class Shared {
34 | public:
35 | Shared()
36 | : ptr_(nullptr)
37 | , ref_(nullptr)
38 | {}
39 |
40 | template
41 | Shared(T2* ptr)
42 | : ptr_(ptr)
43 | , ref_(ptr)
44 | {
45 | if (ref_) ref_->AddRef();
46 | }
47 |
48 | Shared(const Shared& other)
49 | : ptr_(other.ptr_)
50 | , ref_(other.ref_)
51 | {
52 | if (ref_) ref_->AddRef();
53 | }
54 |
55 | template
56 | Shared(const Shared& other)
57 | : ptr_(other.ptr_)
58 | , ref_(other.ref_)
59 | {
60 | if (ref_) ref_->AddRef();
61 | }
62 |
63 | ~Shared() {
64 | if (ref_) ref_->Release();
65 | }
66 |
67 | Shared& operator = (const Shared& other) {
68 | if (&other != this)
69 | Shared(other).Swap(*this);
70 | return *this;
71 | }
72 |
73 | void Swap(Shared& other) {
74 | std::swap(ptr_, other.ptr_);
75 | std::swap(ref_, other.ref_);
76 | }
77 |
78 | T& operator * () const {
79 | return *ptr_;
80 | }
81 |
82 | T* operator -> () const {
83 | return ptr_;
84 | }
85 |
86 | T* Get() const {
87 | return ptr_;
88 | }
89 |
90 | operator T* () const {
91 | return ptr_;
92 | }
93 |
94 | private:
95 | template
96 | friend class Shared;
97 |
98 | T* ptr_;
99 | SharedObjectBase* ref_;
100 | };
101 |
102 | } // namespace detail
103 | } // namespace webdriverxx
104 |
105 | #endif
106 |
--------------------------------------------------------------------------------
/include/webdriverxx/browsers/ie.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_BROWSERS_IE_H
2 | #define WEBDRIVERXX_BROWSERS_IE_H
3 |
4 | #include "../capabilities.h"
5 |
6 | namespace webdriverxx {
7 | namespace ie {
8 |
9 | namespace log_level {
10 | typedef std::string Value;
11 | typedef const char* const ConstValue;
12 | ConstValue Trace = "TRACE";
13 | ConstValue Debug = "DEBUG";
14 | ConstValue Info = "INFO";
15 | ConstValue Warning = "WARN";
16 | ConstValue Error = "ERROR";
17 | ConstValue Fatal = "FATAL";
18 | } // namespace log_level
19 |
20 | } // namespace ie
21 |
22 | struct InternetExplorer : Capabilities { // copyable
23 | InternetExplorer(const Capabilities& defaults = Capabilities())
24 | : Capabilities(defaults) {
25 | SetBrowserName(browser::InternetExplorer);
26 | SetVersion("");
27 | SetPlatform(platform::Any);
28 | }
29 |
30 | WEBDRIVERXX_PROPERTIES_BEGIN(InternetExplorer)
31 | WEBDRIVERXX_PROPERTY(SkipProtectedModeCheck, "ignoreProtectedModeSettings", bool)
32 | WEBDRIVERXX_PROPERTY(IgnoreZoomSetting, "ignoreZoomSetting", bool)
33 | WEBDRIVERXX_PROPERTY(InitialUrl, "initialBrowserUrl", std::string)
34 | WEBDRIVERXX_PROPERTY(EnablePersistentHover, "enablePersistentHover", bool)
35 | WEBDRIVERXX_PROPERTY(EnableElementCacheCleanup, "enableElementCacheCleanup", bool)
36 | WEBDRIVERXX_PROPERTY(RequireWindowFocus, "requireWindowFocus", bool)
37 | WEBDRIVERXX_PROPERTY(BrowserAttachTimeoutMs, "browserAttachTimeout", int)
38 | WEBDRIVERXX_PROPERTY(ForceCreateProcessApi, "ie.forceCreateProcessApi", bool)
39 | WEBDRIVERXX_PROPERTY(CommandLineSwitches, "ie.browserCommandLineSwitches", std::string)
40 | WEBDRIVERXX_PROPERTY(UsePerProcessProxy, "ie.usePerProcessProxy", bool)
41 | WEBDRIVERXX_PROPERTY(EnsureCleanSession, "ie.ensureCleanSession", bool)
42 | WEBDRIVERXX_PROPERTY(LogFile, "logFile", std::string)
43 | WEBDRIVERXX_PROPERTY(LogLevel, "logLevel", ie::log_level::Value)
44 | WEBDRIVERXX_PROPERTY(Host, "host", std::string)
45 | WEBDRIVERXX_PROPERTY(ExtractPath, "extractPath", std::string)
46 | WEBDRIVERXX_PROPERTY(Silent, "silent", bool)
47 | WEBDRIVERXX_PROPERTY(ProxyByServer, "ie.setProxyByServer", bool)
48 | WEBDRIVERXX_PROPERTIES_END()
49 | };
50 |
51 | } // namespace webdriverxx
52 |
53 | #endif
54 |
--------------------------------------------------------------------------------
/test/capabilities_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace test {
5 |
6 | using namespace webdriverxx;
7 |
8 | TEST(Capabilities, AllowsToSetAndGetCustomValues) {
9 | Capabilities c;
10 | c.Set("int", 123);
11 | c.Set("double", 456.7);
12 | c.Set("string", "abc");
13 | c.Set("bool", true);
14 | ASSERT_EQ(123, c.Get("int"));
15 | ASSERT_EQ(456.7, c.Get("double"));
16 | ASSERT_EQ("abc", c.Get("string"));
17 | ASSERT_EQ(true, c.Get("bool"));
18 | }
19 |
20 | TEST(Capabilities, ConvertibleToJson) {
21 | Capabilities c;
22 | c.Set("int", 123);
23 | c.Set("string", "abc");
24 | const auto json = ToJson(c);
25 | const auto c_copy = FromJson(json);
26 | ASSERT_EQ(123, c_copy.Get("int"));
27 | ASSERT_EQ("abc", c_copy.Get("string"));
28 | }
29 |
30 | TEST(Capabilities, AllowsToSetProxy) {
31 | Capabilities().SetProxy(DirectConnection());
32 | Capabilities().SetProxy(AutodetectProxy());
33 | Capabilities().SetProxy(SystemProxy());
34 | Capabilities().SetProxy(FtpProxy("127.0.0.1:3128").SetNoProxyFor("custom.host"));
35 | Capabilities().SetProxy(HttpProxy("127.0.0.1:3128").SetNoProxyFor("custom.host"));
36 | Capabilities().SetProxy(SslProxy("127.0.0.1:3128").SetNoProxyFor("custom.host"));
37 | Capabilities().SetProxy(SocksProxy("127.0.0.1:3128")
38 | .SetUsername("user").SetPassword("12345").SetNoProxyFor("custom.host")
39 | );
40 | Capabilities().SetProxy(AutomaticProxyFromUrl("http://some.url"));
41 | }
42 |
43 | TEST(Capabilities, ConvertsProxyToJson) {
44 | Capabilities c;
45 | c.SetProxy(SocksProxy("127.0.0.1:3128").SetUsername("user")
46 | .SetPassword("12345").SetNoProxyFor("custom.host"));
47 | const auto json = ToJson(c);
48 | const auto c_copy = FromJson(json);
49 | const auto proxy = FromJson(c_copy.Get("proxy"));
50 | ASSERT_EQ("manual", proxy.Get("proxyType"));
51 | ASSERT_EQ("127.0.0.1:3128", proxy.Get("socksProxy"));
52 | ASSERT_EQ("user", proxy.Get("socksUsername"));
53 | ASSERT_EQ("12345", proxy.Get("socksPassword"));
54 | ASSERT_EQ("custom.host", proxy.Get("noProxy"));
55 | }
56 |
57 | } // namespace test
58 |
--------------------------------------------------------------------------------
/include/webdriverxx/client.inl:
--------------------------------------------------------------------------------
1 | #include "conversions.h"
2 | #include "detail/shared.h"
3 | #include "detail/error_handling.h"
4 | #include "detail/types.h"
5 | #include
6 |
7 | namespace webdriverxx {
8 |
9 | inline
10 | Client::Client(const std::string& url)
11 | : resource_(new detail::RootResource(
12 | url,
13 | detail::Shared(new detail::HttpConnection)
14 | ))
15 | {}
16 |
17 | inline
18 | picojson::object Client::GetStatus() const {
19 | WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()
20 | const auto value = resource_->Get("status").get("value");
21 | WEBDRIVERXX_CHECK(value.is(), "Value is not an object");
22 | return value.get();
23 | WEBDRIVERXX_FUNCTION_CONTEXT_END()
24 | }
25 |
26 | inline
27 | std::vector Client::GetSessions() const {
28 | WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()
29 | const auto sessions =
30 | FromJson>(
31 | resource_->Get("sessions").get("value")
32 | );
33 | std::vector result;
34 | result.reserve(sessions.size());
35 | std::transform(sessions.begin(), sessions.end(), std::back_inserter(result),
36 | [this](const detail::SessionRef& session_ref) {
37 | return MakeSession(session_ref.id, detail::Resource::IsObserver);
38 | });
39 | return result;
40 | WEBDRIVERXX_FUNCTION_CONTEXT_END()
41 | }
42 |
43 | inline
44 | Session Client::CreateSession(
45 | const Capabilities& desired,
46 | const Capabilities& required
47 | ) const {
48 | WEBDRIVERXX_FUNCTION_CONTEXT_BEGIN()
49 | const auto response = resource_->Post("session",
50 | JsonObject()
51 | .Set("desiredCapabilities", static_cast(desired))
52 | .Set("requiredCapabilities", static_cast(required))
53 | );
54 |
55 | WEBDRIVERXX_CHECK(response.get("sessionId").is(), "Session ID is not a string");
56 | WEBDRIVERXX_CHECK(response.get("value").is(), "Capabilities is not an object");
57 |
58 | const auto sessionId = response.get("sessionId").to_str();
59 |
60 | return MakeSession(sessionId, detail::Resource::IsOwner);
61 | WEBDRIVERXX_FUNCTION_CONTEXT_END()
62 | }
63 |
64 | inline
65 | Session Client::MakeSession(
66 | const std::string& id,
67 | detail::Resource::Ownership mode
68 | ) const {
69 | return Session(detail::MakeSubResource(resource_, "session", id, mode));
70 | }
71 |
72 | } // namespace webdriverxx
73 |
--------------------------------------------------------------------------------
/test/wait_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace test {
5 |
6 | using namespace webdriverxx;
7 | using namespace webdriverxx::detail;
8 |
9 | int FunctionGetter() { return 123; }
10 |
11 | struct FunctorGetter {
12 | int operator () () const {
13 | return 456;
14 | }
15 | };
16 |
17 | TEST(WaitForValue, CanBeUsedWithFunctionFunctorAndLambda) {
18 | ASSERT_EQ(123, WaitForValue(FunctionGetter));
19 | ASSERT_EQ(456, WaitForValue(FunctorGetter()));
20 | ASSERT_EQ(789, WaitForValue([]{ return 789; }));
21 | }
22 |
23 | TEST(WaitForValue, DoesNotWaitIfValueIsReturned) {
24 | Duration timeout = 1000;
25 | const TimePoint start = Now();
26 | WaitForValue(FunctionGetter, timeout);
27 | ASSERT_TRUE(Now() - start < timeout/2);
28 | }
29 |
30 | TEST(WaitForValue, CallsGetterOnce) {
31 | int counter = 0;
32 | WaitForValue([&counter]{ return ++counter; });
33 | ASSERT_EQ(1, counter);
34 | }
35 |
36 | TEST(WaitForValue, ThrowsExceptionOnTimeout) {
37 | Duration timeout = 0;
38 | ASSERT_THROW(WaitForValue([]() -> int { throw std::exception(); }, timeout), WebDriverException);
39 | }
40 |
41 | TEST(WaitForValue, CallsGetterUntilItSucceeds) {
42 | Duration timeout = 1000;
43 | Duration interval = 0;
44 | int counter = 0;
45 | WaitForValue([&counter]() -> int {
46 | if (++counter < 10) throw std::exception();
47 | return counter;
48 | }, timeout, interval);
49 | ASSERT_EQ(10, counter);
50 | }
51 |
52 | TEST(WaitForValue, PassesErrorMessageFromGetter) {
53 | Duration timeout = 0;
54 | try {
55 | WaitForValue([]() -> int { throw std::runtime_error("abc"); }, timeout);
56 | FAIL();
57 | } catch (const WebDriverException& e) {
58 | std::string message = e.what();
59 | const auto npos = std::string::npos;
60 | ASSERT_NE(npos, message.find("abc"));
61 | ASSERT_NE(npos, message.find("imeout"));
62 | }
63 | }
64 |
65 | TEST(WaitUntil, DoesNotWaitIfValueNotFalsy) {
66 | Duration timeout = 1000;
67 | const TimePoint start = Now();
68 | WaitUntil([]{ return true; }, timeout);
69 | ASSERT_TRUE(Now() - start < timeout/2);
70 | }
71 |
72 | TEST(WaitUntil, CallsGetterOnce) {
73 | int counter = 0;
74 | WaitUntil([&counter]{ return ++counter; });
75 | ASSERT_EQ(1, counter);
76 | }
77 |
78 | TEST(WaitUntil, ThrowsExceptionOnTimeout) {
79 | Duration timeout = 0;
80 | ASSERT_THROW(WaitUntil([]() -> bool { throw std::exception(); }, timeout), WebDriverException);
81 | }
82 |
83 | TEST(WaitUntil, ThrowsExceptionOnTimeout2) {
84 | Duration timeout = 0;
85 | ASSERT_THROW(WaitUntil([]{ return false; }, timeout), WebDriverException);
86 | }
87 |
88 | } // namespace test
89 |
--------------------------------------------------------------------------------
/test/webdriver_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | TEST(WebDriver, CreatesSession) {
10 | Client client(GetWebDriverUrl());
11 | size_t number_of_sessions_before = client.GetSessions().size();
12 | WebDriver testee = CreateDriver();
13 | size_t number_of_sessions_after = client.GetSessions().size();
14 | ASSERT_EQ(number_of_sessions_before + 1, number_of_sessions_after);
15 | }
16 |
17 | TEST(WebDriver, DeletesSessionOnDestruction) {
18 | Client client(GetWebDriverUrl());
19 | size_t number_of_sessions_before = 0;
20 | {
21 | WebDriver testee = CreateDriver();
22 | number_of_sessions_before = client.GetSessions().size();
23 | }
24 | size_t number_of_sessions_after = client.GetSessions().size();
25 | ASSERT_EQ(number_of_sessions_before - 1, number_of_sessions_after);
26 | }
27 |
28 | TEST(WebDriver, IsCopyable) {
29 | WebDriver driver1(GetDriver());
30 | const WebDriver driver2 = driver1;
31 | WebDriver driver3 = driver1;
32 | driver3 = driver2;
33 | ASSERT_NO_THROW(GetDriver().GetSessions());
34 | ASSERT_NO_THROW(driver1.GetSessions());
35 | ASSERT_NO_THROW(driver2.GetSessions());
36 | ASSERT_NO_THROW(driver3.GetSessions());
37 | }
38 |
39 | TEST(WebDriver, CopyableToClient) {
40 | WebDriver driver = GetDriver();
41 | Client client = driver;
42 | ASSERT_NO_THROW(client.GetSessions());
43 | ASSERT_NO_THROW(driver.GetSessions());
44 | }
45 |
46 | TEST(WebDriver, CopyableToSession) {
47 | WebDriver driver = GetDriver();
48 | Session session = driver;
49 | ASSERT_NO_THROW(session.GetWindows());
50 | ASSERT_NO_THROW(driver.GetWindows());
51 | }
52 |
53 | TEST(WebDriver, AndSatelliteObjectsHasNoLifetimeIssues) {
54 | // It is too expensive to restart the driver ->
55 | // try to test all objects in one test.
56 | WebDriver& driver = GetDriver();
57 | driver.Navigate(GetTestPageUrl("webdriver.html"));
58 |
59 | Element body = driver.FindElement(ByTag("body"));
60 | {
61 | Window window = driver.GetCurrentWindow();
62 | {
63 | Session session = driver;
64 | {
65 | Client client = driver;
66 | {
67 | WebDriver local_driver = driver;
68 | GetFreshDriver(); // Destroy global instance
69 | ASSERT_NO_THROW(local_driver.GetSessions());
70 | ASSERT_NO_THROW(local_driver.GetWindows());
71 | ASSERT_NO_THROW(local_driver.FindElement(ByTag("input")));
72 | }
73 | ASSERT_NO_THROW(client.GetSessions());
74 | }
75 | ASSERT_NO_THROW(session.GetWindows());
76 | ASSERT_NO_THROW(session.FindElement(ByTag("input")));
77 | }
78 | ASSERT_NO_THROW(window.GetSize());
79 | }
80 | ASSERT_NO_THROW(body.FindElement(ByTag("input")));
81 | }
82 |
83 | } // namespace test
84 |
--------------------------------------------------------------------------------
/include/webdriverxx/wait.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_WAIT_H
2 | #define WEBDRIVERXX_WAIT_H
3 |
4 | #include "detail/error_handling.h"
5 | #include "detail/time.h"
6 | #include "detail/to_string.h"
7 | #include
8 | #include
9 |
10 | namespace webdriverxx {
11 | namespace detail {
12 |
13 | template
14 | Value Wait(
15 | DescriptiveGetter getter,
16 | Duration timeoutMs = 5000,
17 | Duration intervalMs = 50
18 | ) {
19 | const TimePoint timeout = detail::Now() + timeoutMs;
20 | for (;;) {
21 | const auto value_ptr = getter(nullptr);
22 | if (value_ptr)
23 | return *value_ptr;
24 | if (detail::Now() >= timeout) {
25 | std::string description;
26 | const auto value_ptr = getter(&description);
27 | if (value_ptr)
28 | return *value_ptr;
29 | throw WebDriverException(detail::Fmt()
30 | << "Timeout after " << timeoutMs << "ms of waiting, last attempt returned: "
31 | << description
32 | );
33 | }
34 | detail::Sleep(intervalMs);
35 | }
36 | }
37 |
38 | template
39 | std::unique_ptr TryToCallGetter(Getter getter, std::string* description) {
40 | std::unique_ptr value_ptr;
41 | try {
42 | value_ptr.reset(new Value(getter()));
43 | } catch (const std::exception& e) {
44 | if (description)
45 | *description = e.what();
46 | }
47 | return value_ptr;
48 | }
49 |
50 | } // namespace detail
51 |
52 | // Waits for a value returned by a supplied getter.
53 | // Returns that value or throws exception on timeout.
54 | // Getter is a function or function-like object that returns some copyable value.
55 | template
56 | auto WaitForValue(
57 | Getter getter,
58 | Duration timeoutMs = 5000,
59 | Duration intervalMs = 50
60 | ) -> decltype(getter()) {
61 | typedef decltype(getter()) Value;
62 | return detail::Wait(
63 | [&getter](std::string* description) {
64 | return detail::TryToCallGetter(getter, description);
65 | },
66 | timeoutMs, intervalMs);
67 | }
68 |
69 | // Waits until a truthy value is returned by a supplied getter.
70 | // Returns that value or throws exception on timeout.
71 | // Getter is a function or function-like object that returns some copyable value.
72 | template
73 | auto WaitUntil(
74 | Getter getter,
75 | Duration timeoutMs = 5000,
76 | Duration intervalMs = 50
77 | ) -> decltype(getter()) {
78 | typedef decltype(getter()) Value;
79 | return detail::Wait(
80 | [&getter](std::string* description) -> std::unique_ptr {
81 | auto value_ptr = detail::TryToCallGetter(getter, description);
82 | if (!value_ptr || !!*value_ptr)
83 | return value_ptr;
84 | if (description)
85 | *description = "Value is falsy";
86 | value_ptr.reset();
87 | return value_ptr;
88 | }, timeoutMs, intervalMs);
89 | }
90 |
91 | } // namespace webdriverxx
92 |
93 | #endif
94 |
--------------------------------------------------------------------------------
/test/element_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | class TestElement : public ::testing::Test {
10 | protected:
11 | static void SetUpTestCase() {
12 | GetDriver().Navigate(GetTestPageUrl("element.html"));
13 | }
14 |
15 | TestElement() : driver(GetDriver()) {}
16 |
17 | WebDriver driver;
18 | };
19 |
20 | TEST_F(TestElement, CanBeClicked) {
21 | driver.FindElement(ByTag("input")).Click();
22 | }
23 |
24 | // TODO: Submit
25 |
26 | TEST_F(TestElement, GetsText) {
27 | ASSERT_EQ("Some text", driver.FindElement(ById("element_with_text")).GetText());
28 | }
29 |
30 | TEST_F(TestElement, CanBeCleared) {
31 | Element e = driver.FindElement(ByTag("input"));
32 | e.SendKeys("abc");
33 | ASSERT_NE("", e.GetAttribute("value"));
34 | e.Clear();
35 | ASSERT_EQ("", e.GetAttribute("value"));
36 | }
37 |
38 | TEST_F(TestElement, GetsTagName) {
39 | ASSERT_EQ("div", driver.FindElement(ByTag("div")).GetTagName());
40 | }
41 |
42 | // TODO: IsEnabled
43 | // TODO: IsSelected
44 |
45 | TEST_F(TestElement, GetsAttributes) {
46 | Element e = driver.FindElement(ById("div_with_attributes"));
47 | ASSERT_EQ("div_with_attributes", e.GetAttribute("id"));
48 | ASSERT_EQ("test value", e.GetAttribute("test"));
49 | }
50 |
51 | TEST_F(TestElement, IsEqualToOtherElement) {
52 | Element e = driver.FindElement(ById("first_div"));
53 | Element other = driver.FindElement(ById("first_div"));
54 | ASSERT_TRUE(e.Equals(other));
55 | ASSERT_TRUE(e == other);
56 | }
57 |
58 | TEST_F(TestElement, IsNotEqualToOtherElement) {
59 | Element e = driver.FindElement(ById("first_div"));
60 | Element other = driver.FindElement(ById("second_div"));
61 | ASSERT_TRUE(!e.Equals(other));
62 | ASSERT_TRUE(e != other);
63 | }
64 |
65 | TEST_F(TestElement, HasStrictWeakOrdering) {
66 | Element a = driver.FindElement(ById("first_div"));
67 | Element b = driver.FindElement(ById("second_div"));
68 | Element c = driver.FindElement(ById("third_div"));
69 | Element a2 = a;
70 | if (c < b) std::swap(b, c);
71 | if (b < a) std::swap(a, b);
72 | if (c < b) std::swap(b, c);
73 | ASSERT_FALSE(a < a2);
74 | ASSERT_FALSE(a2 < a);
75 | ASSERT_TRUE(a < b && !(b < a));
76 | ASSERT_TRUE(a < b && b < c && a < c);
77 | }
78 |
79 | TEST_F(TestElement, GetsIsDisplayed) {
80 | ASSERT_TRUE(driver.FindElement(ById("visible")).IsDisplayed());
81 | ASSERT_FALSE(driver.FindElement(ById("hidden")).IsDisplayed());
82 | }
83 |
84 | TEST_F(TestElement, GetsLocation) {
85 | driver.FindElement(ById("visible")).GetLocation();
86 | driver.FindElement(ById("visible")).GetLocationInView();
87 | }
88 |
89 | TEST_F(TestElement, GetsSize) {
90 | Size size = driver.FindElement(ById("visible")).GetSize();
91 | ASSERT_NE(0, size.width);
92 | ASSERT_NE(0, size.height);
93 | }
94 |
95 | TEST_F(TestElement, GetsCssProperty) {
96 | ASSERT_EQ("none", driver.FindElement(ById("hidden")).GetCssProperty("display"));
97 | }
98 |
99 | } // namespace test
100 |
--------------------------------------------------------------------------------
/test/to_string_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace test {
5 |
6 | using namespace webdriverxx;
7 | using namespace webdriverxx::detail;
8 |
9 | TEST(ToString, ConvertsIntegralTypes) {
10 | ASSERT_EQ("123", ToString(123));
11 | int i = 123;
12 | ASSERT_EQ("123", ToString(i));
13 | ASSERT_EQ("123", ToString(static_cast(i)));
14 | ASSERT_EQ("'z'", ToString('z'));
15 | char c = 'z';
16 | ASSERT_EQ("'z'", ToString(c));
17 | ASSERT_EQ("'z'", ToString(static_cast(c)));
18 | }
19 |
20 | namespace custom {
21 |
22 | struct A {};
23 |
24 | struct B {};
25 | std::ostream& operator << (std::ostream& s, const B&) {
26 | return s << "B";
27 | }
28 |
29 | struct C {};
30 |
31 | void ToStream(const C&, std::ostream& s) {
32 | s << "C";
33 | }
34 |
35 | struct G {};
36 | void PrintTo(const G&, std::ostream* s) {
37 | *s << "G";
38 | }
39 |
40 | } // namespace custom
41 |
42 | TEST(ToString, ConvertsCustomTypes) {
43 | ASSERT_EQ("", ToString(custom::A()));
44 | ASSERT_EQ("B", ToString(custom::B()));
45 | ASSERT_EQ("C", ToString(custom::C()));
46 | ASSERT_EQ("G", ToString(custom::G()));
47 | }
48 |
49 | TEST(ToString, ConvertsStrings) {
50 | ASSERT_EQ("\"abc\"", ToString("abc"));
51 | char a[] = "abc";
52 | ASSERT_EQ("\"abc\"", ToString(a));
53 | const char ca[] = "abc";
54 | ASSERT_EQ("\"abc\"", ToString(ca));
55 | char* pc = a;
56 | ASSERT_EQ("\"abc\"", ToString(pc));
57 | const char* pcc = "abc";
58 | ASSERT_EQ("\"abc\"", ToString(pcc));
59 |
60 | ASSERT_EQ("\"abc\"", ToString(std::string("abc")));
61 | std::string s("abc");
62 | ASSERT_EQ("\"abc\"", ToString(s));
63 | const std::string cs("abc");
64 | ASSERT_EQ("\"abc\"", ToString(cs));
65 | }
66 |
67 | TEST(ToString, ConvertsPointers) {
68 | int i = 123;
69 | ASSERT_EQ("*123", ToString(&i));
70 | const int* cpi = &i;
71 | ASSERT_EQ("**123", ToString(&cpi));
72 | const std::string s = "abc";
73 | ASSERT_EQ("*\"abc\"", ToString(&s));
74 | }
75 |
76 | TEST(ToString, ConvertsContainersOfIntegralTypes) {
77 | ASSERT_EQ("[]", ToString(std::vector()));
78 | std::vector v;
79 | v.push_back(123);
80 | v.push_back(456);
81 | ASSERT_EQ("*[123, 456]", ToString(&v));
82 | int a[3] = { 123, 456, 789 };
83 | ASSERT_EQ("[123, 456, 789]", ToString(a));
84 | }
85 |
86 | TEST(ToString, ConvertsContainersOfCustomTypes) {
87 | std::vector as(1);
88 | ASSERT_EQ("[]", ToString(as));
89 | std::vector bs(1);
90 | ASSERT_EQ("[B]", ToString(bs));
91 | std::vector cs(1);
92 | ASSERT_EQ("[C]", ToString(cs));
93 | std::vector gs(1);
94 | ASSERT_EQ("[G]", ToString(gs));
95 | }
96 |
97 | TEST(ToString, ConvertsContainersOfStrings) {
98 | const char* ss[] = { "abc", "def" };
99 | ASSERT_EQ("[\"abc\", \"def\"]", ToString(ss));
100 | ASSERT_EQ("*[\"abc\", \"def\"]", ToString(&ss));
101 | }
102 |
103 | } // namespace test
104 |
--------------------------------------------------------------------------------
/include/webdriverxx/detail/to_string.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_TO_STRING_H
2 | #define WEBDRIVERXX_TO_STRING_H
3 |
4 | #include "meta_tools.h"
5 | #include
6 | #include
7 |
8 | namespace webdriverxx {
9 | namespace detail {
10 |
11 | template
12 | void ToStream(const T& value, std::ostream& stream);
13 |
14 | namespace to_string_impl {
15 |
16 | template
17 | void WriteNonStreamableValue(const T&, std::ostream& stream) {
18 | stream << "";
19 | }
20 |
21 | } // namespace to_string_impl
22 | } // detail
23 | } // webdriverxx
24 |
25 | namespace webdriverxx_to_string_impl {
26 |
27 | template
28 | std::ostream& operator << (std::ostream& stream, const T& value) {
29 | webdriverxx::detail::to_string_impl::WriteNonStreamableValue(value, stream);
30 | return stream;
31 | }
32 |
33 | } // namespace webdriverxx_to_string_impl
34 |
35 | namespace webdriverxx {
36 | namespace detail {
37 | namespace to_string_impl {
38 |
39 | struct DefaultTag {};
40 | struct IterableTag {};
41 | struct StringTag {};
42 |
43 | template
44 | struct Tag :
45 | if_, type_is,
46 | if_, type_is,
47 | type_is
48 | >> {};
49 |
50 | template
51 | void ToStreamImpl(const T& value, std::ostream& stream, DefaultTag) {
52 | using namespace webdriverxx_to_string_impl;
53 | stream << value;
54 | }
55 |
56 | template
57 | void ToStreamImpl(T* value, std::ostream& stream, DefaultTag) {
58 | stream << '*';
59 | ToStream(*value, stream);
60 | }
61 |
62 | inline
63 | void ToStreamImpl(const char value, std::ostream& stream, DefaultTag) {
64 | stream << "'" << value << "'";
65 | }
66 |
67 | inline
68 | void ToStreamImpl(const char* value, std::ostream& stream, StringTag) {
69 | stream << '"' << value << '"';
70 | }
71 |
72 | inline
73 | void ToStreamImpl(const std::string& value, std::ostream& stream, StringTag) {
74 | ToStream(value.c_str(), stream);
75 | }
76 |
77 | template
78 | void ToStreamImpl(const T& value, std::ostream& stream, IterableTag) {
79 | auto it = std::begin(value);
80 | const auto end = std::end(value);
81 | int limit = 20;
82 | stream << "[";
83 | if (it != end) {
84 | ToStream(*it, stream);
85 | while (++it != end && --limit > 0) {
86 | stream << ", ";
87 | ToStream(*it, stream);
88 | }
89 | }
90 | stream << "]";
91 | }
92 |
93 | } // namespace to_string_impl
94 |
95 | template
96 | void PrintTo(const T& value, std::ostream* stream) {
97 | using to_string_impl::ToStreamImpl;
98 | using to_string_impl::Tag;
99 | ToStreamImpl(value, *stream, typename Tag::type());
100 | }
101 |
102 | template
103 | void ToStream(const T& value, std::ostream& stream)
104 | {
105 | PrintTo(value, &stream); // for compatibility with Google Test's values printers
106 | }
107 |
108 | template
109 | std::string ToString(const T& value) {
110 | std::ostringstream s;
111 | ToStream(value, s);
112 | return s.str();
113 | }
114 |
115 | } // namespace detail
116 | } // namespace webdriverxx
117 |
118 | #endif
119 |
--------------------------------------------------------------------------------
/test/wait_match_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace test {
5 |
6 | using namespace webdriverxx;
7 | using namespace webdriverxx::detail;
8 |
9 | bool FunctionMatcher(int) { return true; }
10 |
11 | struct FunctorMatcher {
12 | bool operator () (int) const {
13 | return true;
14 | }
15 | };
16 |
17 | TEST(WaitForMatch, CanBeUsedWithFunctionFunctorAndLambda) {
18 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctionMatcher));
19 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctorMatcher()));
20 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));
21 | }
22 |
23 | TEST(WaitForMatch, ReturnsMatchedValue) {
24 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));
25 | }
26 |
27 | TEST(WaitForMatch, DoesNotWaitIfValueIsMatched) {
28 | Duration timeout = 1000;
29 | const TimePoint start = Now();
30 | WaitForMatch([]{ return 0; }, [](int){ return true; }, timeout);
31 | ASSERT_TRUE(Now() - start < timeout/2);
32 | }
33 |
34 | TEST(WaitForMatch, WaitsUntilValueIsMatched) {
35 | Duration timeout = 1000;
36 | Duration interval = 0;
37 | int counter = 0;
38 | WaitForMatch([]{ return 0; }, [&counter](int){ return ++counter == 10; }, timeout, interval);
39 | ASSERT_EQ(10, counter);
40 | }
41 |
42 | TEST(WaitForMatch, ThrowsExceptionOnTimeout) {
43 | Duration timeout = 0;
44 | ASSERT_THROW(WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout), WebDriverException);
45 | }
46 |
47 | TEST(WaitForMatch, ExplainsTimeout) {
48 | try {
49 | Duration timeout = 0;
50 | WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout);
51 | FAIL();
52 | } catch (const std::exception& e) {
53 | std::string message = e.what();
54 | const auto npos = std::string::npos;
55 | ASSERT_NE(npos, message.find("imeout"));
56 | }
57 | }
58 |
59 | TEST(WaitForMatch, CanUseGMockMatchers) {
60 | using namespace ::testing;
61 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, Eq(123)));
62 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, 123));
63 | ASSERT_EQ("abc", WaitForMatch([]{ return std::string("abc"); }, "abc"));
64 | ASSERT_EQ("abc", WaitForMatch([]{ return std::string("abc"); }, Eq("abc")));
65 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, _));
66 | ASSERT_EQ(123, WaitForMatch([]{ return 123; }, An()));
67 | std::vector v(1, 123);
68 | ASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Contains(123)));
69 | ASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Not(Contains(456))));
70 | Duration timeout = 0;
71 | ASSERT_THROW(WaitForMatch([&v]{ return v; }, Not(Contains(123)), timeout), WebDriverException);
72 | }
73 |
74 | TEST(WaitForMatch, ExplainsGMockMatcherMismatch) {
75 | try {
76 | Duration timeout = 0;
77 | using namespace ::testing;
78 | WaitForMatch([]{ return 123; }, Eq(456), timeout);
79 | FAIL();
80 | } catch (const std::exception& e) {
81 | std::string message = e.what();
82 | const auto npos = std::string::npos;
83 | ASSERT_NE(npos, message.find("123"));
84 | ASSERT_NE(npos, message.find("456"));
85 | ASSERT_NE(npos, message.find("imeout"));
86 | }
87 | }
88 |
89 | } // namespace test
90 |
--------------------------------------------------------------------------------
/include/webdriverxx/keys.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_KEYS_H
2 | #define WEBDRIVERXX_KEYS_H
3 |
4 | #include
5 | #include
6 |
7 | namespace webdriverxx {
8 | namespace keys {
9 |
10 | const char *const Null = "\xee\x80\x80";
11 | const char *const Cancel = "\xee\x80\x81";
12 | const char *const Help = "\xee\x80\x82";
13 | const char *const Backspace = "\xee\x80\x83";
14 | const char *const Tab = "\xee\x80\x84";
15 | const char *const Clear = "\xee\x80\x85";
16 | const char *const Return = "\xee\x80\x86";
17 | const char *const Enter = "\xee\x80\x87";
18 | const char *const Shift = "\xee\x80\x88";
19 | const char *const Control = "\xee\x80\x89";
20 | const char *const Alt = "\xee\x80\x8a";
21 | const char *const Pause = "\xee\x80\x8b";
22 | const char *const Escape = "\xee\x80\x8c";
23 | const char *const Space = "\xee\x80\x8d";
24 | const char *const PageUp = "\xee\x80\x8e";
25 | const char *const PageDown = "\xee\x80\x8f";
26 | const char *const End = "\xee\x80\x90";
27 | const char *const Home = "\xee\x80\x91";
28 | const char *const Left = "\xee\x80\x92";
29 | const char *const Up = "\xee\x80\x93";
30 | const char *const Right = "\xee\x80\x94";
31 | const char *const Down = "\xee\x80\x95";
32 | const char *const Insert = "\xee\x80\x96";
33 | const char *const Delete = "\xee\x80\x97";
34 | const char *const Semicolon = "\xee\x80\x98";
35 | const char *const Equals = "\xee\x80\x99";
36 | const char *const Numpad0 = "\xee\x80\x9a";
37 | const char *const Numpad1 = "\xee\x80\x9b";
38 | const char *const Numpad2 = "\xee\x80\x9c";
39 | const char *const Numpad3 = "\xee\x80\x9d";
40 | const char *const Numpad4 = "\xee\x80\x9e";
41 | const char *const Numpad5 = "\xee\x80\x9f";
42 | const char *const Numpad6 = "\xee\x80\xa0";
43 | const char *const Numpad7 = "\xee\x80\xa1";
44 | const char *const Numpad8 = "\xee\x80\xa2";
45 | const char *const Numpad9 = "\xee\x80\xa3";
46 | const char *const Multiply = "\xee\x80\xa4";
47 | const char *const Add = "\xee\x80\xa5";
48 | const char *const Separator = "\xee\x80\xa6";
49 | const char *const Subtract = "\xee\x80\xa7";
50 | const char *const Decimal = "\xee\x80\xa8";
51 | const char *const Divide = "\xee\x80\xa9";
52 | const char *const F1 = "\xee\x80\xb1";
53 | const char *const F2 = "\xee\x80\xb2";
54 | const char *const F3 = "\xee\x80\xb3";
55 | const char *const F4 = "\xee\x80\xb4";
56 | const char *const F5 = "\xee\x80\xb5";
57 | const char *const F6 = "\xee\x80\xb6";
58 | const char *const F7 = "\xee\x80\xb7";
59 | const char *const F8 = "\xee\x80\xb8";
60 | const char *const F9 = "\xee\x80\xb9";
61 | const char *const F10 = "\xee\x80\xba";
62 | const char *const F11 = "\xee\x80\xbb";
63 | const char *const F12 = "\xee\x80\xbc";
64 | const char *const Command = "\xee\x80\xbd";
65 | const char *const Meta = Command;
66 |
67 | } // namespace keys
68 |
69 | namespace detail {
70 | class Keyboard;
71 | } // namespace detail
72 |
73 | class Shortcut // copyable
74 | {
75 | public:
76 | Shortcut& operator << (const std::string& key) {
77 | keys_.push_back(key);
78 | return *this;
79 | }
80 |
81 | Shortcut& operator << (const char* key) {
82 | keys_.push_back(key);
83 | return *this;
84 | }
85 |
86 | private:
87 | friend class detail::Keyboard;
88 | std::vector keys_;
89 | };
90 |
91 | } // namespace webdriverxx
92 |
93 | #endif
94 |
--------------------------------------------------------------------------------
/test/environment.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_ENVIRONMENT_H
2 | #define WEBDRIVERXX_ENVIRONMENT_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | namespace test {
11 |
12 | const char* const kDefaultTestWebDriverUrl = "http://localhost:7777/";
13 | const char* const kDefaultTestPagesUrl = "http://localhost:8080/";
14 |
15 | struct Parameters {
16 | std::string web_driver_url;
17 | webdriverxx::Capabilities required;
18 | webdriverxx::Capabilities desired;
19 | std::string test_pages_url;
20 | bool test_real_browsers;
21 |
22 | Parameters()
23 | : web_driver_url(kDefaultTestWebDriverUrl)
24 | , test_pages_url(kDefaultTestPagesUrl)
25 | , test_real_browsers(false)
26 | {}
27 | };
28 |
29 | class Environment : public ::testing::Environment {
30 | public:
31 | static Environment& Instance() {
32 | return *instance_;
33 | }
34 |
35 | explicit Environment(const Parameters& parameters)
36 | : driver_(0)
37 | , parameters_(parameters)
38 | {}
39 |
40 | webdriverxx::WebDriver& GetDriver() {
41 | return driver_ ? *driver_ : GetFreshDriver();
42 | }
43 |
44 | webdriverxx::WebDriver& GetFreshDriver() {
45 | DeleteDriver();
46 | driver_ = new webdriverxx::WebDriver(CreateDriver());
47 | return *driver_;
48 | }
49 |
50 | webdriverxx::WebDriver CreateDriver() {
51 | return webdriverxx::WebDriver(
52 | parameters_.desired,
53 | parameters_.required,
54 | parameters_.web_driver_url
55 | );
56 | }
57 |
58 | std::string GetWebDriverUrl() const { return parameters_.web_driver_url; }
59 |
60 | Parameters GetParameters() const { return parameters_; }
61 |
62 | std::string GetTestPageUrl(const std::string& page_name) const {
63 | std::string url = parameters_.test_pages_url;
64 | if (!url.empty() && url[url.length() - 1] != '/')
65 | url += "/";
66 | url += page_name;
67 | return url;
68 | }
69 |
70 | private:
71 | void SetUp() {
72 | instance_ = this;
73 | }
74 |
75 | void TearDown() {
76 | instance_ = 0;
77 | DeleteDriver();
78 | }
79 |
80 | void DeleteDriver() {
81 | delete driver_;
82 | driver_ = 0;
83 | }
84 |
85 | private:
86 | static Environment* instance_;
87 | webdriverxx::WebDriver* driver_;
88 | Parameters parameters_;
89 | };
90 |
91 | inline Parameters GetParameters() { return Environment::Instance().GetParameters(); }
92 | inline std::string GetWebDriverUrl() { return Environment::Instance().GetWebDriverUrl(); }
93 | inline std::string GetTestPageUrl(const std::string& page_name) { return Environment::Instance().GetTestPageUrl(page_name); }
94 | inline webdriverxx::WebDriver& GetDriver() { return Environment::Instance().GetDriver(); }
95 | inline webdriverxx::WebDriver& GetFreshDriver() { return Environment::Instance().GetFreshDriver(); }
96 | inline webdriverxx::WebDriver CreateDriver() { return Environment::Instance().CreateDriver(); }
97 | inline bool TestRealBrowsers() { return GetParameters().test_real_browsers; }
98 | inline std::string GetBrowserName() { return GetDriver().GetCapabilities().GetBrowserName(); }
99 | inline bool IsFirefox() { return GetBrowserName() == webdriverxx::browser::Firefox; }
100 | inline bool IsPhantom() { return GetBrowserName() == webdriverxx::browser::Phantom; }
101 |
102 | } // namespace test
103 |
104 | #endif
105 |
--------------------------------------------------------------------------------
/test/mouse_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | class TestMouse : public ::testing::Test {
10 | protected:
11 | static void SetUpTestCase() {
12 | GetDriver().Navigate(GetTestPageUrl("mouse.html"));
13 | }
14 |
15 | TestMouse() : driver(GetDriver()) {}
16 |
17 | void SetUp() {
18 | target = driver.FindElement(ById("target"));
19 | click_type = driver.FindElement(ById("click_type")).Clear();
20 | updown_type = driver.FindElement(ById("updown_type")).Clear();
21 | updown_button = driver.FindElement(ById("updown_button")).Clear();
22 | }
23 |
24 | std::string GetValue(const Element& element) {
25 | return element.GetAttribute("value");
26 | }
27 |
28 | WebDriver driver;
29 | Element target;
30 | Element click_type;
31 | Element updown_type;
32 | Element updown_button;
33 | };
34 |
35 | TEST_F(TestMouse, SendsClick) {
36 | driver.MoveToCenterOf(target).Click();
37 | ASSERT_EQ("click", GetValue(click_type));
38 | }
39 |
40 | TEST_F(TestMouse, MovesPointerInsideTarget) {
41 | driver.MoveToCenterOf(target).MoveTo(Offset(-45,-45)).Click();
42 | ASSERT_EQ("click", GetValue(click_type));
43 | }
44 |
45 | TEST_F(TestMouse, MovesPointerOutsideTarget) {
46 | if (IsFirefox()) return;
47 | driver.MoveToCenterOf(target).MoveTo(Offset(55,55)).Click();
48 | driver.MoveToCenterOf(target).MoveTo(Offset(-55,55)).Click();
49 | driver.MoveToCenterOf(target).MoveTo(Offset(-55,-55)).Click();
50 | driver.MoveToCenterOf(target).MoveTo(Offset(55,-55)).Click();
51 | ASSERT_EQ("", GetValue(click_type));
52 | }
53 |
54 | TEST_F(TestMouse, MovesPointerToTopLeftCorner) {
55 | driver.MoveToTopLeftOf(target).Click();
56 | ASSERT_EQ("click", GetValue(click_type));
57 | }
58 |
59 | TEST_F(TestMouse, MovesPointerToTopLeftCornerWithOffset) {
60 | driver.MoveToTopLeftOf(target, Offset(95,95)).Click();
61 | ASSERT_EQ("click", GetValue(click_type));
62 | }
63 |
64 | TEST_F(TestMouse, MovesPointerToTopLeftCornerWithOffset2) {
65 | if (IsFirefox()) return;
66 | driver.MoveToTopLeftOf(target, Offset(-5,-5)).Click();
67 | driver.MoveToTopLeftOf(target, Offset(105,105)).Click();
68 | ASSERT_EQ("", GetValue(click_type));
69 | }
70 |
71 | TEST_F(TestMouse, SendsDoubleclicks) {
72 | driver.MoveToCenterOf(target).DoubleClick();
73 | ASSERT_EQ("dblclick", GetValue(click_type));
74 | }
75 |
76 | TEST_F(TestMouse, SendsButtonDown) {
77 | driver.MoveToCenterOf(target).ButtonDown();
78 | ASSERT_EQ("mousedown", GetValue(updown_type));
79 | driver.ButtonUp();
80 | }
81 |
82 | TEST_F(TestMouse, SendsButtonUp) {
83 | driver.MoveToCenterOf(target).ButtonDown().ButtonUp();
84 | ASSERT_EQ("mouseup", GetValue(updown_type));
85 | }
86 |
87 | TEST_F(TestMouse, SendsDifferentButtons) {
88 | if (IsFirefox()) return;
89 | driver.MoveToCenterOf(target).ButtonDown(mouse::LeftButton).ButtonUp(mouse::LeftButton);
90 | const auto left_button = GetValue(updown_button);
91 | driver.ButtonDown(mouse::RightButton).ButtonUp(mouse::RightButton);
92 | const auto right_button = GetValue(updown_button);
93 | driver.ButtonDown(mouse::MiddleButton).ButtonUp(mouse::MiddleButton);
94 | const auto middle_button = GetValue(updown_button);
95 | ASSERT_NE(left_button, right_button);
96 | ASSERT_NE(left_button, middle_button);
97 | ASSERT_NE(right_button, middle_button);
98 | }
99 |
100 | } // namespace test
101 |
--------------------------------------------------------------------------------
/test/shared_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx::detail;
8 |
9 | struct WidgetMonitor {
10 | WidgetMonitor()
11 | : created(0)
12 | , copied(0)
13 | , deleted(0)
14 | {}
15 |
16 | int created;
17 | int copied;
18 | int deleted;
19 | };
20 |
21 | struct Simple : SharedObjectBase {
22 | int n;
23 | Simple() : n() {}
24 | };
25 |
26 | class Widget : public SharedObjectBase {
27 | public:
28 | Widget(WidgetMonitor& monitor)
29 | : monitor(monitor) {
30 | ++monitor.created;
31 | }
32 |
33 | Widget(const Widget& other)
34 | : monitor(other.monitor) {
35 | ++monitor.created;
36 | }
37 |
38 | Widget& operator = (const Widget& other) {
39 | assert(&monitor == &other.monitor);
40 | ++monitor.copied;
41 | return *this;
42 | }
43 |
44 | virtual ~Widget() {
45 | ++monitor.deleted;
46 | }
47 |
48 | private:
49 | WidgetMonitor& monitor;
50 | };
51 |
52 | class WidgetSubclass : public Widget {
53 | public:
54 | WidgetSubclass(WidgetMonitor& monitor) : Widget(monitor) {}
55 | };
56 |
57 | TEST(WidgetMonitor, ZeroByDefault) {
58 | WidgetMonitor m;
59 | ASSERT_EQ(0, m.created);
60 | ASSERT_EQ(0, m.copied);
61 | ASSERT_EQ(0, m.deleted);
62 | }
63 |
64 | TEST(WidgetMonitor, ShowsCreateAndDelete) {
65 | WidgetMonitor m;
66 | ((void)Widget(m));
67 | ASSERT_EQ(1, m.created);
68 | ASSERT_EQ(0, m.copied);
69 | ASSERT_EQ(1, m.deleted);
70 | }
71 |
72 | TEST(WidgetMonitor, ShowsCopy) {
73 | WidgetMonitor m;
74 | Widget w1(m);
75 | Widget w2(m);
76 | w2 = w1;
77 | ASSERT_EQ(1, m.copied);
78 |
79 | }
80 |
81 | TEST(WidgetMonitor, MonitorsWidgetSubclass) {
82 | WidgetMonitor m;
83 | ((void)WidgetSubclass(m));
84 | ASSERT_EQ(1, m.created);
85 | ASSERT_EQ(0, m.copied);
86 | ASSERT_EQ(1, m.deleted);
87 | }
88 |
89 | TEST(Shared, DeletesWidget) {
90 | WidgetMonitor m;
91 | Shared(new Widget(m));
92 | ASSERT_EQ(1, m.created);
93 | ASSERT_EQ(1, m.deleted);
94 | }
95 |
96 | TEST(Shared, ShareSingleWidget) {
97 | WidgetMonitor m;
98 | {
99 | Shared a(new Widget(m));
100 | Shared b = a;
101 | Shared c;
102 | c = b;
103 | }
104 | ASSERT_EQ(1, m.created);
105 | ASSERT_EQ(0, m.copied);
106 | ASSERT_EQ(1, m.deleted);
107 | }
108 |
109 | TEST(Shared, SupportsImplicitTypecasts) {
110 | WidgetMonitor m;
111 | {
112 | Shared c;
113 | Shared a(new WidgetSubclass(m));
114 | Shared b = a;
115 | c = b;
116 | }
117 | ASSERT_EQ(1, m.created);
118 | ASSERT_EQ(0, m.copied);
119 | ASSERT_EQ(1, m.deleted);
120 | }
121 |
122 | TEST(Shared, CanBeUsedInBoolContext) {
123 | Shared s1;
124 | Shared s2(new Simple);
125 | ASSERT_TRUE(!s1);
126 | ASSERT_TRUE(!!s2);
127 | }
128 |
129 | TEST(Shared, CanBeDereferenced) {
130 | Simple* p = new Simple;
131 | Shared s(p);
132 | p->n = 123;
133 | ASSERT_EQ(123, (*s).n);
134 | ASSERT_EQ(123, s->n);
135 | }
136 |
137 | TEST(Shared, CanBeCompared) {
138 | Shared s1;
139 | Shared s2(new Simple);
140 | Shared s3 = s2;
141 | Shared s4(new Simple);
142 | ASSERT_TRUE(s1 != s2);
143 | ASSERT_TRUE(s1 != s3);
144 | ASSERT_TRUE(s2 == s3);
145 | ASSERT_TRUE(s2 != s4);
146 | ASSERT_TRUE(s1 == s1);
147 | ASSERT_TRUE(s2 == s2);
148 | ASSERT_TRUE(s3 == s3);
149 | ASSERT_TRUE(s4 == s4);
150 | ASSERT_TRUE(s1 == 0);
151 | ASSERT_TRUE(s2 != 0);
152 | }
153 |
154 | } // namespace test
155 |
--------------------------------------------------------------------------------
/test/finder_test.cpp:
--------------------------------------------------------------------------------
1 | #include "environment.h"
2 | #include
3 | #include
4 |
5 | namespace test {
6 |
7 | using namespace webdriverxx;
8 |
9 | class TestFinder : public ::testing::Test {
10 | protected:
11 | static void SetUpTestCase() {
12 | WebDriver& driver = GetDriver();
13 | driver.Navigate(GetTestPageUrl("finder.html"));
14 | driver.FindElement(ById("finder_loaded"));
15 | driver.SetImplicitTimeoutMs(0);
16 | }
17 |
18 | static void TearDownTestCase() {
19 | WebDriver& driver = GetDriver();
20 | driver.SetImplicitTimeoutMs(1000);
21 | }
22 |
23 | TestFinder() : driver(GetDriver()) {}
24 |
25 | WebDriver driver;
26 | };
27 |
28 | TEST_F(TestFinder, CanFindElement) {
29 | driver.FindElement(ById("test_id"));
30 | }
31 |
32 | TEST_F(TestFinder, ThrowsIfElementNotFound) {
33 | ASSERT_THROW(driver.FindElement(ById("non_existing")), WebDriverException);
34 | }
35 |
36 | TEST_F(TestFinder, CanFindMoreThanOneElement) {
37 | ASSERT_TRUE(0u < driver.FindElements(ByTag("div")).size());
38 | }
39 |
40 | TEST_F(TestFinder, ReturnsZeroIfElementsNotFound) {
41 | ASSERT_EQ(0u, driver.FindElements(ById("non_existing")).size());
42 | }
43 |
44 | TEST_F(TestFinder, FindsElementById) {
45 | driver.FindElement(ById("test_id"));
46 | ASSERT_EQ(0u, driver.FindElements(ById("non_existing")).size());
47 | }
48 |
49 | TEST_F(TestFinder, FindsElementByClassName) {
50 | driver.FindElement(ByClass("test_class"));
51 | ASSERT_EQ(0u, driver.FindElements(ByClass("non_existing")).size());
52 | }
53 |
54 | TEST_F(TestFinder, FindsElementByCssSelector) {
55 | driver.FindElement(ByCss("body div#css_selectable"));
56 | ASSERT_EQ(0u, driver.FindElements(ByCss("non_existing")).size());
57 | }
58 |
59 | TEST_F(TestFinder, FindsElementByName) {
60 | driver.FindElement(ByName("test_name"));
61 | ASSERT_EQ(0u, driver.FindElements(ByName("non_existing")).size());
62 | }
63 |
64 | TEST_F(TestFinder, FindsElementByLinkText) {
65 | driver.FindElement(ByLinkText("test link text"));
66 | ASSERT_EQ(0u, driver.FindElements(ByLinkText("non_existing")).size());
67 | }
68 |
69 | TEST_F(TestFinder, FindsElementByPartialLinkText) {
70 | driver.FindElement(ByPartialLinkText("link text"));
71 | ASSERT_EQ(0u, driver.FindElements(ByPartialLinkText("non_existing")).size());
72 | }
73 |
74 | TEST_F(TestFinder, FindsElementByTagName) {
75 | driver.FindElement(ByTag("body"));
76 | ASSERT_EQ(0u, driver.FindElements(ByTag("non_existing")).size());
77 | }
78 |
79 | TEST_F(TestFinder, FindsElementByXPath) {
80 | driver.FindElement(ByXPath("//div"));
81 | ASSERT_EQ(0u, driver.FindElements(ByXPath("//non_existing")).size());
82 | }
83 |
84 | TEST_F(TestFinder, OfElementFindsInnerElement) {
85 | Element outer = driver.FindElement(ById("outer"));
86 | outer.FindElement(ById("inner"));
87 | }
88 |
89 | TEST_F(TestFinder, OfElementDoesNotFindItself) {
90 | Element outer = driver.FindElement(ById("outer"));
91 | ASSERT_EQ(0u, outer.FindElements(ById("outer")).size());
92 | }
93 |
94 | TEST_F(TestFinder, OfElementDoesNotFindNonExistingInnerElements) {
95 | Element outer = driver.FindElement(ById("outer"));
96 | driver.FindElement(ById("next_after_outer"));
97 | ASSERT_THROW(outer.FindElement(ById("next_after_outer")), WebDriverException);
98 | ASSERT_EQ(0u, outer.FindElements(ById("next_after_outer")).size());
99 | }
100 |
101 | TEST_F(TestFinder, OfElementFindsMoreThanOneInnerElement) {
102 | ASSERT_EQ(2u, driver.FindElement(ById("outer")).FindElements(ByTag("div")).size());
103 | }
104 |
105 | } // namespace test
106 |
--------------------------------------------------------------------------------
/include/webdriverxx/response_status_code.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_RESPONSE_STATUS_CODE_H
2 | #define WEBDRIVERXX_RESPONSE_STATUS_CODE_H
3 |
4 | namespace webdriverxx {
5 | namespace response_status_code {
6 |
7 | enum Value {
8 | kSuccess = 0,
9 | kNoSuchDriver = 6,
10 | kNoSuchElement = 7,
11 | kNoSuchFrame = 8,
12 | kUnknownCommand = 9,
13 | kStaleElementReference = 10,
14 | kElementNotVisible = 11,
15 | kInvalidElementState = 12,
16 | kUnknownError = 13,
17 | kElementIsNotSelectable = 15,
18 | kJavaScriptError = 17,
19 | kXPathLookupError = 19,
20 | kTimeout = 21,
21 | kNoSuchWindow = 23,
22 | kInvalidCookieDomain = 24,
23 | kUnableToSetCookie = 25,
24 | kUnexpectedAlertOpen = 26,
25 | kNoAlertOpenError = 27,
26 | kScriptTimeout = 28,
27 | kInvalidElementCoordinates = 29,
28 | kIMENotAvailable = 30,
29 | kIMEEngineActivationFailed = 31,
30 | kInvalidSelector = 32,
31 | kSessionNotCreatedException = 33,
32 | kMoveTargetOutOfBounds = 34
33 | };
34 |
35 | inline
36 | const char* ToString(Value code) {
37 | switch(code) {
38 | case kSuccess: return "The command executed successfully.";
39 | case kNoSuchDriver: return "A session is either terminated or not started";
40 | case kNoSuchElement: return "An element could not be located on the page using the given search parameters.";
41 | case kNoSuchFrame: return "A request to switch to a frame could not be satisfied because the frame could not be found.";
42 | case kUnknownCommand: return "The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource.";
43 | case kStaleElementReference: return "An element command failed because the referenced element is no longer attached to the DOM.";
44 | case kElementNotVisible: return "An element command could not be completed because the element is not visible on the page.";
45 | case kInvalidElementState: return "An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element).";
46 | case kUnknownError: return "An unknown server-side error occurred while processing the command.";
47 | case kElementIsNotSelectable: return "An attempt was made to select an element that cannot be selected.";
48 | case kJavaScriptError: return "An error occurred while executing user supplied JavaScript.";
49 | case kXPathLookupError: return "An error occurred while searching for an element by XPath.";
50 | case kTimeout: return "An operation did not complete before its timeout expired.";
51 | case kNoSuchWindow: return "A request to switch to a different window could not be satisfied because the window could not be found.";
52 | case kInvalidCookieDomain: return "An illegal attempt was made to set a cookie under a different domain than the current page.";
53 | case kUnableToSetCookie: return "A request to set a cookie's value could not be satisfied.";
54 | case kUnexpectedAlertOpen: return "A modal dialog was open, blocking this operation";
55 | case kNoAlertOpenError: return "An attempt was made to operate on a modal dialog when one was not open.";
56 | case kScriptTimeout: return "A script did not complete before its timeout expired.";
57 | case kInvalidElementCoordinates: return "The coordinates provided to an interactions operation are invalid.";
58 | case kIMENotAvailable: return "IME was not available.";
59 | case kIMEEngineActivationFailed: return "An IME engine could not be started.";
60 | case kInvalidSelector: return "Argument was an invalid selector (e.g. XPath/CSS).";
61 | case kSessionNotCreatedException: return "A new session could not be created.";
62 | case kMoveTargetOutOfBounds: return "Target provided for a move action is out of bounds.";
63 | }
64 | return "Unknown";
65 | }
66 |
67 | } // namespace response_status_code
68 | } // namespace webdriverxx
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/include/webdriverxx/element.inl:
--------------------------------------------------------------------------------
1 | #include "conversions.h"
2 | #include "detail/finder.h"
3 | #include "detail/error_handling.h"
4 |
5 | namespace webdriverxx {
6 |
7 | inline
8 | picojson::value CustomToJson(const Element& element) {
9 | detail::ElementRef ref = { element.GetRef() };
10 | return ToJson(ref);
11 | }
12 |
13 | inline
14 | Element::Element() {}
15 |
16 | inline
17 | Element::Element(
18 | const std::string& ref,
19 | const detail::Shared& resource,
20 | const detail::Shared& factory
21 | )
22 | : ref_(ref)
23 | , resource_(resource)
24 | , factory_(factory)
25 | {}
26 |
27 | inline
28 | std::string Element::GetRef() const {
29 | return ref_;
30 | }
31 |
32 | inline
33 | bool Element::IsDisplayed() const {
34 | return GetResource().GetBool("displayed");
35 | }
36 |
37 | inline
38 | bool Element::IsEnabled() const {
39 | return GetResource().GetBool("enabled");
40 | }
41 |
42 | inline
43 | bool Element::IsSelected() const {
44 | return GetResource().GetBool("selected");
45 | }
46 |
47 | inline
48 | Point Element::GetLocation() const {
49 | return GetResource().GetValue("location");
50 | }
51 |
52 | inline
53 | Point Element::GetLocationInView() const {
54 | return GetResource().GetValue("location_in_view");
55 | }
56 |
57 | inline
58 | Size Element::GetSize() const {
59 | return GetResource().GetValue("size");
60 | }
61 |
62 | inline
63 | std::string Element::GetAttribute(const std::string& name) const {
64 | return GetResource().GetString(std::string("attribute/") + name);
65 | }
66 |
67 | inline
68 | std::string Element::GetCssProperty(const std::string& name) const {
69 | return GetResource().GetString(std::string("css/") + name);
70 | }
71 |
72 | inline
73 | std::string Element::GetTagName() const {
74 | return GetResource().GetString("name");
75 | }
76 | inline
77 | std::string Element::GetText() const {
78 | return GetResource().GetString("text");
79 | }
80 |
81 | inline
82 | Element Element::FindElement(const By& by) const {
83 | return factory_->MakeFinder(&GetResource()).FindElement(by);
84 | }
85 |
86 | inline
87 | std::vector Element::FindElements(const By& by) const {
88 | return factory_->MakeFinder(&GetResource()).FindElements(by);
89 | }
90 |
91 | inline
92 | const Element& Element::Clear() const {
93 | GetResource().Post("clear");
94 | return *this;
95 | }
96 |
97 | inline
98 | const Element& Element::Click() const {
99 | GetResource().Post("click");
100 | return *this;
101 | }
102 |
103 | inline
104 | const Element& Element::Submit() const {
105 | GetResource().Post("submit");
106 | return *this;
107 | }
108 |
109 | inline
110 | const Element& Element::SendKeys(const std::string& keys) const {
111 | GetKeyboard().SendKeys(keys);
112 | return *this;
113 | }
114 |
115 | inline
116 | const Element& Element::SendKeys(const Shortcut& shortcut) const {
117 | GetKeyboard().SendKeys(shortcut);
118 | return *this;
119 | }
120 |
121 | inline
122 | bool Element::Equals(const Element& other) const {
123 | return GetResource().GetBool(std::string("equals/") + other.ref_);
124 | }
125 |
126 | inline
127 | bool Element::operator != (const Element& other) const {
128 | return ref_ != other.ref_;
129 | }
130 |
131 | inline
132 | bool Element::operator == (const Element& other) const {
133 | return ref_ == other.ref_;
134 | }
135 |
136 | inline
137 | bool Element::operator < (const Element& other) const {
138 | return ref_ < other.ref_;
139 | }
140 |
141 | inline
142 | detail::Resource& Element::GetResource() const {
143 | WEBDRIVERXX_CHECK(resource_, "Attempt to use empty element");
144 | return *resource_;
145 | }
146 |
147 | inline
148 | detail::Keyboard Element::GetKeyboard() const
149 | {
150 | return detail::Keyboard(&GetResource(), "value");
151 | }
152 |
153 | } // namespace webdriverxx
154 |
--------------------------------------------------------------------------------
/include/webdriverxx/wait_match.h:
--------------------------------------------------------------------------------
1 | #ifndef WEBDRIVERXX_WAIT_MATCH_H
2 | #define WEBDRIVERXX_WAIT_MATCH_H
3 |
4 | #include "wait.h"
5 | #include "detail/to_string.h"
6 | #include
7 |
8 | #ifdef WEBDRIVERXX_ENABLE_GMOCK_MATCHERS
9 |
10 | #include
11 | #include
12 |
13 | namespace webdriverxx {
14 | namespace detail {
15 |
16 | template
17 | class GMockMatcherAdapter {
18 | public:
19 | explicit GMockMatcherAdapter(::testing::Matcher matcher) : matcher_(matcher) {}
20 |
21 | bool Apply(const T& value) const {
22 | return matcher_.Matches(value);
23 | }
24 |
25 | std::string DescribeMismatch(const T& value) const {
26 | std::ostringstream s;
27 | s << "Expected: ";
28 | matcher_.DescribeTo(&s);
29 | s << ", actual: ";
30 | ToStream(value, s);
31 | const auto mismatch_details = GetMismatchDetails(value);
32 | if (!mismatch_details.empty())
33 | s << ", " << mismatch_details;
34 | return s.str();
35 | }
36 |
37 | private:
38 | std::string GetMismatchDetails(const T& value) const {
39 | std::ostringstream s;
40 | matcher_.ExplainMatchResultTo(value, &s);
41 | return s.str();
42 | }
43 |
44 | private:
45 | ::testing::Matcher matcher_;
46 | };
47 |
48 | } // detail
49 |
50 | template
51 | detail::GMockMatcherAdapter MakeMatcherAdapter(const M& matcher, typename std::enable_if>::value>::type* = nullptr) {
52 | return detail::GMockMatcherAdapter(matcher);
53 | };
54 |
55 | } // namespace webdriverxx
56 |
57 | #endif // WEBDRIVERXX_ENABLE_GMOCK_MATCHERS
58 |
59 | namespace webdriverxx {
60 | namespace detail {
61 |
62 | template