Merge branch 'master' into test-177
This commit is contained in:
commit
633ee28fd7
|
@ -15,6 +15,7 @@ Added
|
|||
Changed
|
||||
+++++++
|
||||
* Step arguments ``"datatable"`` and ``"docstring"`` are now reserved, and they can't be used as step argument names.
|
||||
* Scenario ``description`` field is now set for JSON output
|
||||
|
||||
Deprecated
|
||||
++++++++++
|
||||
|
|
118
README.rst
118
README.rst
|
@ -565,39 +565,6 @@ Example:
|
|||
assert datatable[1][1] in ["user1", "user2"]
|
||||
|
||||
|
||||
Rules
|
||||
-----
|
||||
|
||||
In Gherkin, `Rules` allow you to group related scenarios or examples under a shared context.
|
||||
This is useful when you want to define different conditions or behaviours
|
||||
for multiple examples that follow a similar structure.
|
||||
You can use either ``Scenario`` or ``Example`` to define individual cases, as they are aliases and function identically.
|
||||
|
||||
Additionally, **tags** applied to a rule will be automatically applied to all the **examples or scenarios**
|
||||
under that rule, making it easier to organize and filter tests during execution.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: gherkin
|
||||
|
||||
Feature: Rules and examples
|
||||
|
||||
@feature_tag
|
||||
Rule: A rule for valid cases
|
||||
|
||||
@rule_tag
|
||||
Example: Valid case 1
|
||||
Given I have a valid input
|
||||
When I process the input
|
||||
Then the result should be successful
|
||||
|
||||
Rule: A rule for invalid cases
|
||||
Example: Invalid case
|
||||
Given I have an invalid input
|
||||
When I process the input
|
||||
Then the result should be an error
|
||||
|
||||
|
||||
Scenario Outlines with Multiple Example Tables
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -663,6 +630,91 @@ only the examples under the "Positive results" table will be executed, and the "
|
|||
pytest -k "positive"
|
||||
|
||||
|
||||
Handling Empty Example Cells
|
||||
----------------------------
|
||||
|
||||
By default, empty cells in the example tables are interpreted as empty strings ("").
|
||||
However, there may be cases where it is more appropriate to handle them as ``None``.
|
||||
In such scenarios, you can use a converter with the ``parsers.re`` parser to define a custom behavior for empty values.
|
||||
|
||||
For example, the following code demonstrates how to use a custom converter to return ``None`` when an empty cell is encountered:
|
||||
|
||||
.. code-block:: gherkin
|
||||
|
||||
# content of empty_example_cells.feature
|
||||
|
||||
Feature: Handling empty example cells
|
||||
Scenario Outline: Using converters for empty cells
|
||||
Given I am starting lunch
|
||||
Then there are <start> cucumbers
|
||||
|
||||
Examples:
|
||||
| start |
|
||||
| |
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pytest_bdd import then, parsers
|
||||
|
||||
|
||||
# Define a converter that returns None for empty strings
|
||||
def empty_to_none(value):
|
||||
return None if value.strip() == "" else value
|
||||
|
||||
|
||||
@given("I am starting lunch")
|
||||
def _():
|
||||
pass
|
||||
|
||||
|
||||
@then(
|
||||
parsers.re("there are (?P<start>.*?) cucumbers"),
|
||||
converters={"start": empty_to_none}
|
||||
)
|
||||
def _(start):
|
||||
# Example assertion to demonstrate the conversion
|
||||
assert start is None
|
||||
|
||||
|
||||
Here, the `start` cell in the example table is empty.
|
||||
When the ``parsers.re`` parser is combined with the ``empty_to_none`` converter,
|
||||
the empty cell will be converted to ``None`` and can be handled accordingly in the step definition.
|
||||
|
||||
|
||||
Rules
|
||||
-----
|
||||
|
||||
In Gherkin, `Rules` allow you to group related scenarios or examples under a shared context.
|
||||
This is useful when you want to define different conditions or behaviours
|
||||
for multiple examples that follow a similar structure.
|
||||
You can use either ``Scenario`` or ``Example`` to define individual cases, as they are aliases and function identically.
|
||||
|
||||
Additionally, **tags** applied to a rule will be automatically applied to all the **examples or scenarios**
|
||||
under that rule, making it easier to organize and filter tests during execution.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: gherkin
|
||||
|
||||
Feature: Rules and examples
|
||||
|
||||
@feature_tag
|
||||
Rule: A rule for valid cases
|
||||
|
||||
@rule_tag
|
||||
Example: Valid case 1
|
||||
Given I have a valid input
|
||||
When I process the input
|
||||
Then the result should be successful
|
||||
|
||||
Rule: A rule for invalid cases
|
||||
|
||||
Example: Invalid case
|
||||
Given I have an invalid input
|
||||
When I process the input
|
||||
Then the result should be an error
|
||||
|
||||
|
||||
Datatables
|
||||
----------
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ class LogBDDCucumberJSON:
|
|||
"id": report.item["name"],
|
||||
"name": scenario["name"],
|
||||
"line": scenario["line_number"],
|
||||
"description": "",
|
||||
"description": scenario["description"],
|
||||
"tags": self._serialize_tags(scenario),
|
||||
"type": "scenario",
|
||||
"steps": [stepmap(step) for step in scenario["steps"]],
|
||||
|
|
|
@ -113,6 +113,7 @@ class ScenarioReport:
|
|||
"name": scenario.name,
|
||||
"line_number": scenario.line_number,
|
||||
"tags": sorted(scenario.tags),
|
||||
"description": scenario.description,
|
||||
"feature": {
|
||||
"keyword": feature.keyword,
|
||||
"name": feature.name,
|
||||
|
|
|
@ -51,9 +51,12 @@ def test_step_trace(pytester):
|
|||
"""
|
||||
@feature-tag
|
||||
Feature: One passing scenario, one failing scenario
|
||||
This is a feature description
|
||||
|
||||
@scenario-passing-tag
|
||||
Scenario: Passing
|
||||
This is a scenario description
|
||||
|
||||
Given a passing step
|
||||
And some other passing step
|
||||
|
||||
|
@ -116,72 +119,72 @@ def test_step_trace(pytester):
|
|||
assert result.ret
|
||||
expected = [
|
||||
{
|
||||
"description": "",
|
||||
"description": "This is a feature description",
|
||||
"elements": [
|
||||
{
|
||||
"description": "",
|
||||
"description": "This is a scenario description",
|
||||
"id": "test_passing",
|
||||
"keyword": "Scenario",
|
||||
"line": 5,
|
||||
"line": 6,
|
||||
"name": "Passing",
|
||||
"steps": [
|
||||
{
|
||||
"keyword": "Given",
|
||||
"line": 6,
|
||||
"line": 9,
|
||||
"match": {"location": ""},
|
||||
"name": "a passing step",
|
||||
"result": {"status": "passed", "duration": OfType(int)},
|
||||
},
|
||||
{
|
||||
"keyword": "And",
|
||||
"line": 7,
|
||||
"line": 10,
|
||||
"match": {"location": ""},
|
||||
"name": "some other passing step",
|
||||
"result": {"status": "passed", "duration": OfType(int)},
|
||||
},
|
||||
],
|
||||
"tags": [{"name": "scenario-passing-tag", "line": 4}],
|
||||
"tags": [{"name": "scenario-passing-tag", "line": 5}],
|
||||
"type": "scenario",
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"id": "test_failing",
|
||||
"keyword": "Scenario",
|
||||
"line": 10,
|
||||
"line": 13,
|
||||
"name": "Failing",
|
||||
"steps": [
|
||||
{
|
||||
"keyword": "Given",
|
||||
"line": 11,
|
||||
"line": 14,
|
||||
"match": {"location": ""},
|
||||
"name": "a passing step",
|
||||
"result": {"status": "passed", "duration": OfType(int)},
|
||||
},
|
||||
{
|
||||
"keyword": "And",
|
||||
"line": 12,
|
||||
"line": 15,
|
||||
"match": {"location": ""},
|
||||
"name": "a failing step",
|
||||
"result": {"error_message": OfType(str), "status": "failed", "duration": OfType(int)},
|
||||
},
|
||||
],
|
||||
"tags": [{"name": "scenario-failing-tag", "line": 9}],
|
||||
"tags": [{"name": "scenario-failing-tag", "line": 12}],
|
||||
"type": "scenario",
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
"keyword": "Scenario Outline",
|
||||
"tags": [{"line": 14, "name": "scenario-outline-passing-tag"}],
|
||||
"tags": [{"line": 17, "name": "scenario-outline-passing-tag"}],
|
||||
"steps": [
|
||||
{
|
||||
"line": 16,
|
||||
"line": 19,
|
||||
"match": {"location": ""},
|
||||
"result": {"status": "passed", "duration": OfType(int)},
|
||||
"keyword": "Given",
|
||||
"name": "type str and value hello",
|
||||
}
|
||||
],
|
||||
"line": 15,
|
||||
"line": 18,
|
||||
"type": "scenario",
|
||||
"id": "test_passing_outline[str-hello]",
|
||||
"name": "Passing outline",
|
||||
|
@ -189,17 +192,17 @@ def test_step_trace(pytester):
|
|||
{
|
||||
"description": "",
|
||||
"keyword": "Scenario Outline",
|
||||
"tags": [{"line": 14, "name": "scenario-outline-passing-tag"}],
|
||||
"tags": [{"line": 17, "name": "scenario-outline-passing-tag"}],
|
||||
"steps": [
|
||||
{
|
||||
"line": 16,
|
||||
"line": 19,
|
||||
"match": {"location": ""},
|
||||
"result": {"status": "passed", "duration": OfType(int)},
|
||||
"keyword": "Given",
|
||||
"name": "type int and value 42",
|
||||
}
|
||||
],
|
||||
"line": 15,
|
||||
"line": 18,
|
||||
"type": "scenario",
|
||||
"id": "test_passing_outline[int-42]",
|
||||
"name": "Passing outline",
|
||||
|
@ -207,17 +210,17 @@ def test_step_trace(pytester):
|
|||
{
|
||||
"description": "",
|
||||
"keyword": "Scenario Outline",
|
||||
"tags": [{"line": 14, "name": "scenario-outline-passing-tag"}],
|
||||
"tags": [{"line": 17, "name": "scenario-outline-passing-tag"}],
|
||||
"steps": [
|
||||
{
|
||||
"line": 16,
|
||||
"line": 19,
|
||||
"match": {"location": ""},
|
||||
"result": {"status": "passed", "duration": OfType(int)},
|
||||
"keyword": "Given",
|
||||
"name": "type float and value 1.0",
|
||||
}
|
||||
],
|
||||
"line": 15,
|
||||
"line": 18,
|
||||
"type": "scenario",
|
||||
"id": "test_passing_outline[float-1.0]",
|
||||
"name": "Passing outline",
|
||||
|
|
|
@ -117,6 +117,7 @@ def test_step_trace(pytester):
|
|||
"keyword": "Scenario",
|
||||
"line_number": 5,
|
||||
"name": "Passing",
|
||||
"description": "",
|
||||
"steps": [
|
||||
{
|
||||
"duration": OfType(float),
|
||||
|
@ -155,6 +156,7 @@ def test_step_trace(pytester):
|
|||
"keyword": "Scenario",
|
||||
"line_number": 10,
|
||||
"name": "Failing",
|
||||
"description": "",
|
||||
"steps": [
|
||||
{
|
||||
"duration": OfType(float),
|
||||
|
@ -192,6 +194,7 @@ def test_step_trace(pytester):
|
|||
"keyword": "Scenario Outline",
|
||||
"line_number": 14,
|
||||
"name": "Outlined",
|
||||
"description": "",
|
||||
"steps": [
|
||||
{
|
||||
"duration": OfType(float),
|
||||
|
@ -237,6 +240,7 @@ def test_step_trace(pytester):
|
|||
"keyword": "Scenario Outline",
|
||||
"line_number": 14,
|
||||
"name": "Outlined",
|
||||
"description": "",
|
||||
"steps": [
|
||||
{
|
||||
"duration": OfType(float),
|
||||
|
|
Loading…
Reference in New Issue