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