diff --git a/pytest_bdd/gherkin_terminal_reporter.py b/pytest_bdd/gherkin_terminal_reporter.py index 3e3623bb..76b90fd9 100644 --- a/pytest_bdd/gherkin_terminal_reporter.py +++ b/pytest_bdd/gherkin_terminal_reporter.py @@ -54,37 +54,25 @@ def pytest_runtest_logreport(self, report): word_markup = {"red": True} elif rep.skipped: word_markup = {"yellow": True} - feature_markup = {"blue": True} scenario_markup = word_markup - if self.verbosity <= 0: - return super().pytest_runtest_logreport(rep) - elif self.verbosity == 1: - if hasattr(report, "scenario"): - self.ensure_newline() - self._tw.write("Feature: ", **feature_markup) - self._tw.write(report.scenario["feature"]["name"], **feature_markup) - self._tw.write("\n") - self._tw.write(" Scenario: ", **scenario_markup) - self._tw.write(report.scenario["name"], **scenario_markup) - self._tw.write(" ") - self._tw.write(word, **word_markup) - self._tw.write("\n") - else: - return super().pytest_runtest_logreport(rep) - elif self.verbosity > 1: - if hasattr(report, "scenario"): - self.ensure_newline() - self._tw.write("Feature: ", **feature_markup) - self._tw.write(report.scenario["feature"]["name"], **feature_markup) - self._tw.write("\n") - self._tw.write(" Scenario: ", **scenario_markup) - self._tw.write(report.scenario["name"], **scenario_markup) - self._tw.write("\n") - for step in report.scenario["steps"]: - self._tw.write(f" {step['keyword']} {step['name']}\n", **scenario_markup) - self._tw.write(" " + word, **word_markup) - self._tw.write("\n\n") - else: - return super().pytest_runtest_logreport(rep) + if self.verbosity <= 0 or not hasattr(report, "scenario"): + return super().pytest_runtest_logreport(report) + + scenario = report.scenario + self.ensure_newline() + self._tw.write(f"Feature: {scenario['feature']['name']}\n", blue=True) + self._tw.write(f" Scenario: {scenario['name']}", **scenario_markup) + if self.verbosity > 1: + self._tw.write("\n") + has_already_failed = False + for step in scenario["steps"]: + step_markup = {"red" if step["failed"] else "green": True} + # Highlight first failed step + if step["failed"] and not has_already_failed: + step_markup["bold"] = True + has_already_failed = True + step_status_text = "(FAILED)" if step["failed"] else "(PASSED)" + self._tw.write(f" {step['keyword']} {step['name']} {step_status_text}\n", **step_markup) + self._tw.write(f" {word}\n", **word_markup) self.stats.setdefault(cat, []).append(rep) diff --git a/tests/feature/test_gherkin_terminal_reporter.py b/tests/feature/test_gherkin_terminal_reporter.py index 52946bfe..788639ed 100644 --- a/tests/feature/test_gherkin_terminal_reporter.py +++ b/tests/feature/test_gherkin_terminal_reporter.py @@ -55,7 +55,7 @@ def test_verbose_mode_should_display_feature_and_scenario_names_instead_of_test_ result = testdir.runpytest("--gherkin-terminal-reporter", "-v") result.assert_outcomes(passed=1, failed=0) result.stdout.fnmatch_lines("Feature: Gherkin terminal output feature") - result.stdout.fnmatch_lines("*Scenario: Scenario example 1 PASSED") + result.stdout.fnmatch_lines("*Scenario: Scenario example 1 PASSED") def test_verbose_mode_should_preserve_displaying_regular_tests_as_usual(testdir): @@ -85,9 +85,9 @@ def test_double_verbose_mode_should_display_full_scenario_description(testdir): result.assert_outcomes(passed=1, failed=0) result.stdout.fnmatch_lines("*Scenario: Scenario example 1") - result.stdout.fnmatch_lines("*Given there is a bar") - result.stdout.fnmatch_lines("*When the bar is accessed") - result.stdout.fnmatch_lines("*Then world explodes") + result.stdout.fnmatch_lines("*Given there is a bar (PASSED)") + result.stdout.fnmatch_lines("*When the bar is accessed (PASSED)") + result.stdout.fnmatch_lines("*Then world explodes (PASSED)") result.stdout.fnmatch_lines("*PASSED") @@ -228,7 +228,7 @@ def test_scenario_2(): result = testdir.runpytest("--gherkin-terminal-reporter", "-vv") result.assert_outcomes(passed=1, failed=0) result.stdout.fnmatch_lines("*Scenario: Scenario example 2") - result.stdout.fnmatch_lines("*Given there are {start} cucumbers".format(**example)) - result.stdout.fnmatch_lines("*When I eat {eat} cucumbers".format(**example)) - result.stdout.fnmatch_lines("*Then I should have {left} cucumbers".format(**example)) + result.stdout.fnmatch_lines("*Given there are {start} cucumbers (PASSED)".format(**example)) + result.stdout.fnmatch_lines("*When I eat {eat} cucumbers (PASSED)".format(**example)) + result.stdout.fnmatch_lines("*Then I should have {left} cucumbers (PASSED)".format(**example)) result.stdout.fnmatch_lines("*PASSED")