1 import os
2 import re
3 import inspect
4
5 import pytest
6 import collections
7 from time import sleep
8
9 from _pytest.python import FixtureRequest
10
11 import jinja2
12 from tlib.base import TestHelper
13 from tlib.base import FileHelper
14 from tlib.base.PytestTester import PytestTester
15 from selenium.webdriver.common.by import By
16 from selenium.webdriver.support.ui import WebDriverWait
17 from selenium.webdriver.support import expected_conditions
18 from selenium.common.exceptions import TimeoutException, NoAlertPresentException
19 from selenium.webdriver.remote.webelement import WebElement
20 from TestHelper import Singleton
25
26 __metaclass__ = Singleton
27
28 _driver = None
29
30 _folder_dest = None
31 _test_case_id = None
32 _test_case_name = None
33 _test_params = None
34
35 _jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(TestHelper.tlib_template_folder()),
36 trim_blocks=True)
37
38 _screenshot_report = None
39
40
41 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html")
42
43 _screenshots = {}
44
45
46 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html")
47
48 _request = None
49
63
65 """
66 Will try to find a folder named "screenshot" starting from the file being executed and up to
67 three levels up
68
69 @return: str
70 """
71
72 curr_folder = os.path.dirname(self._request.fspath.strpath)
73
74
75 for i in range(1, 4):
76 curr_folder = os.path.abspath(os.path.join(curr_folder, os.pardir))
77
78
79 screenshot_folder = os.path.join(curr_folder, 'screenshots')
80 if os.path.exists(screenshot_folder):
81 return screenshot_folder
82
83
85 """
86 Gets a string based on test case id and name, taking into account if test case has already been run or not
87 @param tc_id: Test case id
88 @type tc_id: str
89 @type tc_name: str
90 """
91 i = 0
92 while True:
93 if i == 0:
94 filename = "%(tc_id)s_%(tc_params)s" % {"tc_id": tc_id, "tc_params": tc_params}
95 else:
96 filename = "%(tc_id)s_%(tc_params)s [retry %(cnt)d]" % {"tc_id": tc_id, "tc_params": tc_params, "cnt": i}
97
98 if not filename in self._screenshot_report:
99 return filename
100
101 i += 1
102
103
104 @pytest.fixture(scope='class', autouse=True)
106 """
107 @type request: FixtureRequest
108 """
109
110
111 self._screenshot_report = collections.OrderedDict()
112 self._folder_dest = os.path.basename(os.path.dirname(os.path.abspath(inspect.getfile(request.cls))))
113
114 def generate_report():
115 if len(self._screenshot_report) > 0:
116
117 html = self._screenshot_report_template.render(test_class=request.cls.__name__,
118 files=self._screenshot_report)
119
120 htm_file = "%s.htm" % self._folder_dest
121 full_filename = os.path.join(self.screenshot_folder(), htm_file)
122
123 f = open(full_filename, "w")
124 try:
125 f.write(html)
126 finally:
127 f.close()
128
129 request.addfinalizer(generate_report)
130
131
132 @pytest.fixture(scope='function', autouse=True)
184
185 request.addfinalizer(generate_report)
186
187
189 """
190 Saves screen shot for the current page
191 """
192
193 self.tlib_logger.debug("Saving screenshot")
194 self.wait_for_page_loaded()
195
196
197 name = self._get_unused_report_name(self._test_case_id, self._test_params)
198 name = FileHelper.get_filename_from_string(name)
199
200 test_folder = os.path.join(self.screenshot_folder(), self._folder_dest, name)
201
202 try:
203 os.makedirs(test_folder)
204 except WindowsError:
205 pass
206
207
208 i = len(os.listdir(test_folder)) + 1
209
210
211 img_filename = "%02d.png" % i
212 full_path = os.path.join(test_folder, img_filename)
213
214 self._screenshots[i] = {"filename": "%s/%s" % (name, img_filename),
215 u"description": description}
216
217 self._driver.get_screenshot_as_file(full_path)
218
219
220 - def wait_for_page_loaded(self, timeout=10):
221 raise NotImplementedError("This method should be implemented by derived classes")
222
223
225 """
226 Waist until an alert is visible
227 @type timeout: Integer
228 @param timeout: Number of seconds before timing out
229 @rtype: bool
230 """
231 def is_alert_visible():
232 try:
233
234 alert = self._driver.switch_to_alert().text
235 return True
236 except NoAlertPresentException as e:
237 return False
238
239 condition = lambda *args: is_alert_visible()
240 try:
241 WebDriverWait(self._driver, timeout).until(condition)
242 return self._driver.switch_to_alert()
243 except TimeoutException:
244 self.test_logger.error('Timeout while waiting for alert to appear')
245 pytest.fail('Timeout while waiting for alert to appear')
246
247
249 """
250 Wait until an element becomes visible
251 @param locator_strategy: Location strategy to use
252 @type locator_strategy: By
253 @param locator_string: String used to locate element
254 @type locator_string: str
255 @param error_msg: Error string to show if element is not found
256 @type error_msg: str
257 @param timeout: Maximum time in seconds to wait for the element to be visible
258 @type timeout: int
259 @rtype: WebElement
260 """
261 try:
262 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
263 return element
264 except TimeoutException:
265 if error_msg is None:
266 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
267 self.save_screenshot("[ERROR] %s" % error_msg)
268 pytest.fail(error_msg)
269
270
272 """
273 Wait until an element cna be clicked
274 @param locator_strategy: Location strategy to use
275 @type locator_strategy: By
276 @param locator_string: String used to locate element
277 @type locator_string: str
278 @param error_msg: Error string to show if element is not found
279 @type error_msg: str
280 @param timeout: Maximum time in seconds to wait for the element to be clickable
281 @type timeout: int
282 @rtype: WebElement
283 """
284 try:
285 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
286 return element
287 except TimeoutException:
288 if error_msg is None:
289 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
290 self.save_screenshot("[ERROR] %s" % error_msg)
291 pytest.fail(error_msg)
292
293
295 """
296 Wait until an element is present
297 @param locator_strategy: Location strategy to use
298 @type locator_strategy: By
299 @param locator_string: String used to locate element
300 @type locator_string: str
301 @param error_msg: Error string to show if element is not found
302 @type error_msg: str
303 @param timeout: Maximum time in seconds to wait for the element to be present
304 @type timeout: int
305 @rtype: WebElement
306 """
307 try:
308 element = WebDriverWait(self._driver, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
309 return element
310 except TimeoutException:
311 if error_msg is None:
312 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
313 self.save_screenshot("[ERROR] %s" % error_msg)
314 pytest.fail(error_msg)
315
316
318 """
319 Wait until an element is selected
320 @param locator_strategy: Location strategy to use
321 @type locator_strategy: By
322 @param locator_string: String used to locate element
323 @type locator_string: str
324 @param error_msg: Error string to show if element is not found
325 @type error_msg: str
326 @param timeout: Maximum time in seconds to wait for the element to be selected
327 @type timeout: int
328 @rtype: WebElement
329 """
330 try:
331 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
332 return element
333 except TimeoutException:
334 if error_msg is None:
335 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
336 self.save_screenshot("[ERROR] %s" % error_msg)
337 pytest.fail(error_msg)
338
339
341 """
342 Wait until an element becomes invisible
343 @param locator_strategy: Location strategy to use
344 @type locator_strategy: By
345 @param locator_string: String used to locate element
346 @type locator_string: str
347 @param error_msg: Error string to show if element is not found
348 @type error_msg: str
349 @param timeout: Maximum time in seconds to wait for the element to be hidden
350 @type timeout: int
351 @rtype: WebElement
352 """
353 try:
354 element = WebDriverWait(self._driver, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
355 return element
356 except TimeoutException:
357 if error_msg is None:
358 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
359 self.save_screenshot("[ERROR] %s" % error_msg)
360 pytest.fail(error_msg)
361
362
364 """
365 Wait until an element that moves on the screen stops moving
366 @param locator_strategy: Location strategy to use
367 @type locator_strategy: By
368 @param locator_string: String used to locate element
369 @type locator_string: str
370 @param error_msg: Error string to show if element is not found
371 @type error_msg: str
372 @param timeout: Maximum time in seconds to wait for the element to be visible
373 @type timeout: int
374 @rtype: WebElement
375 """
376 try:
377 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
378
379
380 old_location = {'x':0, 'y':0}
381 while old_location != element.location:
382 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % (old_location, element.location))
383 old_location = element.location
384 sleep(0.1)
385 element = self._driver.find_element(locator_strategy, locator_string)
386
387 return element
388 except TimeoutException:
389 if error_msg is None:
390 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
391 self.save_screenshot("[ERROR] %s" % error_msg)
392 pytest.fail(error_msg)
393
394
395 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
396 """
397 Wait for an element that contains specified text
398 @param locator_strategy: Location strategy to use
399 @type locator_strategy: By
400 @param locator_string: String used to locate element
401 @type locator_string: str
402 @param error_msg: Error string to show if element is not found
403 @type error_msg: str
404 @param timeout: Maximum time in seconds to wait
405 @type timeout: int
406 """
407 try:
408 WebDriverWait(self._driver, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
409 except TimeoutException:
410 if error_msg is None:
411 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
412 self.save_screenshot("[ERROR] %s" % error_msg)
413 pytest.fail(error_msg)
414
415
416 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
417 """
418 Wait for an element's value to contain some test
419 @param locator_strategy: Location strategy to use
420 @type locator_strategy: By
421 @param locator_string: String used to locate element
422 @type locator_string: str
423 @param error_msg: Error string to show if element is not found
424 @type error_msg: str
425 @param timeout: Maximum time in seconds to wait
426 @type timeout: int
427 """
428 try:
429 WebDriverWait(self._driver, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
430 except TimeoutException:
431 if error_msg is None:
432 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
433 self.save_screenshot("[ERROR] %s" % error_msg)
434 pytest.fail(error_msg)
435