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.support.ui import WebDriverWait
17 from selenium.webdriver.support import expected_conditions
18 from selenium.common.exceptions import TimeoutException
19 import logging
25
26 _homepage = ""
27 _test_logger = None
28 _tlib_logger = None
29 _browser = None
30
31 _folder_dest = None
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
39 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html")
40
41 _screenshots = {}
42 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html")
43
44
46 """
47 Returns Instance of the WebDriver browser
48 """
49 return self.__class__._browser
50
51
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
81 """
82 Logger object to log test information
83 @type: logging
84 """
85 return self.__class__._test_logger
86
87
88 @staticmethod
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)
108
109
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
122 filename = "%(tc_id)s" % { "tc_id": tc_id}
123 else:
124
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)
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
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)
205
206
207 request.addfinalizer(generate_report)
208
209
210 - def navigate(self, page, save_screenshot=True):
218
219
220 - def go_home(self, save_screenshot=True):
227
228
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
241 self._tlib_logger.debug("Saving screenshot")
242 self.wait_for_page_loaded()
243
244
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
256 i = len(os.listdir(test_folder)) + 1
257
258
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 return
276 else:
277 self._tlib_logger.debug("Waiting for '%s' to load" % self.browser.current_url)
278
279 condition = lambda *args: self.browser.execute_script("return document.readyState") == "complete"
280 try:
281 WebDriverWait(self.browser, timeout).until(condition)
282 except TimeoutException:
283 self.test_logger.error('Timeout while waiting for page to load')
284 pytest.fail('Timeout while waiting for page to load')
285
286 self._tlib_logger.debug("Page '%s' finished loading" % self.browser.current_url)
287
288 @pytest.fixture(scope='function', autouse=True)
290 """
291 Goes to homepage before each test, unless marker skipsetup is given
292 """
293
294 marks = {}
295 for k,v in request.node.function.__dict__.iteritems():
296 if isinstance(v, MarkInfo):
297 marks[k] = v
298
299
300 if not marks.has_key('skipsetup'):
301
302 self.go_home(save_screenshot=False)
303 self.browser.delete_all_cookies()
304 self.go_home()
305 else:
306 self.test_logger.info("Skipping setup")
307
308
310 try:
311 WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
312 except TimeoutException:
313 if error_msg is None:
314 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
315 self.save_screenshot("[ERROR] %s" % error_msg)
316 pytest.fail(error_msg)
317
318
320 try:
321 WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
322 except TimeoutException:
323 if error_msg is None:
324 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
325 self.save_screenshot("[ERROR] %s" % error_msg)
326 pytest.fail(error_msg)
327
328
330 try:
331 WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
332 except TimeoutException:
333 if error_msg is None:
334 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
335 self.save_screenshot("[ERROR] %s" % error_msg)
336 pytest.fail(error_msg)
337
338
340 try:
341 WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
342 except TimeoutException:
343 if error_msg is None:
344 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
345 self.save_screenshot("[ERROR] %s" % error_msg)
346 pytest.fail(error_msg)
347
348
350 try:
351 WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
352 except TimeoutException:
353 if error_msg is None:
354 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
355 self.save_screenshot("[ERROR] %s" % error_msg)
356 pytest.fail(error_msg)
357
358
360 try:
361 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
362 except TimeoutException:
363 if error_msg is None:
364 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
365 self.save_screenshot("[ERROR] %s" % error_msg)
366 pytest.fail(error_msg)
367
368
370 try:
371 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
372 except TimeoutException:
373 if error_msg is None:
374 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
375 self.save_screenshot("[ERROR] %s" % error_msg)
376 pytest.fail(error_msg)
377