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

Source Code for Module tlib.base.WebDriverTester

  1  import os 
  2  import re 
  3  import inspect 
  4  # noinspection PyPackageRequirements 
  5  import pytest 
  6  import collections 
  7  from time import sleep 
  8  # noinspection PyPackageRequirements 
  9  from _pytest.python import FixtureRequest 
 10  # noinspection PyPackageRequirements 
 11  import jinja2 
 12  from tlib.base import TestHelper 
 13  from tlib.base import FileHelper 
 14  from tlib.base.PytestTester import PytestTester 
 15  from selenium.webdriver.common.by import By 
 16  from selenium.webdriver.support.ui import WebDriverWait 
 17  from selenium.webdriver.support import expected_conditions 
 18  from selenium.common.exceptions import TimeoutException, NoAlertPresentException 
 19  from selenium.webdriver.remote.webelement import WebElement 
20 21 22 # noinspection PyMethodParameters 23 # noinspection PyUnresolvedReferences 24 -class WebDriverTester(PytestTester):
25 26 _driver = None 27 28 _folder_dest = None # destination of report for the current class 29 _test_case_id = None 30 _test_case_name = None 31 _test_params = None 32 33 _jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(TestHelper.tlib_template_folder()), 34 trim_blocks=True) 35 36 _screenshot_report = None # List of tests for which there are screenshots 37 38 # Template for generating screenshot report 39 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html") 40 41 _screenshots = {} # Screenshots generated during a test case 42 43 # Template for generating screenshots for a test case 44 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html") 45 46 _request = None 47
48 - def screenshot_folder(self):
49 """ 50 Returns location of screenshot folder 51 52 @return: str 53 """ 54 screenshot_folder = self._find_screenshot_folder() 55 if screenshot_folder is None: 56 #Couldn't find screenshot folder 57 raise NotImplementedError("Could not find screenshot folder. " 58 "Class should implement method screenshot_folder") 59 else: 60 return screenshot_folder
61
62 - def _find_screenshot_folder(self):
63 """ 64 Will try to find a folder named "screenshot" starting from the file being executed and up to 65 three levels up 66 67 @return: str 68 """ 69 #Get current folder 70 curr_folder = os.path.dirname(self._request.fspath.strpath) 71 72 #Go up to three levels to find screenshot folder 73 for i in range(1, 4): 74 curr_folder = os.path.abspath(os.path.join(curr_folder, os.pardir)) 75 76 #Check if there is a folder 'screenshots' 77 screenshot_folder = os.path.join(curr_folder, 'screenshots') 78 if os.path.exists(screenshot_folder): 79 return screenshot_folder
80 81
82 - def _get_unused_report_name(self, tc_id, tc_params):
83 """ 84 Gets a string based on test case id and name, taking into account if test case has already been run or not 85 @param tc_id: Test case id 86 @type tc_id: str 87 @type tc_name: str 88 """ 89 i = 0 90 while True: 91 if i == 0: 92 filename = "%(tc_id)s_%(tc_params)s" % {"tc_id": tc_id, "tc_params": tc_params} 93 else: 94 filename = "%(tc_id)s_%(tc_params)s [retry %(cnt)d]" % {"tc_id": tc_id, "tc_params": tc_params, "cnt": i} 95 96 if not filename in self._screenshot_report: 97 return filename 98 99 i += 1
100 101 102 @pytest.fixture(scope='class', autouse=True)
103 - def initialize_webdriver_class(self, request):
104 """ 105 @type request: FixtureRequest 106 """ 107 108 #Generates initial HTML page with all test case results for the class 109 self._screenshot_report = collections.OrderedDict() 110 self._folder_dest = os.path.basename(os.path.dirname(os.path.abspath(inspect.getfile(request.cls)))) 111 112 def generate_report(): 113 if len(self._screenshot_report) > 0: 114 #Generate HTML based on template 115 html = self._screenshot_report_template.render(test_class=request.cls.__name__, 116 files=self._screenshot_report) 117 118 htm_file = "%s.htm" % self._folder_dest 119 full_filename = os.path.join(self.screenshot_folder(), htm_file) 120 121 f = open(full_filename, "w") 122 try: 123 f.write(html) 124 finally: 125 f.close()
126 127 request.addfinalizer(generate_report)
128 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
186 - def save_screenshot(self, description):
187 """ 188 Saves screen shot for the current page 189 """ 190 #Waits until page is loaded 191 self.tlib_logger.debug("Saving screenshot") 192 self.wait_for_page_loaded() 193 194 #Folder containing images for test case 195 name = self._get_unused_report_name(self._test_case_id, self._test_params) 196 name = FileHelper.get_filename_from_string(name) 197 198 test_folder = os.path.join(self.screenshot_folder(), self._folder_dest, name) 199 200 try: 201 os.makedirs(test_folder) 202 except WindowsError: 203 pass 204 205 #Get number of existing images 206 i = len(os.listdir(test_folder)) + 1 207 208 #Get filename 209 img_filename = "%02d.png" % i 210 full_path = os.path.join(test_folder, img_filename) 211 212 self._screenshots[i] = {"filename": "%s/%s" % (name, img_filename), 213 u"description": description} 214 215 self._driver.get_screenshot_as_file(full_path)
216 217
218 - def wait_for_page_loaded(self, timeout=10):
219 raise NotImplementedError("This method should be implemented by derived classes")
220 221
222 - def wait_for_alert(self, timeout=10):
223 """ 224 Waist until an alert is visible 225 @type timeout: Integer 226 @param timeout: Number of seconds before timing out 227 @rtype: bool 228 """ 229 def is_alert_visible(): 230 try: 231 #Try to get alert text to trigger exception if alert is not visible 232 alert = self._driver.switch_to_alert().text 233 return True 234 except NoAlertPresentException as e: 235 return False
236 237 condition = lambda *args: is_alert_visible() 238 try: 239 WebDriverWait(self._driver, timeout).until(condition) 240 return self._driver.switch_to_alert() 241 except TimeoutException: 242 self.test_logger.error('Timeout while waiting for alert to appear') 243 pytest.fail('Timeout while waiting for alert to appear') 244 245
246 - def wait_for_element_to_be_visible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
247 """ 248 Wait until an element becomes visible 249 @param locator_strategy: Location strategy to use 250 @type locator_strategy: By 251 @param locator_string: String used to locate element 252 @type locator_string: str 253 @param error_msg: Error string to show if element is not found 254 @type error_msg: str 255 @param timeout: Maximum time in seconds to wait for the element to be visible 256 @type timeout: int 257 @rtype: WebElement 258 """ 259 try: 260 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 261 return element 262 except TimeoutException: 263 if error_msg is None: 264 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 265 self.save_screenshot("[ERROR] %s" % error_msg) 266 pytest.fail(error_msg)
267 268
269 - def wait_for_element_to_be_clickable(self, locator_strategy, locator_string, error_msg=None, timeout=10):
270 """ 271 Wait until an element cna be clicked 272 @param locator_strategy: Location strategy to use 273 @type locator_strategy: By 274 @param locator_string: String used to locate element 275 @type locator_string: str 276 @param error_msg: Error string to show if element is not found 277 @type error_msg: str 278 @param timeout: Maximum time in seconds to wait for the element to be clickable 279 @type timeout: int 280 @rtype: WebElement 281 """ 282 try: 283 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string))) 284 return element 285 except TimeoutException: 286 if error_msg is None: 287 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string 288 self.save_screenshot("[ERROR] %s" % error_msg) 289 pytest.fail(error_msg)
290 291
292 - def wait_for_element_to_be_present(self, locator_strategy, locator_string, error_msg=None, timeout=10):
293 """ 294 Wait until an element is present 295 @param locator_strategy: Location strategy to use 296 @type locator_strategy: By 297 @param locator_string: String used to locate element 298 @type locator_string: str 299 @param error_msg: Error string to show if element is not found 300 @type error_msg: str 301 @param timeout: Maximum time in seconds to wait for the element to be present 302 @type timeout: int 303 @rtype: WebElement 304 """ 305 try: 306 element = WebDriverWait(self._driver, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string))) 307 return element 308 except TimeoutException: 309 if error_msg is None: 310 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string 311 self.save_screenshot("[ERROR] %s" % error_msg) 312 pytest.fail(error_msg)
313 314
315 - def wait_for_element_to_be_selected(self, locator_strategy, locator_string, error_msg=None, timeout=10):
316 """ 317 Wait until an element is selected 318 @param locator_strategy: Location strategy to use 319 @type locator_strategy: By 320 @param locator_string: String used to locate element 321 @type locator_string: str 322 @param error_msg: Error string to show if element is not found 323 @type error_msg: str 324 @param timeout: Maximum time in seconds to wait for the element to be selected 325 @type timeout: int 326 @rtype: WebElement 327 """ 328 try: 329 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string))) 330 return element 331 except TimeoutException: 332 if error_msg is None: 333 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string 334 self.save_screenshot("[ERROR] %s" % error_msg) 335 pytest.fail(error_msg)
336 337
338 - def wait_for_element_to_be_invisible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
339 """ 340 Wait until an element becomes invisible 341 @param locator_strategy: Location strategy to use 342 @type locator_strategy: By 343 @param locator_string: String used to locate element 344 @type locator_string: str 345 @param error_msg: Error string to show if element is not found 346 @type error_msg: str 347 @param timeout: Maximum time in seconds to wait for the element to be hidden 348 @type timeout: int 349 @rtype: WebElement 350 """ 351 try: 352 element = WebDriverWait(self._driver, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string))) 353 return element 354 except TimeoutException: 355 if error_msg is None: 356 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string 357 self.save_screenshot("[ERROR] %s" % error_msg) 358 pytest.fail(error_msg)
359 360
361 - def wait_for_element_to_be_static(self, locator_strategy, locator_string, error_msg=None, timeout=10):
362 """ 363 Wait until an element that moves on the screen stops moving 364 @param locator_strategy: Location strategy to use 365 @type locator_strategy: By 366 @param locator_string: String used to locate element 367 @type locator_string: str 368 @param error_msg: Error string to show if element is not found 369 @type error_msg: str 370 @param timeout: Maximum time in seconds to wait for the element to be visible 371 @type timeout: int 372 @rtype: WebElement 373 """ 374 try: 375 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 376 377 #wait until element is not moving or click will fail 378 old_location = {'x':0, 'y':0} 379 while old_location != element.location: 380 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % (old_location, element.location)) 381 old_location = element.location 382 sleep(0.1) 383 element = self._driver.find_element(locator_strategy, locator_string) 384 385 return element 386 except TimeoutException: 387 if error_msg is None: 388 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 389 self.save_screenshot("[ERROR] %s" % error_msg) 390 pytest.fail(error_msg)
391 392
393 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
394 """ 395 Wait for an element that contains specified text 396 @param locator_strategy: Location strategy to use 397 @type locator_strategy: By 398 @param locator_string: String used to locate element 399 @type locator_string: str 400 @param error_msg: Error string to show if element is not found 401 @type error_msg: str 402 @param timeout: Maximum time in seconds to wait 403 @type timeout: int 404 """ 405 try: 406 WebDriverWait(self._driver, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text)) 407 except TimeoutException: 408 if error_msg is None: 409 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string} 410 self.save_screenshot("[ERROR] %s" % error_msg) 411 pytest.fail(error_msg)
412 413
414 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, 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).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text)) 428 except TimeoutException: 429 if error_msg is None: 430 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string} 431 self.save_screenshot("[ERROR] %s" % error_msg) 432 pytest.fail(error_msg)
433