Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ lint.isort.required-imports = [

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"if typing\\.TYPE_CHECKING:",
]
Expand Down
22 changes: 16 additions & 6 deletions src/pytest_bdd/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os.path
import re
import textwrap
import warnings
from collections import OrderedDict
from collections.abc import Generator, Iterable, Mapping, Sequence
from dataclasses import dataclass, field
Expand Down Expand Up @@ -492,12 +493,21 @@ def parse(self) -> Feature:
)

for child in feature_data.children:
if child.background:
feature.background = self.parse_background(child.background)
elif child.rule:
self._parse_and_add_rule(child.rule, feature)
elif child.scenario:
self._parse_and_add_scenario(child.scenario, feature)
match child.background or child.rule or child.scenario:
case GherkinBackground() as background:
feature.background = self.parse_background(background)
case GherkinRule() as rule:
self._parse_and_add_rule(rule, feature)
case GherkinScenario() as scenario:
self._parse_and_add_scenario(scenario, feature)
case _:
# An empty Child, or a child kind newer than this gherkin version;
# skip it and warn instead of crashing, to keep working against
# future gherkin releases that add new child types.
warnings.warn(
f"Unknown gherkin child skipped in {self.rel_filename!r}; consider upgrading pytest-bdd.",
stacklevel=2,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

)

return feature

Expand Down
38 changes: 38 additions & 0 deletions tests/parser/test_parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from __future__ import annotations

import textwrap
from pathlib import Path
from unittest.mock import patch

import pytest

from src.pytest_bdd import parser as parser_module
from src.pytest_bdd.gherkin_parser import (
Background,
Cell,
Expand Down Expand Up @@ -851,3 +856,36 @@ def test_parser():
)

assert gherkin_doc == expected_document


def test_feature_parser_warns_on_unknown_child_kinds(tmp_path):
"""A Child with none of background/rule/scenario set is skipped with a warning.

The gherkin AST reserves the right to grow new child kinds; ``Child.from_dict``
would map such a child to an all-``None`` dataclass, and ``FeatureParser.parse``
must warn and skip it instead of crashing, so pytest-bdd keeps working against
future gherkin releases.
"""
(tmp_path / "minimal.feature").write_text(
textwrap.dedent(
"""\
Feature: Minimal
Scenario: A scenario
Given a step
"""
)
)

real_get_gherkin_document = parser_module.get_gherkin_document

def get_gherkin_document_with_unknown_child(abs_filename: str, encoding: str = "utf-8") -> GherkinDocument:
document = real_get_gherkin_document(abs_filename, encoding)
document.feature.children.append(Child())
return document

with patch.object(parser_module, "get_gherkin_document", get_gherkin_document_with_unknown_child):
with pytest.warns(UserWarning, match="Unknown gherkin child"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for a nested with, we can have 2 context managers in the same with-statement

feature = parser_module.FeatureParser(str(tmp_path), "minimal.feature").parse()

assert list(feature.scenarios) == ["A scenario"]
assert feature.background is None
Loading