Skip to content

Commit

Permalink
Require "Scenario Outline" keyword for outlined scenario.
Browse files Browse the repository at this point in the history
This should fix #447
  • Loading branch information
youtux committed Mar 12, 2022
1 parent a10e93a commit e3e0cff
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 12 deletions.
16 changes: 14 additions & 2 deletions pytest_bdd/new_parser.py
Expand Up @@ -115,13 +115,25 @@ def tag_lines(self, value: list[Tree]) -> set[str]:
return tags

@v_args(inline=True)
def scenario(
def scenario(self, tag_lines: set[str] | None, scenario_line: Token, steps: list[Step] | None):
# TODO: Try to remove duplicated code with "scenario_outline"
scenario = ScenarioTemplate(
name=scenario_line.strip(),
line_number=scenario_line.line,
tags=tag_lines or set(),
feature=None, # added later
)
for step in steps or []:
scenario.add_step(step)
return scenario

@v_args(inline=True)
def scenario_outline(
self, tag_lines: set[str] | None, scenario_line: Token, steps: list[Step] | None, examples: Examples | None
):
scenario = ScenarioTemplate(
name=scenario_line.strip(),
line_number=scenario_line.line,
# example_converters=None,
tags=tag_lines or set(),
feature=None, # added later
examples=examples,
Expand Down
9 changes: 5 additions & 4 deletions pytest_bdd/parser_data/gherkin.grammar.lark
Expand Up @@ -17,8 +17,9 @@ scenarios: scenario*
feature_header: [tag_lines]
feature_line: FEATURE STRING _NL?

scenario: [tag_lines] scenario_line [_INDENT [steps] [examples] _DEDENT]
scenario_line: (SCENARIO | SCENARIO_OUTLINE) STRING _NL?
scenario: [tag_lines] scenario_line{SCENARIO} [_INDENT [steps] _DEDENT] -> scenario
| [tag_lines] scenario_line{SCENARIO_OUTLINE} [_INDENT [steps] examples _DEDENT] -> scenario_outline
scenario_line{type}: type STRING _NL?

examples: example_line example_table
example_line: EXAMPLES [STRING] _NL?
Expand Down Expand Up @@ -60,10 +61,10 @@ AND: "And "
BUT: "But "

SCENARIO: "Scenario:"
SCENARIO_OUTLINE: "Scenario Outline:"
SCENARIO_OUTLINE: "Scenario Outline:" | "Scenario Template:"
BACKGROUND: "Background:"
FEATURE: "Feature:"
EXAMPLES: "Examples:"
EXAMPLES: "Examples:" | "Scenarios:"

// TODO: Probably the following does not need the negative lookbehind part
//step_docstring: /"""\n.*?(?<!\\)(\\\\)*?\n\s*"""/is
Expand Down
2 changes: 1 addition & 1 deletion tests/feature/test_cucumber_json.py
Expand Up @@ -62,7 +62,7 @@ def test_step_trace(testdir):
And a failing step
@scenario-outline-passing-tag
Scenario: Passing outline
Scenario Outline: Passing outline
Given type <type> and value <value>
Examples: example1
Expand Down
57 changes: 52 additions & 5 deletions tests/test_new_parser.py
Expand Up @@ -11,6 +11,7 @@
# - "Feature:" line is always required.
# - Other changes. Check the modifications to the tests.
# - Tags can only be "valid" identifiers, e.g. no spaces.
# - Must use "Scenario Outline" (or "Scenario Template") for outlined scenarios. "Scenario" will not work anymore


def test_feature():
Expand Down Expand Up @@ -567,20 +568,43 @@ def test_empty_lines(src):
@pytest.mark.parametrize(
["src", "expected"],
[
(
pytest.param(
"""\
Feature: A feature
Scenario: A scenario
Scenario Outline: A scenario
Examples:
| foo |
| bar |
""",
[{"foo": "bar"}],
id="basic",
),
pytest.param(
"""\
Feature: A feature
Scenario Template: A scenario
Examples:
| foo |
| bar |
""",
[{"foo": "bar"}],
id="scenario_template_instead_of_scenario_outline_keyword",
),
pytest.param(
"""\
Feature: A feature
Scenario Outline: A scenario
Scenarios:
| foo |
| bar |
""",
[{"foo": "bar"}],
id="scenarios_instead_of_examples_keyword",
),
(
"""\
Feature: A feature
Scenario: A scenario
Scenario Outline: A scenario
Examples:
| first name | last name |
| Alessio | Bogon |
Expand All @@ -594,14 +618,14 @@ def test_empty_lines(src):
(
"""\
Feature: A feature
Scenario: A scenario
Scenario Outline: A scenario
""",
[],
),
(
"""\
Feature: A feature
Scenario: A scenario
Scenario Outline: A scenario
Examples:
| pipe in the \\| middle |
| foo |
Expand All @@ -618,6 +642,29 @@ def test_scenario_examples(src, expected):
assert list(scenario.examples.as_contexts()) == expected


@pytest.mark.parametrize(
["src", "expected"],
[
(
"""\
Feature: A feature
Scenario: A scenario
Given foo is <foo>
Examples:
| foo |
| bar |
""",
[{"foo": "bar"}],
),
],
)
def test_examples_not_allowed_in_scenario(src, expected):
"""Test that "Examples:" are not allowed in scenarios (only in scenario outlines)"""
with pytest.raises(Exception):
feature = parse(src)
# TODO: Test exception


def test_comment():
src = """\
# feature comment
Expand Down

0 comments on commit e3e0cff

Please sign in to comment.