Skip to content

Commit 83cf085

Browse files
committed
feat(allure-pytest): allow to add parameter directly in step via allure.add_parameter
1 parent 63017ae commit 83cf085

7 files changed

Lines changed: 331 additions & 0 deletions

File tree

allure-behave/src/listener.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from allure_commons.utils import md5
66
from allure_commons.utils import now
77
from allure_commons.utils import platform_label
8+
from allure_commons.utils import represent
89
from allure_commons.types import LabelType, AttachmentType, LinkType
910
from allure_commons.model2 import TestResult
1011
from allure_commons.model2 import TestStepResult
@@ -163,6 +164,27 @@ def start_step(self, uuid, title, params):
163164
step = TestStepResult(name=title, start=now(), parameters=parameters)
164165
self.logger.start_step(None, uuid, step)
165166

167+
@allure_commons.hookimpl
168+
def add_step_parameter(self, uuid, name, value, excluded, mode):
169+
step = self.logger.get_item(uuid)
170+
if step:
171+
parameter = Parameter(
172+
name=name,
173+
value=represent(value),
174+
excluded=excluded,
175+
mode=mode.value if mode else None
176+
)
177+
step.parameters.append(parameter)
178+
179+
@allure_commons.hookimpl
180+
def get_current_step_uuid(self):
181+
items_list = list(self.logger._items)
182+
for uuid in reversed(items_list):
183+
item = self.logger.get_item(uuid)
184+
if isinstance(item, TestStepResult):
185+
return uuid
186+
return None
187+
166188
@allure_commons.hookimpl
167189
def stop_step(self, uuid, exc_type, exc_val, exc_tb):
168190
self.logger.stop_step(uuid,

allure-pytest/src/listener.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@ def start_step(self, uuid, title, params):
5050
step = TestStepResult(name=title, start=now(), parameters=parameters)
5151
self.allure_logger.start_step(None, uuid, step)
5252

53+
@allure_commons.hookimpl
54+
def add_step_parameter(self, uuid, name, value, excluded, mode):
55+
step = self.allure_logger.get_item(uuid)
56+
if step:
57+
parameter = Parameter(
58+
name=name,
59+
value=represent(value),
60+
excluded=excluded,
61+
mode=mode.value if mode else None
62+
)
63+
step.parameters.append(parameter)
64+
65+
@allure_commons.hookimpl
66+
def get_current_step_uuid(self):
67+
items_list = list(self.allure_logger._items)
68+
for uuid in reversed(items_list):
69+
item = self.allure_logger.get_item(uuid)
70+
if isinstance(item, TestStepResult):
71+
return uuid
72+
return None
73+
5374
@allure_commons.hookimpl
5475
def stop_step(self, uuid, exc_type, exc_val, exc_tb):
5576
self.allure_logger.stop_step(uuid,

allure-python-commons/src/allure/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from allure_commons._allure import link, issue, testcase
1010
from allure_commons._allure import Dynamic as dynamic
1111
from allure_commons._allure import step
12+
from allure_commons._allure import add_parameter
1213
from allure_commons._allure import attach
1314
from allure_commons._allure import manual
1415
from allure_commons.types import Severity as severity_level
@@ -35,6 +36,7 @@
3536
"testcase",
3637
"manual",
3738
"step",
39+
"add_parameter",
3840
"dynamic",
3941
"severity_level",
4042
"attach",

allure-python-commons/src/allure_commons/_allure.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,25 @@ def step(title: _TFunc) -> _TFunc:
171171
...
172172

173173

174+
def add_parameter(name, value, excluded=None, mode=None):
175+
results = plugin_manager.hook.get_current_step_uuid()
176+
current_step_uuid = results[0] if results else None
177+
178+
if current_step_uuid is None:
179+
raise RuntimeError(
180+
"No active step found. Use 'allure.add_parameter()' only inside "
181+
"a step context (with allure.step(...):) or a decorated step function."
182+
)
183+
184+
plugin_manager.hook.add_step_parameter(
185+
uuid=current_step_uuid,
186+
name=name,
187+
value=value,
188+
excluded=excluded,
189+
mode=mode
190+
)
191+
192+
174193
def step(title):
175194
if callable(title):
176195
return StepContext(title.__name__, {})(title)

allure-python-commons/src/allure_commons/_hooks.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ def add_link(self, url, link_type, name):
5050
def add_parameter(self, name, value, excluded, mode):
5151
""" parameter """
5252

53+
@hookspec
54+
def add_step_parameter(self, uuid, name, value, excluded, mode):
55+
""" step parameter """
56+
57+
@hookspec
58+
def get_current_step_uuid(self):
59+
""" get current active step uuid """
60+
5361
@hookspec
5462
def start_step(self, uuid, title, params):
5563
""" step """

allure-robotframework/src/listener/allure_listener.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
from allure_commons.utils import platform_label
1111
from allure_commons.utils import host_tag
1212
from allure_commons.utils import format_exception, format_traceback
13+
from allure_commons.utils import represent
1314
from allure_commons.model2 import Label, Link
1415
from allure_commons.model2 import Status, StatusDetails
16+
from allure_commons.model2 import TestStepResult
1517
from allure_commons.model2 import Parameter
1618
from allure_commons.types import LabelType, AttachmentType, Severity, LinkType
1719
from allure_robotframework.utils import get_allure_status
@@ -246,6 +248,27 @@ def start_step(self, uuid, title, params):
246248
step.start = now()
247249
step.parameters = [Parameter(name=name, value=value) for name, value in params.items()]
248250

251+
@allure_commons.hookimpl
252+
def add_step_parameter(self, uuid, name, value, excluded, mode):
253+
with self.lifecycle.update_step(uuid=uuid) as step:
254+
if step:
255+
parameter = Parameter(
256+
name=name,
257+
value=represent(value),
258+
excluded=excluded,
259+
mode=mode.value if mode else None
260+
)
261+
step.parameters.append(parameter)
262+
263+
@allure_commons.hookimpl
264+
def get_current_step_uuid(self):
265+
items_list = list(self.lifecycle._items)
266+
for uuid in reversed(items_list):
267+
item = self.lifecycle._items.get(uuid)
268+
if isinstance(item, TestStepResult):
269+
return uuid
270+
return None
271+
249272
@allure_commons.hookimpl
250273
def stop_step(self, uuid, exc_type, exc_val, exc_tb):
251274
with self.lifecycle.update_step() as step:
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
from hamcrest import assert_that
2+
from tests.allure_pytest.pytest_runner import AllurePytestRunner
3+
4+
from allure_commons_test.report import has_test_case
5+
from allure_commons_test.result import has_step
6+
from allure_commons_test.result import has_parameter
7+
from allure_commons_test.result import get_parameter_matcher
8+
from allure_commons_test.result import with_mode
9+
from allure_commons_test.result import with_excluded
10+
from allure_commons_test.result import with_status
11+
12+
13+
def test_add_parameter_context_manager(allure_pytest_runner: AllurePytestRunner):
14+
"""
15+
>>> import allure
16+
17+
>>> def test_add_parameter_context_manager():
18+
... with allure.step("Step 1"):
19+
... allure.add_parameter("env", "production")
20+
... allure.add_parameter("version", "1.0.0")
21+
"""
22+
allure_results = allure_pytest_runner.run_docstring()
23+
24+
assert_that(
25+
allure_results,
26+
has_test_case(
27+
"test_add_parameter_context_manager",
28+
has_step(
29+
"Step 1",
30+
has_parameter("env", "'production'"),
31+
has_parameter("version", "'1.0.0'")
32+
)
33+
)
34+
)
35+
36+
37+
def test_add_parameter_decorator(allure_pytest_runner: AllurePytestRunner):
38+
"""
39+
>>> import allure
40+
41+
>>> @allure.step("Step 2")
42+
... def decorated_step():
43+
... allure.add_parameter("decorated_param", "decorated_value")
44+
45+
>>> def test_add_parameter_decorator():
46+
... decorated_step()
47+
"""
48+
allure_results = allure_pytest_runner.run_docstring()
49+
50+
assert_that(
51+
allure_results,
52+
has_test_case(
53+
"test_add_parameter_decorator",
54+
has_step(
55+
"Step 2",
56+
has_parameter("decorated_param", "'decorated_value'")
57+
)
58+
)
59+
)
60+
61+
62+
def test_add_parameter_nested(allure_pytest_runner: AllurePytestRunner):
63+
"""
64+
>>> import allure
65+
66+
>>> def test_add_parameter_nested():
67+
... with allure.step("Parent Step"):
68+
... with allure.step("Child Step"):
69+
... allure.add_parameter("nested_param", "nested_value")
70+
"""
71+
allure_results = allure_pytest_runner.run_docstring()
72+
73+
assert_that(
74+
allure_results,
75+
has_test_case(
76+
"test_add_parameter_nested",
77+
has_step(
78+
"Parent Step",
79+
has_step(
80+
"Child Step",
81+
has_parameter("nested_param", "'nested_value'")
82+
)
83+
)
84+
)
85+
)
86+
87+
88+
def test_add_parameter_no_active_step_raises_error(allure_pytest_runner: AllurePytestRunner):
89+
"""
90+
>>> import allure
91+
92+
>>> def test_add_parameter_no_active_step_raises_error():
93+
... try:
94+
... allure.add_parameter("test", "value")
95+
... assert False, "Should raise RuntimeError"
96+
... except RuntimeError:
97+
... pass # Expected error
98+
"""
99+
allure_results = allure_pytest_runner.run_docstring()
100+
101+
assert_that(
102+
allure_results,
103+
has_test_case(
104+
"test_add_parameter_no_active_step_raises_error",
105+
with_status("passed")
106+
)
107+
)
108+
109+
110+
def test_add_parameter_with_mode(allure_pytest_runner: AllurePytestRunner):
111+
"""
112+
>>> import allure
113+
114+
>>> def test_add_parameter_with_mode():
115+
... with allure.step("Step 1"):
116+
... allure.add_parameter(
117+
... "password", "secret", mode=allure.parameter_mode.MASKED
118+
... )
119+
"""
120+
allure_results = allure_pytest_runner.run_docstring()
121+
122+
assert_that(
123+
allure_results,
124+
has_test_case(
125+
"test_add_parameter_with_mode",
126+
has_step(
127+
"Step 1",
128+
get_parameter_matcher(
129+
"password",
130+
with_mode("masked")
131+
)
132+
)
133+
)
134+
)
135+
136+
137+
def test_add_parameter_hidden_mode(allure_pytest_runner: AllurePytestRunner):
138+
"""
139+
>>> import allure
140+
141+
>>> def test_add_parameter_hidden_mode():
142+
... with allure.step("Step 1"):
143+
... allure.add_parameter(
144+
... "environment", "staging", mode=allure.parameter_mode.HIDDEN
145+
... )
146+
"""
147+
allure_results = allure_pytest_runner.run_docstring()
148+
149+
assert_that(
150+
allure_results,
151+
has_test_case(
152+
"test_add_parameter_hidden_mode",
153+
has_step(
154+
"Step 1",
155+
get_parameter_matcher(
156+
"environment",
157+
with_mode("hidden")
158+
)
159+
)
160+
)
161+
)
162+
163+
164+
def test_add_parameter_excluded(allure_pytest_runner: AllurePytestRunner):
165+
"""
166+
>>> import allure
167+
168+
>>> def test_add_parameter_excluded():
169+
... with allure.step("Step 1"):
170+
... allure.add_parameter("work-dir", "/tmp", excluded=True)
171+
"""
172+
allure_results = allure_pytest_runner.run_docstring()
173+
174+
assert_that(
175+
allure_results,
176+
has_test_case(
177+
"test_add_parameter_excluded",
178+
has_step(
179+
"Step 1",
180+
get_parameter_matcher(
181+
"work-dir",
182+
with_excluded()
183+
)
184+
)
185+
)
186+
)
187+
188+
189+
def test_add_parameter_multiple(allure_pytest_runner: AllurePytestRunner):
190+
"""
191+
>>> import allure
192+
193+
>>> def test_add_parameter_multiple():
194+
... with allure.step("Step 1"):
195+
... allure.add_parameter("env", "staging")
196+
... allure.add_parameter("version", "1.0.0")
197+
... allure.add_parameter("host", "localhost")
198+
"""
199+
allure_results = allure_pytest_runner.run_docstring()
200+
201+
assert_that(
202+
allure_results,
203+
has_test_case(
204+
"test_add_parameter_multiple",
205+
has_step(
206+
"Step 1",
207+
has_parameter("env", "'staging'"),
208+
has_parameter("version", "'1.0.0'"),
209+
has_parameter("host", "'localhost'")
210+
)
211+
)
212+
)
213+
214+
215+
def test_add_parameter_vs_test_parameter(allure_pytest_runner: AllurePytestRunner):
216+
"""
217+
>>> import allure
218+
219+
>>> def test_add_parameter_vs_test_parameter():
220+
... allure.dynamic.parameter("test_param", "test_value")
221+
... with allure.step("Step 1"):
222+
... allure.add_parameter("step_param", "step_value")
223+
"""
224+
allure_results = allure_pytest_runner.run_docstring()
225+
226+
assert_that(
227+
allure_results,
228+
has_test_case(
229+
"test_add_parameter_vs_test_parameter",
230+
has_parameter("test_param", "'test_value'"),
231+
has_step(
232+
"Step 1",
233+
has_parameter("step_param", "'step_value'")
234+
)
235+
)
236+
)

0 commit comments

Comments
 (0)