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)
110
111
113 """
114 Gets a string based on test case id and name, taking into account if test case has already been run or not
115 @param tc_id: Test case id
116 @type tc_id: str
117 @param tc_name: Test case name
118 @type tc_name: str
119 """
120 i = 0
121 while True:
122 if i == 0:
123
124 filename = "%(tc_id)s" % { "tc_id": tc_id}
125 else:
126
127 filename = "%(tc_id)s [retry %(cnt)d]" % { "tc_id": tc_id, "cnt": i}
128
129 if not filename in self.__class__._screenshot_report:
130 return filename
131
132 i += 1
133
134
135 @pytest.fixture(scope='class', autouse=True)
137 """
138 Generates HTML page with all test case results for the class
139 @type request: FixtureRequest
140 """
141 self.__class__._screenshot_report = collections.OrderedDict()
142 self.__class__._folder_dest = re.sub('\.py$', '', os.path.relpath(inspect.getfile(request.cls)))
143
144 def generate_report():
145 if len(self.__class__._screenshot_report) > 0:
146
147 html = self.__class__._screenshot_report_template.render(test_class=self.__class__.__name__,
148 files=self.__class__._screenshot_report)
149
150 htm_file = "%s.htm" % self.__class__._folder_dest
151 full_filename = os.path.join(self.screenshot_folder(), htm_file)
152
153 f = open(full_filename, "w")
154 try:
155 f.write(html)
156 finally:
157 f.close()
158
159 request.addfinalizer(generate_report)
160
161
162 @pytest.fixture(scope='function', autouse=True)
207
208
209 request.addfinalizer(generate_report)
210
211
212 - def navigate(self, page, save_screenshot=True):
220
221
222 - def go_home(self, save_screenshot=True):
229
230
232 """
233 Saves screen shot for the current page
234 """
235
236 def get_params():
237 if self.__class__._test_params is None:
238 return ""
239 else:
240 return self.__class__._test_params
241
242
243 self._tlib_logger.debug("Saving screenshot")
244 self.wait_for_page_loaded()
245
246
247 name = self.get_unused_report_name(self.__class__._test_case_id, self.__class__._test_case_name)
248 name = FileHelper.get_filename_from_string(name)
249
250 test_folder = os.path.join(self.screenshot_folder(), self.__class__._folder_dest, name)
251
252 try:
253 os.makedirs(test_folder)
254 except WindowsError:
255 pass
256
257
258 i = len(os.listdir(test_folder)) + 1
259
260
261 img_filename = "%02d.jpg" % i
262 full_path = os.path.join(test_folder, img_filename)
263
264 self.__class__._screenshots[i] = {"filename": "%s/%s" % (name, img_filename),
265 "description": description}
266
267 self.browser.get_screenshot_as_file(full_path)
268
269
270 - def wait_for_page_loaded(self, timeout=10):
271 """
272 Waist until document.readyState is equal to complete
273 @type timeout: Integer
274 @param timeout: Number of seconds before timing out
275 """
276 if self.browser.execute_script("return document.readyState") == "complete":
277 return
278 else:
279 self._tlib_logger.debug("Waiting for '%s' to load" % self.browser.current_url)
280
281 condition = lambda *args: self.browser.execute_script("return document.readyState") == "complete"
282 try:
283 WebDriverWait(self.browser, timeout).until(condition)
284 except TimeoutException:
285 self.test_logger.error('Timeout while waiting for page to load')
286 pytest.fail('Timeout while waiting for page to load')
287
288 self._tlib_logger.debug("Page '%s' finished loading" % self.browser.current_url)
289
290 @pytest.fixture(scope='function', autouse=True)
292 """
293 Goes to homepage before each test, unless marker skipsetup is given
294 """
295
296 marks = {}
297 for k,v in request.node.function.__dict__.iteritems():
298 if isinstance(v, MarkInfo):
299 marks[k] = v
300
301
302 if not marks.has_key('skipsetup'):
303
304 self.go_home(save_screenshot=False)
305 self.browser.delete_all_cookies()
306 self.go_home()
307 else:
308 self.test_logger.info("Skipping setup")
309
310
312 try:
313 element = WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
314 return element
315 except TimeoutException:
316 if error_msg is None:
317 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
318 self.save_screenshot("[ERROR] %s" % error_msg)
319 pytest.fail(error_msg)
320
321
323 try:
324 element = WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
325 return element
326 except TimeoutException:
327 if error_msg is None:
328 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
329 self.save_screenshot("[ERROR] %s" % error_msg)
330 pytest.fail(error_msg)
331
332
334 try:
335 element = WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
336 return element
337 except TimeoutException:
338 if error_msg is None:
339 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
340 self.save_screenshot("[ERROR] %s" % error_msg)
341 pytest.fail(error_msg)
342
343
345 try:
346 element = WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
347 return element
348 except TimeoutException:
349 if error_msg is None:
350 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
351 self.save_screenshot("[ERROR] %s" % error_msg)
352 pytest.fail(error_msg)
353
354
356 try:
357 element = WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
358 return element
359 except TimeoutException:
360 if error_msg is None:
361 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
362 self.save_screenshot("[ERROR] %s" % error_msg)
363 pytest.fail(error_msg)
364
365
367 try:
368 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
369 except TimeoutException:
370 if error_msg is None:
371 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
372 self.save_screenshot("[ERROR] %s" % error_msg)
373 pytest.fail(error_msg)
374
375
377 try:
378 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
379 except TimeoutException:
380 if error_msg is None:
381 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
382 self.save_screenshot("[ERROR] %s" % error_msg)
383 pytest.fail(error_msg)
384