1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_TEST_WEBDRIVER_WEBDRIVER_SESSION_H_
6#define CHROME_TEST_WEBDRIVER_WEBDRIVER_SESSION_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/callback_forward.h"
13#include "base/files/file_path.h"
14#include "base/files/scoped_temp_dir.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/strings/string16.h"
17#include "base/threading/thread.h"
18#include "chrome/common/automation_constants.h"
19#include "chrome/test/automation/automation_json_requests.h"
20#include "chrome/test/webdriver/frame_path.h"
21#include "chrome/test/webdriver/webdriver_automation.h"
22#include "chrome/test/webdriver/webdriver_basic_types.h"
23#include "chrome/test/webdriver/webdriver_capabilities_parser.h"
24#include "chrome/test/webdriver/webdriver_element_id.h"
25#include "chrome/test/webdriver/webdriver_logging.h"
26
27namespace base {
28class DictionaryValue;
29class FilePath;
30class ListValue;
31class Value;
32class WaitableEvent;
33}
34
35namespace webdriver {
36
37class Error;
38class ValueParser;
39
40// A view ID and frame path combination that uniquely identifies a specific
41// frame within a session.
42struct FrameId {
43  FrameId();
44  FrameId(const WebViewId& view_id, const FramePath& frame_path);
45
46  WebViewId view_id;
47  FramePath frame_path;
48};
49
50enum StorageType {
51  kLocalStorageType = 0,
52  kSessionStorageType
53};
54
55// Every connection made by WebDriver maps to a session object.
56// This object creates the chrome instance and keeps track of the
57// state necessary to control the chrome browser created.
58// A session manages its own lifetime.
59class Session {
60 public:
61  // Adds this |Session| to the |SessionManager|. The session manages its own
62  // lifetime. Call |Terminate|, not delete, if you need to quit.
63  Session();
64
65  // Removes this |Session| from the |SessionManager|.
66  ~Session();
67
68  // Initializes the session with the given capabilities.
69  Error* Init(const base::DictionaryValue* capabilities_dict);
70
71  // Should be called before executing a command.
72  Error* BeforeExecuteCommand();
73
74  // Should be called after executing a command.
75  Error* AfterExecuteCommand();
76
77  // Terminates this session and deletes itself.
78  void Terminate();
79
80  // Executes the given |script| in the context of the given frame.
81  // The |script| should be in the form of a function body
82  // (e.g. "return arguments[0]"), where |args| is the list of arguments to
83  // pass to the function. The caller is responsible for the script result
84  // |value|, which is set only if there is no error.
85  Error* ExecuteScript(const FrameId& frame_id,
86                       const std::string& script,
87                       const base::ListValue* const args,
88                       base::Value** value);
89
90  // Same as above, but uses the currently targeted window and frame.
91  Error* ExecuteScript(const std::string& script,
92                       const base::ListValue* const args,
93                       base::Value** value);
94
95  // Executes the given script in the context of the given frame and parses
96  // the value with the given parser. The script should be in the form of an
97  // anonymous function. |script_name| is only used when creating error
98  // messages. This function takes ownership of |args| and |parser|.
99  Error* ExecuteScriptAndParse(const FrameId& frame_id,
100                               const std::string& anonymous_func_script,
101                               const std::string& script_name,
102                               const base::ListValue* args,
103                               const ValueParser* parser);
104
105  // Executes given |script| in the context of the given frame.
106  // The |script| should be in the form of a function body
107  // (e.g. "return arguments[0]"), where |args| is the list of arguments to
108  // pass to the function. The caller is responsible for the script result
109  // |value|, which is set only if there is no error.
110  Error* ExecuteAsyncScript(const FrameId& frame_id,
111                            const std::string& script,
112                            const base::ListValue* const args,
113                            base::Value** value);
114
115  // Send the given keys to the given element dictionary. This function takes
116  // ownership of |element|.
117  Error* SendKeys(const ElementId& element, const string16& keys);
118  // Send the given keys to the active element.
119  Error* SendKeys(const string16& keys);
120
121  // Sets the file paths to the file upload control under the given location.
122  Error* DragAndDropFilePaths(
123      const Point& location,
124      const std::vector<base::FilePath::StringType>& paths);
125
126  // Clicks the mouse at the given location using the given button.
127  Error* MouseMoveAndClick(const Point& location,
128                           automation::MouseButton button);
129  Error* MouseMove(const Point& location);
130  Error* MouseDrag(const Point& start, const Point& end);
131  Error* MouseClick(automation::MouseButton button);
132  Error* MouseButtonDown();
133  Error* MouseButtonUp();
134  Error* MouseDoubleClick();
135
136  Error* NavigateToURL(const std::string& url);
137  Error* GoForward();
138  Error* GoBack();
139  Error* Reload();
140  Error* GetURL(std::string* url);
141  Error* GetTitle(std::string* tab_title);
142  Error* GetScreenShot(std::string* png);
143#if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS))
144  Error* HeapProfilerDump(const std::string& reason);
145#endif  // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS))
146  Error* GetCookies(const std::string& url,
147                    scoped_ptr<base::ListValue>* cookies);
148  Error* DeleteCookie(const std::string& url, const std::string& cookie_name);
149  Error* SetCookie(const std::string& url, base::DictionaryValue* cookie_dict);
150
151  // Gets all the currently open views.
152  Error* GetViews(std::vector<WebViewInfo>* views);
153
154  // Switches the view used by default. |id_or_name| is either a view ID
155  // returned by |GetViews| or the name attribute of a DOM window.
156  // Only tabs are considered when searching by name.
157  Error* SwitchToView(const std::string& id_or_name);
158
159  // Switches the frame used by default. |name_or_id| is either the name or id
160  // of a frame element.
161  Error* SwitchToFrameWithNameOrId(const std::string& name_or_id);
162
163  // Switches the frame used by default. |index| is the zero-based frame index.
164  Error* SwitchToFrameWithIndex(int index);
165
166  // Switches to the frame identified by the given |element|. The element must
167  // be either an IFRAME or FRAME element.
168  Error* SwitchToFrameWithElement(const ElementId& element);
169
170  // Switches the target frame to the topmost frame.
171  void SwitchToTopFrame();
172
173  // Switches the target frame to the topmost frame if the current frame is
174  // invalid.
175  Error* SwitchToTopFrameIfCurrentFrameInvalid();
176
177  // Closes the current window. Returns true on success.
178  // Note: The session will be deleted if this closes the last window in the
179  // session.
180  Error* CloseWindow();
181
182  // Gets the bounds for the specified window.
183  Error* GetWindowBounds(const WebViewId& window, Rect* bounds);
184
185  // Sets the bounds for the specified window.
186  Error* SetWindowBounds(const WebViewId& window, const Rect& bounds);
187
188  // Maximizes the specified window.
189  Error* MaximizeWindow(const WebViewId& window);
190
191  // Gets the message of the currently active JavaScript modal dialog.
192  Error* GetAlertMessage(std::string* text);
193
194  // Sets the prompt text to use when accepting or dismissing a JavaScript
195  // modal dialog.
196  Error* SetAlertPromptText(const std::string& alert_prompt_text);
197
198  // Accept or dismiss the currently active JavaScript modal dialog with the
199  // previously set alert prompt text. Then clears the saved alert prompt text.
200  Error* AcceptOrDismissAlert(bool accept);
201
202  // Gets the version of the running browser.
203  std::string GetBrowserVersion();
204
205  // Gets whether the running browser's version is newer or equal to the given
206  // version. Returns true on successful comparison. For example, in the version
207  // 11.0.632.4, 632 is the build number and 4 is the patch number.
208  Error* CompareBrowserVersion(int build_no,
209                               int patch_no,
210                               bool* is_newer_or_equal);
211
212  // Finds a single element in the given frame, starting at the given
213  // |root_element|, using the given locator strategy. |locator| should be a
214  // constant from |LocatorType|. Returns an error code. If successful,
215  // |element| will be set as the found element.
216  Error* FindElement(const FrameId& frame_id,
217                     const ElementId& root_element,
218                     const std::string& locator,
219                     const std::string& query,
220                     ElementId* element);
221
222  // Same as above, but finds multiple elements.
223  Error* FindElements(const FrameId& frame_id,
224                      const ElementId& root_element,
225                      const std::string& locator,
226                      const std::string& query,
227                      std::vector<ElementId>* elements);
228
229  // Scroll the element into view and get its location relative to
230  // the client's viewport.
231  Error* GetElementLocationInView(
232      const ElementId& element,
233      Point* location);
234
235  // Scroll the element's region into view and get its location relative to
236  // the client's viewport. If |center| is true, the element will be centered
237  // if it is too big to fit in view. If |verify_clickable_at_middle| is true,
238  // an error will be returned if the element is not clickable in the middle
239  // of the given region.
240  Error* GetElementRegionInView(
241      const ElementId& element,
242      const Rect& region,
243      bool center,
244      bool verify_clickable_at_middle,
245      Point* location);
246
247  // Gets the size of the element from the given window and frame, even if
248  // its display is none.
249  Error* GetElementSize(const FrameId& frame_id,
250                        const ElementId& element,
251                        Size* size);
252
253  // Gets the size of the element's first client rect. If the element has
254  // no client rects, this will return an error.
255  Error* GetElementFirstClientRect(const FrameId& frame_id,
256                                   const ElementId& element,
257                                   Rect* rect);
258
259  // Gets the element's effective style for the given property.
260  Error* GetElementEffectiveStyle(
261      const FrameId& frame_id,
262      const ElementId& element,
263      const std::string& prop,
264      std::string* value);
265
266  // Gets the top and left element border widths for the given frame.
267  Error* GetElementBorder(const FrameId& frame_id,
268                          const ElementId& element,
269                          int* border_left,
270                          int* border_top);
271
272  // Gets whether the element is currently displayed.
273  Error* IsElementDisplayed(const FrameId& frame_id,
274                            const ElementId& element,
275                            bool ignore_opacity,
276                            bool* is_visible);
277
278  // Gets whether the element is currently enabled.
279  Error* IsElementEnabled(const FrameId& frame_id,
280                          const ElementId& element,
281                          bool* is_enabled);
282
283  // Gets whether the option element is currently selected.
284  Error* IsOptionElementSelected(const FrameId& frame_id,
285                                 const ElementId& element,
286                                 bool* is_selected);
287
288  // Set the selection state of the given option element. The option element
289  // must support multi selection if |selected| is false.
290  Error* SetOptionElementSelected(const FrameId& frame_id,
291                                  const ElementId& element,
292                                  bool selected);
293
294  // Toggles the option element's selection state. The option element should
295  // support multi selection.
296  Error* ToggleOptionElement(const FrameId& frame_id,
297                             const ElementId& element);
298
299  // Gets the tag name of the given element.
300  Error* GetElementTagName(const FrameId& frame_id,
301                           const ElementId& element,
302                           std::string* tag_name);
303
304  // Gets the clickable location of the given element. It will be the center
305  // location of the element. If the element is not clickable, or if the
306  // location cannot be determined, an error will be returned.
307  Error* GetClickableLocation(const ElementId& element,
308                              Point* location);
309
310  // Gets the attribute of the given element. If there are no errors, the
311  // function sets |value| and the caller takes ownership.
312  Error* GetAttribute(const ElementId& element, const std::string& key,
313                      base::Value** value);
314
315  // Waits for all views to stop loading. Returns true on success.
316  Error* WaitForAllViewsToStopLoading();
317
318  // Install extension at |path|.
319  Error* InstallExtension(const base::FilePath& path, std::string* extension_id);
320
321  Error* GetExtensionsInfo(base::ListValue* extension_ids);
322
323  Error* IsPageActionVisible(const WebViewId& tab_id,
324                             const std::string& extension_id,
325                             bool* is_visible);
326
327  Error* SetExtensionState(const std::string& extension_id,
328                           bool enable);
329
330  Error* ClickExtensionButton(const std::string& extension_id,
331                              bool browser_action);
332
333  Error* UninstallExtension(const std::string& extension_id);
334
335  // Sets the preference to the given value. This function takes ownership
336  // of |value|. If the preference is a user preference (instead of local
337  // state preference) |is_user_pref| should be true.
338  Error* SetPreference(const std::string& pref,
339                       bool is_user_pref,
340                       base::Value* value);
341
342  // Returns a copy of the current log entries. Caller is responsible for
343  // returned value.
344  base::ListValue* GetLog() const;
345
346  // Gets the browser connection state.
347  Error* GetBrowserConnectionState(bool* online);
348
349  // Gets the status of the application cache.
350  Error* GetAppCacheStatus(int* status);
351
352  // Sets an item in the HTML5 localStorage object.
353  Error* SetStorageItem(StorageType type,
354                        const std::string& key,
355                        const std::string& value);
356
357  // Gets the value of an item in the HTML5 localStorage object.
358  Error* GetStorageItem(StorageType type,
359                        const std::string& key,
360                        std::string* value);
361
362  // Removes an item from the HTML5 localStorage object.
363  Error* RemoveStorageItem(StorageType type,
364                           const std::string& key,
365                           std::string* value);
366
367  // Gets the total number of items in the HTML5 localStorage object.
368  Error* GetStorageSize(StorageType type, int* size);
369
370  // Removes all items in the HTML5 localStorage object.
371  Error* ClearStorage(StorageType type);
372
373  // Gets the keys of all items of the HTML5 localStorage object. If there are
374  // no errors, the function sets |keys| and the caller takes ownership.
375  Error* GetStorageKeys(StorageType type, base::ListValue** keys);
376
377  // Gets the current geolocation.
378  Error* GetGeolocation(scoped_ptr<base::DictionaryValue>* geolocation);
379
380  // Overrides the current geolocation.
381  Error* OverrideGeolocation(const base::DictionaryValue* geolocation);
382
383  const std::string& id() const;
384
385  const FrameId& current_target() const;
386
387  void set_async_script_timeout(int timeout_ms);
388  int async_script_timeout() const;
389
390  void set_implicit_wait(int timeout_ms);
391  int implicit_wait() const;
392
393  const Point& get_mouse_position() const;
394
395  const Logger& logger() const;
396
397  const base::FilePath& temp_dir() const;
398
399  const Capabilities& capabilities() const;
400
401 private:
402  void RunSessionTask(const base::Closure& task);
403  void RunClosureOnSessionThread(
404      const base::Closure& task,
405      base::WaitableEvent* done_event);
406  void InitOnSessionThread(const Automation::BrowserOptions& options,
407                           int* build_no,
408                           Error** error);
409  void TerminateOnSessionThread();
410
411  // Executes the given |script| in the context of the given frame.
412  // Waits for script to finish and parses the response.
413  // The caller is responsible for the script result |value|.
414  Error* ExecuteScriptAndParseValue(const FrameId& frame_id,
415                                    const std::string& script,
416                                    base::Value** value);
417  void SendKeysOnSessionThread(const string16& keys,
418                               bool release_modifiers,
419                               Error** error);
420  Error* ProcessWebMouseEvents(const std::vector<WebMouseEvent>& events);
421  WebMouseEvent CreateWebMouseEvent(automation::MouseEventType type,
422                                    automation::MouseButton button,
423                                    const Point& point,
424                                    int click_count);
425  Error* SwitchToFrameWithJavaScriptLocatedFrame(
426      const std::string& script,
427      base::ListValue* args);
428  Error* FindElementsHelper(const FrameId& frame_id,
429                            const ElementId& root_element,
430                            const std::string& locator,
431                            const std::string& query,
432                            bool find_one,
433                            std::vector<ElementId>* elements);
434  Error* ExecuteFindElementScriptAndParse(const FrameId& frame_id,
435                                          const ElementId& root_element,
436                                          const std::string& locator,
437                                          const std::string& query,
438                                          bool find_one,
439                                          std::vector<ElementId>* elements);
440  // Returns an error if the element is not clickable.
441  Error* VerifyElementIsClickable(
442      const FrameId& frame_id,
443      const ElementId& element,
444      const Point& location);
445  Error* GetElementRegionInViewHelper(
446      const FrameId& frame_id,
447      const ElementId& element,
448      const Rect& region,
449      bool center,
450      bool verify_clickable_at_middle,
451      Point* location);
452  Error* PostBrowserStartInit();
453  Error* InitForWebsiteTesting();
454  Error* SetPrefs();
455
456  scoped_ptr<InMemoryLog> session_log_;
457  Logger logger_;
458
459  const std::string id_;
460  FrameId current_target_;
461
462  scoped_ptr<Automation> automation_;
463  base::Thread thread_;
464
465  // Timeout (in ms) for asynchronous script execution.
466  int async_script_timeout_;
467
468  // Time (in ms) of how long to wait while searching for a single element.
469  int implicit_wait_;
470
471  // Vector of the |ElementId|s for each frame of the current target frame
472  // path. The first refers to the first frame element in the root document.
473  // If the target frame is window.top, this will be empty.
474  std::vector<ElementId> frame_elements_;
475
476  // Last mouse position. Advanced APIs need this value.
477  Point mouse_position_;
478
479  // Chrome does not have an individual method for setting the prompt text
480  // of an alert. Instead, when the WebDriver client wants to set the text,
481  // we store it here and pass the text when the alert is accepted or
482  // dismissed. This text should only be used if |has_alert_prompt_text_|
483  // is true, so that the default prompt text is not overridden.
484  std::string alert_prompt_text_;
485  bool has_alert_prompt_text_;
486
487  // Temporary directory containing session data.
488  base::ScopedTempDir temp_dir_;
489  Capabilities capabilities_;
490
491  // Current state of all modifier keys.
492  int sticky_modifiers_;
493
494  // Chrome's build number. This is the 3rd number in Chrome's version string
495  // (e.g., 18.0.995.0 -> 995). Only valid after Chrome has started.
496  // See http://dev.chromium.org/releases/version-numbers.
497  int build_no_;
498
499  DISALLOW_COPY_AND_ASSIGN(Session);
500};
501
502}  // namespace webdriver
503
504#endif  // CHROME_TEST_WEBDRIVER_WEBDRIVER_SESSION_H_
505