blob: 2f64afc956d9bdca0e3a13d8bf65680fceb4428b [file] [log] [blame]
# coding=utf-8
"""
BDD lettuce framework runner
TODO: Support other params (like tags) as well.
Supports only 2 params now: folder to search "features" for or file and "-s scenario_index"
"""
import argparse
import os
import _bdd_utils
__author__ = 'Ilya.Kazakevich'
from lettuce.exceptions import ReasonToFail
import lettuce
from lettuce import core
class _LettuceRunner(_bdd_utils.BddRunner):
"""
Lettuce runner (BddRunner for lettuce)
"""
def __init__(self, base_dir, what_to_run, scenarios):
"""
:param scenarios scenario numbers to run
:type scenarios list
:param base_dir base directory to run tests in
:type base_dir: str
:param what_to_run folder or file to run
:type what_to_run str
"""
super(_LettuceRunner, self).__init__(base_dir)
self.__runner = lettuce.Runner(what_to_run, ",".join(scenarios))
def _get_features_to_run(self):
super(_LettuceRunner, self)._get_features_to_run()
features = []
if self.__runner.single_feature: # We need to run one and only one feature
features = [core.Feature.from_file(self.__runner.single_feature)]
else:
# Find all features in dir
for feature_file in self.__runner.loader.find_feature_files():
feature = core.Feature.from_file(feature_file)
assert isinstance(feature, core.Feature), feature
# TODO: cut out due to https://github.com/gabrielfalcao/lettuce/issues/451 Fix when this issue fixed
feature.scenarios = filter(lambda s: not s.outlines, feature.scenarios)
if feature.scenarios:
features.append(feature)
# Choose only selected scenarios
if self.__runner.scenarios:
for feature in features:
filtered_feature_scenarios = []
for index in [i - 1 for i in self.__runner.scenarios]: # decrease index by 1
if index < len(feature.scenarios):
filtered_feature_scenarios.append(feature.scenarios[index])
feature.scenarios = filtered_feature_scenarios
return features
def _run_tests(self):
super(_LettuceRunner, self)._run_tests()
self.__install_hooks()
self.__runner.run()
def __step(self, is_started, step):
"""
Reports step start / stop
:type step core.Step
:param step: step
"""
test_name = step.sentence
if is_started:
self._test_started(test_name, step.described_at)
elif step.passed:
self._test_passed(test_name)
elif step.failed:
reason = step.why
assert isinstance(reason, ReasonToFail), reason
self._test_failed(test_name, message=reason.exception, details=reason.traceback)
elif step.has_definition:
self._test_skipped(test_name, "In lettuce, we do know the reason", step.described_at)
else:
self._test_undefined(test_name, step.described_at)
def __install_hooks(self):
"""
Installs required hooks
"""
# Install hooks
lettuce.before.each_feature(
lambda f: self._feature_or_scenario(True, f.name, f.described_at))
lettuce.after.each_feature(
lambda f: self._feature_or_scenario(False, f.name, f.described_at))
lettuce.before.each_scenario(
lambda s: self.__scenario(True, s))
lettuce.after.each_scenario(
lambda s: self.__scenario(False, s))
lettuce.before.each_background(
lambda b, *args: self._background(True, b.feature.described_at))
lettuce.after.each_background(
lambda b, *args: self._background(False, b.feature.described_at))
lettuce.before.each_step(lambda s: self.__step(True, s))
lettuce.after.each_step(lambda s: self.__step(False, s))
def __scenario(self, is_started, scenario):
"""
Reports scenario launched
:type scenario core.Scenario
:param scenario: scenario
"""
if scenario.outlines:
scenario.steps = [] # Clear to prevent running. TODO: Fix when this issue fixed
scenario.background = None # TODO: undocumented
return
self._feature_or_scenario(is_started, scenario.name, scenario.described_at)
if __name__ == "__main__":
(base_dir, scenarios, what_to_run) = _bdd_utils.get_what_to_run_by_env(os.environ)
if len(what_to_run) > 1:
raise Exception("Lettuce can't run more than one file now")
_bdd_utils.fix_win_drive(what_to_run[0])
_LettuceRunner(base_dir, what_to_run[0], scenarios).run()