1 # Copyright 2008-2011 WebDriver committers
2 # Copyright 2008-2011 Google Inc.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 The WebDriver implementation.
19 from command import Command
20 from webelement import WebElement
21 from remote_connection import RemoteConnection
22 from errorhandler import ErrorHandler
23 from selenium.common.exceptions import WebDriverException
24 from selenium.common.exceptions import InvalidSelectorException
25 from selenium.webdriver.common.by import By
26 from selenium.webdriver.common.alert import Alert
27 from selenium.webdriver.common.html5.application_cache import ApplicationCache
30 class WebDriver(object):
32 Controls a browser by sending commands to a remote server.
33 This server is expected to be running the WebDriver wire protocol as defined
34 here: http://code.google.com/p/selenium/wiki/JsonWireProtocol
37 - command_executor - The command.CommandExecutor object used to execute commands.
38 - error_handler - errorhandler.ErrorHandler object used to verify that the server did not return an error.
39 - session_id - The session ID to send with every command.
40 - capabilities - A dictionary of capabilities of the underlying browser for this instance's session.
43 def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
44 desired_capabilities=None, browser_profile=None):
46 Create a new driver that will issue commands using the wire protocol.
49 - command_executor - Either a command.CommandExecutor object or a string that specifies the URL of a remote server to send commands to.
50 - desired_capabilities - Dictionary holding predefined values for starting a browser
51 - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object. Only used if Firefox is requested.
53 if desired_capabilities is None:
54 raise WebDriverException("Desired Capabilities can't be None")
55 if not isinstance(desired_capabilities, dict):
56 raise WebDriverException("Desired Capabilities must be a dictionary")
57 self.command_executor = command_executor
58 if type(self.command_executor) is str or type(self.command_executor) is unicode:
59 self.command_executor = RemoteConnection(command_executor)
60 self.session_id = None
61 self.capabilities = {}
62 self.error_handler = ErrorHandler()
64 self.start_session(desired_capabilities, browser_profile)
68 """Returns the name of the underlying browser for this instance.
73 if 'browserName' in self.capabilities:
74 return self.capabilities['browserName']
76 raise KeyError('browserName not specified in session capabilities')
78 def start_client(self):
80 Called before starting a new session. This method may be overridden
81 to define custom startup behavior.
85 def stop_client(self):
87 Called after executing a quit command. This method may be overridden
88 to define custom shutdown behavior.
92 def start_session(self, desired_capabilities, browser_profile=None):
94 Creates a new session with the desired capabilities.
97 - browser_name - The name of the browser to request.
98 - version - Which browser version to request.
99 - platform - Which platform to request the browser on.
100 - javascript_enabled - Whether the new session should support JavaScript.
101 - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object. Only used if Firefox is requested.
104 desired_capabilities['firefox_profile'] = browser_profile.encoded
105 response = self.execute(Command.NEW_SESSION, {
106 'desiredCapabilities': desired_capabilities,
108 self.session_id = response['sessionId']
109 self.capabilities = response['value']
111 def _wrap_value(self, value):
112 if isinstance(value, dict):
114 for key, val in value.items():
115 converted[key] = self._wrap_value(val)
117 elif isinstance(value, WebElement):
118 return {'ELEMENT': value.id}
119 elif isinstance(value, list):
120 return list(self._wrap_value(item) for item in value)
124 def create_web_element(self, element_id):
126 Creates a web element with the specified element_id.
128 return WebElement(self, element_id)
130 def _unwrap_value(self, value):
131 if isinstance(value, dict) and 'ELEMENT' in value:
132 return self.create_web_element(value['ELEMENT'])
133 elif isinstance(value, list):
134 return list(self._unwrap_value(item) for item in value)
138 def execute(self, driver_command, params=None):
140 Sends a command to be executed by a command.CommandExecutor.
143 - driver_command: The name of the command to execute as a string.
144 - params: A dictionary of named parameters to send with the command.
147 The command's JSON response loaded into a dictionary object.
150 params = {'sessionId': self.session_id}
151 elif 'sessionId' not in params:
152 params['sessionId'] = self.session_id
154 params = self._wrap_value(params)
155 response = self.command_executor.execute(driver_command, params)
157 self.error_handler.check_response(response)
158 response['value'] = self._unwrap_value(
159 response.get('value', None))
161 # If the server doesn't send a response, assume the command was
163 return {'success': 0, 'value': None, 'sessionId': self.session_id}
167 Loads a web page in the current browser session.
169 self.execute(Command.GET, {'url': url})
173 """Returns the title of the current page.
178 resp = self.execute(Command.GET_TITLE)
179 return resp['value'] if resp['value'] is not None else ""
181 def find_element_by_id(self, id_):
182 """Finds an element by id.
185 - id\_ - The id of the element to be found.
188 driver.find_element_by_id('foo')
190 return self.find_element(by=By.ID, value=id_)
192 def find_elements_by_id(self, id_):
194 Finds multiple elements by id.
197 - id\_ - The id of the elements to be found.
200 driver.find_element_by_id('foo')
202 return self.find_elements(by=By.ID, value=id_)
204 def find_element_by_xpath(self, xpath):
206 Finds an element by xpath.
209 - xpath - The xpath locator of the element to find.
212 driver.find_element_by_xpath('//div/td[1]')
214 return self.find_element(by=By.XPATH, value=xpath)
216 def find_elements_by_xpath(self, xpath):
218 Finds multiple elements by xpath.
221 - xpath - The xpath locator of the elements to be found.
224 driver.find_elements_by_xpath("//div[contains(@class, 'foo')]")
226 return self.find_elements(by=By.XPATH, value=xpath)
228 def find_element_by_link_text(self, link_text):
230 Finds an element by link text.
233 - link_text: The text of the element to be found.
236 driver.find_element_by_link_text('Sign In')
238 return self.find_element(by=By.LINK_TEXT, value=link_text)
240 def find_elements_by_link_text(self, text):
242 Finds elements by link text.
245 - link_text: The text of the elements to be found.
248 driver.find_elements_by_link_text('Sign In')
250 return self.find_elements(by=By.LINK_TEXT, value=text)
252 def find_element_by_partial_link_text(self, link_text):
254 Finds an element by a partial match of its link text.
257 - link_text: The text of the element to partially match on.
260 driver.find_element_by_partial_link_text('Sign')
262 return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
264 def find_elements_by_partial_link_text(self, link_text):
266 Finds elements by a partial match of their link text.
269 - link_text: The text of the element to partial match on.
272 driver.find_element_by_partial_link_text('Sign')
274 return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
276 def find_element_by_name(self, name):
278 Finds an element by name.
281 - name: The name of the element to find.
284 driver.find_element_by_name('foo')
286 return self.find_element(by=By.NAME, value=name)
288 def find_elements_by_name(self, name):
290 Finds elements by name.
293 - name: The name of the elements to find.
296 driver.find_elements_by_name('foo')
298 return self.find_elements(by=By.NAME, value=name)
300 def find_element_by_tag_name(self, name):
302 Finds an element by tag name.
305 - name: The tag name of the element to find.
308 driver.find_element_by_tag_name('foo')
310 return self.find_element(by=By.TAG_NAME, value=name)
312 def find_elements_by_tag_name(self, name):
314 Finds elements by tag name.
317 - name: The tag name the use when finding elements.
320 driver.find_elements_by_tag_name('foo')
322 return self.find_elements(by=By.TAG_NAME, value=name)
324 def find_element_by_class_name(self, name):
326 Finds an element by class name.
329 - name: The class name of the element to find.
332 driver.find_element_by_class_name('foo')
334 return self.find_element(by=By.CLASS_NAME, value=name)
336 def find_elements_by_class_name(self, name):
338 Finds elements by class name.
341 - name: The class name of the elements to find.
344 driver.find_elements_by_class_name('foo')
346 return self.find_elements(by=By.CLASS_NAME, value=name)
348 def find_element_by_css_selector(self, css_selector):
350 Finds an element by css selector.
353 - css_selector: The css selector to use when finding elements.
356 driver.find_element_by_css_selector('#foo')
358 return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
360 def find_elements_by_css_selector(self, css_selector):
362 Finds elements by css selector.
365 - css_selector: The css selector to use when finding elements.
368 driver.find_element_by_css_selector('#foo')
370 return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
372 def execute_script(self, script, *args):
374 Synchronously Executes JavaScript in the current window/frame.
377 - script: The JavaScript to execute.
378 - \*args: Any applicable arguments for your JavaScript.
381 driver.execute_script('document.title')
384 converted_args = args[0]
386 converted_args = list(args)
387 converted_args = list(args)
388 return self.execute(Command.EXECUTE_SCRIPT,
389 {'script': script, 'args':converted_args})['value']
391 def execute_async_script(self, script, *args):
393 Asynchronously Executes JavaScript in the current window/frame.
396 - script: The JavaScript to execute.
397 - \*args: Any applicable arguments for your JavaScript.
400 driver.execute_async_script('document.title')
403 converted_args = args[0]
405 converted_args = list(args)
406 converted_args = list(args)
407 return self.execute(Command.EXECUTE_ASYNC_SCRIPT,
408 {'script': script, 'args':converted_args})['value']
411 def current_url(self):
413 Gets the URL of the current page.
418 return self.execute(Command.GET_CURRENT_URL)['value']
421 def page_source(self):
423 Gets the source of the current page.
428 return self.execute(Command.GET_PAGE_SOURCE)['value']
432 Closes the current window.
437 self.execute(Command.CLOSE)
441 Quits the driver and closes every associated window.
447 self.execute(Command.QUIT)
452 def current_window_handle(self):
454 Returns the handle of the current window.
457 driver.current_window_handle
459 return self.execute(Command.GET_CURRENT_WINDOW_HANDLE)['value']
462 def window_handles(self):
464 Returns the handles of all windows within the current session.
467 driver.window_handles
469 return self.execute(Command.GET_WINDOW_HANDLES)['value']
471 def maximize_window(self):
473 Maximizes the current window that webdriver is using
475 self.execute(Command.MAXIMIZE_WINDOW, {"windowHandle": "current"})
478 def switch_to_active_element(self):
480 Returns the element with focus, or BODY if nothing has focus.
483 driver.switch_to_active_element()
485 return self.execute(Command.GET_ACTIVE_ELEMENT)['value']
487 def switch_to_window(self, window_name):
489 Switches focus to the specified window.
492 - window_name: The name or window handle of the window to switch to.
495 driver.switch_to_window('main')
497 self.execute(Command.SWITCH_TO_WINDOW, {'name': window_name})
499 def switch_to_frame(self, frame_reference):
501 Switches focus to the specified frame, by index, name, or webelement.
504 - frame_reference: The name of the window to switch to, an integer representing the index,
505 or a webelement that is an (i)frame to switch to.
508 driver.switch_to_frame('frame_name')
509 driver.switch_to_frame(1)
510 driver.switch_to_frame(driver.find_elements_by_tag_name("iframe")[0])
512 self.execute(Command.SWITCH_TO_FRAME, {'id': frame_reference})
514 def switch_to_default_content(self):
516 Switch focus to the default frame.
519 driver.switch_to_default_content()
521 self.execute(Command.SWITCH_TO_FRAME, {'id': None})
523 def switch_to_alert(self):
525 Switches focus to an alert on the page.
528 driver.switch_to_alert()
535 Goes one step backward in the browser history.
540 self.execute(Command.GO_BACK)
544 Goes one step forward in the browser history.
549 self.execute(Command.GO_FORWARD)
553 Refreshes the current page.
558 self.execute(Command.REFRESH)
561 def get_cookies(self):
563 Returns a set of dictionaries, corresponding to cookies visible in the current session.
568 return self.execute(Command.GET_ALL_COOKIES)['value']
570 def get_cookie(self, name):
572 Get a single cookie by name. Returns the cookie if found, None if not.
575 driver.get_cookie('my_cookie')
577 cookies = self.get_cookies()
578 for cookie in cookies:
579 if cookie['name'] == name:
583 def delete_cookie(self, name):
585 Deletes a single cookie with the given name.
588 driver.delete_cookie('my_cookie')
590 self.execute(Command.DELETE_COOKIE, {'name': name})
592 def delete_all_cookies(self):
594 Delete all cookies in the scope of the session.
597 driver.delete_all_cookies()
599 self.execute(Command.DELETE_ALL_COOKIES)
601 def add_cookie(self, cookie_dict):
603 Adds a cookie to your current session.
606 - cookie_dict: A dictionary object, with required keys - "name" and "value";
607 optional keys - "path", "domain", "secure", "expiry"
610 driver.add_cookie({'name' : 'foo', 'value' : 'bar'})
611 driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'path' : '/'})
612 driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'path' : '/', 'secure':True})
615 self.execute(Command.ADD_COOKIE, {'cookie': cookie_dict})
618 def implicitly_wait(self, time_to_wait):
620 Sets a sticky timeout to implicitly wait for an element to be found,
621 or a command to complete. This method only needs to be called one
622 time per session. To set the timeout for calls to
623 execute_async_script, see set_script_timeout.
626 - time_to_wait: Amount of time to wait (in seconds)
629 driver.implicitly_wait(30)
631 self.execute(Command.IMPLICIT_WAIT, {'ms': float(time_to_wait) * 1000})
633 def set_script_timeout(self, time_to_wait):
635 Set the amount of time that the script should wait during an
636 execute_async_script call before throwing an error.
639 - time_to_wait: The amount of time to wait (in seconds)
642 driver.set_script_timeout(30)
644 self.execute(Command.SET_SCRIPT_TIMEOUT,
645 {'ms': float(time_to_wait) * 1000})
647 def set_page_load_timeout(self, time_to_wait):
649 Set the amount of time to wait for a page load to complete
650 before throwing an error.
653 - time_to_wait: The amount of time to wait
656 driver.set_page_load_timeout(30)
658 self.execute(Command.SET_TIMEOUTS,
659 {'ms': float(time_to_wait) * 1000, 'type':'page load'})
661 def find_element(self, by=By.ID, value=None):
663 'Private' method used by the find_element_by_* methods.
666 Use the corresponding find_element_by_* instead of this.
668 if isinstance(by, tuple) or isinstance(value, int) or value==None:
669 raise InvalidSelectorException("Invalid locator values passed in")
671 return self.execute(Command.FIND_ELEMENT,
672 {'using': by, 'value': value})['value']
674 def find_elements(self, by=By.ID, value=None):
676 'Private' method used by the find_elements_by_* methods.
679 Use the corresponding find_elements_by_* instead of this.
681 if isinstance(by, tuple) or isinstance(value, int) or value==None:
682 raise InvalidSelectorException("Invalid locator values passed in")
684 return self.execute(Command.FIND_ELEMENTS,
685 {'using': by, 'value': value})['value']
687 def desired_capabilities(self):
689 returns the drivers current desired capabilities being used
691 return self.capabilities
693 def get_screenshot_as_file(self, filename):
695 Gets the screenshot of the current window. Returns False if there is
696 any IOError, else returns True. Use full paths in your filename.
699 - filename: The full path you wish to save your screenshot to.
702 driver.get_screenshot_as_file('/Screenshots/foo.png')
704 png = self.execute(Command.SCREENSHOT)['value']
706 with open(filename, 'wb') as f:
707 f.write(base64.decodestring(png))
713 def get_screenshot_as_base64(self):
715 Gets the screenshot of the current window as a base64 encoded string
716 which is useful in embedded images in HTML.
719 driver.get_screenshot_as_base64()
721 return self.execute(Command.SCREENSHOT)['value']
723 def set_window_size(self, width, height, windowHandle='current'):
725 Sets the width and height of the current window. (window.resizeTo)
728 - width: the width in pixels to set the window to
729 - height: the height in pixels to set the window to
732 driver.set_window_size(800,600)
734 self.execute(Command.SET_WINDOW_SIZE, {'width': width, 'height': height,
735 'windowHandle': windowHandle})
737 def get_window_size(self, windowHandle='current'):
739 Gets the width and height of the current window.
742 driver.get_window_size()
744 return self.execute(Command.GET_WINDOW_SIZE,
745 {'windowHandle': windowHandle})['value']
747 def set_window_position(self, x, y, windowHandle='current'):
749 Sets the x,y position of the current window. (window.moveTo)
752 - x: the x-coordinate in pixels to set the window position
753 - y: the y-coordinate in pixels to set the window position
756 driver.set_window_position(0,0)
758 self.execute(Command.SET_WINDOW_POSITION, {'x': x, 'y': y,
759 'windowHandle': windowHandle})
761 def get_window_position(self, windowHandle='current'):
763 Gets the x,y position of the current window.
766 driver.get_window_position()
768 return self.execute(Command.GET_WINDOW_POSITION,
769 {'windowHandle': windowHandle})['value']
772 def orientation(self):
774 Gets the current orientation of the device
777 orientation = driver.orientation
779 return self.execute(Command.GET_SCREEN_ORIENTATION)['value']
782 def orientation(self, value):
784 Sets the current orientation of the device
787 - value: orientation to set it to.
790 driver.orientation = 'landscape'
792 allowed_values = ['LANDSCAPE', 'PORTRAIT']
793 if value.upper() in allowed_values:
794 self.execute(Command.SET_SCREEN_ORIENTATION, {'orientation': value})['value']
796 raise WebDriverException("You can only set the orientation to 'LANDSCAPE' and 'PORTRAIT'")
799 """ Returns a boolean if the browser is online or offline"""
800 return self.execute(Command.IS_BROWSER_ONLINE)['value']
803 def application_cache(self):
804 """ Returns a ApplicationCache Object to interact with the browser app cache"""
805 return ApplicationCache(self)
807 def save_screenshot(self, filename):
809 Gets the screenshot of the current window. Returns False if there is
810 any IOError, else returns True. Use full paths in your filename.
812 png = self.execute(Command.SCREENSHOT)['value']
814 f = open(filename, 'wb')
815 f.write(base64.decodestring(png))