Package tlib :: Package base :: Module WebDriverTester
[hide private]
[frames] | no frames]

Source Code for Module tlib.base.WebDriverTester

  1  import os 
  2  import inspect 
  3  # noinspection PyPackageRequirements 
  4  import pytest 
  5  import collections 
  6  from time import sleep 
  7  # noinspection PyPackageRequirements 
  8  from _pytest.python import FixtureRequest 
  9  # noinspection PyPackageRequirements 
 10  import jinja2 
 11  from tlib.base import TestHelper 
 12  from tlib.base import FileHelper 
 13  from tlib.base.PytestTester import PytestTester 
 14  from selenium.webdriver.common.by import By 
 15  from selenium.webdriver.support.ui import WebDriverWait 
 16  from selenium.webdriver.support import expected_conditions 
 17  from selenium.common.exceptions import TimeoutException, NoAlertPresentException, NoSuchElementException 
 18  from selenium.webdriver.remote.webelement import WebElement 
 19  from TestHelper import Singleton 
 20  from uuid import uuid4 
21 22 23 # noinspection PyMethodParameters 24 # noinspection PyUnresolvedReferences 25 -class WebDriverTester(PytestTester):
26 27 __metaclass__ = Singleton 28 29 _driver = None 30 31 _folder_dest = None # destination of report for the current class 32 _test_case_id = None 33 _test_case_name = None 34 _test_params = None 35 36 _jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(TestHelper.tlib_template_folder()), 37 trim_blocks=True) 38 39 _screenshot_report = None # List of tests for which there are screenshots 40 41 # Template for generating screenshot report 42 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html") 43 44 _screenshots = {} # Screenshots generated during a test case 45 46 # Template for generating screenshots for a test case 47 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html") 48 49 _request = None 50
51 - def screenshot_folder(self):
52 """ 53 Returns location of screenshot folder 54 55 @return: str 56 """ 57 screenshot_folder = self._find_screenshot_folder() 58 if screenshot_folder is None: 59 #Couldn't find screenshot folder 60 raise NotImplementedError("Could not find screenshot folder. " 61 "Class should implement method screenshot_folder") 62 else: 63 return screenshot_folder
64
65 - def _find_screenshot_folder(self):
66 """ 67 Will try to find a folder named "screenshot" starting from the file being executed and up to 68 three levels up 69 70 @return: str 71 """ 72 #Get current folder 73 curr_folder = os.path.dirname(self._request.fspath.strpath) 74 75 #Go up to three levels to find screenshot folder 76 for i in range(1, 4): 77 curr_folder = os.path.abspath(os.path.join(curr_folder, os.pardir)) 78 79 #Check if there is a folder 'screenshots' 80 screenshot_folder = os.path.join(curr_folder, 'screenshots') 81 if os.path.exists(screenshot_folder): 82 return screenshot_folder
83
84 - def _get_unused_report_name(self, tc_id, tc_params):
85 """ 86 Gets a string based on test case id and name, taking into account if test case has already been run or not 87 @param tc_id: Test case id 88 @type tc_id: str 89 @type tc_name: str 90 """ 91 return uuid4().hex
92 93 @pytest.fixture(scope='class', autouse=True)
94 - def initialize_webdriver_class(self, request):
95 """ 96 @type request: FixtureRequest 97 """ 98 99 #Generates initial HTML page with all test case results for the class 100 self._screenshot_report = collections.OrderedDict() 101 self._folder_dest = os.path.basename(os.path.dirname(os.path.abspath(inspect.getfile(request.cls)))) 102 103 def generate_report(): 104 if len(self._screenshot_report) > 0: 105 #Generate HTML based on template 106 html = self._screenshot_report_template.render(test_class=request.cls.__name__, 107 files=self._screenshot_report) 108 109 htm_file = "%s.htm" % self._folder_dest 110 full_filename = os.path.join(self.screenshot_folder(), htm_file) 111 112 f = open(full_filename, "w") 113 try: 114 f.write(html.encode('utf-8')) 115 finally: 116 f.close()
117 118 request.addfinalizer(generate_report)
119 120 @pytest.fixture(scope='function', autouse=True)
121 - def setup_webdriver_test(self, request):
122 """ 123 Goes to homepage before each test, unless marker skipsetup is given 124 125 @type request: FixtureRequest 126 """ 127 #Store an instance of the request object. Required for the generation of screenshots 128 self._request = request 129 130 #Initialization required for screenshot generation 131 # noinspection PyProtectedMember 132 self._test_params = request.keywords.node._genid 133 self._test_case_name = request.keywords.node.name.decode('utf-8') 134 self._screenshots = {} 135 136 #Get marker test case name or use a default if there is none 137 marker = request.node.get_marker("testcasename") 138 if marker is None: 139 self.test_logger.warn("Test case doesn't have marker testcasename") 140 self._test_case_id = "UNKNOWN_TEST_CASE_ID" 141 else: 142 self._test_case_id = marker.args[0] 143 144 def generate_report(): 145 """ 146 Generates HTML page with all the screenshots for a test case 147 Supports generating different files when test cases are run multiple times with the same arguments 148 """ 149 150 if len(self._screenshots) > 0: 151 name = self._get_unused_report_name(self._test_case_id, self._test_params) 152 153 #Generate HTML based on template 154 html = self._tc_screenshot_template.render(test_case_id=self._test_case_id, 155 test_case_name=self._test_case_name, 156 screenshots=self._screenshots) 157 158 #Filename includes a counter in case test case is being run more than once 159 htm_file = FileHelper.get_filename_from_string(name) + '.htm' 160 relative_filename = os.path.join(self._folder_dest, htm_file) 161 full_filename = os.path.join(self.screenshot_folder(), relative_filename) 162 163 self._screenshot_report[name] = {"tc_id": self._test_case_id, 164 "tc_name": self._test_case_name, 165 "filename": relative_filename} 166 167 f = open(full_filename, "w") 168 try: 169 f.write(html.encode('utf-8')) 170 finally: 171 f.close()
172 173 request.addfinalizer(generate_report) 174
175 - def save_screenshot(self, description):
176 """ 177 Saves screen shot for the current page 178 """ 179 #Waits until page is loaded 180 self.tlib_logger.debug("Saving screenshot") 181 self.wait_for_page_loaded() 182 183 #Folder containing images for test case 184 name = self._get_unused_report_name(self._test_case_id, self._test_params) 185 name = FileHelper.get_filename_from_string(name) 186 187 test_folder = os.path.join(self.screenshot_folder(), self._folder_dest, name) 188 189 os.makedirs(test_folder) 190 191 192 #Get number of existing images 193 i = len(os.listdir(test_folder)) + 1 194 195 #Get filename 196 img_filename = "%02d.png" % i 197 full_path = os.path.join(test_folder, img_filename) 198 199 self._screenshots[i] = {"filename": "%s/%s" % (name, img_filename), 200 u"description": description} 201 202 self._driver.get_screenshot_as_file(full_path)
203
204 - def wait_for_page_loaded(self, timeout=10):
205 raise NotImplementedError("This method should be implemented by derived classes")
206
207 - def wait_for_alert(self, timeout=10):
208 """ 209 Waist until an alert is visible 210 @type timeout: Integer 211 @param timeout: Number of seconds before timing out 212 @rtype: bool 213 """ 214 def is_alert_visible(): 215 try: 216 #Try to get alert text to trigger exception if alert is not visible 217 alert = self._driver.switch_to_alert().text 218 return True 219 except NoAlertPresentException as e: 220 return False
221 222 condition = lambda *args: is_alert_visible() 223 try: 224 WebDriverWait(self._driver, timeout).until(condition) 225 return self._driver.switch_to_alert() 226 except TimeoutException: 227 self.test_logger.error('Timeout while waiting for alert to appear') 228 pytest.fail('Timeout while waiting for alert to appear') 229
230 - def wait_for_element_to_be_visible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
231 """ 232 Wait until an element becomes visible 233 @param locator_strategy: Location strategy to use 234 @type locator_strategy: By 235 @param locator_string: String used to locate element 236 @type locator_string: str 237 @param error_msg: Error string to show if element is not found 238 @type error_msg: str 239 @param timeout: Maximum time in seconds to wait for the element to be visible 240 @type timeout: int 241 @rtype: WebElement 242 """ 243 try: 244 element = WebDriverWait(self._driver, timeout).\ 245 until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 246 return element 247 except TimeoutException: 248 if error_msg is None: 249 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 250 self.save_screenshot("[ERROR] %s" % error_msg) 251 pytest.fail(error_msg)
252
253 - def wait_for_element_to_be_clickable(self, locator_strategy, locator_string, error_msg=None, timeout=10):
254 """ 255 Wait until an element cna be clicked 256 @param locator_strategy: Location strategy to use 257 @type locator_strategy: By 258 @param locator_string: String used to locate element 259 @type locator_string: str 260 @param error_msg: Error string to show if element is not found 261 @type error_msg: str 262 @param timeout: Maximum time in seconds to wait for the element to be clickable 263 @type timeout: int 264 @rtype: WebElement 265 """ 266 try: 267 element = WebDriverWait(self._driver, timeout).\ 268 until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string))) 269 return element 270 except TimeoutException: 271 if error_msg is None: 272 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string 273 self.save_screenshot("[ERROR] %s" % error_msg) 274 pytest.fail(error_msg)
275
276 - def wait_for_element_to_be_present(self, locator_strategy, locator_string, error_msg=None, timeout=10):
277 """ 278 Wait until an element is present 279 @param locator_strategy: Location strategy to use 280 @type locator_strategy: By 281 @param locator_string: String used to locate element 282 @type locator_string: str 283 @param error_msg: Error string to show if element is not found 284 @type error_msg: str 285 @param timeout: Maximum time in seconds to wait for the element to be present 286 @type timeout: int 287 @rtype: WebElement 288 """ 289 try: 290 element = WebDriverWait(self._driver, timeout).\ 291 until(expected_conditions.presence_of_element_located((locator_strategy, locator_string))) 292 return element 293 except TimeoutException: 294 if error_msg is None: 295 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string 296 self.save_screenshot("[ERROR] %s" % error_msg) 297 pytest.fail(error_msg)
298
299 - def wait_for_element_to_be_selected(self, locator_strategy, locator_string, error_msg=None, timeout=10):
300 """ 301 Wait until an element is selected 302 @param locator_strategy: Location strategy to use 303 @type locator_strategy: By 304 @param locator_string: String used to locate element 305 @type locator_string: str 306 @param error_msg: Error string to show if element is not found 307 @type error_msg: str 308 @param timeout: Maximum time in seconds to wait for the element to be selected 309 @type timeout: int 310 @rtype: WebElement 311 """ 312 try: 313 element = WebDriverWait(self._driver, timeout).\ 314 until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string))) 315 return element 316 except TimeoutException: 317 if error_msg is None: 318 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string 319 self.save_screenshot("[ERROR] %s" % error_msg) 320 pytest.fail(error_msg)
321
322 - def wait_for_element_to_be_invisible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
323 """ 324 Wait until an element becomes invisible 325 @param locator_strategy: Location strategy to use 326 @type locator_strategy: By 327 @param locator_string: String used to locate element 328 @type locator_string: str 329 @param error_msg: Error string to show if element is not found 330 @type error_msg: str 331 @param timeout: Maximum time in seconds to wait for the element to be hidden 332 @type timeout: int 333 @rtype: WebElement 334 """ 335 try: 336 element = WebDriverWait(self._driver, timeout).\ 337 until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string))) 338 return element 339 except TimeoutException: 340 if error_msg is None: 341 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string 342 self.save_screenshot("[ERROR] %s" % error_msg) 343 pytest.fail(error_msg)
344
345 - def wait_for_element_to_be_static(self, locator_strategy, locator_string, error_msg=None, timeout=10):
346 """ 347 Wait until an element that moves on the screen stops moving 348 @param locator_strategy: Location strategy to use 349 @type locator_strategy: By 350 @param locator_string: String used to locate element 351 @type locator_string: str 352 @param error_msg: Error string to show if element is not found 353 @type error_msg: str 354 @param timeout: Maximum time in seconds to wait for the element to be visible 355 @type timeout: int 356 @rtype: WebElement 357 """ 358 try: 359 element = WebDriverWait(self._driver, timeout).\ 360 until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 361 362 #wait until element is not moving or click will fail 363 old_location = {'x': 0, 'y': 0} 364 while old_location != element.location: 365 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % 366 (old_location, element.location)) 367 old_location = element.location 368 sleep(0.1) 369 element = self._driver.find_element(locator_strategy, locator_string) 370 371 return element 372 except TimeoutException: 373 if error_msg is None: 374 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 375 self.save_screenshot("[ERROR] %s" % error_msg) 376 pytest.fail(error_msg)
377
378 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, 379 error_msg=None, timeout=10):
380 """ 381 Wait for an element that contains specified text 382 @param locator_strategy: Location strategy to use 383 @type locator_strategy: By 384 @param locator_string: String used to locate element 385 @type locator_string: str 386 @param error_msg: Error string to show if element is not found 387 @type error_msg: str 388 @param timeout: Maximum time in seconds to wait 389 @type timeout: int 390 """ 391 try: 392 WebDriverWait(self._driver, timeout).\ 393 until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text)) 394 except TimeoutException: 395 if error_msg is None: 396 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % \ 397 {"text": text, "element": locator_string} 398 self.save_screenshot("[ERROR] %s" % error_msg) 399 pytest.fail(error_msg)
400
401 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, 402 error_msg=None, timeout=10):
403 """ 404 Wait for an element's value to contain some test 405 @param locator_strategy: Location strategy to use 406 @type locator_strategy: By 407 @param locator_string: String used to locate element 408 @type locator_string: str 409 @param error_msg: Error string to show if element is not found 410 @type error_msg: str 411 @param timeout: Maximum time in seconds to wait 412 @type timeout: int 413 """ 414 try: 415 WebDriverWait(self._driver, timeout).\ 416 until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text)) 417 except TimeoutException: 418 if error_msg is None: 419 error_msg = "Timeout while waiting for text %(text)s to be present " \ 420 "in the value of element '%(element)s'" % {"text": text, "element": locator_string} 421 self.save_screenshot("[ERROR] %s" % error_msg) 422 pytest.fail(error_msg)
423 424 439
440 - def get_webelement_by_xpath(self, locator_string):
441 """ 442 Get the webelement by xpath 443 @param locator_string: String used to locate element 444 @type locator_string: str 445 @param error_msg: Error string to show if element is not found 446 @type error_msg: str 447 """ 448 try: 449 self.wait_for_element_to_be_visible(By.XPATH, locator_string) 450 return self.browser.find_element_by_xpath(locator_string) 451 except NoSuchElementException: 452 error_msg="Could not find the xpath: '%s'" 453 self.save_screenshot(error_msg % locator_string) 454 pytest.fail(error_msg % locator_string)
455 #
456 - def get_webelement_by_css(self, locator_string):
457 """ 458 Get the webelement by CSS 459 @param locator_string: String used to locate element 460 @type locator_string: str 461 @param error_msg: Error string to show if element is not found 462 @type error_msg: str 463 """ 464 try: 465 self.wait_for_element_to_be_visible(By.CSS_SELECTOR, locator_string) 466 return self.browser.find_element_by_css_selector(locator_string) 467 except NoSuchElementException: 468 error_msg="Could not find css: '%s'" 469 self.save_screenshot(error_msg % locator_string) 470 pytest.fail(error_msg %locator_string)
471 #
472 - def get_webelements_by_xpath(self, locator_string):
473 """ 474 Get the webelement list by xpath 475 @param locator_string: String used to locate element 476 @type locator_string: str 477 @param error_msg: Error string to show if element is not found 478 @type error_msg: str 479 """ 480 try: 481 return self.browser.find_elements_by_xpath(locator_string) 482 except NoSuchElementException: 483 error_msg="Could not find the link: '%s'" 484 self.save_screenshot(error_msg % locator_string) 485 pytest.fail(error_msg+ " '%s'" % locator_string)
486 #
487 - def get_webelements_by_css(self, locator_string):
488 """ 489 Get the webelement list by CSS 490 @param locator_string: String used to locate element 491 @type locator_string: str 492 @param error_msg: Error string to show if element is not found 493 @type error_msg: str 494 """ 495 try: 496 return self.browser.find_elements_by_css_selector(locator_string) 497 except NoSuchElementException: 498 error_msg="Could not find css: '%s'" 499 self.save_screenshot(error_msg % locator_string) 500 pytest.fail(error_msg % locator_string)
501