Skip to content

Commit f6830c8

Browse files
committed
Add Recorder option to generate Behave-Gherkin files
1 parent 3ba2801 commit f6830c8

File tree

9 files changed

+630
-24
lines changed

9 files changed

+630
-24
lines changed

seleniumbase/behave/behave_helper.py

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
# -*- coding: utf-8 -*-
2+
import sys
3+
4+
python3 = True
5+
if sys.version_info[0] < 3:
6+
python3 = False
7+
8+
9+
def generate_gherkin(srt_actions):
10+
sb_actions = []
11+
for action in srt_actions:
12+
if action[0] == "begin" or action[0] == "_url_":
13+
if "%" in action[2] and python3:
14+
try:
15+
from urllib.parse import unquote
16+
17+
action[2] = unquote(action[2], errors="strict")
18+
except Exception:
19+
pass
20+
sb_actions.append('Open "%s"' % action[2])
21+
elif action[0] == "f_url":
22+
if "%" in action[2] and python3:
23+
try:
24+
from urllib.parse import unquote
25+
26+
action[2] = unquote(action[2], errors="strict")
27+
except Exception:
28+
pass
29+
sb_actions.append('Open if not "%s"' % action[2])
30+
elif action[0] == "click":
31+
if '"' not in action[1]:
32+
sb_actions.append('Click "%s"' % action[1])
33+
else:
34+
sb_actions.append("Click '%s'" % action[1])
35+
elif action[0] == "js_cl":
36+
if '"' not in action[1]:
37+
sb_actions.append('JS click "%s"' % action[1])
38+
else:
39+
sb_actions.append("JS click '%s'" % action[1])
40+
elif action[0] == "js_ca":
41+
if '"' not in action[1]:
42+
sb_actions.append('JS click all "%s"' % action[1])
43+
else:
44+
sb_actions.append("JS click all '%s'" % action[1])
45+
elif action[0] == "canva":
46+
selector = action[1][0]
47+
p_x = action[1][1]
48+
p_y = action[1][2]
49+
if '"' not in selector:
50+
sb_actions.append(
51+
'Click "%s" at (%s, %s)' % (selector, p_x, p_y)
52+
)
53+
else:
54+
sb_actions.append(
55+
"Click '%s' at (%s, %s)" % (selector, p_x, p_y)
56+
)
57+
elif action[0] == "input" or action[0] == "js_ty":
58+
if action[0] == "js_ty":
59+
method = "js_type"
60+
text = action[2].replace("\n", "\\n")
61+
if '"' not in action[1] and '"' not in text:
62+
sb_actions.append(
63+
'Into "%s" type "%s"' % (action[1], text)
64+
)
65+
elif '"' not in action[1] and '"' in text:
66+
sb_actions.append(
67+
'Into "%s" type \'%s\')' % (action[1], text)
68+
)
69+
elif '"' in action[1] and '"' not in text:
70+
sb_actions.append(
71+
'Into \'%s\' type "%s")' % (action[1], text)
72+
)
73+
elif '"' in action[1] and '"' in text:
74+
sb_actions.append(
75+
"Into '%s' type '%s')" % (action[1], text)
76+
)
77+
elif action[0] == "e_mfa":
78+
text = action[2].replace("\n", "\\n")
79+
if '"' not in action[1] and '"' not in text:
80+
sb_actions.append(
81+
'Into "%s" do MFA "%s"' % (action[1], text)
82+
)
83+
elif '"' not in action[1] and '"' in text:
84+
sb_actions.append(
85+
'Into "%s" do MFA \'%s\'' % (action[1], text)
86+
)
87+
elif '"' in action[1] and '"' not in text:
88+
sb_actions.append(
89+
'Into \'%s\' do MFA "%s"' % (action[1], text)
90+
)
91+
elif '"' in action[1] and '"' in text:
92+
sb_actions.append(
93+
"Into '%s' do MFA '%s'" % (action[1], text)
94+
)
95+
elif action[0] == "h_clk":
96+
if '"' not in action[1] and '"' not in action[2]:
97+
sb_actions.append(
98+
'Hover "%s" and click "%s"' % (action[1], action[2])
99+
)
100+
elif '"' not in action[1] and '"' in action[2]:
101+
sb_actions.append(
102+
'Hover "%s" and click \'%s\'' % (action[1], action[2])
103+
)
104+
elif '"' in action[1] and '"' not in action[2]:
105+
sb_actions.append(
106+
'Hover \'%s\' and click "%s"' % (action[1], action[2])
107+
)
108+
elif '"' in action[1] and '"' in action[2]:
109+
sb_actions.append(
110+
"Hover '%s' and click '%s'" % (action[1], action[2])
111+
)
112+
elif action[0] == "ddrop":
113+
if '"' not in action[1] and '"' not in action[2]:
114+
sb_actions.append(
115+
'Drag "%s" into "%s"' % (action[1], action[2])
116+
)
117+
elif '"' not in action[1] and '"' in action[2]:
118+
sb_actions.append(
119+
'Drag "%s" into \'%s\'' % (action[1], action[2])
120+
)
121+
elif '"' in action[1] and '"' not in action[2]:
122+
sb_actions.append(
123+
'Drag \'%s\' into "%s"' % (action[1], action[2])
124+
)
125+
elif '"' in action[1] and '"' in action[2]:
126+
sb_actions.append(
127+
"Drag '%s' into '%s'" % (action[1], action[2])
128+
)
129+
elif action[0] == "s_opt":
130+
if '"' not in action[1] and '"' not in action[2]:
131+
sb_actions.append(
132+
'Find "%s" and select "%s"' % (action[1], action[2])
133+
)
134+
elif '"' not in action[1] and '"' in action[2]:
135+
sb_actions.append(
136+
'Find "%s" and select \'%s\'' % (action[1], action[2])
137+
)
138+
elif '"' in action[1] and '"' not in action[2]:
139+
sb_actions.append(
140+
'Find \'%s\' and select "%s"' % (action[1], action[2])
141+
)
142+
elif '"' in action[1] and '"' in action[2]:
143+
sb_actions.append(
144+
"Find '%s' and select '%s'" % (action[1], action[2])
145+
)
146+
elif action[0] == "set_v":
147+
if '"' not in action[1] and '"' not in action[2]:
148+
sb_actions.append(
149+
'Set value of "%s" to "%s"' % (action[1], action[2])
150+
)
151+
elif '"' not in action[1] and '"' in action[2]:
152+
sb_actions.append(
153+
'Set value of "%s" to \'%s\'' % (action[1], action[2])
154+
)
155+
elif '"' in action[1] and '"' not in action[2]:
156+
sb_actions.append(
157+
'Set value of \'%s\' to "%s"' % (action[1], action[2])
158+
)
159+
elif '"' in action[1] and '"' in action[2]:
160+
sb_actions.append(
161+
"Set value of '%s' to '%s'" % (action[1], action[2])
162+
)
163+
elif action[0] == "cho_f":
164+
action[2] = action[2].replace("\\", "\\\\")
165+
if '"' not in action[1] and '"' not in action[2]:
166+
sb_actions.append(
167+
'Into "%s" choose file "%s"' % (action[1], action[2])
168+
)
169+
elif '"' not in action[1] and '"' in action[2]:
170+
sb_actions.append(
171+
'Into "%s" choose file \'%s\'' % (action[1], action[2])
172+
)
173+
elif '"' in action[1] and '"' not in action[2]:
174+
sb_actions.append(
175+
'Into \'%s\' choose file "%s"' % (action[1], action[2])
176+
)
177+
elif '"' in action[1] and '"' in action[2]:
178+
sb_actions.append(
179+
"Into '%s' choose file '%s'" % (action[1], action[2])
180+
)
181+
elif action[0] == "sw_fr":
182+
method = "Switch to frame"
183+
if '"' not in action[1]:
184+
sb_actions.append('%s "%s"' % (method, action[1]))
185+
else:
186+
sb_actions.append("%s '%s'" % (method, action[1]))
187+
elif action[0] == "sw_dc":
188+
sb_actions.append("Switch to default content")
189+
elif action[0] == "sw_pf":
190+
sb_actions.append("Switch to parent frame")
191+
elif action[0] == "s_c_f":
192+
method = "Set content to frame"
193+
if '"' not in action[1]:
194+
sb_actions.append('%s "%s"' % (method, action[1]))
195+
else:
196+
sb_actions.append("%s '%s'" % (method, action[1]))
197+
elif action[0] == "s_c_d":
198+
nested = action[1]
199+
if nested:
200+
sb_actions.append("Set content to parent")
201+
else:
202+
sb_actions.append("Set content to default")
203+
elif action[0] == "sleep":
204+
sb_actions.append("Sleep for %s seconds" % action[1])
205+
elif action[0] == "as_el":
206+
method = "Assert element"
207+
if '"' not in action[1]:
208+
sb_actions.append('%s "%s"' % (method, action[1]))
209+
else:
210+
sb_actions.append("%s '%s'" % (method, action[1]))
211+
elif action[0] == "as_ep":
212+
method = "Assert element present"
213+
if '"' not in action[1]:
214+
sb_actions.append('%s "%s"' % (method, action[1]))
215+
else:
216+
sb_actions.append("%s '%s'" % (method, action[1]))
217+
elif action[0] == "asenv":
218+
method = "Assert element not visible"
219+
if '"' not in action[1]:
220+
sb_actions.append('%s "%s"' % (method, action[1]))
221+
else:
222+
sb_actions.append("%s '%s'" % (method, action[1]))
223+
elif action[0] == "hi_li":
224+
method = "Highlight"
225+
if '"' not in action[1]:
226+
sb_actions.append('%s "%s"' % (method, action[1]))
227+
else:
228+
sb_actions.append("%s '%s'" % (method, action[1]))
229+
elif action[0] == "as_lt":
230+
method = "Assert link text"
231+
if '"' not in action[1]:
232+
sb_actions.append('%s "%s"' % (method, action[1]))
233+
else:
234+
sb_actions.append("%s '%s'" % (method, action[1]))
235+
elif action[0] == "as_ti":
236+
method = "Assert title"
237+
if '"' not in action[1]:
238+
sb_actions.append('%s "%s"' % (method, action[1]))
239+
else:
240+
sb_actions.append("%s '%s'" % (method, action[1]))
241+
elif action[0] == "as_df":
242+
method = "Assert downloaded file"
243+
if '"' not in action[1]:
244+
sb_actions.append('%s "%s"' % (method, action[1]))
245+
else:
246+
sb_actions.append("%s '%s'" % (method, action[1]))
247+
elif action[0] == "do_fi":
248+
method = "Download file"
249+
file_url = action[1][0]
250+
dest = action[1][1]
251+
if not dest:
252+
sb_actions.append('%s "%s" to downloads' % (method, file_url))
253+
else:
254+
sb_actions.append(
255+
'%s "%s" to "%s")' % (method, file_url, dest)
256+
)
257+
elif action[0] == "as_at":
258+
if ('"' not in action[1][0]) and action[1][2]:
259+
sb_actions.append(
260+
'In "%s" assert attribute/value "%s"/"%s"'
261+
% (action[1][0], action[1][1], action[1][2])
262+
)
263+
elif ('"' not in action[1][0]) and not action[1][2]:
264+
sb_actions.append(
265+
'In "%s" assert attribute "%s"'
266+
% (action[1][0], action[1][1])
267+
)
268+
elif ('"' in action[1][0]) and action[1][2]:
269+
sb_actions.append(
270+
'In \'%s\' assert attribute/value "%s"/"%s"'
271+
% (action[1][0], action[1][1], action[1][2])
272+
)
273+
else:
274+
sb_actions.append(
275+
'In \'%s\' assert attribute "%s"'
276+
% (action[1][0], action[1][1])
277+
)
278+
elif action[0] == "as_te" or action[0] == "as_et":
279+
import unicodedata
280+
281+
action[1][0] = unicodedata.normalize("NFKC", action[1][0])
282+
method = "Assert text"
283+
if action[0] == "as_et":
284+
method = "Assert exact text"
285+
if action[1][1] != "html":
286+
if '"' not in action[1][0] and '"' not in action[1][1]:
287+
sb_actions.append(
288+
'%s "%s" in "%s"'
289+
% (method, action[1][0], action[1][1])
290+
)
291+
elif '"' not in action[1][0] and '"' in action[1][1]:
292+
sb_actions.append(
293+
'%s "%s" in \'%s\''
294+
% (method, action[1][0], action[1][1])
295+
)
296+
elif '"' in action[1] and '"' not in action[1][1]:
297+
sb_actions.append(
298+
'%s \'%s\' in "%s"'
299+
% (method, action[1][0], action[1][1])
300+
)
301+
elif '"' in action[1] and '"' in action[1][1]:
302+
sb_actions.append(
303+
"%s '%s' in '%s'"
304+
% (method, action[1][0], action[1][1])
305+
)
306+
else:
307+
if '"' not in action[1][0]:
308+
sb_actions.append(
309+
'%s "%s"' % (method, action[1][0])
310+
)
311+
else:
312+
sb_actions.append(
313+
"%s '%s'" % (method, action[1][0])
314+
)
315+
elif action[0] == "ss_tl":
316+
sb_actions.append("Save screenshot to logs")
317+
elif action[0] == "sh_fc":
318+
sb_actions.append("Show file choosers")
319+
elif action[0] == "c_l_s":
320+
sb_actions.append("Clear Local Storage")
321+
elif action[0] == "c_s_s":
322+
sb_actions.append("Clear Session Storage")
323+
elif action[0] == "d_a_c":
324+
sb_actions.append("Delete all cookies")
325+
elif action[0] == "c_box":
326+
method = "Check if unchecked"
327+
if action[2] == "no":
328+
method = "Uncheck if checked"
329+
if '"' not in action[1]:
330+
sb_actions.append('%s "%s"' % (method, action[1]))
331+
else:
332+
sb_actions.append("%s '%s'" % (method, action[1]))
333+
return sb_actions

seleniumbase/behave/behave_sb.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
-D block-images (Block images from loading during tests.)
6060
-D verify-delay=SECONDS (The delay before MasterQA verification checks.)
6161
-D recorder (Enables the Recorder for turning browser actions into code.)
62+
-D rec-behave (Same as Recorder Mode, but also generates behave-gherkin.)
63+
-D rec-sleep (If the Recorder is enabled, also records self.sleep calls.)
6264
-D disable-csp (Disable the Content Security Policy of websites.)
6365
-D disable-ws (Disable Web Security on Chromium-based browsers.)
6466
-D enable-ws (Enable Web Security on Chromium-based browsers.)
@@ -166,6 +168,8 @@ def get_configured_sb(context):
166168
sb.js_checking_on = False
167169
sb.recorder_mode = False
168170
sb.recorder_ext = False
171+
sb.record_sleep = False
172+
sb.rec_behave = False
169173
sb.report_on = False
170174
sb.is_pytest = False
171175
sb.slow_mode = False
@@ -499,6 +503,14 @@ def get_configured_sb(context):
499503
sb.recorder_mode = True
500504
sb.recorder_ext = True
501505
continue
506+
# Handle: -D rec-behave / rec-gherkin
507+
if low_key in ["rec-behave", "rec-gherkin"]:
508+
sb.rec_behave = True
509+
continue
510+
# Handle: -D record-sleep / record_sleep / rec-sleep / rec_sleep
511+
if low_key in ["record-sleep", "rec-sleep"]:
512+
sb.record_sleep = True
513+
continue
502514
# Handle: -D slow / slowmo / slow-mode / slow_mode
503515
if low_key in ["slow", "slowmo", "slow-mode", "slow_mode"]:
504516
sb.slow_mode = True
@@ -681,9 +693,13 @@ def get_configured_sb(context):
681693
sb_config.variables = sb.variables
682694
sb_config.dashboard = sb.dashboard
683695
sb_config.pdb_option = sb.pdb_option
696+
sb_config.rec_behave = sb.rec_behave
697+
sb_config.record_sleep = sb.record_sleep
684698
sb_config._is_timeout_changed = False
685699
sb_config._SMALL_TIMEOUT = settings.SMALL_TIMEOUT
686700
sb_config._LARGE_TIMEOUT = settings.LARGE_TIMEOUT
701+
sb_config._recorded_actions = {}
702+
sb_config._behave_recorded_actions = {}
687703
# Dashboard-specific variables
688704
sb_config._results = {} # SBase Dashboard test results
689705
sb_config._duration = {} # SBase Dashboard test duration

0 commit comments

Comments
 (0)