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