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 WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
314 except TimeoutException:
315 if error_msg is None:
316 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
317 self.save_screenshot("[ERROR] %s" % error_msg)
318 pytest.fail(error_msg)
319
320
322 try:
323 WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
324 except TimeoutException:
325 if error_msg is None:
326 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
327 self.save_screenshot("[ERROR] %s" % error_msg)
328 pytest.fail(error_msg)
329
330
332 try:
333 WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
334 except TimeoutException:
335 if error_msg is None:
336 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
337 self.save_screenshot("[ERROR] %s" % error_msg)
338 pytest.fail(error_msg)
339
340
342 try:
343 WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
344 except TimeoutException:
345 if error_msg is None:
346 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
347 self.save_screenshot("[ERROR] %s" % error_msg)
348 pytest.fail(error_msg)
349
350
352 try:
353 WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
354 except TimeoutException:
355 if error_msg is None:
356 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
357 self.save_screenshot("[ERROR] %s" % error_msg)
358 pytest.fail(error_msg)
359
360
362 try:
363 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
364 except TimeoutException:
365 if error_msg is None:
366 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
367 self.save_screenshot("[ERROR] %s" % error_msg)
368 pytest.fail(error_msg)
369
370
372 try:
373 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
374 except TimeoutException:
375 if error_msg is None:
376 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
377 self.save_screenshot("[ERROR] %s" % error_msg)
378 pytest.fail(error_msg)
379