diff --git a/pytest_bdd/cucumber_json.py b/pytest_bdd/cucumber_json.py index 61e9c2b4..8fe8f1c4 100644 --- a/pytest_bdd/cucumber_json.py +++ b/pytest_bdd/cucumber_json.py @@ -143,6 +143,7 @@ def stepmap(step): "keyword": step["keyword"], "name": step_name, "line": step["line_number"], + "embeddings": step["embeddings"], "match": {"location": ""}, "result": self._get_result(step, report, error_message), } diff --git a/pytest_bdd/feature.py b/pytest_bdd/feature.py index 822a382e..131c7778 100644 --- a/pytest_bdd/feature.py +++ b/pytest_bdd/feature.py @@ -454,6 +454,14 @@ def add_step(self, step): step.scenario = self self._steps.append(step) + def attach(self, data, media_type="text/plain"): + """Add attachment to step, such as text, images. + + :param data: actual data of Attachment, can be plain text or base64 encoded + :param media_type: actual media type of Attachment, such as text/plain, image/png + """ + self.steps[-1].attach(data, media_type) + @property def steps(self): """Get scenario steps including background steps. @@ -521,6 +529,7 @@ def __init__(self, name, type, indent, line_number, keyword): self.type = type self.line_number = line_number self.failed = False + self.embeddings = [] self.start = 0 self.stop = 0 self.scenario = None @@ -533,6 +542,15 @@ def add_line(self, line): """ self.lines.append(line) + def attach(self, data, media_type="text/plain"): + """Add attachment to step, such as text, images. + + :param data: actual data of Attachment, can be plain text or base64 encoded + :param media_type: actual media type of Attachment, such as text/plain, image/png + """ + json_attachment = {"data": data, "media": {"type": media_type}} + self.embeddings.append(json_attachment) + @property def name(self): """Get step name.""" diff --git a/pytest_bdd/reporting.py b/pytest_bdd/reporting.py index 45a8e9e7..a37a13bc 100644 --- a/pytest_bdd/reporting.py +++ b/pytest_bdd/reporting.py @@ -33,6 +33,7 @@ def serialize(self): """ return { "name": self.step.name, + "embeddings": self.step.embeddings, "type": self.step.type, "keyword": self.step.keyword, "line_number": self.step.line_number, diff --git a/tests/feature/test_cucumber_json.py b/tests/feature/test_cucumber_json.py index de41e50b..b206c2d5 100644 --- a/tests/feature/test_cucumber_json.py +++ b/tests/feature/test_cucumber_json.py @@ -124,6 +124,7 @@ def test_passing_outline(): "steps": [ { "keyword": "Given", + "embeddings": [], "line": 6, "match": {"location": ""}, "name": "a passing step", @@ -131,6 +132,7 @@ def test_passing_outline(): }, { "keyword": "And", + "embeddings": [], "line": 7, "match": {"location": ""}, "name": "some other passing step", @@ -149,6 +151,7 @@ def test_passing_outline(): "steps": [ { "keyword": "Given", + "embeddings": [], "line": 11, "match": {"location": ""}, "name": "a passing step", @@ -156,6 +159,7 @@ def test_passing_outline(): }, { "keyword": "And", + "embeddings": [], "line": 12, "match": {"location": ""}, "name": "a failing step", @@ -176,6 +180,7 @@ def test_passing_outline(): "steps": [ { "line": 16, + "embeddings": [], "match": {"location": ""}, "result": {"status": "passed", "duration": equals_any(int)}, "keyword": "Given", @@ -194,6 +199,7 @@ def test_passing_outline(): "steps": [ { "line": 16, + "embeddings": [], "match": {"location": ""}, "result": {"status": "passed", "duration": equals_any(int)}, "keyword": "Given", @@ -212,6 +218,7 @@ def test_passing_outline(): "steps": [ { "line": 16, + "embeddings": [], "match": {"location": ""}, "result": {"status": "passed", "duration": equals_any(int)}, "keyword": "Given", diff --git a/tests/feature/test_report.py b/tests/feature/test_report.py index 732f0e60..99a0ee9f 100644 --- a/tests/feature/test_report.py +++ b/tests/feature/test_report.py @@ -122,6 +122,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): "steps": [ { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "Given", "line_number": 6, @@ -130,6 +131,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): }, { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "And", "line_number": 7, @@ -159,6 +161,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): "steps": [ { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "Given", "line_number": 11, @@ -167,6 +170,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): }, { "duration": equals_any(float), + "embeddings": [], "failed": True, "keyword": "And", "line_number": 12, @@ -195,6 +199,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): "steps": [ { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "Given", "line_number": 15, @@ -203,6 +208,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): }, { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "When", "line_number": 16, @@ -211,6 +217,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): }, { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "Then", "line_number": 17, @@ -246,6 +253,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): "steps": [ { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "Given", "line_number": 15, @@ -254,6 +262,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): }, { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "When", "line_number": 16, @@ -262,6 +271,7 @@ def should_have_left_cucumbers(start_cucumbers, start, eat, left): }, { "duration": equals_any(float), + "embeddings": [], "failed": False, "keyword": "Then", "line_number": 17,