示例#1
0
def run(filename,
        suite,
        as_str=None,
        scenario=r'.*',
        verbose=False,
        show_all_missing=True,
        **kwargs):  # NOQA
    """Parse file and run tests on given suite.

    :param str filename: file name
    :param unittest.TestCase suite: TestCase instance
    :param string as_str: None to use file or a string containing the feature to parse
    :param string scenario: a regex pattern to match the scenario to run
    :param boolean verbose: be verbose
    :param boolean show_all_missing: show all missing steps
    """
    formatter = kwargs.get('formatter', None)
    if verbose and not formatter:
        if has_color_support():
            formatter = ColorTextFormatter()
        else:
            formatter = PlainTextFormatter()
        kwargs['formatter'] = formatter
    kwargs['show_all_missing'] = show_all_missing
    parser = Parser()
    ast = parser.parse_file(filename, scenario=scenario) if as_str is None \
        else parser.parse_as_str(filename, as_str, scenario=scenario)
    return ast.evaluate(suite, **kwargs)
示例#2
0
 def test_should_report_on_all_failing_scenarios(self):
     self._add_failure_pattern = re.compile('Scenario: Add two numbers\n\s*Then the result should be "120" on the screen\n\s*.*AssertionError:\s*70 != 120', re.DOTALL)
     self._substract_failure_pattern = re.compile('Scenario: Subtract two numbers\n\s*Then the result should be "80" on the screen\n\s*.*AssertionError:\s*70 != 80', re.DOTALL)
     self._multiply_failure_pattern = re.compile('Scenario: Multiply two numbers\n\s*Then the result should be "12" on the screen\n\s*.*AssertionError:\s*3 != 12', re.DOTALL)
     self._division_failure_pattern = re.compile('Scenario: Divide two numbers\n\s*Then the result should be "4" on the screen\n\s*.*AssertionError:\s*2 != 4', re.DOTALL)
     filename = os.path.join(pwd, 'features/info_on_all_failing_scenarios.feature')
     ast = Parser().parse_file(filename)
     ast.evaluate(self)
示例#3
0
    def step_Morelia_evaluates_the_file(self):
        self.diagnostic = None

        try:
            language = self._get_language()
            p = Parser(language=language)
            self.file_contents.replace('\\#', '#')  # note - this is how to unescape characters - DIY
            prefix = u'{}: Sample\n{}: Sample\n'.format(self.feature_keyword, self.scenario_keyword)
            p.parse_features(prefix + self.file_contents).evaluate(self)
        except (MissingStepError, AssertionError) as e:
            self.diagnostic = str(e)
示例#4
0
    def step_Morelia_evaluates_the_file(self):
        self.diagnostic = None

        try:
            p = Parser()
            self.file_contents.replace(
                "\\#", "#")  # note - this is how to unescape characters - DIY
            prefix = "Feature: Sample\nScenario: Sample\n"
            feature = p.parse_features(prefix + self.file_contents)
            execute_script(feature, self)
        except (MissingStepError, AssertionError) as e:
            self.diagnostic = str(e)
示例#5
0
    def step_Morelia_evaluates_the_file(self):
        self.diagnostic = None

        try:
            p = Parser()
            self.file_contents.replace(
                "\\#", "#"
            )  # note - this is how to unescape characters - DIY
            prefix = "Feature: Sample\nScenario: Sample\n"
            feature = p.parse_features(prefix + self.file_contents)
            execute_script(feature, self)
        except (MissingStepError, AssertionError) as e:
            self.diagnostic = str(e)
示例#6
0
    def step_a_file_contains_statements_produce_diagnostics_(self, statements, diagnostics):
        r'a file contains (.+), it produces (.+)'

        try:
            statements = statements.replace('\\n', '\n')
            statements = statements.replace('\\', '')
            language = self._get_language()
            p = Parser(language=language).parse_features(statements)
            p.evaluate(self)
            raise Exception('we expect syntax errors here')  # pragma: nocover
        except (SyntaxError, AssertionError) as e:
            e = e.args[0]
            self.assert_regex_contains(re.escape(diagnostics), e)
示例#7
0
    def step_Morelia_evaluates_the_file(self):
        self.diagnostic = None

        try:
            language = self._get_language()
            p = Parser(language=language)
            self.file_contents.replace(
                '\\#', '#')  # note - this is how to unescape characters - DIY
            prefix = u'{}: Sample\n{}: Sample\n'.format(
                self.feature_keyword, self.scenario_keyword)
            p.parse_features(prefix + self.file_contents).evaluate(self)
        except (MissingStepError, AssertionError) as e:
            self.diagnostic = str(e)
示例#8
0
    def step_a_file_contains_statements_produce_diagnostics_(
            self, statements, diagnostics):
        r'a file contains (.+), it produces (.+)'

        try:
            statements = statements.replace('\\n', '\n')
            statements = statements.replace('\\', '')
            language = self._get_language()
            p = Parser(language=language).parse_features(statements)
            p.evaluate(self)
            raise Exception('we expect syntax errors here')  # pragma: nocover
        except (SyntaxError, AssertionError) as e:
            e = e.args[0]
            self.assert_regex_contains(re.escape(diagnostics), e)
示例#9
0
    def test_fail_informatively_on_bad_scenario_regex(self):
        filename = os.path.join(pwd, 'features/scenario_matching.feature')
        self._matching_pattern = '\\'

        with self.assertRaises(SyntaxError):
            self._ast = Parser().parse_file(filename,
                                            scenario=self._matching_pattern)
示例#10
0
def run(filename,
        suite,
        as_str=None,
        scenario=r".*",
        verbose=False,
        show_all_missing=True,
        **kwargs):  # NOQA
    """Parse file and run tests on given suite.

    :param str filename: file name
    :param unittest.TestCase suite: TestCase instance
    :param string as_str: None to use file or a string containing the feature to parse
    :param string scenario: a regex pattern to match the scenario to run
    :param boolean verbose: be verbose
    :param boolean show_all_missing: show all missing steps
    """
    formatter = kwargs.get("formatter", None)
    if verbose and not formatter:
        if has_color_support():
            formatter = ColorTextFormatter()
        else:
            formatter = PlainTextFormatter()
        kwargs["formatter"] = formatter
    kwargs["show_all_missing"] = show_all_missing
    if as_str is None:
        source = File(filename)
    else:
        source = Text(as_str, filename)
    feature = Parser().parse_features(source)
    return execute_script(feature, suite, scenario=scenario, **kwargs)
示例#11
0
 def test_record_filename(self):
     filename = features_dir / "morelia.feature"
     feature = Parser().parse_features(File(filename))
     assert feature.__class__ == Feature
     assert str(filename) == feature.filename
     step = feature.steps[3].steps[1]
     assert str(filename) == step.get_filename()
示例#12
0
 def test_deal_with_pesky_carriage_returns(
         self):  # because Morse Code will live forever!
     source = "Given a string with spacies and   \r\n  another string  "
     steps = Parser().parse_feature(source)
     step = steps[0]
     assert isinstance(step, Given)
     assert step.predicate == "a string with spacies and\nanother string"
示例#13
0
 def test_step_multiline_predicate(self):
     feature = '%s multiline predicate' % self.when_keyword
     language = self._get_language()
     steps = Parser(language=language).parse_feature(feature)
     matcher = self._get_default_machers()
     visitor = TestVisitor(self, matcher, NullFormatter())
     visitor.visit(steps[0])
示例#14
0
 def test_given_a_string_with_given_in_it(self):
     source = "Given a string with Given in it   \nAnd another string"
     steps = Parser().parse_feature(source)  # ^ note the spacies
     step = steps[0]
     assert isinstance(step, Given)
     assert (step.predicate == "a string with Given in it"
             )  # <-- note spacies are gone
示例#15
0
 def test_two_dimensional_table_reconstruction(self):
     language = self._get_language()
     p = Parser(language=language).parse_features(
         self.assemble_short_scene_table())
     step = p.steps[0].steps[0].steps[0]
     self.assertEqual(step.keyword + ': ' + step.predicate,
                      step.reconstruction().strip())
示例#16
0
 def test_language_directive(self):
     input = '# language: pl\n%s: prevent wild animals from eating us' % self.feature_keyword
     steps = Parser().parse_feature(input)
     step = steps[0]
     assert step.__class__ == Feature
     self.assertEqual(step.keyword, self.feature_keyword)
     self.assertEqual(step.predicate, 'prevent wild animals from eating us')
示例#17
0
 def test___scenario(self):
     input = '  %s: with spacies' % self.scenario_keyword
     language = self._get_language()
     steps = Parser(language=language).parse_feature(input)
     step = steps[0]
     assert step.__class__ == Scenario
     self.assertEqual(step.keyword, self.scenario_keyword)
     self.assertEqual(step.predicate, 'with spacies')
示例#18
0
 def test_feature(self):
     language = self._get_language()
     input = '%s: prevent wild animals from eating us' % self.feature_keyword
     steps = Parser(language=language).parse_feature(input)
     step = steps[0]
     assert step.__class__ == Feature
     self.assertEqual(step.keyword, self.feature_keyword)
     self.assertEqual(step.predicate, 'prevent wild animals from eating us')
示例#19
0
 def test_given_a_string_with_a_line_breaker_followed_by_a_keyword(self):
     source = "Given a string \\\n And another string"
     steps = Parser().parse_feature(source)
     assert 1 == len(steps)
     step = steps[0]
     assert isinstance(step, Given)
     assert step.source == "Given a string \\\n And another string"
     assert step.predicate == "a string \\\n And another string"
示例#20
0
    def test_feature_with_lone_comment(self):
        input = 'i be a newbie feature'
        language = self._get_language()
        p = Parser(language=language)

        try:
            p.parse_feature(input)
            assert False  # should fail!  # pragma: nocover
        except SyntaxError as e:
            e = e.args[0]
            try:
                feature_name = TRANSLATIONS[language].get('feature', self.feature_keyword)
            except KeyError:
                feature_name = self.feature_keyword
            else:
                feature_name = feature_name.replace('|', ' or ')
            self.assert_regex_contains(r'feature files must start with a %s' % feature_name, e)
示例#21
0
 def test_record_filename(self):
     language = self._get_language()
     filename = pwd + '/features/morelia%s.feature' % (language or '')
     thang = Parser(language=language).parse_file(filename)
     feature = thang.steps[0]
     assert feature.__class__ == Feature
     assert feature.filename == filename
     step = feature.steps[3].steps[1]
     assert filename == step.get_filename()
示例#22
0
 def test_two_dimensional_table(self):
     global elements, factions
     elements = []
     factions = []
     language = self._get_language()
     Parser(language=language).parse_features(
         self.assemble_short_scene_table()).evaluate(self)
     self.assertEqual([['Pangolin', 'Glyptodon'], ['Pangea', 'Laurasia']],
                      [factions, elements])
示例#23
0
 def test_given_a_broken_string_with_excess_spacies(self):
     input = '%s a string with spacies and   \n  another string  ' % self.given_keyword
     language = self._get_language()
     steps = Parser(language=language).parse_feature(input)
     step = steps[0]
     assert step.__class__ == Given
     self.assertEqual(step.keyword, self.given_keyword)
     self.assertEqual(step.predicate,
                      'a string with spacies and\nanother string')
示例#24
0
 def test_should_only_run_matching_scenarios(self):
     filename = os.path.join(pwd, 'features/scenario_matching.feature')
     self._matching_pattern = r'Scenario Matches [12]'
     self._ast = Parser().parse_file(filename,
                                     scenario=self._matching_pattern)
     scenario_matcher_re = re.compile(self._matching_pattern)
     for included_scenario in self._ast.steps[0].steps:
         self.assertIsNotNone(
             scenario_matcher_re.match(included_scenario.predicate))
示例#25
0
 def test_deal_with_pesky_carriage_returns(
         self):  # because Morse Code will live forever!
     input = '%s a string with spacies and   \r\n  another string  ' % self.given_keyword
     language = self._get_language()
     steps = Parser(language=language).parse_feature(input)
     step = steps[0]
     assert step.__class__ == Given
     self.assertEqual(step.keyword, self.given_keyword)
     self.assertEqual(step.predicate,
                      'a string with spacies and\nanother string')
示例#26
0
    def test_file_without_feature_defined(self):
        input = 'i be a newbie feature'
        language = self._get_language()
        p = Parser(language=language)

        try:
            p.parse_feature(input)
            assert False  # should fail!  # pragma: nocover
        except SyntaxError as e:
            e = e.args[0]
            try:
                feature_name = TRANSLATIONS[language].get(
                    'feature', self.feature_keyword)
            except KeyError:
                feature_name = self.feature_keyword
            else:
                feature_name = feature_name.replace('|', ' or ')
            self.assert_regex_contains(
                r'feature files must start with a %s' % feature_name, e)
示例#27
0
 def test_scenario_with_steps_is_parsed(self):
     scenario = self.__sample_scenario()
     steps = Parser().parse_feature(scenario)
     scenario, given_step, and_step, when_step, then_step = steps
     assert scenario.predicate == "See all vendors"
     assert (given_step.predicate ==
             "I am logged in as a user in the administrator role")
     assert and_step.predicate == "There are 3 vendors"
     assert when_step.predicate == "I go to the manage vendors page"
     assert then_step.predicate == "I should see the first 3 vendor names"
示例#28
0
 def test_feature_with_scenario(self):
     source = """Feature: Civi-lie-zation
                Scenario: starz upon tharz bucks"""
     steps = Parser().parse_feature(source)
     step = steps[0]
     assert isinstance(step, Feature)
     assert step.predicate == "Civi-lie-zation"
     step = steps[1]
     assert isinstance(step, Scenario)
     assert step.predicate == "starz upon tharz bucks"
示例#29
0
    def test_feature_with_long_comment(self):  # ERGO how to detect shadowed test cases??
        language = self._get_language()
        p = Parser(language=language)

        input = '''%s: The Sacred Giant Mosquito of the Andes
                   #  at http://www.onagocag.com/nazbird.jpg
                        so pay no attention to the skeptics!''' % self.feature_keyword
        try:
            p.parse_feature(input)
            assert False  # should raise a SyntaxError  # pragma: nocover
        except SyntaxError as e:
            self.assert_regex_contains('linefeed in comment', str(e))
            self.assert_regex_contains('line 2', str(e))

        steps = p.steps
        assert steps[0].__class__ == Feature
        step = steps[1]
        assert step.__class__ == Comment
        self.assertEqual(step.keyword, '#')
示例#30
0
    def test_feature_with_long_comment(
            self):  # ERGO how to detect shadowed test cases??
        language = self._get_language()
        p = Parser(language=language)

        input = '''%s: The Sacred Giant Mosquito of the Andes
                   #  at http://www.onagocag.com/nazbird.jpg
                        so pay no attention to the skeptics!''' % self.feature_keyword
        try:
            p.parse_feature(input)
            assert False  # should raise a SyntaxError  # pragma: nocover
        except SyntaxError as e:
            self.assert_regex_contains('linefeed in comment', str(e))
            self.assert_regex_contains('line 2', str(e))

        steps = p.steps
        assert steps[0].__class__ == Feature
        step = steps[1]
        assert step.__class__ == Comment
        self.assertEqual(step.keyword, '#')
示例#31
0
 def test_given_a_string_with_a_line_breaker_followed_by_a_keyword(self):
     input = '%(given)s a string \\\n And another string' % {
         'given': self.given_keyword,
         'and': self.and_keyword,
     }
     language = self._get_language()
     steps = Parser(language=language).parse_feature(input)
     assert 1 == len(steps)
     step = steps[0]
     assert step.__class__ == Given
     self.assertEqual(step.keyword, self.given_keyword)
     self.assertEqual(step.predicate, 'a string \\\n And another string')
示例#32
0
 def test_another_two_dimensional_table(self):
     global crunks, zones
     crunks = []
     zones = []
     scene = self.assemble_scene_table_source(
         'Step my milkshake brings all the boys to the yard\n')
     language = self._get_language()
     Parser(language=language).parse_features(scene).evaluate(self)
     self.assertEqual(['work', 'mall', 'jail', 'work', 'mall', 'jail'],
                      crunks)
     self.assertEqual(
         ['beach', 'beach', 'beach', 'hotel', 'hotel', 'hotel'], zones)
示例#33
0
 def step_a_file_contains_statements_produce_diagnostics_(
         self, statements, diagnostics):
     r"a file contains (.+), it produces (.+)"
     try:
         statements = statements.replace("\\n", "\n")
         statements = statements.replace("\\", "")
         feature = Parser().parse_features(statements)
         execute_script(feature, self)
         raise Exception("we expect syntax errors here")  # pragma: nocover
     except (SyntaxError, AssertionError) as e:
         e = e.args[0]
         self.assert_regex_contains(re.escape(diagnostics), e)
示例#34
0
 def test_given_a_string_with_given_in_it(self):
     input = '%(given)s a string with Given in it   \n%(and)s another string' % {
         'given': self.given_keyword,
         'and': self.and_keyword,
     }
     language = self._get_language()
     steps = Parser(language=language).parse_feature(
         input)  # ^ note the spacies
     step = steps[0]
     assert step.__class__ == Given
     self.assertEqual(step.keyword, self.given_keyword)
     self.assertEqual(
         step.predicate,
         'a string with Given in it')  # <-- note spacies are gone
示例#35
0
    def test_format_faults_like_python_errors(self):
        language = self._get_language()
        filename = pwd + '/features/morelia%s.feature' % (language or '')
        thang = Parser(language=language).parse_file(filename)
        step = thang.steps[0].steps[3].steps[1]
        assert filename == step.get_filename()
        omen = 'The Alpine glaciers move'
        diagnostic = step.format_fault(omen)
        parent_reconstruction = step.parent.reconstruction().strip('\n')
        reconstruction = step.reconstruction()

        expect = '\n  File "%s", line %s, in %s\n %s\n%s' % \
            (step.get_filename(), step.line_number, parent_reconstruction, reconstruction, omen)

        assert expect == diagnostic
示例#36
0
 def test_feature_with_scenario(self):
     input = '''%(feature)s: Civi-lie-zation
                %(scenario)s: starz upon tharz bucks''' % {
         'feature': self.feature_keyword,
         'scenario': self.scenario_keyword,
     }
     language = self._get_language()
     steps = Parser(language=language).parse_feature(input)
     step = steps[0]
     assert step.__class__ == Feature
     self.assertEqual(step.keyword, self.feature_keyword)
     self.assertEqual(step.predicate, 'Civi-lie-zation')
     step = steps[1]
     assert step.__class__ == Scenario
     self.assertEqual(step.keyword, self.scenario_keyword)
     self.assertEqual(step.predicate, 'starz upon tharz bucks')
示例#37
0
 def test_labels(self):
     filename = os.path.join(pwd, 'features/labels.feature')
     ast = Parser().parse_file(filename)
     ast.evaluate(self, show_all_missing=True)
示例#38
0
 def test_many_test_methods(self):
     """Check setUp/tearDown when many tests in one TestCase."""
     filename = os.path.join(pwd, 'features/setupteardown.feature')
     ast = Parser().parse_file(filename)
     ast.evaluate(self, show_all_missing=True)
示例#39
0
 def test_setup_teardown(self):
     """Check for multiple setUp/tearDown calls."""
     filename = os.path.join(pwd, 'features/setupteardown.feature')
     ast = Parser().parse_file(filename)
     ast.evaluate(self, show_all_missing=True)
示例#40
0
 def test_docstrings_should_be_passed_as_text_to_step(self):
     filename = os.path.join(pwd, 'features/docstrings.feature')
     ast = Parser().parse_file(filename)
     ast.evaluate(self, show_all_missing=True)
示例#41
0
class InfoOnAllFailingScenariosTest(TestCase):

    def test_should_report_on_all_failing_scenarios(self):
        self._add_failure_pattern = re.compile('Scenario: Add two numbers\n\s*Then the result should be "120" on the screen\n\s*.*AssertionError:\s*70 != 120', re.DOTALL)
        self._substract_failure_pattern = re.compile('Scenario: Subtract two numbers\n\s*Then the result should be "80" on the screen\n\s*.*AssertionError:\s*70 != 80', re.DOTALL)
        self._multiply_failure_pattern = re.compile('Scenario: Multiply two numbers\n\s*Then the result should be "12" on the screen\n\s*.*AssertionError:\s*3 != 12', re.DOTALL)
        self._division_failure_pattern = re.compile('Scenario: Divide two numbers\n\s*Then the result should be "4" on the screen\n\s*.*AssertionError:\s*2 != 4', re.DOTALL)
        filename = os.path.join(pwd, 'features/info_on_all_failing_scenarios.feature')
        ast = Parser().parse_file(filename)
        ast.evaluate(self)

    def step_feature_with_number_scenarios_has_been_described_in_file(self, feature_file):
        r'that feature with 4 scenarios has been described in file "([^"]+)"'
        filename = os.path.join(pwd, 'features/{}'.format(feature_file))
        self._ast = Parser().parse_file(filename)

    def step_that_test_case_passing_number_and_number_scenario_and_failing_number_and_number_has_been_written(self):
        r'that test case passing 1 and 3 scenario and failing 2 and 4 has been written'

        class _EvaluatedTestCase(SampleTestCaseMixIn, TestCase):

            def step_I_press_subtract(self):
                pass

            def step_I_press_divide(self):
                pass

        self._evaluated_test_case = _EvaluatedTestCase
        self._failing_patterns = [
            self._substract_failure_pattern,
            self._division_failure_pattern
        ]

    def step_that_test_case_failing_all_scenarios_been_written(self):
        r'that test case failing all scenarios been written'

        class _EvaluatedTestCase(SampleTestCaseMixIn, TestCase):

            def step_I_press_add(self):
                pass

            def step_I_press_subtract(self):
                pass

            def step_I_press_multiply(self):
                pass

            def step_I_press_divide(self):
                pass

        self._evaluated_test_case = _EvaluatedTestCase
        self._failing_patterns = [
            self._add_failure_pattern,
            self._substract_failure_pattern,
            self._multiply_failure_pattern,
            self._division_failure_pattern
        ]

    def step_that_test_case_passing_number_number_and_number_scenario_and_failing_number_has_been_written(self):
        r'that test case passing 2, 3 and 4 scenario and failing 1 has been written'

        class _EvaluatedTestCase(SampleTestCaseMixIn, TestCase):

            def step_I_press_add(self):
                pass

        self._evaluated_test_case = _EvaluatedTestCase
        self._failing_patterns = [
            self._add_failure_pattern,
        ]

    def step_that_test_case_passing_all_scenarios_been_written(self):
        r'that test case passing all scenarios been written'

        class _EvaluatedTestCase(SampleTestCaseMixIn, TestCase):
            pass

        self._evaluated_test_case = _EvaluatedTestCase

    def step_that_test_case_failing_number_number_and_number_scenario_and_passing_number_has_been_written(self):
        r'that test case failing 1, 2 and 3 scenario and passing 4 has been written'

        class _EvaluatedTestCase(SampleTestCaseMixIn, TestCase):

            def step_I_press_add(self):
                pass

            def step_I_press_subtract(self):
                pass

            def step_I_press_multiply(self):
                pass

        self._evaluated_test_case = _EvaluatedTestCase
        self._failing_patterns = [
            self._add_failure_pattern,
            self._substract_failure_pattern,
            self._multiply_failure_pattern,
        ]

    def step_I_run_test_case(self):
        r'I run test case'

        self._catch_exception = None
        try:
            tc = self._evaluated_test_case()
            self._ast.evaluate(tc)
        except Exception as e:
            self._catch_exception = e  # warning: possible leak, use with caution

    def step_I_will_get_assertion_error_with_information_number_scenarios_passed_number_scenarios_failed(self, message):
        r'I will get assertion error with information "([^"]+)"'

        message = self._catch_exception.args[0]
        self.assertTrue(message.startswith(message))

    def step_I_will_get_traceback_of_each_failing_scenario(self):
        r'I will get traceback of each failing scenario'

        patterns = self._failing_patterns
        message = self._catch_exception.args[0]
        for pattern in patterns:
            self.assertRegexpMatches(message, pattern)

    def step_I_won_t_get_assertion_error(self):
        r'I won\'t get assertion error'

        self.assertIsNone(self._catch_exception)
示例#42
0
 def test_evaluate_file(self):
     language = self._get_language()
     thang = Parser(language=language).parse_file(pwd + '/features/morelia%s.feature' % (language or ''))
     thang.evaluate(self)
示例#43
0
 def assemble_scene_table(self, moar=''):
     scene = self.assemble_scene_table_source(moar)
     language = self._get_language()
     p = Parser(language=language)
     self.table_scene = p.parse_features(scene)
示例#44
0
 def test_parse_feature_Row(self):
     language = self._get_language()
     p = Parser(language=language)
     p.parse_feature(''' | piggy | op |''')
     assert Row == p.steps[0].__class__
     assert p.steps[0].predicate == 'piggy | op |'
示例#45
0
 def step_feature_with_number_scenarios_has_been_described_in_file(self, feature_file):
     r'that feature with 4 scenarios has been described in file "([^"]+)"'
     filename = os.path.join(pwd, 'features/{}'.format(feature_file))
     self._ast = Parser().parse_file(filename)