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