Skip to content

Commit

Permalink
Add live progress style and refactor output and progress styles (#233)
Browse files Browse the repository at this point in the history
* code is not great, but it works!

* more consistent de-rendering of footer content

* leave failed tests behind in live output

* woops, remove debugging sleep

* disable live when entering debugger; re-enable after test finishes

* maybe better names

* add docs, offset boring docs with fun emoji

* fix global dots output, remove some unused code

* start adding tests for more terminal code

* start adding tests for more terminal code

* big cleanup pass, fix some bugs, refactor some widgets

* remove emoji; XPASS is bad too

* naming

* add tests for new TestOutcome properties

Co-authored-by: Darren Burns <darrenb900@gmail.com>
  • Loading branch information
JoshKarpel and darrenburns committed Jun 5, 2021
1 parent b840a94 commit cdcea6a
Show file tree
Hide file tree
Showing 9 changed files with 491 additions and 310 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ test:

coverage:
poetry run coverage run -m ward
poetry run coverage html -i
poetry run coverage report --skip-empty --show-missing --sort=-cover
poetry run coverage html
.PHONY: coverage

update:
Expand Down
14 changes: 0 additions & 14 deletions tests/test_cli.py

This file was deleted.

73 changes: 72 additions & 1 deletion tests/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
from rich.table import Table
from rich.text import Text

from tests.utilities import example_test
from tests.utilities import example_test, testable_test
from ward import fixture, using
from ward._terminal import (
SessionPrelude,
TestProgressStyle,
TestTimingStatsPanel,
get_dot,
get_exit_code,
get_test_result_line,
outcome_to_style,
)
from ward._testing import _Timer
Expand Down Expand Up @@ -206,3 +209,71 @@ def _(timing_stats_panel=timing_stats_panel):
assert table.columns[0]._cells == expected_durations
assert len(table.columns[1]._cells) == 3
assert table.columns[2]._cells == expected_test_descriptions


@fixture
def test_result() -> TestResult:
@testable_test
def _():
assert True

return TestResult(
test=Test(
timer=_Timer(duration=4.0),
fn=_,
description="test1",
module_name="mod1",
),
outcome=TestOutcome.FAIL,
)


for idx, num_tests, expected_output in [
(0, 2, " 50%"),
(1, 2, "100%"),
(1, 3, " 67%"),
(2, 3, "100%"),
(16, 17, "100%"),
]:

@test(
"get_test_result_line with inline progress for test {idx} with {num_tests} tests emits {expected_output!r}"
)
def _(
idx=idx,
num_tests=num_tests,
expected_output=expected_output,
test_result=test_result,
):
output = get_test_result_line(
test_result=test_result,
test_index=idx,
num_tests=num_tests,
progress_styles=[TestProgressStyle.INLINE],
)

assert expected_output == list(output.columns[-1].cells)[0]


for outcome, expected_output in [
(TestOutcome.PASS, Text(".", style="pass")),
(TestOutcome.FAIL, Text("F", style="fail")),
(TestOutcome.SKIP, Text("-", style="skip")),
(TestOutcome.XPASS, Text("U", style="xpass")),
(TestOutcome.XFAIL, Text("x", style="xfail")),
(TestOutcome.DRYRUN, Text(".", style="dryrun")),
]:

@test("get_dot emits {expected_output!r} for test outcome {outcome}")
def _(outcome=outcome, expected_output=expected_output):
assert expected_output == get_dot(
TestResult(
test=Test(
timer=_Timer(duration=4.0),
fn=lambda: 1,
description="test1",
module_name="mod1",
),
outcome=outcome,
)
)
18 changes: 18 additions & 0 deletions tests/test_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,24 @@ def _(func=example_test):
assert len(dest) == 0


for outcome, should_fail_session in [
(TestOutcome.PASS, False),
(TestOutcome.FAIL, True),
(TestOutcome.SKIP, False),
(TestOutcome.XPASS, True),
(TestOutcome.XFAIL, False),
(TestOutcome.DRYRUN, False),
]:

@test("{outcome}.will_fail_session is `{should_fail_session}`")
def _(outcome=outcome, should_fail_session=should_fail_session):
assert outcome.will_fail_session is should_fail_session

@test("{outcome}.{will,wont}_fail_session are opposites")
def _(outcome=outcome):
assert outcome.will_fail_session is (not outcome.wont_fail_session)


@test("fixtures_used_directly_by_tests finds used fixture")
def _():
@fixture
Expand Down
2 changes: 1 addition & 1 deletion tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def square(x):
return x ** 2


@test("group {items!r} by {key} returns {result}")
@test("group {items!r} by {key.__name__} returns {result}")
def _(
items=each(range(5), "echolocation", [-2, 3, 4, -3, 2, 3]),
key=each(is_even, is_vowel, square),
Expand Down
14 changes: 12 additions & 2 deletions ward/_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ def _breakpointhook(*args, **kwargs):
capture_enabled = context.params.get("capture_output")
capture_active = isinstance(sys.stdout, io.StringIO)

# Stop an active Live.
# It is the responsibility of the test executor
# to re-enable the Live.
live = console._live
if live is not None:
live.refresh()
live.stop()

if capture_enabled and capture_active:
sys.stdout = original_stdout
console.print("Entering debugger - output capturing disabled.", style="info")
return hook(*args, **kwargs)
console.print(
f"Entering debugger [bold]{hookname}[/] - output capturing disabled.",
style="info",
)

return hook(*args, **kwargs)

Expand Down
20 changes: 5 additions & 15 deletions ward/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,18 @@ def run(ctx: click.Context):
)
@click.option(
"--test-output-style",
type=click.Choice(list(TestOutputStyle), case_sensitive=False),
type=click.Choice([s.value for s in TestOutputStyle], case_sensitive=False),
default="test-per-line",
help="The style of output for displaying individual test results during the run.",
)
@click.option(
"--progress-style",
type=click.Choice(list(TestProgressStyle), case_sensitive=False),
type=click.Choice([s.value for s in TestProgressStyle], case_sensitive=False),
multiple=True,
default=["inline"],
help=f"""\
help="""\
The style of progress indicator to use during the run.
Pass multiple times to enable multiple styles.
The '{TestProgressStyle.BAR}' style is not compatible with the
'{TestOutputStyle.DOTS_GLOBAL}' and '{TestOutputStyle.DOTS_MODULE}' test output styles.
""",
)
@click.option(
Expand Down Expand Up @@ -184,17 +182,9 @@ def test(
config_params.pop("config")

config = Config(**config_params, plugin_config=config_params.get("plugins", {}))
progress_styles = [TestProgressStyle(ps) for ps in progress_style]

if TestProgressStyle.BAR in progress_styles and test_output_style in {
"dots-global",
"dots-module",
}:
raise click.BadOptionUsage(
"progress_style",
f"The '{TestProgressStyle.BAR}' progress style cannot be used with dots-based "
f"test output styles (you asked for '{test_output_style}').",
)
test_output_style = TestOutputStyle(test_output_style)
progress_styles = [TestProgressStyle(ps) for ps in progress_style]

init_breakpointhooks(pdb, sys)
start_run = default_timer()
Expand Down

0 comments on commit cdcea6a

Please sign in to comment.