1 import os
2 import re
3 import inspect
4
5 import pytest
6 import collections
7 from time import sleep
8
9 from selenium import webdriver
10 from _pytest.python import FixtureRequest
11
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.common.by import By
17 from selenium.webdriver.support.ui import WebDriverWait
18 from selenium.webdriver.support import expected_conditions
19 from selenium.common.exceptions import TimeoutException, NoAlertPresentException
20 from selenium.webdriver.remote.webelement import WebElement
21 import logging
27
28 _homepage = None
29 _test_logger = None
30 _tlib_logger = None
31 _browser = None
32
33 _folder_dest = None
34 _test_case_id = None
35 _test_case_name = None
36 _test_params = None
37
38 _jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(TestHelper.tlib_template_folder()), trim_blocks = True)
39
40 _screenshot_report = None
41 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html")
42
43 _screenshots = {}
44 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html")
45
46
48 """
49 Returns Instance of the WebDriver browser
50 @rtype: webdriver.Remote
51 """
52 return self.__class__._browser
53
54
56 """
57 Instance of the WebDriver browser
58 @type browser: webdriver.Remote
59 """
60 self.__class__._browser = browser
61
62 browser = property(_get_browser, _set_browser)
63
64 - def _get_homepage(self):
65 """
66 Instance of the WebDriver homepage
67 """
68 return self.__class__._homepage
69
70
71 - def _set_homepage(self, homepage):
72 """
73 Instance of the WebDriver homepage
74 @type homepage: webdriver.Remote
75 """
76 self.__class__._homepage = homepage
77
78 homepage = property(_get_homepage, _set_homepage)
79
80
81 @property
83 """
84 Logger object to log test information
85 """
86 return self.__class__._test_logger
87
88
89 @staticmethod
91 """
92 Returns project's screenshot folder
93 This method must be defined in subclasses
94 """
95 raise NotImplementedError("Subclasses should implement this!")
96
97
98 @pytest.fixture(scope='class', autouse=True)
111
112
114 """
115 Gets a string based on test case id and name, taking into account if test case has already been run or not
116 @param tc_id: Test case id
117 @type tc_id: str
118 @param tc_name: Test case name
119 @type tc_name: str
120 """
121 i = 0
122 while True:
123 if i == 0:
124
125 filename = "%(tc_id)s" % { "tc_id": tc_id}
126 else:
127
128 filename = "%(tc_id)s [retry %(cnt)d]" % { "tc_id": tc_id, "cnt": i}
129
130 if not filename in self.__class__._screenshot_report:
131 return filename
132
133 i += 1
134
135
136 @pytest.fixture(scope='class', autouse=True)
138 """
139 Generates HTML page with all test case results for the class
140 @type request: FixtureRequest
141 """
142 self.__class__._screenshot_report = collections.OrderedDict()
143 self.__class__._folder_dest = re.sub('\.py$', '', os.path.relpath(inspect.getfile(request.cls)))
144
145 def generate_report():
146 if len(self.__class__._screenshot_report) > 0:
147
148 html = self.__class__._screenshot_report_template.render(test_class=self.__class__.__name__,
149 files=self.__class__._screenshot_report)
150
151 htm_file = "%s.htm" % self.__class__._folder_dest
152 full_filename = os.path.join(self.screenshot_folder(), htm_file)
153
154 f = open(full_filename, "w")
155 try:
156 f.write(html)
157 finally:
158 f.close()
159
160 request.addfinalizer(generate_report)
161
162
163 @pytest.fixture(scope='function', autouse=True)
208
209
210 request.addfinalizer(generate_report)
211
212
213 - def navigate(self, page, save_screenshot=True):
221
222
223 - def go_home(self, save_screenshot=True):
230
231
233 """
234 Saves screen shot for the current page
235 """
236
237 def get_params():
238 if self.__class__._test_params is None:
239 return ""
240 else:
241 return self.__class__._test_params
242
243
244 self._tlib_logger.debug("Saving screenshot")
245 self.wait_for_page_loaded()
246
247
248 name = self.get_unused_report_name(self.__class__._test_case_id, self.__class__._test_case_name)
249 name = FileHelper.get_filename_from_string(name)
250
251 test_folder = os.path.join(self.screenshot_folder(), self.__class__._folder_dest, name)
252
253 try:
254 os.makedirs(test_folder)
255 except WindowsError:
256 pass
257
258
259 i = len(os.listdir(test_folder)) + 1
260
261
262 img_filename = "%02d.png" % i
263 full_path = os.path.join(test_folder, img_filename)
264
265 self.__class__._screenshots[i] = {"filename": "%s/%s" % (name, img_filename),
266 u"description": description}
267
268 self.browser.get_screenshot_as_file(full_path)
269
270
271 - def wait_for_page_loaded(self, timeout=10):
272 """
273 Waist until document.readyState is equal to complete
274 @type timeout: Integer
275 @param timeout: Number of seconds before timing out
276 """
277 if self.browser.execute_script("return document.readyState") == "complete":
278 return
279 else:
280 self._tlib_logger.debug("Waiting for '%s' to load" % self.browser.current_url)
281
282 condition = lambda *args: self.browser.execute_script("return document.readyState") == "complete"
283 try:
284 WebDriverWait(self.browser, timeout).until(condition)
285 except TimeoutException:
286 self.test_logger.error('Timeout while waiting for page to load')
287 pytest.fail('Timeout while waiting for page to load')
288
289 self._tlib_logger.debug("Page '%s' finished loading" % self.browser.current_url)
290
292 """
293 Waist until an alert is visible
294 @type timeout: Integer
295 @param timeout: Number of seconds before timing out
296 @rtype: bool
297 """
298 def is_alert_visible():
299 try:
300
301 alert = self.browser.switch_to_alert().text
302 return True
303 except NoAlertPresentException as e:
304 return False
305
306 condition = lambda *args: is_alert_visible()
307 try:
308 WebDriverWait(self.browser, timeout).until(condition)
309 return self.browser.switch_to_alert()
310 except TimeoutException:
311 self.test_logger.error('Timeout while waiting for alert to appear')
312 pytest.fail('Timeout while waiting for alert to appear')
313
314 @pytest.fixture(scope='function', autouse=True)
315 - def setup_test(self, request, test_logger, browser):
316 """
317 Goes to homepage before each test, unless marker skipsetup is given
318 """
319
320 if not request.node.function.__dict__.has_key('skipsetup'):
321
322 self.go_home(save_screenshot=False)
323 browser.delete_all_cookies()
324 self.go_home()
325 else:
326 test_logger.info("Skipping setup")
327
328
330 """
331 Wait until an element becomes visible
332 @param locator_strategy: Location strategy to use
333 @type locator_strategy: By
334 @param locator_string: String used to locate element
335 @type locator_string: str
336 @param error_msg: Error string to show if element is not found
337 @type error_msg: str
338 @param timeout: Maximum time in seconds to wait for the element to be visible
339 @type timeout: int
340 @rtype: WebElement
341 """
342 try:
343 element = WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
344 return element
345 except TimeoutException:
346 if error_msg is None:
347 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
348 self.save_screenshot("[ERROR] %s" % error_msg)
349 pytest.fail(error_msg)
350
351
353 """
354 Wait until an element cna be clicked
355 @param locator_strategy: Location strategy to use
356 @type locator_strategy: By
357 @param locator_string: String used to locate element
358 @type locator_string: str
359 @param error_msg: Error string to show if element is not found
360 @type error_msg: str
361 @param timeout: Maximum time in seconds to wait for the element to be clickable
362 @type timeout: int
363 @rtype: WebElement
364 """
365 try:
366 element = WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
367 return element
368 except TimeoutException:
369 if error_msg is None:
370 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
371 self.save_screenshot("[ERROR] %s" % error_msg)
372 pytest.fail(error_msg)
373
374
376 """
377 Wait until an element is present
378 @param locator_strategy: Location strategy to use
379 @type locator_strategy: By
380 @param locator_string: String used to locate element
381 @type locator_string: str
382 @param error_msg: Error string to show if element is not found
383 @type error_msg: str
384 @param timeout: Maximum time in seconds to wait for the element to be present
385 @type timeout: int
386 @rtype: WebElement
387 """
388 try:
389 element = WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
390 return element
391 except TimeoutException:
392 if error_msg is None:
393 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
394 self.save_screenshot("[ERROR] %s" % error_msg)
395 pytest.fail(error_msg)
396
397
399 """
400 Wait until an element is selected
401 @param locator_strategy: Location strategy to use
402 @type locator_strategy: By
403 @param locator_string: String used to locate element
404 @type locator_string: str
405 @param error_msg: Error string to show if element is not found
406 @type error_msg: str
407 @param timeout: Maximum time in seconds to wait for the element to be selected
408 @type timeout: int
409 @rtype: WebElement
410 """
411 try:
412 element = WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
413 return element
414 except TimeoutException:
415 if error_msg is None:
416 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
417 self.save_screenshot("[ERROR] %s" % error_msg)
418 pytest.fail(error_msg)
419
420
422 """
423 Wait until an element becomes invisible
424 @param locator_strategy: Location strategy to use
425 @type locator_strategy: By
426 @param locator_string: String used to locate element
427 @type locator_string: str
428 @param error_msg: Error string to show if element is not found
429 @type error_msg: str
430 @param timeout: Maximum time in seconds to wait for the element to be hidden
431 @type timeout: int
432 @rtype: WebElement
433 """
434 try:
435 element = WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
436 return element
437 except TimeoutException:
438 if error_msg is None:
439 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
440 self.save_screenshot("[ERROR] %s" % error_msg)
441 pytest.fail(error_msg)
442
443
445 """
446 Wait until an element that moves on the screen stops moving
447 @param locator_strategy: Location strategy to use
448 @type locator_strategy: By
449 @param locator_string: String used to locate element
450 @type locator_string: str
451 @param error_msg: Error string to show if element is not found
452 @type error_msg: str
453 @param timeout: Maximum time in seconds to wait for the element to be visible
454 @type timeout: int
455 @rtype: WebElement
456 """
457 try:
458 element = WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
459
460
461 old_location = {'x':0, 'y':0}
462 while old_location != element.location:
463 self._tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % (old_location, element.location))
464 old_location = element.location
465 sleep(0.1)
466 element = self.browser.find_element(locator_strategy, locator_string)
467
468 return element
469 except TimeoutException:
470 if error_msg is None:
471 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
472 self.save_screenshot("[ERROR] %s" % error_msg)
473 pytest.fail(error_msg)
474
475
476 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
477 """
478 Wait for an element that contains specified text
479 @param locator_strategy: Location strategy to use
480 @type locator_strategy: By
481 @param locator_string: String used to locate element
482 @type locator_string: str
483 @param error_msg: Error string to show if element is not found
484 @type error_msg: str
485 @param timeout: Maximum time in seconds to wait
486 @type timeout: int
487 """
488 try:
489 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
490 except TimeoutException:
491 if error_msg is None:
492 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
493 self.save_screenshot("[ERROR] %s" % error_msg)
494 pytest.fail(error_msg)
495
496
497 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
498 """
499 Wait for an element's value to contain some test
500 @param locator_strategy: Location strategy to use
501 @type locator_strategy: By
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 @param timeout: Maximum time in seconds to wait
507 @type timeout: int
508 """
509 try:
510 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
511 except TimeoutException:
512 if error_msg is None:
513 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
514 self.save_screenshot("[ERROR] %s" % error_msg)
515 pytest.fail(error_msg)
516