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 self.tlib_logger.debug("Waiting for element '%s' to be visible with locator strategy: %s" % 360 (locator_string, locator_strategy)) 361 element = WebDriverWait(self._driver, timeout).\ 362 until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 363 364 self.tlib_logger.debug("Waiting until element stops moving") 365 #wait until element is not moving or click will fail 366 old_location = {'x': 0, 'y': 0} 367 while old_location != element.location: 368 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % 369 (old_location, element.location)) 370 old_location = element.location 371 sleep(0.1) 372 element = self._driver.find_element(locator_strategy, locator_string) 373 374 return element 375 except TimeoutException: 376 if error_msg is None: 377 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 378 self.save_screenshot("[ERROR] %s" % error_msg) 379 pytest.fail(error_msg)
380
381 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, 382 error_msg=None, timeout=10):
383 """ 384 Wait for an element that contains specified text 385 @param locator_strategy: Location strategy to use 386 @type locator_strategy: By 387 @param locator_string: String used to locate element 388 @type locator_string: str 389 @param error_msg: Error string to show if element is not found 390 @type error_msg: str 391 @param timeout: Maximum time in seconds to wait 392 @type timeout: int 393 """ 394 try: 395 WebDriverWait(self._driver, timeout).\ 396 until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text)) 397 except TimeoutException: 398 if error_msg is None: 399 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % \ 400 {"text": text, "element": locator_string} 401 self.save_screenshot("[ERROR] %s" % error_msg) 402 pytest.fail(error_msg)
403
404 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, 405 error_msg=None, timeout=10):
406 """ 407 Wait for an element's value to contain some test 408 @param locator_strategy: Location strategy to use 409 @type locator_strategy: By 410 @param locator_string: String used to locate element 411 @type locator_string: str 412 @param error_msg: Error string to show if element is not found 413 @type error_msg: str 414 @param timeout: Maximum time in seconds to wait 415 @type timeout: int 416 """ 417 try: 418 WebDriverWait(self._driver, timeout).\ 419 until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text)) 420 except TimeoutException: 421 if error_msg is None: 422 error_msg = "Timeout while waiting for text %(text)s to be present " \ 423 "in the value of element '%(element)s'" % {"text": text, "element": locator_string} 424 self.save_screenshot("[ERROR] %s" % error_msg) 425 pytest.fail(error_msg)
426 427 442
443 - def get_webelement_by_xpath(self, locator_string):
444 """ 445 Get the webelement by xpath 446 @param locator_string: String used to locate element 447 @type locator_string: str 448 @param error_msg: Error string to show if element is not found 449 @type error_msg: str 450 """ 451 try: 452 self.wait_for_element_to_be_visible(By.XPATH, locator_string) 453 return self.browser.find_element_by_xpath(locator_string) 454 except NoSuchElementException: 455 error_msg="Could not find the xpath: '%s'" 456 self.save_screenshot(error_msg % locator_string) 457 pytest.fail(error_msg % locator_string)
458 #
459 - def get_webelement_by_css(self, locator_string):
460 """ 461 Get the webelement by CSS 462 @param locator_string: String used to locate element 463 @type locator_string: str 464 @param error_msg: Error string to show if element is not found 465 @type error_msg: str 466 """ 467 try: 468 self.wait_for_element_to_be_visible(By.CSS_SELECTOR, locator_string) 469 return self.browser.find_element_by_css_selector(locator_string) 470 except NoSuchElementException: 471 error_msg="Could not find css: '%s'" 472 self.save_screenshot(error_msg % locator_string) 473 pytest.fail(error_msg %locator_string)
474 #
475 - def get_webelements_by_xpath(self, locator_string):
476 """ 477 Get the webelement list by xpath 478 @param locator_string: String used to locate element 479 @type locator_string: str 480 @param error_msg: Error string to show if element is not found 481 @type error_msg: str 482 """ 483 try: 484 return self.browser.find_elements_by_xpath(locator_string) 485 except NoSuchElementException: 486 error_msg="Could not find the link: '%s'" 487 self.save_screenshot(error_msg % locator_string) 488 pytest.fail(error_msg+ " '%s'" % locator_string)
489 #
490 - def get_webelements_by_css(self, locator_string):
491 """ 492 Get the webelement list by CSS 493 @param locator_string: String used to locate element 494 @type locator_string: str 495 @param error_msg: Error string to show if element is not found 496 @type error_msg: str 497 """ 498 try: 499 return self.browser.find_elements_by_css_selector(locator_string) 500 except NoSuchElementException: 501 error_msg="Could not find css: '%s'" 502 self.save_screenshot(error_msg % locator_string) 503 pytest.fail(error_msg % locator_string)
504