1 import os
2 import inspect
3
4 import pytest
5 import collections
6 from time import sleep
7
8 from _pytest.python import FixtureRequest
9
10 import jinja2
11 from tlib.base import TestHelper
12 from tlib.base import FileHelper
13 from tlib.base.PytestTester import PytestTester
14 from selenium.webdriver.common.by import By
15 from selenium.webdriver.support.ui import WebDriverWait
16 from selenium.webdriver.support import expected_conditions
17 from selenium.common.exceptions import TimeoutException, NoAlertPresentException
18 from selenium.webdriver.remote.webelement import WebElement
19 from TestHelper import Singleton
24
25 __metaclass__ = Singleton
26
27 _driver = None
28
29 _folder_dest = None
30 _test_case_id = None
31 _test_case_name = None
32 _test_params = None
33
34 _jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(TestHelper.tlib_template_folder()),
35 trim_blocks=True)
36
37 _screenshot_report = None
38
39
40 _screenshot_report_template = _jinja_env.get_template("screenshot_report.html")
41
42 _screenshots = {}
43
44
45 _tc_screenshot_template = _jinja_env.get_template("testcase_screenshots.html")
46
47 _request = None
48
62
64 """
65 Will try to find a folder named "screenshot" starting from the file being executed and up to
66 three levels up
67
68 @return: str
69 """
70
71 curr_folder = os.path.dirname(self._request.fspath.strpath)
72
73
74 for i in range(1, 4):
75 curr_folder = os.path.abspath(os.path.join(curr_folder, os.pardir))
76
77
78 screenshot_folder = os.path.join(curr_folder, 'screenshots')
79 if os.path.exists(screenshot_folder):
80 return screenshot_folder
81
82
84 """
85 Gets a string based on test case id and name, taking into account if test case has already been run or not
86 @param tc_id: Test case id
87 @type tc_id: str
88 @type tc_name: str
89 """
90 i = 0
91 while True:
92 if i == 0:
93 filename = "%(tc_id)s_%(tc_params)s" % {"tc_id": tc_id, "tc_params": tc_params}
94 else:
95 filename = "%(tc_id)s_%(tc_params)s [retry %(cnt)d]" % {"tc_id": tc_id, "tc_params": tc_params, "cnt": i}
96
97 if not filename in self._screenshot_report:
98 return filename
99
100 i += 1
101
102
103 @pytest.fixture(scope='class', autouse=True)
105 """
106 @type request: FixtureRequest
107 """
108
109
110 self._screenshot_report = collections.OrderedDict()
111 self._folder_dest = os.path.basename(os.path.dirname(os.path.abspath(inspect.getfile(request.cls))))
112
113 def generate_report():
114 if len(self._screenshot_report) > 0:
115
116 html = self._screenshot_report_template.render(test_class=request.cls.__name__,
117 files=self._screenshot_report)
118
119 htm_file = "%s.htm" % self._folder_dest
120 full_filename = os.path.join(self.screenshot_folder(), htm_file)
121
122 f = open(full_filename, "w")
123 try:
124 f.write(html)
125 finally:
126 f.close()
127
128 request.addfinalizer(generate_report)
129
130
131 @pytest.fixture(scope='function', autouse=True)
183
184 request.addfinalizer(generate_report)
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.presence_of_element_located((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