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
187 - def save_screenshot(self, description):
188 """ 189 Saves screen shot for the current page 190 """ 191 #Waits until page is loaded 192 self.tlib_logger.debug("Saving screenshot") 193 self.wait_for_page_loaded() 194 195 #Folder containing images for test case 196 name = self.get_unused_report_name(self._test_case_id, self._test_params) 197 name = FileHelper.get_filename_from_string(name) 198 199 test_folder = os.path.join(self.screenshot_folder(), self._folder_dest, name) 200 201 try: 202 os.makedirs(test_folder) 203 except WindowsError: 204 pass 205 206 #Get number of existing images 207 i = len(os.listdir(test_folder)) + 1 208 209 #Get filename 210 img_filename = "%02d.png" % i 211 full_path = os.path.join(test_folder, img_filename) 212 213 self._screenshots[i] = {"filename": "%s/%s" % (name, img_filename), 214 u"description": description} 215 216 self._driver.get_screenshot_as_file(full_path)
217 218
219 - def wait_for_page_loaded(self, timeout=10):
220 raise NotImplementedError("This method should be implemented by derived classes")
221 222
223 - def wait_for_alert(self, timeout=10):
224 """ 225 Waist until an alert is visible 226 @type timeout: Integer 227 @param timeout: Number of seconds before timing out 228 @rtype: bool 229 """ 230 def is_alert_visible(): 231 try: 232 #Try to get alert text to trigger exception if alert is not visible 233 alert = self._driver.switch_to_alert().text 234 return True 235 except NoAlertPresentException as e: 236 return False
237 238 condition = lambda *args: is_alert_visible() 239 try: 240 WebDriverWait(self._driver, timeout).until(condition) 241 return self._driver.switch_to_alert() 242 except TimeoutException: 243 self.test_logger.error('Timeout while waiting for alert to appear') 244 pytest.fail('Timeout while waiting for alert to appear') 245 246
247 - def wait_for_element_to_be_visible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
248 """ 249 Wait until an element becomes visible 250 @param locator_strategy: Location strategy to use 251 @type locator_strategy: By 252 @param locator_string: String used to locate element 253 @type locator_string: str 254 @param error_msg: Error string to show if element is not found 255 @type error_msg: str 256 @param timeout: Maximum time in seconds to wait for the element to be visible 257 @type timeout: int 258 @rtype: WebElement 259 """ 260 try: 261 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 262 return element 263 except TimeoutException: 264 if error_msg is None: 265 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 266 self.save_screenshot("[ERROR] %s" % error_msg) 267 pytest.fail(error_msg)
268 269
270 - def wait_for_element_to_be_clickable(self, locator_strategy, locator_string, error_msg=None, timeout=10):
271 """ 272 Wait until an element cna be clicked 273 @param locator_strategy: Location strategy to use 274 @type locator_strategy: By 275 @param locator_string: String used to locate element 276 @type locator_string: str 277 @param error_msg: Error string to show if element is not found 278 @type error_msg: str 279 @param timeout: Maximum time in seconds to wait for the element to be clickable 280 @type timeout: int 281 @rtype: WebElement 282 """ 283 try: 284 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string))) 285 return element 286 except TimeoutException: 287 if error_msg is None: 288 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string 289 self.save_screenshot("[ERROR] %s" % error_msg) 290 pytest.fail(error_msg)
291 292
293 - def wait_for_element_to_be_present(self, locator_strategy, locator_string, error_msg=None, timeout=10):
294 """ 295 Wait until an element is present 296 @param locator_strategy: Location strategy to use 297 @type locator_strategy: By 298 @param locator_string: String used to locate element 299 @type locator_string: str 300 @param error_msg: Error string to show if element is not found 301 @type error_msg: str 302 @param timeout: Maximum time in seconds to wait for the element to be present 303 @type timeout: int 304 @rtype: WebElement 305 """ 306 try: 307 element = WebDriverWait(self._driver, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string))) 308 return element 309 except TimeoutException: 310 if error_msg is None: 311 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string 312 self.save_screenshot("[ERROR] %s" % error_msg) 313 pytest.fail(error_msg)
314 315
316 - def wait_for_element_to_be_selected(self, locator_strategy, locator_string, error_msg=None, timeout=10):
317 """ 318 Wait until an element is selected 319 @param locator_strategy: Location strategy to use 320 @type locator_strategy: By 321 @param locator_string: String used to locate element 322 @type locator_string: str 323 @param error_msg: Error string to show if element is not found 324 @type error_msg: str 325 @param timeout: Maximum time in seconds to wait for the element to be selected 326 @type timeout: int 327 @rtype: WebElement 328 """ 329 try: 330 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string))) 331 return element 332 except TimeoutException: 333 if error_msg is None: 334 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string 335 self.save_screenshot("[ERROR] %s" % error_msg) 336 pytest.fail(error_msg)
337 338
339 - def wait_for_element_to_be_invisible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
340 """ 341 Wait until an element becomes invisible 342 @param locator_strategy: Location strategy to use 343 @type locator_strategy: By 344 @param locator_string: String used to locate element 345 @type locator_string: str 346 @param error_msg: Error string to show if element is not found 347 @type error_msg: str 348 @param timeout: Maximum time in seconds to wait for the element to be hidden 349 @type timeout: int 350 @rtype: WebElement 351 """ 352 try: 353 element = WebDriverWait(self._driver, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string))) 354 return element 355 except TimeoutException: 356 if error_msg is None: 357 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string 358 self.save_screenshot("[ERROR] %s" % error_msg) 359 pytest.fail(error_msg)
360 361
362 - def wait_for_element_to_be_static(self, locator_strategy, locator_string, error_msg=None, timeout=10):
363 """ 364 Wait until an element that moves on the screen stops moving 365 @param locator_strategy: Location strategy to use 366 @type locator_strategy: By 367 @param locator_string: String used to locate element 368 @type locator_string: str 369 @param error_msg: Error string to show if element is not found 370 @type error_msg: str 371 @param timeout: Maximum time in seconds to wait for the element to be visible 372 @type timeout: int 373 @rtype: WebElement 374 """ 375 try: 376 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 377 378 #wait until element is not moving or click will fail 379 old_location = {'x':0, 'y':0} 380 while old_location != element.location: 381 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % (old_location, element.location)) 382 old_location = element.location 383 sleep(0.1) 384 element = self._driver.find_element(locator_strategy, locator_string) 385 386 return element 387 except TimeoutException: 388 if error_msg is None: 389 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 390 self.save_screenshot("[ERROR] %s" % error_msg) 391 pytest.fail(error_msg)
392 393
394 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
395 """ 396 Wait for an element that contains specified text 397 @param locator_strategy: Location strategy to use 398 @type locator_strategy: By 399 @param locator_string: String used to locate element 400 @type locator_string: str 401 @param error_msg: Error string to show if element is not found 402 @type error_msg: str 403 @param timeout: Maximum time in seconds to wait 404 @type timeout: int 405 """ 406 try: 407 WebDriverWait(self._driver, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text)) 408 except TimeoutException: 409 if error_msg is None: 410 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string} 411 self.save_screenshot("[ERROR] %s" % error_msg) 412 pytest.fail(error_msg)
413 414
415 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
416 """ 417 Wait for an element's value to contain some test 418 @param locator_strategy: Location strategy to use 419 @type locator_strategy: By 420 @param locator_string: String used to locate element 421 @type locator_string: str 422 @param error_msg: Error string to show if element is not found 423 @type error_msg: str 424 @param timeout: Maximum time in seconds to wait 425 @type timeout: int 426 """ 427 try: 428 WebDriverWait(self._driver, timeout).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 in the value of element '%(element)s'" % {"text": text, "element":locator_string} 432 self.save_screenshot("[ERROR] %s" % error_msg) 433 pytest.fail(error_msg)
434