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
186
188 """
189 Saves screen shot for the current page
190 """
191
192 self.tlib_logger.debug("Saving screenshot")
193 self.wait_for_page_loaded()
194
195
196 name = self.get_unused_report_name(self._test_case_id, self._test_params)
197 name = FileHelper.get_filename_from_string(name)
198
199 test_folder = os.path.join(self.screenshot_folder(), self._folder_dest, name)
200
201 try:
202 os.makedirs(test_folder)
203 except WindowsError:
204 pass
205
206
207 i = len(os.listdir(test_folder)) + 1
208
209
210 img_filename = "%02d.png" % i
211 full_path = os.path.join(test_folder, img_filename)
212
213 self._screenshots[i] = {"filename": "%s/%s" % (name, img_filename),
214 u"description": description}
215
216 self._driver.get_screenshot_as_file(full_path)
217
218
219 - def wait_for_page_loaded(self, timeout=10):
220 raise NotImplementedError("This method should be implemented by derived classes")
221
222
224 """
225 Waist until an alert is visible
226 @type timeout: Integer
227 @param timeout: Number of seconds before timing out
228 @rtype: bool
229 """
230 def is_alert_visible():
231 try:
232
233 alert = self._driver.switch_to_alert().text
234 return True
235 except NoAlertPresentException as e:
236 return False
237
238 condition = lambda *args: is_alert_visible()
239 try:
240 WebDriverWait(self._driver, timeout).until(condition)
241 return self._driver.switch_to_alert()
242 except TimeoutException:
243 self.test_logger.error('Timeout while waiting for alert to appear')
244 pytest.fail('Timeout while waiting for alert to appear')
245
246
248 """
249 Wait until an element becomes visible
250 @param locator_strategy: Location strategy to use
251 @type locator_strategy: By
252 @param locator_string: String used to locate element
253 @type locator_string: str
254 @param error_msg: Error string to show if element is not found
255 @type error_msg: str
256 @param timeout: Maximum time in seconds to wait for the element to be visible
257 @type timeout: int
258 @rtype: WebElement
259 """
260 try:
261 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
262 return element
263 except TimeoutException:
264 if error_msg is None:
265 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
266 self.save_screenshot("[ERROR] %s" % error_msg)
267 pytest.fail(error_msg)
268
269
271 """
272 Wait until an element cna be clicked
273 @param locator_strategy: Location strategy to use
274 @type locator_strategy: By
275 @param locator_string: String used to locate element
276 @type locator_string: str
277 @param error_msg: Error string to show if element is not found
278 @type error_msg: str
279 @param timeout: Maximum time in seconds to wait for the element to be clickable
280 @type timeout: int
281 @rtype: WebElement
282 """
283 try:
284 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_to_be_clickable((locator_strategy, locator_string)))
285 return element
286 except TimeoutException:
287 if error_msg is None:
288 error_msg = "Timeout while waiting for element '%s' to be clickable" % locator_string
289 self.save_screenshot("[ERROR] %s" % error_msg)
290 pytest.fail(error_msg)
291
292
294 """
295 Wait until an element is present
296 @param locator_strategy: Location strategy to use
297 @type locator_strategy: By
298 @param locator_string: String used to locate element
299 @type locator_string: str
300 @param error_msg: Error string to show if element is not found
301 @type error_msg: str
302 @param timeout: Maximum time in seconds to wait for the element to be present
303 @type timeout: int
304 @rtype: WebElement
305 """
306 try:
307 element = WebDriverWait(self._driver, timeout).until(expected_conditions.alert_is_present((locator_strategy, locator_string)))
308 return element
309 except TimeoutException:
310 if error_msg is None:
311 error_msg = "Timeout while waiting for element '%s' to be present" % locator_string
312 self.save_screenshot("[ERROR] %s" % error_msg)
313 pytest.fail(error_msg)
314
315
317 """
318 Wait until an element is selected
319 @param locator_strategy: Location strategy to use
320 @type locator_strategy: By
321 @param locator_string: String used to locate element
322 @type locator_string: str
323 @param error_msg: Error string to show if element is not found
324 @type error_msg: str
325 @param timeout: Maximum time in seconds to wait for the element to be selected
326 @type timeout: int
327 @rtype: WebElement
328 """
329 try:
330 element = WebDriverWait(self._driver, timeout).until(expected_conditions.element_located_to_be_selected((locator_strategy, locator_string)))
331 return element
332 except TimeoutException:
333 if error_msg is None:
334 error_msg = "Timeout while waiting for element '%s' to be selected" % locator_string
335 self.save_screenshot("[ERROR] %s" % error_msg)
336 pytest.fail(error_msg)
337
338
340 """
341 Wait until an element becomes invisible
342 @param locator_strategy: Location strategy to use
343 @type locator_strategy: By
344 @param locator_string: String used to locate element
345 @type locator_string: str
346 @param error_msg: Error string to show if element is not found
347 @type error_msg: str
348 @param timeout: Maximum time in seconds to wait for the element to be hidden
349 @type timeout: int
350 @rtype: WebElement
351 """
352 try:
353 element = WebDriverWait(self._driver, timeout).until(expected_conditions.invisibility_of_element_located((locator_strategy, locator_string)))
354 return element
355 except TimeoutException:
356 if error_msg is None:
357 error_msg = "Timeout while waiting for element '%s' to be invisible" % locator_string
358 self.save_screenshot("[ERROR] %s" % error_msg)
359 pytest.fail(error_msg)
360
361
363 """
364 Wait until an element that moves on the screen stops moving
365 @param locator_strategy: Location strategy to use
366 @type locator_strategy: By
367 @param locator_string: String used to locate element
368 @type locator_string: str
369 @param error_msg: Error string to show if element is not found
370 @type error_msg: str
371 @param timeout: Maximum time in seconds to wait for the element to be visible
372 @type timeout: int
373 @rtype: WebElement
374 """
375 try:
376 element = WebDriverWait(self._driver, timeout).until(expected_conditions.visibility_of_element_located((locator_strategy, locator_string)))
377
378
379 old_location = {'x':0, 'y':0}
380 while old_location != element.location:
381 self.tlib_logger.debug("Pop-up is still moving. Previous position: %s, current position: %s" % (old_location, element.location))
382 old_location = element.location
383 sleep(0.1)
384 element = self._driver.find_element(locator_strategy, locator_string)
385
386 return element
387 except TimeoutException:
388 if error_msg is None:
389 error_msg = "Timeout while waiting for element '%s' to be visible" % locator_string
390 self.save_screenshot("[ERROR] %s" % error_msg)
391 pytest.fail(error_msg)
392
393
394 - def wait_for_text_to_be_present_in_element(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
395 """
396 Wait for an element that contains specified text
397 @param locator_strategy: Location strategy to use
398 @type locator_strategy: By
399 @param locator_string: String used to locate element
400 @type locator_string: str
401 @param error_msg: Error string to show if element is not found
402 @type error_msg: str
403 @param timeout: Maximum time in seconds to wait
404 @type timeout: int
405 """
406 try:
407 WebDriverWait(self._driver, timeout).until(expected_conditions.text_to_be_present_in_element((locator_strategy, locator_string), text))
408 except TimeoutException:
409 if error_msg is None:
410 error_msg = "Timeout while waiting for text %(text)s to be present in element '%(element)s'" % {"text": text, "element":locator_string}
411 self.save_screenshot("[ERROR] %s" % error_msg)
412 pytest.fail(error_msg)
413
414
415 - def wait_for_text_to_be_present_in_element_value(self, locator_strategy, locator_string, text, error_msg=None, timeout=10):
416 """
417 Wait for an element's value to contain some test
418 @param locator_strategy: Location strategy to use
419 @type locator_strategy: By
420 @param locator_string: String used to locate element
421 @type locator_string: str
422 @param error_msg: Error string to show if element is not found
423 @type error_msg: str
424 @param timeout: Maximum time in seconds to wait
425 @type timeout: int
426 """
427 try:
428 WebDriverWait(self._driver, timeout).until(expected_conditions.text_to_be_present_in_element_value((locator_strategy, locator_string), text))
429 except TimeoutException:
430 if error_msg is None:
431 error_msg = "Timeout while waiting for text %(text)s to be present in the value of element '%(element)s'" % {"text": text, "element":locator_string}
432 self.save_screenshot("[ERROR] %s" % error_msg)
433 pytest.fail(error_msg)
434