1 import os
2 import inspect
3
4 import pytest
5 import collections
6 from time import sleep
7
8 from _pytest.python import FixtureRequest
9
10 import jinja2
11 from tlib.base import TestHelper
12 from tlib.base import FileHelper
13 from tlib.base.PytestTester import PytestTester
14 from selenium.webdriver.common.by import By
15 from selenium.webdriver.support.ui import WebDriverWait
16 from selenium.webdriver.support import expected_conditions
17 from selenium.common.exceptions import TimeoutException, NoAlertPresentException, NoSuchElementException
18 from selenium.webdriver.remote.webelement import WebElement
19 from TestHelper import Singleton
25
26 __metaclass__ = Singleton
27
28 _driver = None
29
30 _folder_dest = None
31 _test_case_id = None
32 _test_case_name = None
33 _test_params = None
34
35 _jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(TestHelper.tlib_template_folder()),
36 trim_blocks=True)
37
38 _screenshot_report = None
39
40
41 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html")
42
43 _screenshots = {}
44
45
46 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html")
47
48 _request = None
49
63
65 """
66 Will try to find a folder named "screenshot" starting from the file being executed and up to
67 three levels up
68
69 @return: str
70 """
71
72 curr_folder = os.path.dirname(self._request.fspath.strpath)
73
74
75 for i in range(1, 4):
76 curr_folder = os.path.abspath(os.path.join(curr_folder, os.pardir))
77
78
79 screenshot_folder = os.path.join(curr_folder, 'screenshots')
80 if os.path.exists(screenshot_folder):
81 return screenshot_folder
82
84 """
85 Gets a string based on test case id and name, taking into account if test case has already been run or not
86 @param tc_id: Test case id
87 @type tc_id: str
88 @type tc_name: str
89 """
90 i = 0
91 while True:
92 if i == 0:
93 filename = "%(tc_id)s_%(tc_params)s" % {"tc_id": tc_id, "tc_params": tc_params}
94 else:
95 filename = "%(tc_id)s_%(tc_params)s [retry %(cnt)d]" % \
96 {"tc_id": tc_id, "tc_params": tc_params, "cnt": i}
97
98 if not filename in self._screenshot_report:
99 return filename
100
101 i += 1
102
103 @pytest.fixture(scope='class', autouse=True)
105 """
106 @type request: FixtureRequest
107 """
108
109
110 self._screenshot_report = collections.OrderedDict()
111 self._folder_dest = os.path.basename(os.path.dirname(os.path.abspath(inspect.getfile(request.cls))))
112
113 def generate_report():
114 if len(self._screenshot_report) > 0:
115
116 html = self._screenshot_report_template.render(test_class=request.cls.__name__,
117 files=self._screenshot_report)
118
119 htm_file = "%s.htm" % self._folder_dest
120 full_filename = os.path.join(self.screenshot_folder(), htm_file)
121
122 f = open(full_filename, "w")
123 try:
124 f.write(html)
125 finally:
126 f.close()
127
128 request.addfinalizer(generate_report)
129
130 @pytest.fixture(scope='function', autouse=True)
187
188 request.addfinalizer(generate_report)
189
221
223 """
224 Removes non-ascii characters from a string
225 @type str: string
226 @param str: String with non-ascii characters
227 @rtype: string
228 """
229 return ''.join([i if ord(i) < 128 else '' for i in str])
230
231 - def wait_for_page_loaded(self, timeout=10):
232 raise NotImplementedError("This method should be implemented by derived classes")
233
235 """
236 Waist until an alert is visible
237 @type timeout: Integer
238 @param timeout: Number of seconds before timing out
239 @rtype: bool
240 """
241 def is_alert_visible():
242 try:
243
244 alert = self._driver.switch_to_alert().text
245 return True
246 except NoAlertPresentException as e:
247 return False
248
249 condition = lambda *args: is_alert_visible()
250 try:
251 WebDriverWait(self._driver, timeout).until(condition)
252 return self._driver.switch_to_alert()
253 except TimeoutException:
254 self.test_logger.error('Timeout while waiting for alert to appear')
255 raise RuntimeError('Timeout while waiting for alert to appear')
256
258 """
259 Wait until an element becomes visible
260 @param locator_strategy: Location strategy to use
261 @type locator_strategy: By
262 @param locator_string: String used to locate element
263 @type locator_string: str
264 @param error_msg: Error string to show if element is not found
265 @type error_msg: str
266 @param timeout: Maximum time in seconds to wait for the element to be visible
267 @type timeout: int
268 @rtype: WebElement
269 """
270 try:
271 element = WebDriverWait(self._driver, timeout).\
272 until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
273 return element
274 except TimeoutException:
275 if error_msg is None:
276 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
277 self.save_screenshot("[ERROR] %s" % error_msg)
278 raise RuntimeError(error_msg)
279
281 """
282 Wait until an element cna be clicked
283 @param locator_strategy: Location strategy to use
284 @type locator_strategy: By
285 @param locator_string: String used to locate element
286 @type locator_string: str
287 @param error_msg: Error string to show if element is not found
288 @type error_msg: str
289 @param timeout: Maximum time in seconds to wait for the element to be clickable
290 @type timeout: int
291 @rtype: WebElement
292 """
293 try:
294 element = WebDriverWait(self._driver, timeout).\
295 until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
296 return element
297 except TimeoutException:
298 if error_msg is None:
299 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
300 self.save_screenshot("[ERROR] %s" % error_msg)
301 raise RuntimeError(error_msg)
302
304 """
305 Wait until an element is present
306 @param locator_strategy: Location strategy to use
307 @type locator_strategy: By
308 @param locator_string: String used to locate element
309 @type locator_string: str
310 @param error_msg: Error string to show if element is not found
311 @type error_msg: str
312 @param timeout: Maximum time in seconds to wait for the element to be present
313 @type timeout: int
314 @rtype: WebElement
315 """
316 try:
317 element = WebDriverWait(self._driver, timeout).\
318 until(expected_conditions.presence_of_element_located((locator_strategy, locator_string)))
319 return element
320 except TimeoutException:
321 if error_msg is None:
322 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
323 self.save_screenshot("[ERROR] %s" % error_msg)
324 raise RuntimeError(error_msg)
325
327 """
328 Wait until an element is selected
329 @param locator_strategy: Location strategy to use
330 @type locator_strategy: By
331 @param locator_string: String used to locate element
332 @type locator_string: str
333 @param error_msg: Error string to show if element is not found
334 @type error_msg: str
335 @param timeout: Maximum time in seconds to wait for the element to be selected
336 @type timeout: int
337 @rtype: WebElement
338 """
339 try:
340 element = WebDriverWait(self._driver, timeout).\
341 until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
342 return element
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 raise RuntimeError(error_msg)
348
350 """
351 Wait until an element becomes invisible
352 @param locator_strategy: Location strategy to use
353 @type locator_strategy: By
354 @param locator_string: String used to locate element
355 @type locator_string: str
356 @param error_msg: Error string to show if element is not found
357 @type error_msg: str
358 @param timeout: Maximum time in seconds to wait for the element to be hidden
359 @type timeout: int
360 @rtype: WebElement
361 """
362 try:
363 element = WebDriverWait(self._driver, timeout).\
364 until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
365 return element
366 except TimeoutException:
367 if error_msg is None:
368 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
369 self.save_screenshot("[ERROR] %s" % error_msg)
370 raise RuntimeError(error_msg)
371
373 """
374 Wait until an element that moves on the screen stops moving
375 @param locator_strategy: Location strategy to use
376 @type locator_strategy: By
377 @param locator_string: String used to locate element
378 @type locator_string: str
379 @param error_msg: Error string to show if element is not found
380 @type error_msg: str
381 @param timeout: Maximum time in seconds to wait for the element to be visible
382 @type timeout: int
383 @rtype: WebElement
384 """
385 try:
386 element = WebDriverWait(self._driver, timeout).\
387 until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
388
389
390 old_location = {'x': 0, 'y': 0}
391 while old_location != element.location:
392 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" %
393 (old_location, element.location))
394 old_location = element.location
395 sleep(0.1)
396 element = self._driver.find_element(locator_strategy, locator_string)
397
398 return element
399 except TimeoutException:
400 if error_msg is None:
401 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
402 self.save_screenshot("[ERROR] %s" % error_msg)
403 raise RuntimeError(error_msg)
404
405 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text,
406 error_msg=None, timeout=10):
407 """
408 Wait for an element that contains specified text
409 @param locator_strategy: Location strategy to use
410 @type locator_strategy: By
411 @param locator_string: String used to locate element
412 @type locator_string: str
413 @param error_msg: Error string to show if element is not found
414 @type error_msg: str
415 @param timeout: Maximum time in seconds to wait
416 @type timeout: int
417 """
418 try:
419 WebDriverWait(self._driver, timeout).\
420 until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
421 except TimeoutException:
422 if error_msg is None:
423 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % \
424 {"text": text, "element": locator_string}
425 self.save_screenshot("[ERROR] %s" % error_msg)
426 raise RuntimeError(error_msg)
427
428 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text,
429 error_msg=None, timeout=10):
430 """
431 Wait for an element's value to contain some test
432 @param locator_strategy: Location strategy to use
433 @type locator_strategy: By
434 @param locator_string: String used to locate element
435 @type locator_string: str
436 @param error_msg: Error string to show if element is not found
437 @type error_msg: str
438 @param timeout: Maximum time in seconds to wait
439 @type timeout: int
440 """
441 try:
442 WebDriverWait(self._driver, timeout).\
443 until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
444 except TimeoutException:
445 if error_msg is None:
446 error_msg = "Timeout while waiting for text %(text)s to be present " \
447 "in the value of element '%(element)s'" % {"text": text, "element": locator_string}
448 self.save_screenshot("[ERROR] %s" % error_msg)
449 raise RuntimeError(error_msg)
450
451
452 - def get_webelement_by_link_text(self, locator_string):
453 """
454 Get the webelement by link text
455 @param locator_string: String used to locate element
456 @type locator_string: str
457 @param error_msg: Error string to show if element is not found
458 @type error_msg: str
459 """
460 try:
461 return self.browser.find_element_by_link_text(locator_string)
462 except NoSuchElementException:
463 error_msg="Could not find the link: '%s'"
464 self.save_screenshot(error_msg % locator_string)
465 raise RuntimeError(error_msg % locator_string)
466
468 """
469 Get the webelement by xpath
470 @param locator_string: String used to locate element
471 @type locator_string: str
472 @param error_msg: Error string to show if element is not found
473 @type error_msg: str
474 """
475 try:
476 self.wait_for_element_to_be_visible(By.XPATH, locator_string)
477 return self.browser.find_element_by_xpath(locator_string)
478 except NoSuchElementException:
479 error_msg="Could not find the xpath: '%s'"
480 self.save_screenshot(error_msg % locator_string)
481 raise RuntimeError(error_msg % locator_string)
482
484 """
485 Get the webelement by CSS
486 @param locator_string: String used to locate element
487 @type locator_string: str
488 @param error_msg: Error string to show if element is not found
489 @type error_msg: str
490 """
491 try:
492 self.wait_for_element_to_be_visible(By.CSS_SELECTOR, locator_string)
493 return self.browser.find_element_by_css_selector(locator_string)
494 except NoSuchElementException:
495 error_msg="Could not find css: '%s'"
496 self.save_screenshot(error_msg % locator_string)
497 raise RuntimeError(error_msg %locator_string)
498
500 """
501 Get the webelement list by xpath
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 """
507 try:
508 return self.browser.find_elements_by_xpath(locator_string)
509 except NoSuchElementException:
510 error_msg="Could not find the link: '%s'"
511 self.save_screenshot(error_msg % locator_string)
512 raise RuntimeError(error_msg+ " '%s'" % locator_string)
513
515 """
516 Get the webelement list by CSS
517 @param locator_string: String used to locate element
518 @type locator_string: str
519 @param error_msg: Error string to show if element is not found
520 @type error_msg: str
521 """
522 try:
523 return self.browser.find_elements_by_css_selector(locator_string)
524 except NoSuchElementException:
525 error_msg="Could not find css: '%s'"
526 self.save_screenshot(error_msg % locator_string)
527 raise RuntimeError(error_msg % locator_string)
528