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