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
101
102
104 """
105 Will try to find a folder named "screenshot" starting from the file being executed and up to
106 three levels up
107
108 @return: str
109 """
110
111 curr_folder = os.path.dirname(self._request.fspath.strpath)
112
113
114 for i in range(1, 4):
115 curr_folder = os.path.abspath(os.path.join(curr_folder, os.pardir))
116
117
118 screenshot_folder = os.path.join(curr_folder, 'screenshots')
119 if os.path.exists(screenshot_folder):
120 return screenshot_folder
121
122 pass
123
124
125 @pytest.fixture(scope='class', autouse=True)
138
139
141 """
142 Gets a string based on test case id and name, taking into account if test case has already been run or not
143 @param tc_id: Test case id
144 @type tc_id: str
145 @param tc_name: Test case name
146 @type tc_name: str
147 """
148 i = 0
149 while True:
150 if i == 0:
151
152 filename = "%(tc_id)s" % { "tc_id": tc_id}
153 else:
154
155 filename = "%(tc_id)s [retry %(cnt)d]" % { "tc_id": tc_id, "cnt": i}
156
157 if not filename in self.__class__._screenshot_report:
158 return filename
159
160 i += 1
161
162
163 @pytest.fixture(scope='class', autouse=True)
165 """
166 Generates HTML page with all test case results for the class
167 @type request: FixtureRequest
168 """
169 self.__class__._screenshot_report = collections.OrderedDict()
170 self.__class__._folder_dest = re.sub('\.py$', '', os.path.relpath(inspect.getfile(request.cls)))
171
172 def generate_report():
173 if len(self.__class__._screenshot_report) > 0:
174
175 html = self.__class__._screenshot_report_template.render(test_class=self.__class__.__name__,
176 files=self.__class__._screenshot_report)
177
178 htm_file = "%s.htm" % self.__class__._folder_dest
179 full_filename = os.path.join(self.screenshot_folder(), htm_file)
180
181 f = open(full_filename, "w")
182 try:
183 f.write(html)
184 finally:
185 f.close()
186
187 request.addfinalizer(generate_report)
188
189
190 @pytest.fixture(scope='function', autouse=True)
235
236
237 request.addfinalizer(generate_report)
238
239
240 - def navigate(self, page, save_screenshot=True):
248
249
250 - def go_home(self, save_screenshot=True):
257
258
260 """
261 Saves screen shot for the current page
262 """
263
264 def get_params():
265 if self.__class__._test_params is None:
266 return ""
267 else:
268 return self.__class__._test_params
269
270
271 self._tlib_logger.debug("Saving screenshot")
272 self.wait_for_page_loaded()
273
274
275 name = self.get_unused_report_name(self.__class__._test_case_id, self.__class__._test_case_name)
276 name = FileHelper.get_filename_from_string(name)
277
278 test_folder = os.path.join(self.screenshot_folder(), self.__class__._folder_dest, name)
279
280 try:
281 os.makedirs(test_folder)
282 except WindowsError:
283 pass
284
285
286 i = len(os.listdir(test_folder)) + 1
287
288
289 img_filename = "%02d.png" % i
290 full_path = os.path.join(test_folder, img_filename)
291
292 self.__class__._screenshots[i] = {"filename": "%s/%s" % (name, img_filename),
293 u"description": description}
294
295 self.browser.get_screenshot_as_file(full_path)
296
297
298 - def wait_for_page_loaded(self, timeout=10):
299 """
300 Waist until document.readyState is equal to complete
301 @type timeout: Integer
302 @param timeout: Number of seconds before timing out
303 """
304 if self.browser.execute_script("return document.readyState") == "complete":
305 return
306 else:
307 self._tlib_logger.debug("Waiting for '%s' to load" % self.browser.current_url)
308
309 condition = lambda *args: self.browser.execute_script("return document.readyState") == "complete"
310 try:
311 WebDriverWait(self.browser, timeout).until(condition)
312 except TimeoutException:
313 self.test_logger.error('Timeout while waiting for page to load')
314 pytest.fail('Timeout while waiting for page to load')
315
316 self._tlib_logger.debug("Page '%s' finished loading" % self.browser.current_url)
317
319 """
320 Waist until an alert is visible
321 @type timeout: Integer
322 @param timeout: Number of seconds before timing out
323 @rtype: bool
324 """
325 def is_alert_visible():
326 try:
327
328 alert = self.browser.switch_to_alert().text
329 return True
330 except NoAlertPresentException as e:
331 return False
332
333 condition = lambda *args: is_alert_visible()
334 try:
335 WebDriverWait(self.browser, timeout).until(condition)
336 return self.browser.switch_to_alert()
337 except TimeoutException:
338 self.test_logger.error('Timeout while waiting for alert to appear')
339 pytest.fail('Timeout while waiting for alert to appear')
340
341 @pytest.fixture(scope='function', autouse=True)
342 - def setup_test(self, request, test_logger, browser):
343 """
344 Goes to homepage before each test, unless marker skipsetup is given
345 """
346
347 self._request = request
348
349
350 if not request.node.function.__dict__.has_key('skipsetup'):
351
352 self.go_home(save_screenshot=False)
353 browser.delete_all_cookies()
354 self.go_home()
355 else:
356 test_logger.info("Skipping setup")
357
358
360 """
361 Wait until an element becomes visible
362 @param locator_strategy: Location strategy to use
363 @type locator_strategy: By
364 @param locator_string: String used to locate element
365 @type locator_string: str
366 @param error_msg: Error string to show if element is not found
367 @type error_msg: str
368 @param timeout: Maximum time in seconds to wait for the element to be visible
369 @type timeout: int
370 @rtype: WebElement
371 """
372 try:
373 element = WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
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
383 """
384 Wait until an element cna be clicked
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 for the element to be clickable
392 @type timeout: int
393 @rtype: WebElement
394 """
395 try:
396 element = WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
397 return element
398 except TimeoutException:
399 if error_msg is None:
400 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
401 self.save_screenshot("[ERROR] %s" % error_msg)
402 pytest.fail(error_msg)
403
404
406 """
407 Wait until an element is present
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 for the element to be present
415 @type timeout: int
416 @rtype: WebElement
417 """
418 try:
419 element = WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
420 return element
421 except TimeoutException:
422 if error_msg is None:
423 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
424 self.save_screenshot("[ERROR] %s" % error_msg)
425 pytest.fail(error_msg)
426
427
429 """
430 Wait until an element is selected
431 @param locator_strategy: Location strategy to use
432 @type locator_strategy: By
433 @param locator_string: String used to locate element
434 @type locator_string: str
435 @param error_msg: Error string to show if element is not found
436 @type error_msg: str
437 @param timeout: Maximum time in seconds to wait for the element to be selected
438 @type timeout: int
439 @rtype: WebElement
440 """
441 try:
442 element = WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
443 return element
444 except TimeoutException:
445 if error_msg is None:
446 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
447 self.save_screenshot("[ERROR] %s" % error_msg)
448 pytest.fail(error_msg)
449
450
452 """
453 Wait until an element becomes invisible
454 @param locator_strategy: Location strategy to use
455 @type locator_strategy: By
456 @param locator_string: String used to locate element
457 @type locator_string: str
458 @param error_msg: Error string to show if element is not found
459 @type error_msg: str
460 @param timeout: Maximum time in seconds to wait for the element to be hidden
461 @type timeout: int
462 @rtype: WebElement
463 """
464 try:
465 element = WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
466 return element
467 except TimeoutException:
468 if error_msg is None:
469 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
470 self.save_screenshot("[ERROR] %s" % error_msg)
471 pytest.fail(error_msg)
472
473
475 """
476 Wait until an element that moves on the screen stops moving
477 @param locator_strategy: Location strategy to use
478 @type locator_strategy: By
479 @param locator_string: String used to locate element
480 @type locator_string: str
481 @param error_msg: Error string to show if element is not found
482 @type error_msg: str
483 @param timeout: Maximum time in seconds to wait for the element to be visible
484 @type timeout: int
485 @rtype: WebElement
486 """
487 try:
488 element = WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
489
490
491 old_location = {'x':0, 'y':0}
492 while old_location != element.location:
493 self._tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % (old_location, element.location))
494 old_location = element.location
495 sleep(0.1)
496 element = self.browser.find_element(locator_strategy, locator_string)
497
498 return element
499 except TimeoutException:
500 if error_msg is None:
501 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
502 self.save_screenshot("[ERROR] %s" % error_msg)
503 pytest.fail(error_msg)
504
505
506 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
507 """
508 Wait for an element that contains specified text
509 @param locator_strategy: Location strategy to use
510 @type locator_strategy: By
511 @param locator_string: String used to locate element
512 @type locator_string: str
513 @param error_msg: Error string to show if element is not found
514 @type error_msg: str
515 @param timeout: Maximum time in seconds to wait
516 @type timeout: int
517 """
518 try:
519 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
520 except TimeoutException:
521 if error_msg is None:
522 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
523 self.save_screenshot("[ERROR] %s" % error_msg)
524 pytest.fail(error_msg)
525
526
527 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
528 """
529 Wait for an element's value to contain some test
530 @param locator_strategy: Location strategy to use
531 @type locator_strategy: By
532 @param locator_string: String used to locate element
533 @type locator_string: str
534 @param error_msg: Error string to show if element is not found
535 @type error_msg: str
536 @param timeout: Maximum time in seconds to wait
537 @type timeout: int
538 """
539 try:
540 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
541 except TimeoutException:
542 if error_msg is None:
543 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
544 self.save_screenshot("[ERROR] %s" % error_msg)
545 pytest.fail(error_msg)
546
547
549 try:
550 return self.browser.find_element_by_link_text(text)
551 except NoSuchElementException:
552 pytest.fail("Could not find the link: '%s'" % text)
553
555 try:
556 self.wait_for_element_to_be_visible(By.XPATH, locator_xpath)
557 return self.browser.find_element_by_xpath(locator_xpath)
558 except NoSuchElementException:
559 pytest.fail("Could not find the xpath: '%s'" % locator_xpath)
560
562 try:
563 self.wait_for_element_to_be_visible(By.CSS_SELECTOR, locator_css)
564 return self.browser.find_element_by_css_selector(locator_css)
565 except NoSuchElementException:
566 pytest.fail("Could not find css: '%s'" %locator_css)
567
569 try:
570 return self.browser.find_elements_by_xpath(text)
571 except NoSuchElementException:
572 pytest.fail("Could not find the xpath: '%s'" %text)
573
575 try:
576 return self.browser.find_elements_by_css_selector(locator_css)
577 except NoSuchElementException:
578 pytest.fail("Could not find css: '%s'" %locator_css)
579