diff --git a/examples/case_plans/basic_test.MyTestClass.test_basics.md b/examples/case_plans/basic_test.MyTestClass.test_basics.md new file mode 100644 index 00000000..e210b558 --- /dev/null +++ b/examples/case_plans/basic_test.MyTestClass.test_basics.md @@ -0,0 +1,9 @@ +``basic_test.py::MyTestClass::test_basics`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | +| 2 | Click on the ``Backpack`` ``ADD TO CART`` button. | The button text changed to ``REMOVE``. | +| 3 | Click on the cart icon. | The ``Backpack`` is seen in the cart. | +| 4 | Remove the ``Backpack`` from the cart. | The ``Backpack`` is no longer in the cart. | +| 5 | Log out from the website. | Logout was successful. | diff --git a/examples/case_plans/list_assert_test.MyTestClass.test_assert_list_of_elements.md b/examples/case_plans/list_assert_test.MyTestClass.test_assert_list_of_elements.md new file mode 100644 index 00000000..ec26b312 --- /dev/null +++ b/examples/case_plans/list_assert_test.MyTestClass.test_assert_list_of_elements.md @@ -0,0 +1,8 @@ +``list_assert_test.py::MyTestClass::test_assert_list_of_elements`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Open https://seleniumbase.io/demo_page. | | +| 2 | Use ``self.assert_elements_present("head", "style", "script")`` to verify that multiple elements are present in the HTML. | The assertion is successful. | +| 3 | Use ``self.assert_elements("h1", "h2", "h3")`` to verify that multiple elements are visible. | The assertion is successful. | +| 4 | Use ``self.assert_elements(["#myDropdown", "#myButton", "#svgRect"])`` to verify that multiple elements are visible. | The assertion is successful. | diff --git a/examples/case_plans/my_first_test.MyTestClass.test_swag_labs.md b/examples/case_plans/my_first_test.MyTestClass.test_swag_labs.md new file mode 100644 index 00000000..42700153 --- /dev/null +++ b/examples/case_plans/my_first_test.MyTestClass.test_swag_labs.md @@ -0,0 +1,10 @@ +``my_first_test.py::MyTestClass::test_swag_labs`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | +| 2 | Click on the ``Backpack`` ``ADD TO CART`` button. | The button text changed to ``REMOVE``. | +| 3 | Click on the cart icon. | The ``Backpack`` is seen in the cart. | +| 4 | Click on the ``CHECKOUT`` button.
Enter user details and click ``CONTINUE``. | The ``Backpack`` is seen in the cart on the ``CHECKOUT: OVERVIEW`` page. | +| 5 | Click on the ``FINISH`` button. | There is a ``Thank You`` message and a ``Pony Express`` delivery logo. | +| 6 | Log out from the website. | Logout was successful. | diff --git a/examples/case_plans/shadow_root_test.ShadowRootTest.test_shadow_root.md b/examples/case_plans/shadow_root_test.ShadowRootTest.test_shadow_root.md new file mode 100644 index 00000000..ac674cb1 --- /dev/null +++ b/examples/case_plans/shadow_root_test.ShadowRootTest.test_shadow_root.md @@ -0,0 +1,5 @@ +``shadow_root_test.py::ShadowRootTest::test_shadow_root`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Open https://seleniumbase.io/other/shadow_dom.
Click each tab and verify the text contained within the Shadow Root sections. | Tab 1 text: ``Content Panel 1``
Tab 2 text: ``Content Panel 2``
Tab 3 text: ``Content Panel 3`` | diff --git a/examples/case_plans/test_calculator.CalculatorTests.test_6_times_7_plus_12_equals_54.md b/examples/case_plans/test_calculator.CalculatorTests.test_6_times_7_plus_12_equals_54.md new file mode 100644 index 00000000..7053790e --- /dev/null +++ b/examples/case_plans/test_calculator.CalculatorTests.test_6_times_7_plus_12_equals_54.md @@ -0,0 +1,5 @@ +``test_calculator.py::CalculatorTests::test_6_times_7_plus_12_equals_54`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Open https://seleniumbase.io/apps/calculator.
Perform the following calculation: ``6 × 7 + 12`` | The output is ``54`` after pressing ``=`` | diff --git a/examples/case_plans/test_demo_site.DemoSiteTests.test_demo_site.md b/examples/case_plans/test_demo_site.DemoSiteTests.test_demo_site.md new file mode 100644 index 00000000..b3f19bde --- /dev/null +++ b/examples/case_plans/test_demo_site.DemoSiteTests.test_demo_site.md @@ -0,0 +1,24 @@ +``test_demo_site.py::DemoSiteTests::test_demo_site`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Open https://seleniumbase.io/demo_page | | +| 2 | Assert the title of the current web page.
Assert that a given element is visible on the page.
Assert that a text substring appears in an element's text. | The assertions were successful. | +| 3 | Type text into various text fields and then verify. | The assertions were successful. | +| 4 | Verify that a hover dropdown link changes page text. | The assertion was successful. | +| 5 | Verify that a button click changes text on the page. | The assertion was successful. | +| 6 | Verify that an SVG element is located on the page. | The assertion was successful. | +| 7 | Verify that a slider control updates a progress bar. | The assertion was successful. | +| 8 | Verify that a "select" option updates a meter bar. | The assertion was successful. | +| 9 | Assert an element located inside an iFrame. | The assertion was successful. | +| 10 | Assert text located inside an iFrame. | The assertion was successful. | +| 11 | Verify that clicking a radio button selects it. | The assertion was successful. | +| 12 | Verify that clicking an empty checkbox makes it selected. | The assertion was successful. | +| 13 | Verify clicking on multiple elements with one call. | The assertions were successful. | +| 14 | Verify that clicking an iFrame checkbox selects it. | The assertions were successful. | +| 15 | Verify that Drag and Drop works. | The assertion was successful. | +| 16 | Assert link text. | The assertion was successful. | +| 17 | Verify clicking on link text. | The action was successful. | +| 18 | Assert exact text in an element. | The assertion was successful. | +| 19 | Highlight a page element. | The action was successful. | +| 20 | Verify that Demo Mode works. | The assertion was successful. | diff --git a/examples/case_plans/test_login.SwagLabsLoginTests.test_swag_labs_login.md b/examples/case_plans/test_login.SwagLabsLoginTests.test_swag_labs_login.md new file mode 100644 index 00000000..5cb6c208 --- /dev/null +++ b/examples/case_plans/test_login.SwagLabsLoginTests.test_swag_labs_login.md @@ -0,0 +1,6 @@ +``test_login.py::SwagLabsLoginTests::test_swag_labs_login`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Log in to https://www.saucedemo.com with ``standard_user``. | Login was successful. | +| 2 | Log out from the website. | Logout was successful. | diff --git a/examples/case_plans/test_mfa_login.TestMFALogin.test_mfa_login.md b/examples/case_plans/test_mfa_login.TestMFALogin.test_mfa_login.md new file mode 100644 index 00000000..b637f85f --- /dev/null +++ b/examples/case_plans/test_mfa_login.TestMFALogin.test_mfa_login.md @@ -0,0 +1,7 @@ +``test_mfa_login.py::TestMFALogin::test_mfa_login`` +--- +| # | Step Description | Expected Result | +| - | ---------------- | --------------- | +| 1 | Open https://seleniumbase.io/realworld/login
Enter credentials and Sign In. | Sign In was successful. | +| 2 | Click the ``This Page`` button.
Save a screenshot to the logs. | | +| 3 | Click to Sign Out | Sign Out was successful. | diff --git a/seleniumbase/console_scripts/run.py b/seleniumbase/console_scripts/run.py index f38eb352..d937525e 100644 --- a/seleniumbase/console_scripts/run.py +++ b/seleniumbase/console_scripts/run.py @@ -11,6 +11,7 @@ sbase methods sbase options sbase commander sbase behave-gui +sbase caseplans sbase mkdir ui_tests sbase mkfile new_test.py sbase mkrec new_test.py @@ -83,6 +84,7 @@ def show_basic_usage(): sc += " behave-options (List common behave options)\n" sc += " gui / commander [OPTIONAL PATH or TEST FILE]\n" sc += " behave-gui (SBase Commander for Behave)\n" + sc += " caseplans [OPTIONAL PATH or TEST FILE]\n" sc += " mkdir [DIRECTORY] [OPTIONS]\n" sc += " mkfile [FILE.py] [OPTIONS]\n" sc += " mkrec / codegen [FILE.py] [OPTIONS]\n" @@ -200,6 +202,27 @@ def show_behave_gui_usage(): print("") +def show_caseplans_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 + "caseplans" + c2 + " **" + cr + print(sc) + print("") + print(" Usage:") + print(" seleniumbase caseplans [OPTIONAL PATH or TEST FILE]") + print(" OR: sbase caseplans [OPTIONAL PATH or TEST FILE]") + print(" Examples:") + print(" sbase caseplans") + print(" sbase caseplans -k agent") + print(" sbase caseplans -m marker2") + print(" sbase caseplans test_suite.py") + print(" sbase caseplans offline_examples/") + print(" Output:") + print(" Launches the SeleniumBase Case Plans Generator.") + print("") + + def show_mkdir_usage(): c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX c3 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX @@ -879,6 +902,7 @@ def show_detailed_help(): show_install_usage() show_commander_usage() show_behave_gui_usage() + show_caseplans_usage() show_mkdir_usage() show_mkfile_usage() show_mkrec_usage() @@ -932,6 +956,10 @@ def main(): from seleniumbase.console_scripts import sb_behave_gui sb_behave_gui.main() + elif command == "caseplans" or command == "case-plans": + from seleniumbase.console_scripts import sb_caseplans + + sb_caseplans.main() elif ( command == "recorder" or (command == "record" and len(command_args) == 0) @@ -1135,6 +1163,14 @@ def main(): print("") show_behave_gui_usage() return + elif command_args[0] == "caseplans": + print("") + show_caseplans_usage() + return + elif command_args[0] == "case-plans": + print("") + show_caseplans_usage() + return elif command_args[0] == "mkdir": print("") show_mkdir_usage() diff --git a/seleniumbase/console_scripts/sb_caseplans.py b/seleniumbase/console_scripts/sb_caseplans.py new file mode 100755 index 00000000..0f9c2b91 --- /dev/null +++ b/seleniumbase/console_scripts/sb_caseplans.py @@ -0,0 +1,526 @@ +# -*- coding: utf-8 -*- +""" +Launches the SeleniumBase Case Plans Generator. + +Usage: + seleniumbase caseplans [OPTIONAL PATH or TEST FILE] + sbase caseplans [OPTIONAL PATH or TEST FILE] + +Examples: + sbase caseplans + sbase caseplans -k agent + sbase caseplans -m marker2 + sbase caseplans test_suite.py + sbase caseplans offline_examples/ + +Output: + Launches the SeleniumBase Case Plans Generator. +""" + +import codecs +import colorama +import os +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 Case Plans Generator requires Python 3.7 or newer!" + "\n** You are currently using Python %s" % current_version + ) +import tkinter as tk # noqa: E402 +from tkinter import messagebox # noqa: E402 +from tkinter.scrolledtext import ScrolledText # noqa: E402 + +is_windows = False +if sys.platform in ["win32", "win64", "x64"]: + is_windows = True + + +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.BLACK + colorama.Back.LIGHTCYAN_EX + 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 show_no_case_plans_warning(): + messagebox.showwarning( + "No existing Case Plans found!", + "\nNo existing Case Plans found!!\n\nCreate some boilerplates first!", + ) + + +def get_test_id(display_id): + """The id used in various places such as the test log path.""" + return display_id.replace(".py::", ".").replace("::", ".") + + +def generate_case_plan_boilerplates( + root, + tests, + selected_tests, + tests_with_case_plan, + tests_without_case_plan, +): + total_tests = len(tests) + total_selected_tests = 0 + for selected_test in selected_tests: + if selected_tests[selected_test].get(): + total_selected_tests += 1 + + test_cases = [] + case_plans_to_create = [] + if total_selected_tests == 0: + messagebox.showwarning( + "No tests were selected!", + "\nℹ️ No tests were selected!\nSelect tests for Case Plans!", + ) + send_window_to_front(root) + return + elif total_tests == total_selected_tests: + for test in tests: + test_cases.append(test) + else: + for test_number, test in enumerate(tests): + if selected_tests[test_number].get(): + test_cases.append(test) + + for test_case in test_cases: + if ( + test_case in tests_without_case_plan + and test_case not in tests_with_case_plan + ): + case_plans_to_create.append(test_case) + + new_plans = 0 + for case_plan in case_plans_to_create: + parts = case_plan.split("/") + test_address = None + folder_path = None + if len(parts) == 1: + test_address = parts[0] + if len(parts) > 1: + test_address = parts[-1] + folder_path = "/".join(parts[0:-1]) + test_id = get_test_id(test_address) + case_id = test_id + ".md" + full_folder_path = None + if len(parts) == 1: + full_folder_path = "case_plans" + if not os.path.exists(full_folder_path): + os.makedirs(full_folder_path) + else: + full_folder_path = os.path.join(folder_path, "case_plans") + if not os.path.exists(full_folder_path): + os.makedirs(full_folder_path) + + data = [] + data.append("``%s``" % test_address) + data.append("---") + data.append("| # | Step Description | Expected Result |") + data.append("| - | ---------------- | --------------- |") + data.append("| 1 | Perform Action 1 | Verify Action 1 |") + data.append("| 2 | Perform Action 2 | Verify Action 2 |") + data.append("") + file_name = case_id + file_path = os.path.join(full_folder_path, file_name) + if not os.path.exists(file_path): + out_file = codecs.open(file_path, "w+", "utf-8") + out_file.writelines("\r\n".join(data)) + out_file.close() + new_plans += 1 + print("Created %s" % file_path) + + if new_plans == 1: + messagebox.showinfo( + "A new Case Plan was generated!", + '\n✅ %s new boilerplate Case Plan was generated!' % new_plans, + ) + elif new_plans >= 2: + messagebox.showinfo( + "New Case Plans were generated!", + '\n✅ %s new boilerplate Case Plans were generated!' % new_plans, + ) + else: + messagebox.showwarning( + "No new Case Plans were generated!", + "\nℹ️ No new boilerplates were generated!\n\n" + "The selected tests already have Case Plans!", + ) + send_window_to_front(root) + + +def view_summary_of_existing_case_plans(root, tests): + case_data_storage = [] + case_to_test_hash = {} + full_t = [] + test_index = -1 + for test in tests: + full_t.append(test) + test_index += 1 + parts = test.strip().split("/") + test_address = None + folder_path = None + if len(parts) == 1: + test_address = parts[0] + folder_path = "." + if len(parts) > 1: + test_address = parts[-1] + folder_path = "/".join(parts[0:-1]) + test_id = get_test_id(test_address) + case_id = test_id + ".md" + case_path = None + if len(parts) == 1: + case_path = os.path.join("case_plans", case_id) + else: + case_path = os.path.join(folder_path, "case_plans", case_id) + if os.path.exists(case_path): + f = open(case_path, "r") + case_data = f.read() + f.close() + case_data_storage.append(case_data) + case_to_test_hash[len(case_data_storage) - 1] = test_index + + full_plan = [] + if len(case_data_storage) > 0: + full_plan.append( + "

Summary of existing Case Plans

" + ) + full_plan.append("") + full_plan.append("| | |") + full_plan.append("| - | - |") + full_plan.append("| 🔵 | Plans with customized step definitions. |") + full_plan.append("| ⭕ | Plans using default boilerplate code. |") + full_plan.append("| 🚧 | Plans under construction with no table. |") + full_plan.append("") + full_plan.append("--------") + else: + show_no_case_plans_warning() + send_window_to_front(root) + return + full_plan.append("") + full_plan.append("

🔎 (Click rows to expand) 🔍

") + full_plan.append("") + + full_plan = [] + num_ready_cases = 0 + num_boilerplate = 0 + num_in_progress = 0 + case_index = -1 + for case_data in case_data_storage: + case_index += 1 + icon = "🔵" + table_missing = False + if "| 1 | Perform Action 1 | Verify Action 1 |" in case_data: + # Still using raw boilerplate code. (Missing real test steps) + icon = "⭕" + if case_data.count("|") < 9 or case_data.count("-") < 3: + # Not enough characters for a minimal Markdown case plan file. + # The dash(es) on line 2, and the Markdown table are required. + # This is what a minimal case plan file might look like: + """ + TEST_ADDRESS + - + | Steps | Results | + | - | - | + | Step1 | Result1 | + """ + icon = "🚧" + table_missing = True + lines = case_data.split("\n") + if len(lines) >= 3 and not table_missing: + first_line = lines[0] + first_line = first_line.strip() + if not (first_line.startswith("``") and first_line.endswith("``")): + first_line = "``%s``" % tests[case_to_test_hash[case_index]] + lines.insert(0, first_line) + else: + first_line = "``%s``" % tests[case_to_test_hash[case_index]] + lines[0] = first_line + lines.insert(0, "
") + lines[1] = ( + " %s " % icon + + first_line[2:-2] + + "" + ) + if ( + lines[2].strip().startswith("-") + and lines[2].strip().endswith("-") + ): + lines[2] = "" + elif lines[2].strip() != "": + lines.insert(2, "") + if lines[-1].strip() != "": + lines.append("") + lines.append("
") + full_plan.append("\r\n".join(lines)) + else: + # No existing Case Plan found. / File is missing boilerplate. + icon = "🚧" + lines = [] + first_line = tests[case_to_test_hash[case_index]] + first_line = "%s %s" % (icon, first_line) + lines.insert(0, first_line) + full_plan.append("\r\n".join(lines)) + full_plan.append("") + if icon == "🔵": + num_ready_cases += 1 + elif icon == "⭕": + num_boilerplate += 1 + elif icon == "🚧": + num_in_progress += 1 + + msg_ready_cases = "%s Case Plans with customized tables" % num_ready_cases + if num_ready_cases == 1: + msg_ready_cases = "1 Case Plan with a customized table" + msg_boilerplate = "%s Case Plans using boilerplate code" % num_boilerplate + if num_boilerplate == 1: + msg_boilerplate = "1 Case Plan using boilerplate code" + msg_in_progress = "%s Case Plans that are missing tables" % num_in_progress + if num_in_progress == 1: + msg_in_progress = "1 Case Plan that is missing a table" + + msg_r = " ".join(msg_ready_cases.split(" ")[1:]) + msg_b = " ".join(msg_boilerplate.split(" ")[1:]) + msg_i = " ".join(msg_in_progress.split(" ")[1:]) + + plan_head = [] + if len(case_data_storage) > 0: + plan_head.append( + "

Summary of existing Case Plans

" + ) + plan_head.append("") + plan_head.append("| | | |") + plan_head.append("| - | -: | - |") + plan_head.append("| 🔵 | %s | %s |" % (num_ready_cases, msg_r)) + plan_head.append("| ⭕ | %s | %s |" % (num_boilerplate, msg_b)) + plan_head.append("| 🚧 | %s | %s |" % (num_in_progress, msg_i)) + plan_head.append("") + plan_head.append("--------") + else: + show_no_case_plans_warning() + send_window_to_front(root) + return + plan_head.append("") + plan_head.append("

🔎 (Click rows to expand) 🔍

") + plan_head.append("") + + for row in full_plan: + plan_head.append(row) + full_plan = plan_head + + file_path = "case_summary.md" + file = codecs.open(file_path, "w+", "utf-8") + file.writelines("\r\n".join(full_plan)) + file.close() + + if num_ready_cases < 10: + msg_ready_cases = " %s" % msg_ready_cases + if num_ready_cases < 100: + msg_ready_cases = " %s" % msg_ready_cases + if num_boilerplate < 10: + msg_boilerplate = " %s" % msg_boilerplate + if num_boilerplate < 100: + msg_boilerplate = " %s" % msg_boilerplate + if num_in_progress < 10: + msg_in_progress = " %s" % msg_in_progress + if num_in_progress < 100: + msg_in_progress = " %s" % msg_in_progress + messagebox.showinfo( + "Case Plans Summary generated!", + '\nSummary generated at "case_summary.md"' + '\n🔵 %s' + '\n⭕ %s' + '\n🚧 %s' + % (msg_ready_cases, msg_boilerplate, msg_in_progress) + ) + send_window_to_front(root) + + +def create_tkinter_gui(tests, command_string): + root = tk.Tk() + root.title("SeleniumBase Case Plans Generator") + root.minsize(820, 652) + tk.Label(root, text="").pack() + run_display = ( + "Select from %s tests found: " + "(Boilerplate Case Plans will be generated as needed)" + % len(tests) + ) + if len(tests) == 1: + run_display = ( + "Select from 1 test found: " + "(Boilerplate Case Plans will be generated as needed)" + ) + run_display_2 = "(Tests with existing Case Plans are already checked)" + tk.Label(root, text=run_display, fg="blue").pack() + tk.Label(root, text=run_display_2, fg="purple").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 = {} + tests_with_case_plan = [] + tests_without_case_plan = [] + for row in tests: + row += " " * 200 + ara[count] = tk.IntVar() + cb = None + if not is_windows: + cb = tk.Checkbutton( + text_area, + text=(row), + bg="white", + anchor="w", + pady=0, + variable=ara[count], + ) + else: + cb = tk.Checkbutton( + text_area, + text=(row), + bg="white", + anchor="w", + pady=0, + borderwidth=0, + highlightthickness=0, + variable=ara[count], + ) + parts = row.strip().split("/") + test_address = None + folder_path = None + if len(parts) == 1: + test_address = parts[0] + if len(parts) > 1: + test_address = parts[-1] + folder_path = "/".join(parts[0:-1]) + test_id = get_test_id(test_address) + case_id = test_id + ".md" + case_path = None + if len(parts) == 1: + case_path = os.path.join("case_plans", case_id) + else: + case_path = os.path.join(folder_path, "case_plans", case_id) + if os.path.exists(case_path): + cb.select() + tests_with_case_plan.append(row.strip()) + else: + tests_without_case_plan.append(row.strip()) + text_area.window_create("end", window=cb) + text_area.insert("end", "\n") + count += 1 + + tk.Label(root, text="").pack() + tk.Button( + root, + text=( + "Generate boilerplate Case Plans " + "for selected tests missing them"), + fg="green", + command=lambda: generate_case_plan_boilerplates( + root, + tests, + ara, + tests_with_case_plan, + tests_without_case_plan, + ), + ).pack() + + tk.Label(root, text="").pack() + tk.Button( + root, + text=( + "Generate Summary of existing Case Plans"), + fg="teal", + command=lambda: view_summary_of_existing_case_plans(root, tests), + ).pack() + tk.Label(root, text="\n").pack() + + # Bring form window to front + send_window_to_front(root) + # Use decoy to set correct focus on main window + decoy = tk.Tk() + decoy.geometry("1x1") + decoy.iconify() + decoy.update() + decoy.deiconify() + decoy.destroy() + # Start tkinter + 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 += "Case Plans" + message += c4 + message += " Generator" + 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 the Case Plans Generator..." + error_msg = c5 + "ERROR: " + error_msg + cr + print(error_msg) + return + + create_tkinter_gui(tests, command_string) + + +if __name__ == "__main__": + print('To open the Case Plans Generator, type "sbase caseplans"')