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

Source Code for Module tlib.base.SeleniumTester

  1  import os 
  2  import re 
  3  import inspect 
  4  # noinspection PyPackageRequirements 
  5  import pytest 
  6  import collections 
  7  # noinspection PyPackageRequirements 
  8  from selenium import webdriver 
  9  from _pytest.python import FixtureRequest 
 10  from _pytest.mark import MarkInfo 
 11  # noinspection PyPackageRequirements 
 12  import jinja2 
 13  from tlib.base import TestHelper 
 14  from tlib.base import FileHelper 
 15  from tlib.base.PytestTester import PytestTester 
 16  from selenium.webdriver.support.ui import WebDriverWait 
 17  from selenium.webdriver.support import expected_conditions 
 18  from selenium.common.exceptions import TimeoutException 
 19  import logging 
20 21 22 # noinspection PyMethodParameters 23 # noinspection PyUnresolvedReferences 24 -class SeleniumTester(PytestTester):
25 26 _homepage = "" 27 _test_logger = None # Reference to test logger 28 _tlib_logger = None # Reference to tlib logger 29 _browser = 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()), trim_blocks = True) 37 38 _screenshot_report = None # List of tests for which there are screenshots 39 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html") # Template for generating screenshot report 40 41 _screenshots = {} # Screenshots generated during a test case 42 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html") # Template for generating screenshots for a test case 43 44
45 - def _get_browser(self):
46 """ 47 Returns Instance of the WebDriver browser 48 """ 49 return self.__class__._browser
50 51
52 - def _set_browser(self, browser):
53 """ 54 Instance of the WebDriver browser 55 @type: webdriver.Remote 56 """ 57 self.__class__._browser = browser
58 59 browser = property(_get_browser, _set_browser) 60
61 - def _get_homepage(self):
62 """ 63 Instance of the WebDriver homepage 64 @type: webdriver.Remote 65 """ 66 return self.__class__._homepage
67 68
69 - def _set_homepage(self, homepage):
70 """ 71 Instance of the WebDriver homepage 72 @type: webdriver.Remote 73 """ 74 self.__class__._homepage = homepage
75 76 homepage = property(_get_homepage, _set_homepage) 77 78 79 @property
80 - def test_logger(self):
81 """ 82 Logger object to log test information 83 @type: logging 84 """ 85 return self.__class__._test_logger
86 87 88 @staticmethod
89 - def screenshot_folder():
90 """ 91 Returns project's screenshot folder 92 This method must be defined in subclasses 93 """ 94 raise NotImplementedError("Subclasses should implement this!")
95 96 97 @pytest.fixture(scope='class', autouse=True)
98 - def initialize_class(self, test_logger, tlib_logger, browser, base_url):
99 """ 100 @type test_logger: logging 101 @type browser: webdriver.Remote 102 Stores an instance of browser and test_logger 103 """ 104 self.__class__._test_logger = test_logger 105 self.__class__._tlib_logger = tlib_logger 106 self.browser = browser 107 self.homepage = base_url
108 109
110 - def get_unused_report_name(self, tc_id, tc_name):
111 """ 112 Gets a string based on test case id and name, taking into account if test case has already been run or not 113 @param tc_id: Test case id 114 @type tc_id: str 115 @param tc_name: Test case name 116 @type tc_name: str 117 """ 118 i = 0 119 while True: 120 if i == 0: 121 # filename = "%(tc_id)s - %(tc_name)s" % { "tc_id": tc_id, "tc_name": tc_name} 122 filename = "%(tc_id)s" % { "tc_id": tc_id} 123 else: 124 # filename = "%(tc_id)s - %(tc_name)s[retry %(cnt)d]" % { "tc_id": tc_id, "tc_name": tc_name, "cnt": i} 125 filename = "%(tc_id)s [retry %(cnt)d]" % { "tc_id": tc_id, "cnt": i} 126 127 if not filename in self.__class__._screenshot_report: 128 return filename 129 130 i += 1
131 132 133 @pytest.fixture(scope='class', autouse=True)
134 - def generate_class_report(self, request):
135 """ 136 Generates HTML page with all test case results for the class 137 @type request: FixtureRequest 138 """ 139 self.__class__._screenshot_report = collections.OrderedDict() 140 self.__class__._folder_dest = re.sub('\.py$', '', os.path.relpath(inspect.getfile(request.cls))) 141 142 def generate_report(): 143 if len(self.__class__._screenshot_report) > 0: 144 #Generate HTML based on template 145 html = self.__class__._screenshot_report_template.render(test_class=self.__class__.__name__, 146 files=self.__class__._screenshot_report) 147 148 htm_file = "%s.htm" % self.__class__._folder_dest 149 full_filename = os.path.join(self.screenshot_folder(), htm_file) 150 151 f = open(full_filename, "w") 152 try: 153 f.write(html) 154 finally: 155 f.close()
156 157 request.addfinalizer(generate_report)
158 159 160 @pytest.fixture(scope='function', autouse=True)
161 - def generate_test_report(self, request):
162 """ 163 Generates HTML page with all the screenshots for a test case 164 Supports generating different When test cases are run multiple times with the same arguments 165 @type request: FixtureRequest 166 """ 167 # noinspection PyProtectedMember 168 self.__class__._test_params = request.keywords.node._genid 169 self.__class__._test_case_name = request.keywords.node.name 170 self.__class__._screenshots = {} 171 172 #Get marker test case name or use a default if there is none 173 marker = request.node.get_marker("testcasename") 174 if marker is None: 175 self._test_logger.warn("Test case doesn't have marker testcasename") 176 self.__class__._test_case_id = "UNKNOWN_TEST_CASE_ID" 177 else: 178 self.__class__._test_case_id = marker.args[0] 179 180 181 def generate_report(): 182 183 if len(self.__class__._screenshots) > 0: 184 name = self.get_unused_report_name(self.__class__._test_case_id, self.__class__._test_case_name) 185 186 #Generate HTML based on template 187 html = self.__class__._tc_screenshot_template.render(test_case_id=self.__class__._test_case_id, 188 test_case_name=self.__class__._test_case_name, 189 screenshots=self.__class__._screenshots) 190 191 #Filename includes a counter in case test case is being run more than once 192 htm_file = FileHelper.get_filename_from_string(name) + '.htm' 193 relative_filename = os.path.join(self.__class__._folder_dest, htm_file) 194 full_filename = os.path.join(self.screenshot_folder(), relative_filename) 195 196 self.__class__._screenshot_report[name] = {"tc_id": self.__class__._test_case_id, 197 "tc_name": self.__class__._test_case_name, 198 "filename": relative_filename} 199 200 f = open(full_filename, "w") 201 try: 202 f.write(html) 203 finally: 204 f.close()
205 206 207 request.addfinalizer(generate_report) 208 209
210 - def navigate(self, page, save_screenshot=True):
211 """ 212 Navigate to "page" 213 """ 214 self.test_logger.info("Navigating to %s" % page) 215 self.browser.get(page) 216 if save_screenshot: 217 self.save_screenshot("Navigate to %s" % page)
218 219
220 - def go_home(self, save_screenshot=True):
221 """ 222 Navigate to home page 223 """ 224 self.navigate(self.homepage, save_screenshot=False) 225 if save_screenshot: 226 self.save_screenshot("Homepage")
227 228
229 - def save_screenshot(self, description):
230 """ 231 Saves screen shot for the current page 232 """ 233 234 def get_params(): 235 if self.__class__._test_params is None: 236 return "" 237 else: 238 return self.__class__._test_params
239 240 #Waits until page is loaded 241 self._tlib_logger.debug("Saving screenshot") 242 self.wait_for_page_loaded() 243 244 #Folder containing images for test case 245 name = self.get_unused_report_name(self.__class__._test_case_id, self.__class__._test_case_name) 246 name = FileHelper.get_filename_from_string(name) 247 248 test_folder = os.path.join(self.screenshot_folder(), self.__class__._folder_dest, name) 249 250 try: 251 os.makedirs(test_folder) 252 except WindowsError: 253 pass 254 255 #Get number of existing images 256 i = len(os.listdir(test_folder)) + 1 257 258 #Get filename 259 img_filename = "%02d.jpg" % i 260 full_path = os.path.join(test_folder, img_filename) 261 262 self.__class__._screenshots[i] = {"filename": "%s/%s" % (name, img_filename), 263 "description": description} 264 265 self.browser.get_screenshot_as_file(full_path) 266 267
268 - def wait_for_page_loaded(self, timeout=10):
269 """ 270 Waist until document.readyState is equal to complete 271 @type timeout: Integer 272 @param timeout: Number of seconds before timing out 273 """ 274 if self.browser.execute_script("return document.readyState") == "complete": 275 self._tlib_logger.debug("Page '%s' already loaded" % self.browser.current_url) 276 return 277 else: 278 self._tlib_logger.debug("Waiting for '%s' to load" % self.browser.current_url) 279 280 condition = lambda *args: self.browser.execute_script("return document.readyState") == "complete" 281 try: 282 WebDriverWait(self.browser, timeout).until(condition) 283 except TimeoutException: 284 self.test_logger.error('Timeout while waiting for page to load') 285 pytest.fail('Timeout while waiting for page to load') 286 287 self._tlib_logger.debug("Page '%s' finished loading" % self.browser.current_url)
288 289 @pytest.fixture(scope='function', autouse=True)
290 - def setup_method(self, request):
291 """ 292 Goes to homepage before each test, unless marker skipsetup is given 293 """ 294 #Get all markers 295 marks = {} 296 for k,v in request.node.function.__dict__.iteritems(): 297 if isinstance(v, MarkInfo): 298 marks[k] = v 299 300 #Don't go to home is skipsetup marker was given 301 if not marks.has_key('skipsetup'): 302 #Before clearing cookies, need to go to home screen, to ensure it's the current domain 303 self.go_home(save_screenshot=False) 304 self.browser.delete_all_cookies() 305 self.go_home() 306 else: 307 self.test_logger.info("Skipping setup")
308 309
310 - def wait_for_element_to_be_visible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
311 try: 312 WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string))) 313 except TimeoutException: 314 if error_msg is None: 315 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string 316 self.save_screenshot("[ERROR] %s" % error_msg) 317 pytest.fail(error_msg)
318 319
320 - def wait_for_element_to_be_clickable(self, locator_strategy, locator_string, error_msg=None, timeout=10):
321 try: 322 WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string))) 323 except TimeoutException: 324 if error_msg is None: 325 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string 326 self.save_screenshot("[ERROR] %s" % error_msg) 327 pytest.fail(error_msg)
328 329
330 - def wait_for_element_to_be_present(self, locator_strategy, locator_string, error_msg=None, timeout=10):
331 try: 332 WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string))) 333 except TimeoutException: 334 if error_msg is None: 335 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string 336 self.save_screenshot("[ERROR] %s" % error_msg) 337 pytest.fail(error_msg)
338 339
340 - def wait_for_element_to_be_selected(self, locator_strategy, locator_string, error_msg=None, timeout=10):
341 try: 342 WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string))) 343 except TimeoutException: 344 if error_msg is None: 345 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string 346 self.save_screenshot("[ERROR] %s" % error_msg) 347 pytest.fail(error_msg)
348 349
350 - def wait_for_element_to_be_invisible(self, locator_strategy, locator_string, error_msg=None, timeout=10):
351 try: 352 WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string))) 353 except TimeoutException: 354 if error_msg is None: 355 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string 356 self.save_screenshot("[ERROR] %s" % error_msg) 357 pytest.fail(error_msg)
358 359
360 - def wait_for_test_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
361 try: 362 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text)) 363 except TimeoutException: 364 if error_msg is None: 365 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string} 366 self.save_screenshot("[ERROR] %s" % error_msg) 367 pytest.fail(error_msg)
368 369
370 - def wait_for_test_to_be_present_in_element_value(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
371 try: 372 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text)) 373 except TimeoutException: 374 if error_msg is None: 375 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string} 376 self.save_screenshot("[ERROR] %s" % error_msg) 377 pytest.fail(error_msg)
378