New feature: SeleniumBase Commander / GUI for pytest
This commit is contained in:
parent
7191a8c8b6
commit
52c04864dd
|
@ -17,6 +17,7 @@ COMMANDS:
|
|||
install [DRIVER] [OPTIONS]
|
||||
methods (List common Python methods)
|
||||
options (List common pytest options)
|
||||
commander / gui [OPTIONAL PATH or TEST FILE]
|
||||
mkdir [DIRECTORY] [OPTIONS]
|
||||
mkfile [FILE.py] [OPTIONS]
|
||||
mkrec / codegen [FILE.py] [OPTIONS]
|
||||
|
@ -143,6 +144,21 @@ that are available when using SeleniumBase.
|
|||
For the full list of command-line options, type: "pytest --help".
|
||||
```
|
||||
|
||||
<h3>commander / gui</h3>
|
||||
|
||||
* Usage:
|
||||
``sbase commander [OPTIONAL PATH or TEST FILE]``
|
||||
``sbase gui [OPTIONAL PATH or TEST FILE]``
|
||||
|
||||
* Examples:
|
||||
``sbase gui``
|
||||
``sbase gui -k agent``
|
||||
``sbase gui examples/``
|
||||
``sbase gui test_suite.py``
|
||||
|
||||
* Output:
|
||||
Launches SeleniumBase Commander | GUI for pytest.
|
||||
|
||||
<h3>mkdir</h3>
|
||||
|
||||
* Usage:
|
||||
|
|
|
@ -9,6 +9,7 @@ Examples:
|
|||
sbase install chromedriver
|
||||
sbase methods
|
||||
sbase options
|
||||
sbase commander
|
||||
sbase mkdir ui_tests
|
||||
sbase mkfile new_test.py
|
||||
sbase mkrec new_test.py
|
||||
|
@ -78,6 +79,7 @@ def show_basic_usage():
|
|||
sc += " install [DRIVER] [OPTIONS]\n"
|
||||
sc += " methods (List common Python methods)\n"
|
||||
sc += " options (List common pytest options)\n"
|
||||
sc += " commander / gui [OPTIONAL PATH or TEST FILE]\n"
|
||||
sc += " mkdir [DIRECTORY] [OPTIONS]\n"
|
||||
sc += " mkfile [FILE.py] [OPTIONS]\n"
|
||||
sc += " mkrec / codegen [FILE.py] [OPTIONS]\n"
|
||||
|
@ -146,6 +148,28 @@ def show_install_usage():
|
|||
print("")
|
||||
|
||||
|
||||
def show_commander_usage():
|
||||
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
||||
c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
|
||||
cr = colorama.Style.RESET_ALL
|
||||
sc = " " + c2 + "** " + c3 + "commander" + c2 + " **" + cr
|
||||
print(sc)
|
||||
print("")
|
||||
print(" Usage:")
|
||||
print(" seleniumbase commander [OPTIONAL PATH or TEST FILE]")
|
||||
print(" OR: sbase commander [OPTIONAL PATH or TEST FILE]")
|
||||
print(" OR: seleniumbase gui [OPTIONAL PATH or TEST FILE]")
|
||||
print(" OR: sbase gui [OPTIONAL PATH or TEST FILE]")
|
||||
print(" Examples:")
|
||||
print(" sbase gui")
|
||||
print(" sbase gui -k agent")
|
||||
print(" sbase gui examples/")
|
||||
print(" sbase gui test_suite.py")
|
||||
print(" Output:")
|
||||
print(" Launches SeleniumBase Commander | GUI for pytest.")
|
||||
print("")
|
||||
|
||||
|
||||
def show_mkdir_usage():
|
||||
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
||||
c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
|
||||
|
@ -250,6 +274,21 @@ def show_codegen_usage():
|
|||
print("")
|
||||
|
||||
|
||||
def show_recorder_usage():
|
||||
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
||||
c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
|
||||
cr = colorama.Style.RESET_ALL
|
||||
sc = " " + c2 + "** " + c3 + "recorder" + c2 + " **" + cr
|
||||
print(sc)
|
||||
print("")
|
||||
print(" Usage:")
|
||||
print(" seleniumbase recorder")
|
||||
print(" OR: sbase recorder")
|
||||
print(" Output:")
|
||||
print(" Launches the SeleniumBase Recorder Desktop App.")
|
||||
print("")
|
||||
|
||||
|
||||
def show_mkpres_usage():
|
||||
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
||||
c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
|
||||
|
@ -629,7 +668,8 @@ def show_methods():
|
|||
sbm += "*.get_attribute(selector, attribute) => Get element attribute.\n"
|
||||
sbm += "*.get_title() => Get the title of the current page.\n"
|
||||
sbm += "*.switch_to_frame(frame) => Switch into the iframe container.\n"
|
||||
sbm += "*.switch_to_default_content() => Leave the iframe container.\n"
|
||||
sbm += "*.switch_to_default_content() => Exit all iframe containers.\n"
|
||||
sbm += "*.switch_to_parent_frame() => Exit from the current iframe.\n"
|
||||
sbm += "*.open_new_window() => Open a new window in the same browser.\n"
|
||||
sbm += "*.switch_to_window(window) => Switch to the browser window.\n"
|
||||
sbm += "*.switch_to_default_window() => Switch to the original window.\n"
|
||||
|
@ -735,10 +775,12 @@ def show_detailed_help():
|
|||
print(c6 + " " + c2 + " Commands: " + c6 + " ")
|
||||
print(cr)
|
||||
show_install_usage()
|
||||
show_commander_usage()
|
||||
show_mkdir_usage()
|
||||
show_mkfile_usage()
|
||||
show_mkrec_usage()
|
||||
show_codegen_usage()
|
||||
show_recorder_usage()
|
||||
show_mkpres_usage()
|
||||
show_mkchart_usage()
|
||||
show_convert_usage()
|
||||
|
@ -779,6 +821,10 @@ def main():
|
|||
else:
|
||||
show_basic_usage()
|
||||
show_install_usage()
|
||||
elif command == "commander" or command == "gui":
|
||||
from seleniumbase.console_scripts import sb_commander
|
||||
|
||||
sb_commander.main()
|
||||
elif (
|
||||
command == "recorder"
|
||||
or (command == "record" and len(command_args) == 0)
|
||||
|
@ -960,6 +1006,14 @@ def main():
|
|||
print("")
|
||||
show_install_usage()
|
||||
return
|
||||
elif command_args[0] == "commander":
|
||||
print("")
|
||||
show_commander_usage()
|
||||
return
|
||||
elif command_args[0] == "gui":
|
||||
print("")
|
||||
show_commander_usage()
|
||||
return
|
||||
elif command_args[0] == "mkdir":
|
||||
print("")
|
||||
show_mkdir_usage()
|
||||
|
@ -976,6 +1030,10 @@ def main():
|
|||
print("")
|
||||
show_codegen_usage()
|
||||
return
|
||||
elif command_args[0] == "recorder":
|
||||
print("")
|
||||
show_recorder_usage()
|
||||
return
|
||||
elif command_args[0] == "mkpres":
|
||||
print("")
|
||||
show_mkpres_usage()
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Launches SeleniumBase Commander | GUI for pytest.
|
||||
|
||||
Usage:
|
||||
seleniumbase commander [OPTIONAL PATH or TEST FILE]
|
||||
sbase commander [OPTIONAL PATH or TEST FILE]
|
||||
seleniumbase gui [OPTIONAL PATH or TEST FILE]
|
||||
sbase gui [OPTIONAL PATH or TEST FILE]
|
||||
|
||||
Output:
|
||||
Launches SeleniumBase Commander | GUI for pytest.
|
||||
"""
|
||||
|
||||
import colorama
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if sys.version_info <= (3, 7):
|
||||
current_version = ".".join(str(ver) for ver in sys.version_info[:3])
|
||||
raise Exception(
|
||||
"\n* SBase Commander requires Python 3.7 or newer!"
|
||||
"\n** You are currently using Python %s" % current_version
|
||||
)
|
||||
import tkinter as tk # noqa: E402
|
||||
from tkinter.scrolledtext import ScrolledText # noqa: E402
|
||||
|
||||
|
||||
def set_colors(use_colors):
|
||||
c0 = ""
|
||||
c1 = ""
|
||||
c2 = ""
|
||||
c3 = ""
|
||||
c4 = ""
|
||||
c5 = ""
|
||||
cr = ""
|
||||
if use_colors:
|
||||
colorama.init(autoreset=True)
|
||||
c0 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
|
||||
c1 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
||||
c2 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
|
||||
c3 = colorama.Fore.LIGHTGREEN_EX + colorama.Back.BLACK
|
||||
c4 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
|
||||
c5 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
|
||||
cr = colorama.Style.RESET_ALL
|
||||
return c0, c1, c2, c3, c4, c5, cr
|
||||
|
||||
|
||||
def send_window_to_front(root):
|
||||
root.lift()
|
||||
root.attributes("-topmost", True)
|
||||
root.after_idle(root.attributes, "-topmost", False)
|
||||
|
||||
|
||||
def do_pytest_run(
|
||||
root,
|
||||
tests,
|
||||
selected_tests,
|
||||
command_string,
|
||||
browser_string,
|
||||
rs_string,
|
||||
thread_string,
|
||||
verbose,
|
||||
demo_mode,
|
||||
mobile_mode,
|
||||
dashboard,
|
||||
html_report,
|
||||
headless,
|
||||
save_screenshots,
|
||||
additional_options,
|
||||
):
|
||||
total_tests = len(tests)
|
||||
total_selected_tests = 0
|
||||
for selected_test in selected_tests:
|
||||
if selected_tests[selected_test].get():
|
||||
total_selected_tests += 1
|
||||
|
||||
full_run_command = "pytest"
|
||||
if (
|
||||
total_selected_tests == 0
|
||||
or total_tests == total_selected_tests
|
||||
):
|
||||
if command_string:
|
||||
full_run_command += " "
|
||||
full_run_command += command_string
|
||||
else:
|
||||
for test_number, test in enumerate(tests):
|
||||
if selected_tests[test_number].get():
|
||||
full_run_command += " "
|
||||
full_run_command += test
|
||||
|
||||
if "(--edge)" in browser_string:
|
||||
full_run_command += " --edge"
|
||||
elif "(--firefox)" in browser_string:
|
||||
full_run_command += " --firefox"
|
||||
elif "(--safari)" in browser_string:
|
||||
full_run_command += " --safari"
|
||||
|
||||
if "(--rs)" in rs_string:
|
||||
full_run_command += " --rs"
|
||||
elif "(--rs --crumbs)" in rs_string:
|
||||
full_run_command += " --rs --crumbs"
|
||||
|
||||
if "(-n=2)" in thread_string:
|
||||
full_run_command += " -n=2"
|
||||
elif "(-n=3)" in thread_string:
|
||||
full_run_command += " -n=3"
|
||||
elif "(-n=4)" in thread_string:
|
||||
full_run_command += " -n=4"
|
||||
|
||||
if demo_mode:
|
||||
full_run_command += " --demo"
|
||||
|
||||
if mobile_mode:
|
||||
full_run_command += " --mobile"
|
||||
|
||||
if dashboard:
|
||||
full_run_command += " --dashboard"
|
||||
|
||||
if html_report:
|
||||
full_run_command += " --html=report.html"
|
||||
|
||||
if headless:
|
||||
full_run_command += " --headless"
|
||||
elif "linux" in sys.platform:
|
||||
full_run_command += " --gui"
|
||||
|
||||
if save_screenshots:
|
||||
full_run_command += " --screenshot"
|
||||
|
||||
dash_s_needed = False
|
||||
if "-s" not in additional_options.split(" "):
|
||||
dash_s_needed = True
|
||||
|
||||
additional_options = additional_options.strip()
|
||||
if additional_options:
|
||||
full_run_command += " "
|
||||
full_run_command += additional_options
|
||||
|
||||
if verbose:
|
||||
full_run_command += " -v"
|
||||
|
||||
if dash_s_needed:
|
||||
full_run_command += " -s"
|
||||
|
||||
print(full_run_command)
|
||||
subprocess.Popen(full_run_command, shell=True)
|
||||
send_window_to_front(root)
|
||||
|
||||
|
||||
def create_tkinter_gui(tests, command_string):
|
||||
root = tk.Tk()
|
||||
root.title("SeleniumBase Commander | GUI for pytest")
|
||||
root.minsize(720, 640)
|
||||
tk.Label(root, text="").pack()
|
||||
|
||||
options_list = [
|
||||
"Use Chrome Browser (Default)",
|
||||
"Use Edge Browser (--edge)",
|
||||
"Use Firefox Browser (--firefox)",
|
||||
]
|
||||
if "darwin" in sys.platform:
|
||||
options_list.append("Use Safari Browser (--safari)")
|
||||
brx = tk.StringVar(root)
|
||||
brx.set(options_list[0])
|
||||
question_menu = tk.OptionMenu(root, brx, *options_list)
|
||||
question_menu.pack()
|
||||
|
||||
options_list = [
|
||||
"New Session Per Test (Default)",
|
||||
"Reuse Session for all tests in thread (--rs)",
|
||||
"Reuse Session / clear cookies (--rs --crumbs)",
|
||||
]
|
||||
rsx = tk.StringVar(root)
|
||||
rsx.set(options_list[0])
|
||||
question_menu = tk.OptionMenu(root, rsx, *options_list)
|
||||
question_menu.pack()
|
||||
|
||||
options_list = [
|
||||
"Number of Threads: 1 (Default)",
|
||||
"Number of Threads: 2 (-n=2)",
|
||||
"Number of Threads: 3 (-n=3)",
|
||||
"Number of Threads: 4 (-n=4)",
|
||||
]
|
||||
ntx = tk.StringVar(root)
|
||||
ntx.set(options_list[0])
|
||||
question_menu = tk.OptionMenu(root, ntx, *options_list)
|
||||
question_menu.pack()
|
||||
|
||||
vox = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Verbose Output (-v)", variable=vox
|
||||
)
|
||||
chk.pack()
|
||||
chk.select()
|
||||
|
||||
dmx = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Demo Mode (--demo)", variable=dmx
|
||||
)
|
||||
chk.pack()
|
||||
|
||||
mmx = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Mobile Mode (--mobile)", variable=mmx
|
||||
)
|
||||
chk.pack()
|
||||
|
||||
dbx = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Dashboard (--dashboard)", variable=dbx
|
||||
)
|
||||
chk.pack()
|
||||
chk.select()
|
||||
|
||||
hrx = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Report (--html=report.html)", variable=hrx
|
||||
)
|
||||
chk.pack()
|
||||
chk.select()
|
||||
|
||||
hbx = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Headless Browser (--headless)", variable=hbx
|
||||
)
|
||||
chk.pack()
|
||||
|
||||
ssx = tk.IntVar()
|
||||
chk = tk.Checkbutton(
|
||||
root, text="Save Screenshots (--screenshot)", variable=ssx
|
||||
)
|
||||
chk.pack()
|
||||
|
||||
tk.Label(root, text="").pack()
|
||||
run_display = (
|
||||
"Select from %s tests: "
|
||||
"(If NO TESTS are selected, then ALL TESTS will be run)"
|
||||
% len(tests)
|
||||
)
|
||||
if len(tests) == 1:
|
||||
run_display = "Only ONE TEST was found: (Will be run automatically)"
|
||||
tk.Label(root, text=run_display, fg="blue").pack()
|
||||
text_area = ScrolledText(
|
||||
root, width=100, height=12, wrap="word", state=tk.DISABLED
|
||||
)
|
||||
text_area.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
|
||||
count = 0
|
||||
ara = {}
|
||||
for row in tests:
|
||||
row += " " * 400
|
||||
ara[count] = tk.IntVar()
|
||||
cb = tk.Checkbutton(
|
||||
text_area,
|
||||
text=(row),
|
||||
bg='white',
|
||||
anchor='w',
|
||||
variable=ara[count],
|
||||
)
|
||||
text_area.window_create('end', window=cb)
|
||||
text_area.insert('end', '\n')
|
||||
count += 1
|
||||
|
||||
tk.Label(root, text="").pack()
|
||||
additional_options = ""
|
||||
aopts = tk.StringVar(value=additional_options)
|
||||
tk.Label(
|
||||
root,
|
||||
text='Additional pytest Options: (space-separated)',
|
||||
fg="blue",
|
||||
).pack()
|
||||
entry = tk.Entry(root, textvariable=aopts)
|
||||
entry.pack()
|
||||
entry.focus()
|
||||
entry.bind(
|
||||
"<Return>",
|
||||
(
|
||||
lambda _: do_pytest_run(
|
||||
root,
|
||||
tests,
|
||||
ara,
|
||||
command_string,
|
||||
brx.get(),
|
||||
rsx.get(),
|
||||
ntx.get(),
|
||||
vox.get(),
|
||||
dmx.get(),
|
||||
mmx.get(),
|
||||
dbx.get(),
|
||||
hrx.get(),
|
||||
hbx.get(),
|
||||
ssx.get(),
|
||||
aopts.get(),
|
||||
)
|
||||
),
|
||||
)
|
||||
tk.Button(
|
||||
root,
|
||||
text="Run Selected Tests",
|
||||
fg="green",
|
||||
command=lambda: do_pytest_run(
|
||||
root,
|
||||
tests,
|
||||
ara,
|
||||
command_string,
|
||||
brx.get(),
|
||||
rsx.get(),
|
||||
ntx.get(),
|
||||
vox.get(),
|
||||
dmx.get(),
|
||||
mmx.get(),
|
||||
dbx.get(),
|
||||
hrx.get(),
|
||||
hbx.get(),
|
||||
ssx.get(),
|
||||
aopts.get(),
|
||||
),
|
||||
).pack()
|
||||
tk.Label(root, text="\n").pack()
|
||||
|
||||
# Bring form window to front
|
||||
send_window_to_front(root)
|
||||
root.mainloop()
|
||||
|
||||
|
||||
def main():
|
||||
use_colors = True
|
||||
if "linux" in sys.platform:
|
||||
use_colors = False
|
||||
c0, c1, c2, c3, c4, c5, cr = set_colors(use_colors)
|
||||
command_args = sys.argv[2:]
|
||||
command_string = " ".join(command_args)
|
||||
message = ""
|
||||
message += c2
|
||||
message += "*"
|
||||
message += c4
|
||||
message += " Starting the "
|
||||
message += c0
|
||||
message += "Selenium"
|
||||
message += c1
|
||||
message += "Base"
|
||||
message += c2
|
||||
message += " "
|
||||
message += c3
|
||||
message += "Commander"
|
||||
message += c4
|
||||
message += " Desktop App"
|
||||
message += c2
|
||||
message += "..."
|
||||
message += cr
|
||||
print(message)
|
||||
|
||||
proc = subprocess.Popen(
|
||||
'pytest --co -q --rootdir="./" %s' % command_string,
|
||||
stdout=subprocess.PIPE,
|
||||
shell=True,
|
||||
)
|
||||
(output, error) = proc.communicate()
|
||||
if error:
|
||||
error_msg = "Error collecting tests: %s" % str(error)
|
||||
error_msg = c5 + error_msg + cr
|
||||
print(error_msg)
|
||||
return
|
||||
tests = []
|
||||
for row in output.decode("utf-8").split("\n"):
|
||||
if ("::") in row:
|
||||
tests.append(row)
|
||||
if not tests:
|
||||
error_msg = "No tests found! Exiting SeleniumBase Commander..."
|
||||
error_msg = c5 + "ERROR: " + error_msg + cr
|
||||
print(error_msg)
|
||||
return
|
||||
|
||||
create_tkinter_gui(tests, command_string)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print('To open SBase Commander, type "sbase commander" or "sbase gui"')
|
Loading…
Reference in New Issue