cucu 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cucu might be problematic. Click here for more details.
- cucu/__init__.py +38 -0
- cucu/ansi_parser.py +58 -0
- cucu/behave_tweaks.py +196 -0
- cucu/browser/__init__.py +0 -0
- cucu/browser/core.py +80 -0
- cucu/browser/frames.py +106 -0
- cucu/browser/selenium.py +323 -0
- cucu/browser/selenium_tweaks.py +27 -0
- cucu/cli/__init__.py +3 -0
- cucu/cli/core.py +788 -0
- cucu/cli/run.py +207 -0
- cucu/cli/steps.py +137 -0
- cucu/cli/thread_dumper.py +55 -0
- cucu/config.py +440 -0
- cucu/edgedriver_autoinstaller/README.md +1 -0
- cucu/edgedriver_autoinstaller/__init__.py +37 -0
- cucu/edgedriver_autoinstaller/utils.py +231 -0
- cucu/environment.py +283 -0
- cucu/external/jquery/jquery-3.5.1.min.js +2 -0
- cucu/formatter/__init__.py +0 -0
- cucu/formatter/cucu.py +261 -0
- cucu/formatter/json.py +321 -0
- cucu/formatter/junit.py +289 -0
- cucu/fuzzy/__init__.py +3 -0
- cucu/fuzzy/core.py +107 -0
- cucu/fuzzy/fuzzy.js +253 -0
- cucu/helpers.py +875 -0
- cucu/hooks.py +205 -0
- cucu/language_server/__init__.py +3 -0
- cucu/language_server/core.py +114 -0
- cucu/lint/__init__.py +0 -0
- cucu/lint/linter.py +397 -0
- cucu/lint/rules/format.yaml +125 -0
- cucu/logger.py +113 -0
- cucu/matcher/__init__.py +0 -0
- cucu/matcher/core.py +30 -0
- cucu/page_checks.py +63 -0
- cucu/reporter/__init__.py +3 -0
- cucu/reporter/external/bootstrap.min.css +7 -0
- cucu/reporter/external/bootstrap.min.js +7 -0
- cucu/reporter/external/dataTables.bootstrap.min.css +1 -0
- cucu/reporter/external/dataTables.bootstrap.min.js +14 -0
- cucu/reporter/external/jquery-3.5.1.min.js +2 -0
- cucu/reporter/external/jquery.dataTables.min.js +192 -0
- cucu/reporter/external/popper.min.js +5 -0
- cucu/reporter/favicon.png +0 -0
- cucu/reporter/html.py +452 -0
- cucu/reporter/templates/feature.html +72 -0
- cucu/reporter/templates/flat.html +48 -0
- cucu/reporter/templates/index.html +49 -0
- cucu/reporter/templates/layout.html +109 -0
- cucu/reporter/templates/scenario.html +200 -0
- cucu/steps/__init__.py +27 -0
- cucu/steps/base_steps.py +88 -0
- cucu/steps/browser_steps.py +337 -0
- cucu/steps/button_steps.py +91 -0
- cucu/steps/checkbox_steps.py +111 -0
- cucu/steps/command_steps.py +181 -0
- cucu/steps/comment_steps.py +17 -0
- cucu/steps/draggable_steps.py +168 -0
- cucu/steps/dropdown_steps.py +467 -0
- cucu/steps/file_input_steps.py +80 -0
- cucu/steps/filesystem_steps.py +144 -0
- cucu/steps/flow_control_steps.py +198 -0
- cucu/steps/image_steps.py +37 -0
- cucu/steps/input_steps.py +301 -0
- cucu/steps/link_steps.py +63 -0
- cucu/steps/menuitem_steps.py +39 -0
- cucu/steps/platform_steps.py +29 -0
- cucu/steps/radio_steps.py +187 -0
- cucu/steps/step_utils.py +55 -0
- cucu/steps/tab_steps.py +68 -0
- cucu/steps/table_steps.py +437 -0
- cucu/steps/tables.js +28 -0
- cucu/steps/text_steps.py +78 -0
- cucu/steps/variable_steps.py +100 -0
- cucu/steps/webserver_steps.py +40 -0
- cucu/utils.py +269 -0
- cucu-1.0.0.dist-info/METADATA +424 -0
- cucu-1.0.0.dist-info/RECORD +83 -0
- cucu-1.0.0.dist-info/WHEEL +4 -0
- cucu-1.0.0.dist-info/entry_points.txt +2 -0
- cucu-1.0.0.dist-info/licenses/LICENSE +32 -0
cucu/helpers.py
ADDED
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
import humanize
|
|
4
|
+
|
|
5
|
+
from cucu import logger, retry, run_steps
|
|
6
|
+
from cucu.config import CONFIG
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class step(object):
|
|
10
|
+
"""
|
|
11
|
+
Only to be used in this file as we're redefining the @step decorator in
|
|
12
|
+
order to fix the code location of the @step() usage.
|
|
13
|
+
|
|
14
|
+
Basically when you use any of the `define_xxx` steps below internally they
|
|
15
|
+
call @step() and when that decorator executes in behave it will take the
|
|
16
|
+
location of the function provided to the decorator and use that to both
|
|
17
|
+
report as the location of the step's "source"
|
|
18
|
+
(ie uv run behave --no-summary --format steps.doc --dry-run). Now that
|
|
19
|
+
would be confusing as the step is likely defined somewhere under
|
|
20
|
+
`src/cucu/steps` but the location in the behave steps output would be wrong
|
|
21
|
+
and then at runtime if there's an exception throw from one of the other
|
|
22
|
+
functions inside the `define_xxx` method that trace would also not originate
|
|
23
|
+
from the `src/cucu/steps` location where the `define_xxx` was called.
|
|
24
|
+
|
|
25
|
+
So this redefinition of @step will basically use a hook in the existing
|
|
26
|
+
@step definition in `src/cucu/behave_tweaks.py` and provide a function
|
|
27
|
+
to "fix" the inner_step function so its own code location now points back
|
|
28
|
+
to the location where the `define_xxx` was called from.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, step_text):
|
|
32
|
+
self.step_text = step_text
|
|
33
|
+
frame = sys._getframe(1).f_back
|
|
34
|
+
|
|
35
|
+
def fix_inner_step(func):
|
|
36
|
+
#
|
|
37
|
+
# Here is where we "fix" the code location for the function being
|
|
38
|
+
# passed to the step() decorator. We are basically realigning the
|
|
39
|
+
# filename and line location so it points to the original caller
|
|
40
|
+
# of the `define_xxx` method. To do this alignment though we have
|
|
41
|
+
# to subtract from the original file line number the number of code
|
|
42
|
+
# lines in the `src/cucu/behave_tweaks.py` between the functions
|
|
43
|
+
# wrapper and inner_step as that is the "actual code location" at
|
|
44
|
+
# runtime and below we can only set the `firstlineno` which is the
|
|
45
|
+
# "first line" of our __code__ point and by the time those N lines
|
|
46
|
+
# execute the line number python would print would be N lines ahead
|
|
47
|
+
# of the original location of the code we're trying to link to.
|
|
48
|
+
#
|
|
49
|
+
func.__code__ = func.__code__.replace(
|
|
50
|
+
co_filename=frame.f_code.co_filename,
|
|
51
|
+
co_firstlineno=frame.f_lineno - 3,
|
|
52
|
+
co_name=frame.f_code.co_name,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
self.fix_inner_step = fix_inner_step
|
|
56
|
+
|
|
57
|
+
def __call__(self, func):
|
|
58
|
+
from behave import step
|
|
59
|
+
|
|
60
|
+
@step(self.step_text, fix_inner_step=self.fix_inner_step)
|
|
61
|
+
def wrapper(*args, **kwargs):
|
|
62
|
+
func(*args, **kwargs)
|
|
63
|
+
|
|
64
|
+
return wrapper
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def nth_to_ordinal(index):
|
|
68
|
+
return "" if index == 0 else f'"{humanize.ordinal(index + 1)}" '
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def define_should_see_thing_with_name_steps(thing, find_func, with_nth=False):
|
|
72
|
+
"""
|
|
73
|
+
defines steps with with the following signatures:
|
|
74
|
+
|
|
75
|
+
I should immediately see the {thing} "{name}"
|
|
76
|
+
I should see the {thing} "{name}"
|
|
77
|
+
I wait to see the {thing} "{name}"
|
|
78
|
+
I wait up to "{seconds}" seconds to see the {thing} "{name}"
|
|
79
|
+
|
|
80
|
+
when with_nth=True we also define:
|
|
81
|
+
I should immediately see the "{nth}" {thing} "{name}"
|
|
82
|
+
I should see the "{nth}" {thing} "{name}"
|
|
83
|
+
I wait to see the "{nth}" {thing} "{name}"
|
|
84
|
+
I wait up to "{seconds}" seconds to see the "{nth}" {thing} "{name}"
|
|
85
|
+
|
|
86
|
+
I should immediately not see the {thing} "{name}"
|
|
87
|
+
I should not see the {thing} "{name}"
|
|
88
|
+
I wait to not see the {thing} "{name}"
|
|
89
|
+
I wait up to "{seconds}" seconds to not see the {thing} "{name}"
|
|
90
|
+
|
|
91
|
+
when with_nth=True we also define:
|
|
92
|
+
I should immediately not see the "{nth}" {thing} "{name}"
|
|
93
|
+
I should not see the "{nth}" {thing} "{name}"
|
|
94
|
+
I wait to not see the "{nth}" {thing} "{name}"
|
|
95
|
+
I wait up to "{seconds}" seconds to not see the "{nth}" {thing} "{name}"
|
|
96
|
+
|
|
97
|
+
parameters:
|
|
98
|
+
thing(string): name of the thing we're creating the steps for such
|
|
99
|
+
as button, dialog, etc.
|
|
100
|
+
find_func(function): function that returns the desired element:
|
|
101
|
+
|
|
102
|
+
def find_func(ctx, name, index=):
|
|
103
|
+
'''
|
|
104
|
+
ctx(object): behave context object
|
|
105
|
+
name(string): name of the thing to find
|
|
106
|
+
index(int): when there are multiple elements
|
|
107
|
+
with the same name and you've
|
|
108
|
+
specified with_nth=True
|
|
109
|
+
'''
|
|
110
|
+
with_nth(bool): when set to True we'll define the expanded set of
|
|
111
|
+
"nth" steps. default: False
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
# should see
|
|
115
|
+
# undecorated def for reference below
|
|
116
|
+
def base_should_see_the(ctx, thing, name, index=0):
|
|
117
|
+
prefix = nth_to_ordinal(index)
|
|
118
|
+
element = find_func(ctx, name, index=index)
|
|
119
|
+
|
|
120
|
+
if element is None:
|
|
121
|
+
raise RuntimeError(f'unable to find the {prefix}{thing} "{name}"')
|
|
122
|
+
logger.debug(f'Success: saw {prefix}{thing} "{name}"')
|
|
123
|
+
|
|
124
|
+
@step(f'I should immediately see the {thing} "{{name}}"')
|
|
125
|
+
def should_immediately_see_the(ctx, thing, name):
|
|
126
|
+
base_should_see_the(ctx, thing, name)
|
|
127
|
+
|
|
128
|
+
@step(f'I should see the {thing} "{{name}}"')
|
|
129
|
+
def should_see_the(ctx, name):
|
|
130
|
+
retry(
|
|
131
|
+
base_should_see_the,
|
|
132
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
133
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
134
|
+
)(ctx, thing, name)
|
|
135
|
+
|
|
136
|
+
@step(f'I wait to see the {thing} "{{name}}"')
|
|
137
|
+
def wait_to_see_the(ctx, name):
|
|
138
|
+
retry(base_should_see_the)(ctx, thing, name)
|
|
139
|
+
|
|
140
|
+
@step(f'I wait up to "{{seconds}}" seconds to see the {thing} "{{name}}"')
|
|
141
|
+
def wait_up_to_seconds_to_see_the(ctx, seconds, name):
|
|
142
|
+
milliseconds = float(seconds)
|
|
143
|
+
retry(base_should_see_the, wait_up_to_s=milliseconds)(ctx, thing, name)
|
|
144
|
+
|
|
145
|
+
if with_nth:
|
|
146
|
+
|
|
147
|
+
@step(f'I should immediately see the "{{nth:nth}}" {thing} "{{name}}"')
|
|
148
|
+
def base_should_see_the_nth(ctx, nth, name):
|
|
149
|
+
base_should_see_the(ctx, thing, name, index=nth)
|
|
150
|
+
|
|
151
|
+
@step(f'I should see the "{{nth:nth}}" {thing} "{{name}}"')
|
|
152
|
+
def should_see_the_nth(ctx, nth, name):
|
|
153
|
+
retry(
|
|
154
|
+
base_should_see_the,
|
|
155
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
156
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
157
|
+
)(ctx, thing, name, index=nth)
|
|
158
|
+
|
|
159
|
+
@step(f'I wait to see the "{{nth:nth}}" {thing} "{{name}}"')
|
|
160
|
+
def wait_to_see_the_nth(ctx, nth, name):
|
|
161
|
+
retry(base_should_see_the)(ctx, thing, name, index=nth)
|
|
162
|
+
|
|
163
|
+
@step(
|
|
164
|
+
f'I wait up to "{{seconds}}" seconds to see the "{{nth:nth}}" {thing} "{{name}}"'
|
|
165
|
+
)
|
|
166
|
+
def wait_up_to_seconds_to_see_the_nth(ctx, seconds, nth, name):
|
|
167
|
+
seconds = float(seconds)
|
|
168
|
+
retry(base_should_see_the, wait_up_to_s=seconds)(
|
|
169
|
+
ctx, thing, name, index=nth
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# should not see
|
|
173
|
+
# undecorated def for reference below
|
|
174
|
+
def base_should_not_see_the(ctx, thing, name, index=0):
|
|
175
|
+
prefix = nth_to_ordinal(index)
|
|
176
|
+
element = find_func(ctx, name, index=index)
|
|
177
|
+
|
|
178
|
+
if element is not None:
|
|
179
|
+
raise RuntimeError(f'able to find the {prefix}{thing} "{name}"')
|
|
180
|
+
logger.debug(f'Success: did not see {prefix}{thing} "{name}"')
|
|
181
|
+
|
|
182
|
+
@step(f'I should immediately not see the {thing} "{{name}}"')
|
|
183
|
+
def should_immediately_not_see_the(ctx, thing, name):
|
|
184
|
+
base_should_not_see_the(ctx, thing, name)
|
|
185
|
+
|
|
186
|
+
@step(f'I should not see the {thing} "{{name}}"')
|
|
187
|
+
def should_not_see_the(ctx, name):
|
|
188
|
+
retry(
|
|
189
|
+
base_should_not_see_the,
|
|
190
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
191
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
192
|
+
)(ctx, thing, name)
|
|
193
|
+
|
|
194
|
+
@step(f'I wait to not see the {thing} "{{name}}"')
|
|
195
|
+
def wait_to_not_see_the(ctx, name):
|
|
196
|
+
retry(base_should_not_see_the)(ctx, thing, name)
|
|
197
|
+
|
|
198
|
+
@step(
|
|
199
|
+
f'I wait up to "{{seconds}}" seconds to not see the {thing} "{{name}}"'
|
|
200
|
+
)
|
|
201
|
+
def wait_up_to_seconds_to_not_see_the(ctx, seconds, name):
|
|
202
|
+
milliseconds = float(seconds)
|
|
203
|
+
retry(base_should_not_see_the, wait_up_to_s=milliseconds)(
|
|
204
|
+
ctx, thing, name
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if with_nth:
|
|
208
|
+
|
|
209
|
+
@step(
|
|
210
|
+
f'I should immediately not see the "{{nth:nth}}" {thing} "{{name}}"'
|
|
211
|
+
)
|
|
212
|
+
def should_immediately_not_see_the_nth(ctx, nth, name):
|
|
213
|
+
base_should_not_see_the(ctx, thing, name, index=nth)
|
|
214
|
+
|
|
215
|
+
@step(f'I should not see the "{{nth:nth}}" {thing} "{{name}}"')
|
|
216
|
+
def should_not_see_the_nth(ctx, nth, name):
|
|
217
|
+
retry(
|
|
218
|
+
base_should_not_see_the,
|
|
219
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
220
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
221
|
+
)(ctx, thing, name, index=nth)
|
|
222
|
+
|
|
223
|
+
@step(f'I wait to not see the "{{nth:nth}}" {thing} "{{name}}"')
|
|
224
|
+
def wait_to_not_see_the_nth(ctx, nth, name):
|
|
225
|
+
retry(base_should_not_see_the)(ctx, thing, name, index=nth)
|
|
226
|
+
|
|
227
|
+
@step(
|
|
228
|
+
f'I wait up to "{{seconds}}" seconds to not see the "{{nth:nth}}" {thing} "{{name}}"'
|
|
229
|
+
)
|
|
230
|
+
def wait_up_to_seconds_to_not_see_the_nth(ctx, seconds, nth, name):
|
|
231
|
+
seconds = float(seconds)
|
|
232
|
+
retry(base_should_not_see_the, wait_up_to_s=seconds)(
|
|
233
|
+
ctx, thing, name, index=nth
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def define_action_on_thing_with_name_steps(
|
|
238
|
+
thing, action, find_func, action_func, with_nth=False
|
|
239
|
+
):
|
|
240
|
+
"""
|
|
241
|
+
defines steps with with the following signatures:
|
|
242
|
+
|
|
243
|
+
I {action} the {thing} "{name}"
|
|
244
|
+
I wait to {action} the {thing} "{name}"
|
|
245
|
+
I wait up to "{seconds}" seconds to {action} the {thing} "{name}"
|
|
246
|
+
...
|
|
247
|
+
I {action} the {thing} "{name}" if it exists
|
|
248
|
+
|
|
249
|
+
when with_nth=True we also define:
|
|
250
|
+
|
|
251
|
+
I {action} the "{nth}" {thing} "{name}"
|
|
252
|
+
I wait to {action} the "{nth}" {thing} "{name}"
|
|
253
|
+
I wait up to "{seconds}" seconds to "{nth}" {action} the {thing} "{name}"
|
|
254
|
+
...
|
|
255
|
+
I {action} the "{nth}" {thing} "{name}" if it exists
|
|
256
|
+
|
|
257
|
+
parameters:
|
|
258
|
+
thing(string): name of the thing we're creating the steps for such
|
|
259
|
+
as button, dialog, etc.
|
|
260
|
+
action(string): the name of the action being performed, such as:
|
|
261
|
+
click, disable, etc.
|
|
262
|
+
find_func(function): function that returns the desired element:
|
|
263
|
+
|
|
264
|
+
def find_func(ctx, name, index=):
|
|
265
|
+
'''
|
|
266
|
+
ctx(object): behave context object
|
|
267
|
+
name(string): name of the thing to find
|
|
268
|
+
index(int): when there are multiple elements
|
|
269
|
+
with the same name and you've
|
|
270
|
+
specified with_nth=True
|
|
271
|
+
'''
|
|
272
|
+
action_func(function): function that performs the desired action:
|
|
273
|
+
|
|
274
|
+
def action_func(ctx, element):
|
|
275
|
+
'''
|
|
276
|
+
ctx(object): behave context object
|
|
277
|
+
element(object): the element found
|
|
278
|
+
'''
|
|
279
|
+
with_nth(bool): when set to True we'll define the expanded set of
|
|
280
|
+
"nth" steps. default: False
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
# undecorated def for reference below
|
|
284
|
+
def base_action_the(ctx, thing, name, index=0, must_exist=True):
|
|
285
|
+
prefix = nth_to_ordinal(index)
|
|
286
|
+
element = find_func(ctx, name, index=index)
|
|
287
|
+
|
|
288
|
+
if element is None:
|
|
289
|
+
if must_exist:
|
|
290
|
+
raise RuntimeError(
|
|
291
|
+
f'unable to find the {prefix}{thing} "{name}"'
|
|
292
|
+
)
|
|
293
|
+
else:
|
|
294
|
+
action_func(ctx, element)
|
|
295
|
+
logger.debug(
|
|
296
|
+
f'Successfully executed {action} {prefix}{thing} "{name}"'
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
@step(f'I immediately {action} the {thing} "{{name}}"')
|
|
300
|
+
def immediately_action_the(ctx, name):
|
|
301
|
+
base_action_the(ctx, thing, name)
|
|
302
|
+
|
|
303
|
+
@step(f'I {action} the {thing} "{{name}}"')
|
|
304
|
+
def action_the(ctx, name):
|
|
305
|
+
retry(
|
|
306
|
+
base_action_the,
|
|
307
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
308
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
309
|
+
)(ctx, thing, name)
|
|
310
|
+
|
|
311
|
+
@step(f'I immediately {action} the {thing} "{{name}}" if it exists')
|
|
312
|
+
def immediately_action_the_if_it_exists(ctx, name):
|
|
313
|
+
base_action_the(ctx, thing, name, must_exist=False)
|
|
314
|
+
|
|
315
|
+
@step(f'I {action} the {thing} "{{name}}" if it exists')
|
|
316
|
+
def action_the_if_it_exists(ctx, name):
|
|
317
|
+
retry(
|
|
318
|
+
base_action_the,
|
|
319
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
320
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
321
|
+
)(ctx, thing, name, must_exist=False)
|
|
322
|
+
|
|
323
|
+
@step(f'I wait to {action} the {thing} "{{name}}"')
|
|
324
|
+
def wait_to_action_the(ctx, name):
|
|
325
|
+
retry(base_action_the)(ctx, thing, name)
|
|
326
|
+
|
|
327
|
+
@step(f'I wait to {action} the {thing} "{{name}}" if it exists')
|
|
328
|
+
def wait_to_action_the_if_it_exists(ctx, name):
|
|
329
|
+
retry(base_action_the)(ctx, thing, name, must_exist=False)
|
|
330
|
+
|
|
331
|
+
@step(
|
|
332
|
+
f'I wait up to "{{seconds}}" seconds to {action} the {thing} "{{name}}"'
|
|
333
|
+
)
|
|
334
|
+
def wait_up_to_seconds_to_action_the(ctx, seconds, name):
|
|
335
|
+
seconds = float(seconds)
|
|
336
|
+
retry(base_action_the, wait_up_to_s=seconds)(ctx, thing, name)
|
|
337
|
+
|
|
338
|
+
if with_nth:
|
|
339
|
+
|
|
340
|
+
@step(f'I immediately {action} the "{{nth:nth}}" {thing} "{{name}}"')
|
|
341
|
+
def immediately_action_the_nth(ctx, nth, name):
|
|
342
|
+
base_action_the(ctx, thing, name, index=nth)
|
|
343
|
+
|
|
344
|
+
@step(f'I {action} the "{{nth:nth}}" {thing} "{{name}}"')
|
|
345
|
+
def action_the_nth(ctx, nth, name):
|
|
346
|
+
retry(
|
|
347
|
+
base_action_the,
|
|
348
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
349
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
350
|
+
)(ctx, thing, name, index=nth)
|
|
351
|
+
|
|
352
|
+
@step(
|
|
353
|
+
f'I immediately {action} the "{{nth:nth}}" {thing} "{{name}}" if it exists'
|
|
354
|
+
)
|
|
355
|
+
def immediately_action_the_nth_if_it_exists(ctx, nth, name):
|
|
356
|
+
base_action_the(ctx, thing, name, index=nth, must_exist=False)
|
|
357
|
+
|
|
358
|
+
@step(f'I {action} the "{{nth:nth}}" {thing} "{{name}}" if it exists')
|
|
359
|
+
def action_the_nth_if_it_exists(ctx, nth, name):
|
|
360
|
+
retry(
|
|
361
|
+
base_action_the,
|
|
362
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
363
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
364
|
+
)(ctx, thing, name, index=nth, must_exist=False)
|
|
365
|
+
|
|
366
|
+
@step(f'I wait to {action} the "{{nth:nth}}" {thing} "{{name}}"')
|
|
367
|
+
def wait_to_action_the_nth(ctx, nth, name):
|
|
368
|
+
retry(base_action_the)(ctx, thing, name, index=nth)
|
|
369
|
+
|
|
370
|
+
@step(
|
|
371
|
+
f'I wait up to "{{seconds}}" seconds to {action} the "{{nth:nth}}" {thing} "{{name}}"'
|
|
372
|
+
)
|
|
373
|
+
def wait_up_to_action_the_nth(ctx, seconds, nth, name):
|
|
374
|
+
seconds = float(seconds)
|
|
375
|
+
retry(base_action_the, wait_up_to_s=seconds)(
|
|
376
|
+
ctx, thing, name, index=nth
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def define_ensure_state_on_thing_with_name_steps(
|
|
381
|
+
thing, state, find_func, state_func, action_func, with_nth=False
|
|
382
|
+
):
|
|
383
|
+
"""
|
|
384
|
+
defines steps with with the following signatures:
|
|
385
|
+
|
|
386
|
+
I ensure the {thing} "{name}" is {state}
|
|
387
|
+
I wait to ensure the {thing} "{name}" is {state}
|
|
388
|
+
I wait up to "{seconds}" seconds to ensure the {thing} "{name}" is {state}
|
|
389
|
+
|
|
390
|
+
when with_nth=True we also define:
|
|
391
|
+
|
|
392
|
+
I ensure the "{nth}" {thing} "{name}" is {state}
|
|
393
|
+
I wait to ensure the "{nth}" {thing} "{name}" is {state}
|
|
394
|
+
I wait up to "{seconds}" seconds to ensure the "{nth}" {thing} "{name}" is {state}
|
|
395
|
+
|
|
396
|
+
parameters:
|
|
397
|
+
thing(string): name of the thing we're creating the steps for such
|
|
398
|
+
as button, dialog, etc.
|
|
399
|
+
state(stirng): the name of the state we want to ensure, such as:
|
|
400
|
+
filled, checked, empty, not empty, etc.
|
|
401
|
+
find_func(function): function that returns the desired element:
|
|
402
|
+
|
|
403
|
+
def find_func(ctx, name, index=):
|
|
404
|
+
'''
|
|
405
|
+
ctx(object): behave context object
|
|
406
|
+
name(string): name of the thing to find
|
|
407
|
+
index(int): when there are multiple elements
|
|
408
|
+
with the same name and you've
|
|
409
|
+
specified with_nth=True
|
|
410
|
+
'''
|
|
411
|
+
state_func(function): function that returns True if the element is in
|
|
412
|
+
the desired state and False otherwise:
|
|
413
|
+
|
|
414
|
+
def state_func(element):
|
|
415
|
+
'''
|
|
416
|
+
element(object): the element found
|
|
417
|
+
'''
|
|
418
|
+
action_func(function): action that will set the desired state on the
|
|
419
|
+
element if state_func returns False:
|
|
420
|
+
def action_func(ctx, element):
|
|
421
|
+
'''
|
|
422
|
+
ctx(object): behave context object
|
|
423
|
+
element(object): the element found
|
|
424
|
+
'''
|
|
425
|
+
with_nth(bool): when set to True we'll define the expanded set of
|
|
426
|
+
"nth" steps. default: False
|
|
427
|
+
"""
|
|
428
|
+
|
|
429
|
+
# undecorated def for reference below
|
|
430
|
+
def base_ensure_the(ctx, thing, name, index=0):
|
|
431
|
+
prefix = nth_to_ordinal(index)
|
|
432
|
+
element = find_func(ctx, name, index=index)
|
|
433
|
+
|
|
434
|
+
if element is None:
|
|
435
|
+
raise RuntimeError(f'unable to find the {prefix}{thing} "{name}"')
|
|
436
|
+
|
|
437
|
+
if not state_func(element):
|
|
438
|
+
action_func(ctx, element)
|
|
439
|
+
|
|
440
|
+
@step(f'I immediately ensure the {thing} "{{name}}" is {state}')
|
|
441
|
+
def immediately_ensure_the(ctx, name, state):
|
|
442
|
+
base_ensure_the(ctx, thing, name)
|
|
443
|
+
|
|
444
|
+
@step(f'I ensure the {thing} "{{name}}" is {state}')
|
|
445
|
+
def ensure_the(ctx, name):
|
|
446
|
+
retry(
|
|
447
|
+
base_ensure_the,
|
|
448
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
449
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
450
|
+
)(ctx, thing, name)
|
|
451
|
+
|
|
452
|
+
@step(f'I wait to ensure the {thing} "{{name}}" is {state}')
|
|
453
|
+
def wait_to_ensure_the(ctx, name):
|
|
454
|
+
retry(base_ensure_the)(ctx, thing, name)
|
|
455
|
+
|
|
456
|
+
@step(
|
|
457
|
+
f'I wait up to "{{seconds}}" seconds to ensure the {thing} "{{name}}" is {state}'
|
|
458
|
+
)
|
|
459
|
+
def wait_up_to_seconds_to_ensure_the(ctx, seconds, name):
|
|
460
|
+
seconds = float(seconds)
|
|
461
|
+
retry(base_ensure_the, wait_up_to_s=seconds)(ctx, thing, name)
|
|
462
|
+
|
|
463
|
+
if with_nth:
|
|
464
|
+
|
|
465
|
+
@step(
|
|
466
|
+
f'I immediately ensure the "{{nth:nth}}" {thing} "{{name}}" is {state}'
|
|
467
|
+
)
|
|
468
|
+
def immediately_ensure_the_nth(ctx, nth, name):
|
|
469
|
+
base_ensure_the(ctx, thing, name, index=nth)
|
|
470
|
+
|
|
471
|
+
@step(f'I ensure the "{{nth:nth}}" {thing} "{{name}}"')
|
|
472
|
+
def ensure_the_nth(ctx, nth, name):
|
|
473
|
+
retry(
|
|
474
|
+
base_ensure_the,
|
|
475
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
476
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
477
|
+
)(ctx, thing, name, index=nth)
|
|
478
|
+
|
|
479
|
+
@step(
|
|
480
|
+
f'I wait to ensure the "{{nth:nth}}" {thing} "{{name}}" is {state}'
|
|
481
|
+
)
|
|
482
|
+
def wait_to_ensure_the_nth(ctx, nth, name):
|
|
483
|
+
retry(base_ensure_the)(ctx, thing, name, index=nth)
|
|
484
|
+
|
|
485
|
+
@step(
|
|
486
|
+
f'I wait up to "{{seconds}}" seconds to ensure the "{{nth:nth}}" {thing} "{{name}}" is {state}'
|
|
487
|
+
)
|
|
488
|
+
def wait_up_to_ensure_the_nth(ctx, seconds, nth, name):
|
|
489
|
+
seconds = float(seconds)
|
|
490
|
+
retry(base_ensure_the, wait_up_to_s=seconds)(
|
|
491
|
+
ctx, thing, name, index=nth
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def define_thing_with_name_in_state_steps(
|
|
496
|
+
thing, state, find_func, is_in_state_func, with_nth=False
|
|
497
|
+
):
|
|
498
|
+
"""
|
|
499
|
+
defines steps with with the following signatures:
|
|
500
|
+
|
|
501
|
+
I should immediately see the {thing} "{name}" is {state_name}
|
|
502
|
+
I should see the {thing} "{name}" is {state_name}
|
|
503
|
+
I wait to see the {thing} "{name}" is {state_name}
|
|
504
|
+
I wait up to "{seconds}" seconds to see the {thing} "{name}" is {state_name}
|
|
505
|
+
|
|
506
|
+
when with_nth=True we also define:
|
|
507
|
+
|
|
508
|
+
I should immediately see the "{nth}" {thing} "{name}" is {state_name}
|
|
509
|
+
I should see the "{nth}" {thing} "{name}" is {state_name}
|
|
510
|
+
I wait to see the "{nth}" {thing} "{name}" is {state_name}
|
|
511
|
+
I wait up to "{seconds}" seconds to see the "{nth}" {thing} "{name}" is {state_name}
|
|
512
|
+
|
|
513
|
+
parameters:
|
|
514
|
+
thing(string): name of the thing we're creating the steps for such
|
|
515
|
+
as button, dialog, etc.
|
|
516
|
+
state(stirng): the name of the state being verified, such as:
|
|
517
|
+
selected, checked, disabled, etc.
|
|
518
|
+
find_func(function): function that returns the desired element:
|
|
519
|
+
|
|
520
|
+
def find_func(ctx, name, index=):
|
|
521
|
+
'''
|
|
522
|
+
ctx(object): behave context object
|
|
523
|
+
name(string): name of the thing to find
|
|
524
|
+
index(int): when there are multiple elements
|
|
525
|
+
with the same name and you've
|
|
526
|
+
specified with_nth=True
|
|
527
|
+
'''
|
|
528
|
+
is_int_state_func(function): function that verifies the element is in
|
|
529
|
+
the desired state:
|
|
530
|
+
|
|
531
|
+
def is_in_state_func(element):
|
|
532
|
+
'''
|
|
533
|
+
element(object): the element found
|
|
534
|
+
returns(bool): returns True if in
|
|
535
|
+
expected state
|
|
536
|
+
'''
|
|
537
|
+
with_nth(bool): when set to True we'll define the expanded set of
|
|
538
|
+
"nth" steps. default: False
|
|
539
|
+
|
|
540
|
+
"""
|
|
541
|
+
|
|
542
|
+
# undecorated def for reference below
|
|
543
|
+
def base_should_see_the_in_state(ctx, thing, name, index=0):
|
|
544
|
+
prefix = nth_to_ordinal(index)
|
|
545
|
+
element = find_func(ctx, name, index=index)
|
|
546
|
+
|
|
547
|
+
if element is None:
|
|
548
|
+
raise RuntimeError(f'unable to find the {prefix}{thing} "{name}"')
|
|
549
|
+
|
|
550
|
+
if not is_in_state_func(element):
|
|
551
|
+
raise RuntimeError(f'{thing} "{name}" is not {state}')
|
|
552
|
+
logger.debug(f'{thing} {name} was in desired state "{state}"')
|
|
553
|
+
|
|
554
|
+
@step(f'I should immediately see the {thing} "{{name}}" is {state}')
|
|
555
|
+
def should_immediately_see_the_in_state(ctx, name, index=0):
|
|
556
|
+
base_should_see_the_in_state(ctx, thing, name, index=0)
|
|
557
|
+
|
|
558
|
+
@step(f'I should see the {thing} "{{name}}" is {state}')
|
|
559
|
+
def should_see_the_in_state(ctx, name):
|
|
560
|
+
retry(
|
|
561
|
+
base_should_see_the_in_state,
|
|
562
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
563
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
564
|
+
)(ctx, thing, name)
|
|
565
|
+
|
|
566
|
+
@step(f'I wait to see the {thing} "{{name}}" is {state}')
|
|
567
|
+
def wait_to_see_the_in_state(ctx, name):
|
|
568
|
+
retry(base_should_see_the_in_state)(ctx, thing, name)
|
|
569
|
+
|
|
570
|
+
@step(
|
|
571
|
+
f'I wait up to "{{seconds}}" seconds to see the {thing} "{{name}}" is {state}'
|
|
572
|
+
)
|
|
573
|
+
def wait_up_to_seconds_to_see_the_in_state(ctx, seconds, name):
|
|
574
|
+
seconds = float(seconds)
|
|
575
|
+
retry(base_should_see_the_in_state, wait_up_to_s=seconds)(
|
|
576
|
+
ctx, thing, name
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
if with_nth:
|
|
580
|
+
|
|
581
|
+
@step(
|
|
582
|
+
f'I should immediately see the "{{nth:nth}}" {thing} "{{name}}" is {state}'
|
|
583
|
+
)
|
|
584
|
+
def base_should_see_the_nth_in_state(ctx, nth, name):
|
|
585
|
+
base_should_see_the_in_state(ctx, thing, name, index=nth)
|
|
586
|
+
|
|
587
|
+
@step(f'I should see the "{{nth:nth}}" {thing} "{{name}}" is {state}')
|
|
588
|
+
def should_see_the_nth_in_state(ctx, nth, name):
|
|
589
|
+
retry(
|
|
590
|
+
base_should_see_the_in_state,
|
|
591
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
592
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
593
|
+
)(ctx, thing, name, index=nth)
|
|
594
|
+
|
|
595
|
+
@step(f'I wait to see the "{{nth:nth}}" {thing} "{{name}}" is {state}')
|
|
596
|
+
def wait_to_see_the_nth_in_state(ctx, nth, name):
|
|
597
|
+
retry(base_should_see_the_in_state)(ctx, thing, name, index=nth)
|
|
598
|
+
|
|
599
|
+
@step(
|
|
600
|
+
f'I wait up to "{{seconds}}" seconds to see the "{{nth:nth}}" {thing} "{{name}}" is {state}'
|
|
601
|
+
)
|
|
602
|
+
def wait_up_to_seconds_to_see_the_nth_in_state(
|
|
603
|
+
ctx, seconds, nth, name
|
|
604
|
+
):
|
|
605
|
+
seconds = float(seconds)
|
|
606
|
+
retry(base_should_see_the_in_state, wait_up_to_s=seconds)(
|
|
607
|
+
ctx, thing, name, index=nth
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
def define_run_steps_if_I_can_see_element_with_name_steps(thing, find_func):
|
|
612
|
+
"""
|
|
613
|
+
defines steps with with the following signatures:
|
|
614
|
+
|
|
615
|
+
I run the following steps if I can immediately see the {thing} "{name}"
|
|
616
|
+
I run the following steps if I can see the {thing} "{name}"
|
|
617
|
+
|
|
618
|
+
I run the following steps if I can immediately not see the {thing} "{name}"
|
|
619
|
+
I run the following steps if I can not see the {thing} "{name}"
|
|
620
|
+
|
|
621
|
+
parameters:
|
|
622
|
+
thing(string): name of the thing we're creating the steps for such
|
|
623
|
+
as button, dialog, etc.
|
|
624
|
+
find_func(function): function that returns the element that matches the
|
|
625
|
+
name provided and is visible
|
|
626
|
+
|
|
627
|
+
def find_func(ctx, name):
|
|
628
|
+
'''
|
|
629
|
+
ctx(object): behave context object
|
|
630
|
+
name(string): name of the thing to find
|
|
631
|
+
'''
|
|
632
|
+
"""
|
|
633
|
+
|
|
634
|
+
# undecorated def for reference below
|
|
635
|
+
def base_run_if_visibile(ctx, name):
|
|
636
|
+
element = find_func(ctx, name)
|
|
637
|
+
|
|
638
|
+
if element is not None:
|
|
639
|
+
run_steps(ctx, ctx.text)
|
|
640
|
+
|
|
641
|
+
@step(
|
|
642
|
+
f'I run the following steps if I can immediately see the {thing} "{{name}}"'
|
|
643
|
+
)
|
|
644
|
+
def run_if_immediately_visibile(ctx, name):
|
|
645
|
+
base_run_if_visibile(ctx, name)
|
|
646
|
+
|
|
647
|
+
@step(f'I run the following steps if I can see the {thing} "{{name}}"')
|
|
648
|
+
def run_if_visibile(ctx, name):
|
|
649
|
+
retry(
|
|
650
|
+
base_run_if_visibile,
|
|
651
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
652
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
653
|
+
)(ctx, name)
|
|
654
|
+
|
|
655
|
+
def base_run_if_not_visibile(ctx, name):
|
|
656
|
+
element = find_func(ctx, name)
|
|
657
|
+
|
|
658
|
+
if element is None:
|
|
659
|
+
run_steps(ctx, ctx.text)
|
|
660
|
+
|
|
661
|
+
@step(
|
|
662
|
+
f'I immediately run the following steps if I can not see the {thing} "{{name}}"'
|
|
663
|
+
)
|
|
664
|
+
def immediately_run_if_not_visibile(ctx, name):
|
|
665
|
+
base_run_if_not_visibile(ctx, name)
|
|
666
|
+
|
|
667
|
+
@step(f'I run the following steps if I can not see the {thing} "{{name}}"')
|
|
668
|
+
def run_if_not_visibile(ctx, name):
|
|
669
|
+
retry(
|
|
670
|
+
base_run_if_not_visibile,
|
|
671
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
672
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
673
|
+
)(ctx, name)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def define_two_thing_interaction_steps(
|
|
677
|
+
action: str,
|
|
678
|
+
action_func,
|
|
679
|
+
thing_1,
|
|
680
|
+
thing_1_find_func,
|
|
681
|
+
preposition: str,
|
|
682
|
+
thing_2,
|
|
683
|
+
thing_2_find_func,
|
|
684
|
+
with_nth=False,
|
|
685
|
+
):
|
|
686
|
+
"""
|
|
687
|
+
defines steps with with the following signatures:
|
|
688
|
+
I {action} the {thing_1} "{name_1}" {preposition} the {thing_2} "{name_2}"
|
|
689
|
+
I wait to {action} the {thing_1} "{name_1}" {preposition} the {thing_2} "{name_2}"
|
|
690
|
+
I wait up to "{seconds}" seconds to {action} the {thing_1} "{name_1}" {preposition} the {thing_2} "{name_2}"
|
|
691
|
+
...
|
|
692
|
+
I {action} the {thing_1} "{name_1}" {preposition} the {thing_2} "{name_2}" if they both exist
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
when with_nth=True we also define:
|
|
696
|
+
|
|
697
|
+
I {action} the "{nth_1}" {thing_1} "{name_1}" {preposition} the "{nth_2}" {thing_2} "{name_2}"
|
|
698
|
+
I wait to {action} the "{nth_1}" {thing_1} "{name_1}" {preposition} the "{nth_2}" {thing_2} "{name_2}"
|
|
699
|
+
I wait up to "{seconds}" seconds to {action} the "{nth_1}" {thing_1} "{name_1}" {preposition} the "{nth_2}" {thing_2} "{name_2}"
|
|
700
|
+
...
|
|
701
|
+
I {action} the "{nth_1}" {thing_1} "{name_1}" {preposition} the "{nth_2}" {thing_2} "{name_2}" if they both exist
|
|
702
|
+
|
|
703
|
+
parameters:
|
|
704
|
+
action(string): the name of the action being performed, such as:
|
|
705
|
+
click, disable, etc.
|
|
706
|
+
action_func(function): function that performs the desired action:
|
|
707
|
+
|
|
708
|
+
def action_func(ctx, element, ):
|
|
709
|
+
'''
|
|
710
|
+
ctx(object): behave context object
|
|
711
|
+
element(object): the element found
|
|
712
|
+
'''
|
|
713
|
+
thing_1(string): name of the thing we're creating the steps for such
|
|
714
|
+
as button, dialog, etc.
|
|
715
|
+
thing_1_find_func(function): function that returns the desired element:
|
|
716
|
+
|
|
717
|
+
def thing_1_find_func(ctx, name_1, index_1=):
|
|
718
|
+
'''
|
|
719
|
+
ctx(object): behave context object
|
|
720
|
+
name_1(string):name of the thing to find
|
|
721
|
+
index_1(int): when there are multiple elements
|
|
722
|
+
with the same name and you've
|
|
723
|
+
specified with_nth=True
|
|
724
|
+
'''
|
|
725
|
+
preposition(string): preposition to help with readability as there are
|
|
726
|
+
many different prepositions that would be valid for
|
|
727
|
+
a desired action
|
|
728
|
+
thing_2(string): name of the thing that is being interacted with
|
|
729
|
+
from the defined action
|
|
730
|
+
thing_2_find_func(function): function that returns the interacted element:
|
|
731
|
+
|
|
732
|
+
def thing_2_find_func(ctx, name_2, index_2=):
|
|
733
|
+
'''
|
|
734
|
+
ctx(object): behave context object
|
|
735
|
+
name_2(string): name of the thing to find
|
|
736
|
+
index_1(int): when there are multiple elements
|
|
737
|
+
with the same name and you've
|
|
738
|
+
specified with_nth=True
|
|
739
|
+
'''
|
|
740
|
+
with_nth(bool): when set to True we'll define the expanded set of
|
|
741
|
+
"nth" steps. default: False
|
|
742
|
+
"""
|
|
743
|
+
|
|
744
|
+
# undecorated def for reference below
|
|
745
|
+
def base_action_the(
|
|
746
|
+
ctx,
|
|
747
|
+
thing_1,
|
|
748
|
+
name_1,
|
|
749
|
+
thing_2,
|
|
750
|
+
name_2,
|
|
751
|
+
index_1=0,
|
|
752
|
+
index_2=0,
|
|
753
|
+
):
|
|
754
|
+
prefix_1 = nth_to_ordinal(index_1)
|
|
755
|
+
prefix_2 = nth_to_ordinal(index_2)
|
|
756
|
+
|
|
757
|
+
element_1 = thing_1_find_func(ctx, name_1, index_1)
|
|
758
|
+
element_2 = thing_2_find_func(ctx, name_2, index_2)
|
|
759
|
+
|
|
760
|
+
if element_1 is None or element_2 is None:
|
|
761
|
+
error_message = []
|
|
762
|
+
if element_1 is None:
|
|
763
|
+
error_message.append(
|
|
764
|
+
f'Unable to find the {prefix_1}{thing_1} "{name_1}"'
|
|
765
|
+
)
|
|
766
|
+
if element_2 is None:
|
|
767
|
+
error_message.append(
|
|
768
|
+
f'Unable to find the {prefix_2}{thing_2} "{name_2}"'
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
raise RuntimeError(", ".join(error_message))
|
|
772
|
+
|
|
773
|
+
else:
|
|
774
|
+
action_func(ctx, element_1, element_2)
|
|
775
|
+
logger.debug(
|
|
776
|
+
f'Successfully executed {action} {prefix_1}{thing_1} "{name_1}" {preposition} {prefix_2}{thing_2} "{name_2}"'
|
|
777
|
+
)
|
|
778
|
+
|
|
779
|
+
@step(
|
|
780
|
+
f'I immediately {action} the {thing_1} "{{name_1}}" {preposition} the {thing_2} "{{name_2}}"'
|
|
781
|
+
)
|
|
782
|
+
def immediately_action_the(ctx, name_1, name_2):
|
|
783
|
+
base_action_the(ctx, thing_1, name_1, thing_2, name_2)
|
|
784
|
+
|
|
785
|
+
@step(
|
|
786
|
+
f'I {action} the {thing_1} "{{name_1}}" {preposition} the {thing_2} "{{name_2}}"'
|
|
787
|
+
)
|
|
788
|
+
def action_the(ctx, name_1, name_2):
|
|
789
|
+
retry(
|
|
790
|
+
base_action_the,
|
|
791
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
792
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
793
|
+
)(ctx, thing_1, name_1, thing_2, name_2)
|
|
794
|
+
|
|
795
|
+
@step(
|
|
796
|
+
f'I wait to {action} the {thing_1} "{{name_1}}" {preposition} the {thing_2} "{{name_2}}"'
|
|
797
|
+
)
|
|
798
|
+
def wait_to_action_the(ctx, name_1, name_2):
|
|
799
|
+
retry(base_action_the)(ctx, thing_1, name_1, thing_2, name_2)
|
|
800
|
+
|
|
801
|
+
@step(
|
|
802
|
+
f'I wait up to "{{seconds}}" seconds to {action} the {thing_1} "{{name_1}}" {preposition} the {thing_2} "{{name_2}}"'
|
|
803
|
+
)
|
|
804
|
+
def wait_up_to_seconds_to_action_the(ctx, seconds, name_1, name_2):
|
|
805
|
+
seconds = float(seconds)
|
|
806
|
+
retry(base_action_the, wait_up_to_s=seconds)(
|
|
807
|
+
ctx, thing_1, name_1, thing_2, name_2
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
if with_nth:
|
|
811
|
+
|
|
812
|
+
@step(
|
|
813
|
+
f'I immediately {action} the "{{nth_1:nth}}" {thing_1} "{{name_1}}" {preposition} the "{{nth_2:nth}}" {thing_2} "{{name_2}}"'
|
|
814
|
+
)
|
|
815
|
+
def immediately_action_the_nth_i_nth(
|
|
816
|
+
ctx, nth_1, name_1, nth_2, name_2
|
|
817
|
+
):
|
|
818
|
+
base_action_the(
|
|
819
|
+
ctx,
|
|
820
|
+
thing_1,
|
|
821
|
+
name_1,
|
|
822
|
+
thing_2,
|
|
823
|
+
name_2,
|
|
824
|
+
index_1=nth_1,
|
|
825
|
+
index_2=nth_2,
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
@step(
|
|
829
|
+
f'I {action} the "{{nth_1:nth}}" {thing_1} "{{name_1}}" {preposition} the "{{nth_2:nth}}" {thing_2} "{{name_2}}"'
|
|
830
|
+
)
|
|
831
|
+
def action_the_nth_i_nth(ctx, nth_1, name_1, nth_2, name_2):
|
|
832
|
+
retry(
|
|
833
|
+
base_action_the,
|
|
834
|
+
retry_after_s=float(CONFIG["CUCU_SHORT_UI_RETRY_AFTER_S"]),
|
|
835
|
+
wait_up_to_s=float(CONFIG["CUCU_SHORT_UI_WAIT_TIMEOUT_S"]),
|
|
836
|
+
)(
|
|
837
|
+
ctx,
|
|
838
|
+
thing_1,
|
|
839
|
+
name_1,
|
|
840
|
+
thing_2,
|
|
841
|
+
name_2,
|
|
842
|
+
index_1=nth_1,
|
|
843
|
+
index_2=nth_2,
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
@step(
|
|
847
|
+
f'I wait to {action} the "{{nth_1:nth}}" {thing_1} "{{name_1}}" {preposition} the "{{nth_2:nth}}" {thing_2} "{{name_2}}"'
|
|
848
|
+
)
|
|
849
|
+
def wait_to_action_the_nth_ith(ctx, nth_1, name_1, nth_2, name_2):
|
|
850
|
+
retry(base_action_the)(
|
|
851
|
+
ctx,
|
|
852
|
+
thing_1,
|
|
853
|
+
name_1,
|
|
854
|
+
thing_2,
|
|
855
|
+
name_2,
|
|
856
|
+
index_1=nth_1,
|
|
857
|
+
index_2=nth_2,
|
|
858
|
+
)
|
|
859
|
+
|
|
860
|
+
@step(
|
|
861
|
+
f'I wait up to "{{seconds}}" seconds to {action} the "{{nth_1:nth}}" {thing_1} "{{name_1}}" {preposition} the "{{nth_2:nth}}" {thing_2} "{{name_2}}"'
|
|
862
|
+
)
|
|
863
|
+
def wait_up_to_action_the_nth_i_nth(
|
|
864
|
+
ctx, seconds, nth_1, name_1, nth_2, name_2
|
|
865
|
+
):
|
|
866
|
+
seconds = float(seconds)
|
|
867
|
+
retry(base_action_the, wait_up_to_s=seconds)(
|
|
868
|
+
ctx,
|
|
869
|
+
thing_1,
|
|
870
|
+
name_1,
|
|
871
|
+
thing_2,
|
|
872
|
+
name_2,
|
|
873
|
+
index_1=nth_1,
|
|
874
|
+
index_2=nth_2,
|
|
875
|
+
)
|