-
Notifications
You must be signed in to change notification settings - Fork 221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Regression: KeyError in replacer #447
Comments
|
The changelog for 5.0.0 doesn't seem to indicate this anywhere - it links to a "Migration from 4.x.x" document which doesn't seem to exist. Also, even if that's really the culprit, it seems to me like the error message should be a bit clearer than just an unhandled |
as a workaround until this is fixed, if we use an examples table to feed the value it will work Given the following step definition: @given(parsers.parse("variable {var} is set to '{value}'"))
def set_var(context, var, value):
context[var] = value This will fail: Scenario: Test fail string with <value>
Given variable v is set to 'some value with <value> in it' This will pass: Scenario: Test pass with example
Given variable v is set to '<value>'
Examples: Vertical
| value | some value with <value> in it | |
FWIW the parameterization example in the README appears broken on 5.0.0 after its changes in #445. What I ran: import pytest
from pytest_bdd import scenario, given, when, then, parsers
# Here we use pytest to parametrize the test with the parameters table
@pytest.mark.parametrize(
['start', 'eat', 'left'],
[(12, 5, 7)])
@scenario(
'parametrized.feature',
'Parametrized given, when, thens',
)
# Note that we should take the same arguments in the test function that we use
# for the test parametrization either directly or indirectly (fixtures depend on them).
def test_parametrized(start, eat, left):
"""We don't need to do anything here, everything will be managed by the scenario decorator."""
@given(parsers.parse('there are {start:d} cucumbers'), target_fixture="start_cucumbers")
def start_cucumbers(start):
return dict(start=start)
@when(parsers.parse('I eat {eat:d} cucumbers'))
def eat_cucumbers(start_cucumbers, start, eat):
start_cucumbers['eat'] = eat
@then(parsers.parse('I should have {left:d} cucumbers'))
def should_have_left_cucumbers(start_cucumbers, start, eat, left):
assert start - eat == left
assert start_cucumbers['start'] == start
assert start_cucumbers['eat'] == eat Feature: parametrized
Scenario: Parametrized given, when, thens
Given there are <start> cucumbers
When I eat <eat> cucumbers
Then I should have <left> cucumbers $ pytest test_parameter.py
===================================================================================== test session starts ======================================================================================
platform linux -- Python 3.6.8, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/bbatliner/package, configfile: pytest.ini
plugins: bdd-5.0.0
collected 1 item
test_parameter.py F [100%]
=========================================================================================== FAILURES ===========================================================================================
__________________________________________________________________________________ test_parametrized[12-5-7] ___________________________________________________________________________________
request = <FixtureRequest for <Function test_parametrized[12-5-7]>>, _pytest_bdd_example = {}
@pytest.mark.usefixtures(*args)
def scenario_wrapper(request, _pytest_bdd_example):
> scenario = templated_scenario.render(_pytest_bdd_example)
../.cache/pypoetry/virtualenvs/package-dlKzdzJ9-py3.6/lib/python3.6/site-packages/pytest_bdd/scenario.py:173:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../.cache/pypoetry/virtualenvs/package-dlKzdzJ9-py3.6/lib/python3.6/site-packages/pytest_bdd/parser.py:257: in render
for templated_step in self.steps
../.cache/pypoetry/virtualenvs/package-dlKzdzJ9-py3.6/lib/python3.6/site-packages/pytest_bdd/parser.py:257: in <listcomp>
for templated_step in self.steps
../.cache/pypoetry/virtualenvs/package-dlKzdzJ9-py3.6/lib/python3.6/site-packages/pytest_bdd/parser.py:364: in render
return STEP_PARAM_RE.sub(replacer, self.name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
m = <_sre.SRE_Match object; span=(10, 17), match='<start>'>
def replacer(m: typing.Match):
varname = m.group(1)
> return str(context[varname])
E KeyError: 'start'
../.cache/pypoetry/virtualenvs/package-dlKzdzJ9-py3.6/lib/python3.6/site-packages/pytest_bdd/parser.py:362: KeyError
=================================================================================== short test summary info ====================================================================================
FAILED test_parameter.py::test_parametrized[12-5-7] - KeyError: 'start' The |
My apologies, the above comment has an issue already: #448. Including a solution that is tested. |
I am having a same issue but my step definitions contain text values with Feature: print values
Scenario: print HTML tag
Given tag p
When printed with text
Then the document contains "<p>text</p>" raises Replacer should only replace keys defined in examples of a scenario outline. |
Sorry for the inconvenience, when I implemented this change (to behave more according to the Gherkin specs) I didn't foresee this edge case. It seems that Gherkin does not mention how to workaround this issue in https://cucumber.io/docs/gherkin/reference/#scenario-outline. I see a couple of options here to solve the problem:
@olegpidsadnyi, what's your opinion on this? |
I find it a less of a problem as it can be solved by renaming example parameters. |
3. We could raise a warning. In case if it really wanted behavior user could just filter it out |
Approach from #439 also could be a solution |
For the record, the approach in Cucumber that hit the stage of "send a PR and we'll see" in cucumber/common#1004 (before the issue timed-out a couple of years ago) was to use hot-comments to change the example-delimiter markers for a feature file. AFAIK pytest-bdd doesn't support the existing |
I'm fixing this in #524 by parsing the params in angular brackets only for |
Wheeee, thanks for the fix! I just upgraded from 4.1.0 to 6.0.0 finally, and it seems to work great again! ✨ (Other than a bug in my own code the upgrade did uncover: tests: Fix broken BDD definition · qutebrowser/qutebrowser@a16aa95) |
This fix could be ok for the current Gherkin dialect implemented in pytest_bdd, but in official gherkin language Scenario, Example and Scenario Outline are just aliases and all of them could be used with angular brackets |
@elchupanebrej I don’t see that in the Gherkin reference. They say that |
You are right! But internal implementation of the official Gherkin parser uses all of them as aliases. This could be checked by using parse directly https://github.com/cucumber/common/tree/main/gherkin |
With #445, I'm seeing many tracebacks like this in my tests:
There are many other such failures, but this one is from this scenario:
specifically, the
And I press the keys "<Home>"
line there.The underlying Python code is simple:
A slightly simpler example:
with this code:
results in a
KeyError: tab
. In other words, it seems like anything in<...>
in a scenario now seems to be parsed in some special way.I've tried to write a reproducer:
bug.feature:
test_bug.py:
but unfortunately, I can not reproduce the issue there. Any ideas what could be going wrong there?
The text was updated successfully, but these errors were encountered: