From b0df87842ef77feb8f75bb5389701e8282791411 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 6 Jun 2016 23:09:19 +0200 Subject: [PATCH] Show BDD scenario on failed tests See #1552 --- qutebrowser/utils/log.py | 20 ++++------ tests/end2end/features/conftest.py | 61 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py index 3fe844469..25ba515b5 100644 --- a/qutebrowser/utils/log.py +++ b/qutebrowser/utils/log.py @@ -38,6 +38,10 @@ except ImportError: colorama = None COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'purple', 'cyan', 'white'] +COLOR_ESCAPES = {color: '\033[{}m'.format(i) + for i, color in enumerate(COLORS, start=30)} +RESET_ESCAPE = '\033[0m' + # Log formats to use. SIMPLE_FMT = ('{green}{asctime:8}{reset} {log_color}{levelname}{reset}: ' @@ -473,28 +477,20 @@ class ColoredFormatter(logging.Formatter): Attributes: use_colors: Whether to do colored logging or not. - - Class attributes: - COLOR_ESCAPES: A dict mapping color names to escape sequences - RESET_ESCAPE: The escape sequence using for resetting colors """ - COLOR_ESCAPES = {color: '\033[{}m'.format(i) - for i, color in enumerate(COLORS, start=30)} - RESET_ESCAPE = '\033[0m' - def __init__(self, fmt, datefmt, style, *, use_colors): super().__init__(fmt, datefmt, style) self._use_colors = use_colors def format(self, record): if self._use_colors: - color_dict = dict(self.COLOR_ESCAPES) - color_dict['reset'] = self.RESET_ESCAPE + color_dict = dict(COLOR_ESCAPES) + color_dict['reset'] = RESET_ESCAPE log_color = LOG_COLORS[record.levelname] - color_dict['log_color'] = self.COLOR_ESCAPES[log_color] + color_dict['log_color'] = COLOR_ESCAPES[log_color] else: - color_dict = {color: '' for color in self.COLOR_ESCAPES} + color_dict = {color: '' for color in COLOR_ESCAPES} color_dict['reset'] = '' color_dict['log_color'] = '' record.__dict__.update(color_dict) diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py index 74b76833b..d61ec2cd8 100644 --- a/tests/end2end/features/conftest.py +++ b/tests/end2end/features/conftest.py @@ -20,6 +20,7 @@ """Steps for bdd-like tests.""" import re +import sys import time import json import os.path @@ -30,9 +31,69 @@ import textwrap import pytest import pytest_bdd as bdd +from qutebrowser.utils import log from helpers import utils +@pytest.hookimpl(hookwrapper=True) +def pytest_runtest_makereport(item, call): + """Add a BDD section to the test output.""" + outcome = yield + if call.when not in ['call', 'teardown']: + return + report = outcome.get_result() + + if report.passed: + return + + if not hasattr(report.longrepr, 'addsection'): + # In some conditions (on OS X and Windows it seems), report.longrepr is + # actually a tuple. This is handled similarily in pytest-qt too. + return + + if sys.stdout.isatty() and item.config.getoption('--color') != 'no': + colors = { + 'failed': log.COLOR_ESCAPES['red'], + 'passed': log.COLOR_ESCAPES['green'], + 'keyword': log.COLOR_ESCAPES['cyan'], + 'reset': log.RESET_ESCAPE, + } + else: + colors = { + 'failed': '', + 'passed': '', + 'keyword': '', + 'reset': '', + } + + output = [] + output.append("{kw_color}Feature:{reset} {name}".format( + kw_color=colors['keyword'], + name=report.scenario['feature']['name'], + reset=colors['reset'], + )) + output.append(" {kw_color}Scenario:{reset} {name} " + "({filename}:{line})".format( + kw_color=colors['keyword'], + name=report.scenario['name'], + filename=report.scenario['feature']['rel_filename'], + line=report.scenario['line_number'], + reset=colors['reset'], + )) + for step in report.scenario['steps']: + output.append(" {kw_color}{keyword}{reset} {color}{name}{reset} " + "({duration:.2f}s)".format( + kw_color=colors['keyword'], + color=colors['failed'] if step['failed'] else colors['passed'], + keyword=step['keyword'], + name=step['name'], + duration=step['duration'], + reset=colors['reset'], + )) + + report.longrepr.addsection("BDD scenario", '\n'.join(output)) + + ## Given