jrnl/tests/lib/when_steps.py
Carl Smedstad 1530ad39a1
Update pytest-bdd to v8.0 (#1955)
* Encapsulate all multiline strings in triple-quotes in Gherkin files

Since pytest-bdd v8.0.0 uses the official Gherkin parser, multiline
strings must now be encapsulated by triple-quotes.

See:
- https://pytest-bdd.readthedocs.io/en/stable/#id2
- https://pytest-bdd.readthedocs.io/en/stable/#docstrings

* Remove comments in Gherkin files causing test breakage

These comments break the step matching.

* Fix compatibility of step-functions matching on multiple lines

In pytest-bdd v8.0.0 it is no longer possible to match based on multiple
lines, which breaks essentially all steps that support docstrings. Solve
this by adding a wrapper-function for each of these instances, that
matches the docstring step, and calls the original function.

So, what used to be:

    @then(parse("the output should match\n{regex}"))
    @then(parse('the output should match "{regex}"'))
    def output_should_match(regex, cli_run):
        ...

Is now:

    @then(parse("the output should match"))
    def output_should_match_docstring(cli_run, docstring):
        output_should_match(docstring, cli_run)

    @then(parse('the output should match "{regex}"'))
    def output_should_match(regex, cli_run):
        ...

There is possibly a way around this that is much better than what I've
done here, but this is a start at least.

* Update version requirement of pytest-bdd to >=8.0

* Update tox config to match poetry config

---------

Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
2025-02-24 20:16:54 -08:00

75 lines
2.3 KiB
Python

# Copyright © 2012-2023 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html
import os
from contextlib import ExitStack
from pytest_bdd import when
from pytest_bdd.parsers import parse
from pytest_bdd.parsers import re
# This is an undocumented and unsupported function:
# https://github.com/pytest-dev/pytest-bdd/issues/684
try:
from pytest_bdd.compat import inject_fixture # pytest_bdd 7.1.2 and later
except ImportError:
from pytest_bdd.steps import inject_fixture # pytest_bdd 7.1.1 and earlier
from jrnl.main import run
@when(parse('we change directory to "{directory_name}"'))
def when_we_change_directory(directory_name):
if not os.path.isdir(directory_name):
os.mkdir(directory_name)
os.chdir(directory_name)
# These variables are used in the `@when(re(...))` section below
command = '(?P<command>[^"]*)'
input_method = "(?P<input_method>enter|pipe|type)"
all_input = '("(?P<all_input>[^"]*)")'
# Note: A line with only a raw newline r'\n' is treated as
# an empty line of input internally for testing purposes.
@when(re(f'we run "jrnl {command}" and {input_method}'))
def we_run_jrnl_docstring(capsys, keyring, request, command, input_method, docstring):
we_run_jrnl(capsys, keyring, request, command, input_method, docstring)
@when(re(f'we run "jrnl ?{command}" and {input_method} {all_input}'))
@when(re(f'we run "jrnl {command}"(?! and)'))
@when('we run "jrnl"')
def we_run_jrnl(capsys, keyring, request, command, input_method, all_input):
from keyring import set_keyring
set_keyring(keyring)
# fixture injection (pytest-bdd >=6.0)
inject_fixture(request, "command", command)
inject_fixture(request, "input_method", input_method)
inject_fixture(request, "all_input", all_input)
cli_run = request.getfixturevalue("cli_run")
with ExitStack() as stack:
mocks = cli_run["mocks"]
factories = cli_run["mock_factories"]
for id in factories:
mocks[id] = stack.enter_context(factories[id]())
try:
cli_run["status"] = run() or 0
except StopIteration:
# This happens when input is expected, but don't have any input left
pass
except SystemExit as e:
cli_run["status"] = e.code
captured = capsys.readouterr()
cli_run["stdout"] = captured.out
cli_run["stderr"] = captured.err