Skip to content

Commit

Permalink
Merge pull request #443 from rtomac/default-screenshot-dir
Browse files Browse the repository at this point in the history
Added screenshot_root_directory argument and set_screenshot_directory keyword
  • Loading branch information
zephraph committed Jul 22, 2015
2 parents 97e2e79 + ab1e481 commit d88545d
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 23 deletions.
11 changes: 9 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ Release Notes

1.7.2 (Unreleased)
----------------
- Added an argument called screenshot_root_directory that can be passed into S2L's
constructor to specify where to store screenshots.
- Added new keyword 'set_screenshot_directory' which can be used to set the output
of screenshots.
[zephraph]

- Added new keyword Input Text Into Prompt
- Modified 'get_alert_message' to accept a parameter 'dismiss' (defaults to true) which can be
used to prevent closing the alert message and instead will just return the alerts text.
Also created new keyword 'dismiss_alert' to dismiss (default) or confirm the alert without
reading the text of the alert.
[KingWarin]
- Added new keyword Input Text Into Prompt

- Added new keyword Input Text Into Prompt
[boakley][ekasteel]

- Fixed issue that caused tests to fail when selenium > 2.26
Expand Down
12 changes: 11 additions & 1 deletion src/Selenium2Library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,13 @@ class Selenium2Library(
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
ROBOT_LIBRARY_VERSION = VERSION

def __init__(self, timeout=5.0, implicit_wait=0.0, run_on_failure='Capture Page Screenshot'):
def __init__(self,
timeout=5.0,
implicit_wait=0.0,
run_on_failure='Capture Page Screenshot',
screenshot_root_directory=None
):

"""Selenium2Library can be imported with optional arguments.
`timeout` is the default timeout used to wait for all waiting actions.
Expand All @@ -156,6 +162,9 @@ def __init__(self, timeout=5.0, implicit_wait=0.0, run_on_failure='Capture Page
`Register Keyword To Run On Failure` keyword for more information about this
functionality.
`screenshot_root_directory` specifies the default root directory that screenshots should be
stored in. If not provided the default directory will be where robotframework places its logfile.
Examples:
| Library `|` Selenium2Library `|` 15 | # Sets default timeout to 15 seconds |
| Library `|` Selenium2Library `|` 0 `|` 5 | # Sets default timeout to 0 seconds and default implicit_wait to 5 seconds |
Expand All @@ -165,6 +174,7 @@ def __init__(self, timeout=5.0, implicit_wait=0.0, run_on_failure='Capture Page
"""
for base in Selenium2Library.__bases__:
base.__init__(self)
self.screenshot_root_directory = screenshot_root_directory
self.set_selenium_timeout(timeout)
self.set_selenium_implicit_wait(implicit_wait)
self.register_keyword_to_run_on_failure(run_on_failure)
Expand Down
3 changes: 2 additions & 1 deletion src/Selenium2Library/keywords/_logging.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os
import sys
from robot.libraries.BuiltIn import BuiltIn
from robot.api import logger
from keywordgroup import KeywordGroup
from robot.libraries.BuiltIn import BuiltIn

class _LoggingKeywords(KeywordGroup):

Expand All @@ -13,6 +13,7 @@ def _debug(self, message):

def _get_log_dir(self):
variables = BuiltIn().get_variables()

logfile = variables['${LOG FILE}']
if logfile != 'NONE':
return os.path.dirname(logfile)
Expand Down
71 changes: 57 additions & 14 deletions src/Selenium2Library/keywords/_screenshot.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import os, errno
import robot
import os, errno

from Selenium2Library import utils
from keywordgroup import KeywordGroup
from robot.libraries.BuiltIn import RobotNotRunningError


class _ScreenshotKeywords(KeywordGroup):

def __init__(self):
self._screenshot_index = 0
self._screenshot_path_stack = []
self.screenshot_root_directory = None

# Public

def set_screenshot_directory(self, path, persist=False):
"""Sets the root output directory for captured screenshots.
``path`` argument specifies the location to where the screenshots should
be written to. If the specified ``path`` does not exist, it will be created.
Setting ``persist`` specifies that the given ``path`` should
be used for the rest of the test execution, otherwise the path will be restored
at the end of the currently executing scope.
"""
self._create_directory(path)
if persist is False:
self._screenshot_path_stack.append(self.screenshot_root_directory)
# Restore after current scope ends
utils.events.on('scope_end', 'current', self._restore_screenshot_directory)

self.screenshot_root_directory = path

def capture_page_screenshot(self, filename=None):
"""Takes a screenshot of the current page and embeds it into the log.
Expand All @@ -18,22 +41,14 @@ def capture_page_screenshot(self, filename=None):
the Robot Framework log file is written into. The `filename` is
also considered relative to the same directory, if it is not
given in absolute format. If an absolute or relative path is given
but the path does not exist it will be created.
but the path does not exist it will be created.
`css` can be used to modify how the screenshot is taken. By default
the bakground color is changed to avoid possible problems with
background leaking when the page layout is somehow broken.
"""
path, link = self._get_screenshot_paths(filename)

target_dir = os.path.dirname(path)
if not os.path.exists(target_dir):
try:
os.makedirs(target_dir)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(target_dir):
pass
else: raise
self._create_directory(path)

if hasattr(self._current_browser(), 'get_screenshot_as_file'):
if not self._current_browser().get_screenshot_as_file(path):
Expand All @@ -47,14 +62,42 @@ def capture_page_screenshot(self, filename=None):
'<img src="%s" width="800px"></a>' % (link, link))

# Private
def _create_directory(self, path):
target_dir = os.path.dirname(path)
if not os.path.exists(target_dir):
try:
os.makedirs(target_dir)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(target_dir):
pass
else:
raise

def _get_screenshot_directory(self):

# Use screenshot root directory if set
if self.screenshot_root_directory is not None:
return self.screenshot_root_directory

# Otherwise use RF's log directory
try:
return self._get_log_dir()

# Unless robotframework isn't running, then use working directory
except RobotNotRunningError:
return os.getcwd()

# should only be called by set_screenshot_directory
def _restore_screenshot_directory(self):
self.screenshot_root_directory = self._screenshot_path_stack.pop()

def _get_screenshot_paths(self, filename):
if not filename:
self._screenshot_index += 1
filename = 'selenium-screenshot-%d.png' % self._screenshot_index
else:
filename = filename.replace('/', os.sep)
logdir = self._get_log_dir()
path = os.path.join(logdir, filename)
link = robot.utils.get_link_path(path, logdir)
screenshotDir = self._get_screenshot_directory()
path = os.path.join(screenshotDir, filename)
link = robot.utils.get_link_path(path, screenshotDir)
return path, link
6 changes: 1 addition & 5 deletions src/Selenium2Library/locators/elementfinder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from Selenium2Library import utils
from robot.api import logger
from robot.utils import NormalizedDict
from robot.libraries.BuiltIn import BuiltIn


class ElementFinder(object):
Expand Down Expand Up @@ -45,10 +44,7 @@ def register(self, strategy, persist):

if not persist:
# Unregister after current scope ends
suite = BuiltIn().get_variable_value('${SUITE NAME}')
test = BuiltIn().get_variable_value('${TEST NAME}', '')
scope = suite + '.' + test if test != '' else suite
utils.events.on('scope_end', scope, self.unregister, strategy.name)
utils.events.on('scope_end', 'current', self.unregister, strategy.name)

def unregister(self, strategy_name):
if strategy_name in self._default_strategies:
Expand Down
6 changes: 6 additions & 0 deletions src/Selenium2Library/utils/events/scope_event.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from event import Event
from robot.libraries.BuiltIn import BuiltIn

class ScopeEvent(Event):
def __init__(self, scope, action, *args, **kwargs):
Expand All @@ -7,6 +8,11 @@ def __init__(self, scope, action, *args, **kwargs):
self.action_args = args
self.action_kwargs = kwargs

if scope == 'current':
suite = BuiltIn().get_variable_value('${SUITE NAME}')
test = BuiltIn().get_variable_value('${TEST NAME}', '')
self.scope = suite + '.' + test if test != '' else suite

def trigger(self, *args, **kwargs):
if args[0] == self.scope:
self.action(*self.action_args, **self.action_kwargs)
Expand Down
11 changes: 11 additions & 0 deletions test/acceptance/keywords/screenshots.robot
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,14 @@ Capture page screenshot to non-existing directory
[Setup] Remove Directory ${OUTPUTDIR}/screenshot recursive
Capture Page Screenshot screenshot/test-screenshot.png
File Should Exist ${OUTPUTDIR}/screenshot/test-screenshot.png

Capture page screenshot to custom root directory
[Setup] Remove Directory ${OUTPUTDIR}/screenshot recursive
Set Screenshot Directory ${OUTPUTDIR}/screenshot
Capture Page Screenshot custom-root-screenshot.png
File Should Exist ${OUTPUTDIR}/screenshot/custom-root-screenshot.png

Ensure screenshot captures revert to default root directory
[Setup] Remove Files ${OUTPUTDIR}/default-root-screenshot.png
Capture Page Screenshot default-root-screenshot.png
File Should Exist ${OUTPUTDIR}/default-root-screenshot.png

0 comments on commit d88545d

Please sign in to comment.