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 self._tlib_logger.debug("Page '%s' already loaded" % self.browser.current_url)
276 return
277 else:
278 self._tlib_logger.debug("Waiting for '%s' to load" % self.browser.current_url)
279
280 condition = lambda *args: self.browser.execute_script("return document.readyState") == "complete"
281 try:
282 WebDriverWait(self.browser, timeout).until(condition)
283 except TimeoutException:
284 self.test_logger.error('Timeout while waiting for page to load')
285 pytest.fail('Timeout while waiting for page to load')
286
287 self._tlib_logger.debug("Page '%s' finished loading" % self.browser.current_url)
288
289 @pytest.fixture(scope='function', autouse=True)
291 """
292 Goes to homepage before each test, unless marker skipsetup is given
293 """
294
295 marks = {}
296 for k,v in request.node.function.__dict__.iteritems():
297 if isinstance(v, MarkInfo):
298 marks[k] = v
299
300
301 if not marks.has_key('skipsetup'):
302
303 self.go_home(save_screenshot=False)
304 self.browser.delete_all_cookies()
305 self.go_home()
306 else:
307 self.test_logger.info("Skipping setup")
308
309
311 try:
312 WebDriverWait(self.browser, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
313 except TimeoutException:
314 if error_msg is None:
315 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
316 self.save_screenshot("[ERROR] %s" % error_msg)
317 pytest.fail(error_msg)
318
319
321 try:
322 WebDriverWait(self.browser, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
323 except TimeoutException:
324 if error_msg is None:
325 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
326 self.save_screenshot("[ERROR] %s" % error_msg)
327 pytest.fail(error_msg)
328
329
331 try:
332 WebDriverWait(self.browser, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
333 except TimeoutException:
334 if error_msg is None:
335 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
336 self.save_screenshot("[ERROR] %s" % error_msg)
337 pytest.fail(error_msg)
338
339
341 try:
342 WebDriverWait(self.browser, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
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 pytest.fail(error_msg)
348
349
351 try:
352 WebDriverWait(self.browser, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
353 except TimeoutException:
354 if error_msg is None:
355 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
356 self.save_screenshot("[ERROR] %s" % error_msg)
357 pytest.fail(error_msg)
358
359
361 try:
362 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
363 except TimeoutException:
364 if error_msg is None:
365 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
366 self.save_screenshot("[ERROR] %s" % error_msg)
367 pytest.fail(error_msg)
368
369
371 try:
372 WebDriverWait(self.browser, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
373 except TimeoutException:
374 if error_msg is None:
375 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
376 self.save_screenshot("[ERROR] %s" % error_msg)
377 pytest.fail(error_msg)
378