Merge pull request #3418 from aws-lumberyard-dev/jckand/EditorAutomationOptimization

Editor automation optimizations with TestAutomationBase/parallelization
monroegm-disable-blank-issue-2
Chris Galvan 4 years ago committed by GitHub
commit b4687fa72f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -51,8 +51,8 @@ class TestAutomationBase:
cls.asset_processor.teardown() cls.asset_processor.teardown()
cls._kill_ly_processes() cls._kill_ly_processes()
def _run_test(self, request, workspace, editor, testcase_module, extra_cmdline_args=[], batch_mode=True,
def _run_test(self, request, workspace, editor, testcase_module, extra_cmdline_args=[], use_null_renderer=True): autotest_mode=True, use_null_renderer=True):
test_starttime = time.time() test_starttime = time.time()
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
errors = [] errors = []
@ -90,9 +90,13 @@ class TestAutomationBase:
editor_starttime = time.time() editor_starttime = time.time()
self.logger.debug("Running automated test") self.logger.debug("Running automated test")
testcase_module_filepath = self._get_testcase_module_filepath(testcase_module) testcase_module_filepath = self._get_testcase_module_filepath(testcase_module)
pycmd = ["--runpythontest", testcase_module_filepath, "-BatchMode", "-autotest_mode", f"-pythontestcase={request.node.originalname}"] pycmd = ["--runpythontest", testcase_module_filepath, f"-pythontestcase={request.node.originalname}"]
if use_null_renderer: if use_null_renderer:
pycmd += ["-rhi=null"] pycmd += ["-rhi=null"]
if batch_mode:
pycmd += ["-BatchMode"]
if autotest_mode:
pycmd += ["-autotest_mode"]
pycmd += extra_cmdline_args pycmd += extra_cmdline_args
editor.args.extend(pycmd) # args are added to the WinLauncher start command editor.args.extend(pycmd) # args are added to the WinLauncher start command
editor.start(backupFiles = False, launch_ap = False) editor.start(backupFiles = False, launch_ap = False)

@ -11,8 +11,23 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
NAME AutomatedTesting::EditorTests_Main NAME AutomatedTesting::EditorTests_Main
TEST_SUITE main TEST_SUITE main
TEST_SERIAL TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR} PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
PYTEST_MARKS "SUITE_main and not REQUIRES_gpu" PYTEST_MARKS "not REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Main_GPU
TEST_SUITE main
TEST_SERIAL
TEST_REQUIRES gpu
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
PYTEST_MARKS "REQUIRES_gpu"
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
Legacy::Editor Legacy::Editor
AZ::AssetProcessor AZ::AssetProcessor
@ -25,8 +40,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
NAME AutomatedTesting::EditorTests_Periodic NAME AutomatedTesting::EditorTests_Periodic
TEST_SUITE periodic TEST_SUITE periodic
TEST_SERIAL TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR} PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Periodic.py
PYTEST_MARKS "SUITE_periodic and not REQUIRES_gpu"
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
Legacy::Editor Legacy::Editor
AZ::AssetProcessor AZ::AssetProcessor
@ -36,12 +50,39 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
) )
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::EditorTests_Main_GPU NAME AutomatedTesting::EditorTests_Sandbox
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox.py
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Main_Optimized
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
PYTEST_MARKS "not REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Main_GPU_Optimized
TEST_SUITE main TEST_SUITE main
TEST_SERIAL TEST_SERIAL
TEST_REQUIRES gpu TEST_REQUIRES gpu
PATH ${CMAKE_CURRENT_LIST_DIR} PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
PYTEST_MARKS "SUITE_main and REQUIRES_gpu" PYTEST_MARKS "REQUIRES_gpu"
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
Legacy::Editor Legacy::Editor
AZ::AssetProcessor AZ::AssetProcessor
@ -51,11 +92,10 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
) )
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::EditorTests_Sandbox NAME AutomatedTesting::EditorTests_Sandbox_Optimized
TEST_SUITE sandbox TEST_SUITE sandbox
TEST_SERIAL TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR} PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox_Optimized.py
PYTEST_MARKS "SUITE_sandbox"
RUNTIME_DEPENDENCIES RUNTIME_DEPENDENCIES
Legacy::Editor Legacy::Editor
AZ::AssetProcessor AZ::AssetProcessor
@ -63,4 +103,5 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
COMPONENT COMPONENT
Editor Editor
) )
endif() endif()

@ -5,30 +5,24 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C13660194 : Asset Browser - Filtering
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general class Tests:
import azlmbr.paths asset_filtered = (
"Asset was filtered to in the Asset Browser",
"Failed to filter to the expected asset"
)
asset_type_filtered = (
"Expected asset type was filtered to in the Asset Browser",
"Failed to filter to the expected asset type"
)
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
def AssetBrowser_SearchFiltering():
class AssetBrowserSearchFilteringTest(EditorTestHelper): import editor_python_test_tools.pyside_utils as pyside_utils
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetBrowser_SearchFiltering", args=["level"])
@pyside_utils.wrap_async @pyside_utils.wrap_async
async def run_test(self): async def run_test():
""" """
Summary: Summary:
Asset Browser - Filtering Asset Browser - Filtering
@ -60,7 +54,13 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
:return: None :return: None
""" """
self.incorrect_file_found = False from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
def verify_files_appeared(model, allowed_asset_extentions, parent_index=QtCore.QModelIndex()): def verify_files_appeared(model, allowed_asset_extentions, parent_index=QtCore.QModelIndex()):
indexes = [parent_index] indexes = [parent_index]
@ -74,25 +74,24 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
and (cur_data.lower().split(".")[-1] not in allowed_asset_extentions) and (cur_data.lower().split(".")[-1] not in allowed_asset_extentions)
and not cur_data[-1] == ")" and not cur_data[-1] == ")"
): ):
print(f"Incorrect file found: {cur_data}") Report.info(f"Incorrect file found: {cur_data}")
self.incorrect_file_found = True return False
indexes = list()
break
indexes.append(cur_index) indexes.append(cur_index)
return True
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# 1) Open level # 2) Open Asset Browser (if not opened already)
self.test_success = self.create_level( editor_window = pyside_utils.get_editor_main_window()
self.args["level"], asset_browser_open = general.is_pane_visible("Asset Browser")
heightmap_resolution=1024, if not asset_browser_open:
heightmap_meters_per_pixel=1, Report.info("Opening Asset Browser")
terrain_texture_resolution=4096, action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Asset Browser")
use_terrain=False, action.trigger()
) else:
Report.info("Asset Browser is already open")
# 2) Open Asset Browser
general.close_pane("Asset Browser")
general.open_pane("Asset Browser")
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
app = QtWidgets.QApplication.instance() app = QtWidgets.QApplication.instance()
@ -103,10 +102,9 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
asset_browser_tree = asset_browser.findChild(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget") asset_browser_tree = asset_browser.findChild(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")
model_index = pyside_utils.find_child_by_pattern(asset_browser_tree, "cedar.fbx") model_index = pyside_utils.find_child_by_pattern(asset_browser_tree, "cedar.fbx")
pyside_utils.item_view_index_mouse_click(asset_browser_tree, model_index) pyside_utils.item_view_index_mouse_click(asset_browser_tree, model_index)
is_filtered = pyside_utils.wait_for_condition( is_filtered = await pyside_utils.wait_for_condition(
lambda: asset_browser_tree.indexBelow(asset_browser_tree.currentIndex()) == QtCore.QModelIndex(), 5.0) lambda: asset_browser_tree.indexBelow(asset_browser_tree.currentIndex()) == QtCore.QModelIndex(), 5.0)
if is_filtered: Report.result(Tests.asset_filtered, is_filtered)
print("cedar.fbx asset is filtered in Asset Browser")
# 4) Click the "X" in the search bar. # 4) Click the "X" in the search bar.
clear_search = asset_browser.findChild(QtWidgets.QToolButton, "ClearToolButton") clear_search = asset_browser.findChild(QtWidgets.QToolButton, "ClearToolButton")
@ -122,40 +120,47 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
tree.model().setData(animation_model_index, 2, Qt.CheckStateRole) tree.model().setData(animation_model_index, 2, Qt.CheckStateRole)
general.idle_wait(1.0) general.idle_wait(1.0)
# check asset types after clicking on Animation filter # check asset types after clicking on Animation filter
verify_files_appeared(asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset"]) asset_type_filter = verify_files_appeared(asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset"])
print(f"Animation file type(s) is present in the file tree: {not self.incorrect_file_found}") Report.result(Tests.asset_type_filtered, asset_type_filter)
# 6) Add additional filter(FileTag) from the filter menu # 6) Add additional filter(FileTag) from the filter menu
self.incorrect_file_found = False
line_edit.setText("FileTag") line_edit.setText("FileTag")
filetag_model_index = await pyside_utils.wait_for_child_by_pattern(tree, "FileTag") filetag_model_index = await pyside_utils.wait_for_child_by_pattern(tree, "FileTag")
tree.model().setData(filetag_model_index, 2, Qt.CheckStateRole) tree.model().setData(filetag_model_index, 2, Qt.CheckStateRole)
general.idle_wait(1.0) general.idle_wait(1.0)
# check asset types after clicking on FileTag filter # check asset types after clicking on FileTag filter
verify_files_appeared( more_types_filtered = verify_files_appeared(
asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset", "filetag"] asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset", "filetag"]
) )
print(f"FileTag file type(s) and Animation file type(s) is present in the file tree: {not self.incorrect_file_found}") Report.result(Tests.asset_type_filtered, more_types_filtered)
# 7) Remove one of the filtered asset types from the list of applied filters # 7) Remove one of the filtered asset types from the list of applied filters
self.incorrect_file_found = False
filter_layout = asset_browser.findChild(QtWidgets.QFrame, "filteredLayout") filter_layout = asset_browser.findChild(QtWidgets.QFrame, "filteredLayout")
animation_close_button = filter_layout.children()[1] animation_close_button = filter_layout.children()[1]
first_close_button = animation_close_button.findChild(QtWidgets.QPushButton, "closeTag") first_close_button = animation_close_button.findChild(QtWidgets.QPushButton, "closeTag")
first_close_button.click() first_close_button.click()
general.idle_wait(1.0) general.idle_wait(1.0)
# check asset types after removing Animation filter # check asset types after removing Animation filter
verify_files_appeared(asset_browser_tree.model(), ["filetag"]) remove_filtered = verify_files_appeared(asset_browser_tree.model(), ["filetag"])
print(f"FileTag file type(s) is present in the file tree after removing Animation filter: {not self.incorrect_file_found}") Report.result(Tests.asset_type_filtered, remove_filtered)
# 8) Remove all of the filter asset types from the list of filters # 8) Remove all of the filter asset types from the list of filters
filetag_close_button = filter_layout.children()[1] filetag_close_button = filter_layout.children()[1]
second_close_button = filetag_close_button.findChild(QtWidgets.QPushButton, "closeTag") second_close_button = filetag_close_button.findChild(QtWidgets.QPushButton, "closeTag")
second_close_button.click() second_close_button.click()
# 9) Close the asset browser # Click off of the Asset Browser filter window to close it
asset_browser.close() QtTest.QTest.mouseClick(tree, Qt.LeftButton, Qt.NoModifier)
# 9) Restore Asset Browser tool state and
if not asset_browser_open:
Report.info("Closing Asset Browser")
general.close_pane("Asset Browser")
run_test()
if __name__ == "__main__":
test = AssetBrowserSearchFilteringTest() from editor_python_test_tools.utils import Report
test.run() Report.start_test(AssetBrowser_SearchFiltering)

@ -5,27 +5,23 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C13660195: Asset Browser - File Tree Navigation
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
class Tests:
collapse_expand = (
"Asset Browser hierarchy successfully collapsed/expanded",
"Failed to collapse/expand Asset Browser hierarchy"
)
asset_visible = (
"Expected asset is visible in the Asset Browser hierarchy",
"Failed to find expected asset in the Asset Browser hierarchy"
)
scrollbar_visible = (
"Scrollbar is visible",
"Scrollbar was not found"
)
class AssetBrowserTreeNavigationTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetBrowser_TreeNavigation", args=["level"])
def run_test(self): def AssetBrowser_TreeNavigation():
""" """
Summary: Summary:
Verify if we are able to expand a file hierarchy in the Asset Browser and ScrollBar appears Verify if we are able to expand a file hierarchy in the Asset Browser and ScrollBar appears
@ -37,7 +33,7 @@ class AssetBrowserTreeNavigationTest(EditorTestHelper):
Assets are present in the Asset Browser. Assets are present in the Asset Browser.
Test Steps: Test Steps:
1) Open a new level 1) Open a simple level
2) Open Asset Browser 2) Open Asset Browser
3) Collapse all files initially 3) Collapse all files initially
4) Get all Model Indexes 4) Get all Model Indexes
@ -52,36 +48,39 @@ class AssetBrowserTreeNavigationTest(EditorTestHelper):
:return: None :return: None
""" """
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
def collapse_expand_and_verify(model_index, hierarchy_level): def collapse_expand_and_verify(model_index, hierarchy_level):
tree.collapse(model_index) tree.collapse(model_index)
collapse_success = not tree.isExpanded(model_index) collapse_success = not tree.isExpanded(model_index)
self.log(f"Level {hierarchy_level} collapsed: {collapse_success}") Report.info(f"Level {hierarchy_level} collapsed: {collapse_success}")
tree.expand(model_index) tree.expand(model_index)
expand_success = tree.isExpanded(model_index) expand_success = tree.isExpanded(model_index)
self.log(f"Level {hierarchy_level} expanded: {expand_success}") Report.info(f"Level {hierarchy_level} expanded: {expand_success}")
return collapse_success and expand_success return collapse_success and expand_success
# This is the hierarchy we are expanding (4 steps inside) # This is the hierarchy we are expanding (4 steps inside)
self.file_path = ("AutomatedTesting", "Assets", "ImageGradients", "image_grad_test_gsi.png") file_path = ("AutomatedTesting", "Assets", "ImageGradients", "image_grad_test_gsi.png")
# 1) Open a new level # 1) Open an existing simple level
self.test_success = self.create_level( helper.init_idle()
self.args["level"], helper.open_level("Physics", "Base")
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 2) Open Asset Browser (if not opened already) # 2) Open Asset Browser (if not opened already)
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
asset_browser_open = general.is_pane_visible("Asset Browser") asset_browser_open = general.is_pane_visible("Asset Browser")
if not asset_browser_open: if not asset_browser_open:
self.log("Opening Asset Browser") Report.info("Opening Asset Browser")
action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Asset Browser") action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Asset Browser")
action.trigger() action.trigger()
else: else:
self.log("Asset Browser is already open") Report.info("Asset Browser is already open")
# 3) Collapse all files initially # 3) Collapse all files initially
main_window = editor_window.findChild(QtWidgets.QMainWindow) main_window = editor_window.findChild(QtWidgets.QMainWindow)
@ -92,16 +91,14 @@ class AssetBrowserTreeNavigationTest(EditorTestHelper):
tree.collapseAll() tree.collapseAll()
# 4) Get all Model Indexes # 4) Get all Model Indexes
model_index_1 = pyside_utils.find_child_by_hierarchy(tree, self.file_path[0]) model_index_1 = pyside_utils.find_child_by_hierarchy(tree, file_path[0])
model_index_2 = pyside_utils.find_child_by_hierarchy(model_index_1, self.file_path[1]) model_index_2 = pyside_utils.find_child_by_hierarchy(model_index_1, file_path[1])
model_index_3 = pyside_utils.find_child_by_hierarchy(model_index_2, self.file_path[2]) model_index_3 = pyside_utils.find_child_by_hierarchy(model_index_2, file_path[2])
model_index_4 = pyside_utils.find_child_by_hierarchy(model_index_3, self.file_path[3]) model_index_4 = pyside_utils.find_child_by_hierarchy(model_index_3, file_path[3])
# 5) Verify each level of the hierarchy to the file can be collapsed/expanded # 5) Verify each level of the hierarchy to the file can be collapsed/expanded
self.test_success = collapse_expand_and_verify(model_index_1, 1) and self.test_success Report.result(Tests.collapse_expand, collapse_expand_and_verify(model_index_1, 1) and
self.test_success = collapse_expand_and_verify(model_index_2, 2) and self.test_success collapse_expand_and_verify(model_index_2, 2) and collapse_expand_and_verify(model_index_3, 3))
self.test_success = collapse_expand_and_verify(model_index_3, 3) and self.test_success
self.log(f"Collapse/Expand tests: {self.test_success}")
# Select the asset # Select the asset
tree.scrollTo(model_index_4) tree.scrollTo(model_index_4)
@ -109,20 +106,18 @@ class AssetBrowserTreeNavigationTest(EditorTestHelper):
# Verify if the currently selected item model index is same as the Asset Model index # Verify if the currently selected item model index is same as the Asset Model index
# to prove that it is visible # to prove that it is visible
asset_visible = tree.currentIndex() == model_index_4 Report.result(Tests.asset_visible, tree.currentIndex() == model_index_4)
self.test_success = asset_visible and self.test_success
self.log(f"Asset visibility test: {asset_visible}")
# 6) Verify if the ScrollBar appears after expanding the tree # 6) Verify if the ScrollBar appears after expanding the tree
scrollbar_visible = scroll_bar.isVisible() Report.result(Tests.scrollbar_visible, scroll_bar.isVisible())
self.test_success = scrollbar_visible and self.test_success
self.log(f"Scrollbar visibility test: {scrollbar_visible}")
# 7) Restore Asset Browser tool state # 7) Restore Asset Browser tool state
if not asset_browser_open: if not asset_browser_open:
self.log("Closing Asset Browser") Report.info("Closing Asset Browser")
general.close_pane("Asset Browser") general.close_pane("Asset Browser")
test = AssetBrowserTreeNavigationTest() if __name__ == "__main__":
test.run()
from editor_python_test_tools.utils import Report
Report.start_test(AssetBrowser_TreeNavigation)

@ -5,33 +5,13 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C13751579: Asset Picker UI/UX
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.asset as asset def AssetPicker_UI_UX():
import azlmbr.bus as bus
import azlmbr.legacy.general as general
import azlmbr.paths
import azlmbr.math as math
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
class AssetPickerUIUXTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetPicker_UI_UX", args=["level"])
@pyside_utils.wrap_async @pyside_utils.wrap_async
async def run_test(self): async def run_test():
""" """
Summary: Summary:
Verify the functionality of Asset Picker and UI/UX properties Verify the functionality of Asset Picker and UI/UX properties
@ -45,7 +25,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
The asset picker is closed and the selected asset is assigned to the mesh component. The asset picker is closed and the selected asset is assigned to the mesh component.
Test Steps: Test Steps:
1) Open a new level 1) Open a simple level
2) Create entity and add Mesh component 2) Create entity and add Mesh component
3) Access Entity Inspector 3) Access Entity Inspector
4) Click Asset Picker (Mesh Asset) 4) Click Asset Picker (Mesh Asset)
@ -68,10 +48,20 @@ class AssetPickerUIUXTest(EditorTestHelper):
:return: None :return: None
""" """
self.file_path = ["AutomatedTesting", "Assets", "Objects", "Foliage"] import os
self.incorrect_file_found = False from PySide2 import QtWidgets, QtTest, QtCore
self.mesh_asset = "cedar.azmodel" from PySide2.QtCore import Qt
self.prefix = ""
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.legacy.general as general
import azlmbr.math as math
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
file_path = ["AutomatedTesting", "Assets", "Objects", "Foliage"]
def is_asset_assigned(component, interaction_option): def is_asset_assigned(component, interaction_option):
path = os.path.join("assets", "objects", "foliage", "cedar.azmodel") path = os.path.join("assets", "objects", "foliage", "cedar.azmodel")
@ -80,7 +70,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
result = hydra.get_component_property_value(component, "Controller|Configuration|Mesh Asset") result = hydra.get_component_property_value(component, "Controller|Configuration|Mesh Asset")
expected_asset_str = expected_asset_id.invoke("ToString") expected_asset_str = expected_asset_id.invoke("ToString")
result_str = result.invoke("ToString") result_str = result.invoke("ToString")
print(f"Asset assigned for {interaction_option} option: {expected_asset_str == result_str}") Report.info(f"Asset assigned for {interaction_option} option: {expected_asset_str == result_str}")
return expected_asset_str == result_str return expected_asset_str == result_str
def move_and_resize_widget(widget): def move_and_resize_widget(widget):
@ -89,9 +79,11 @@ class AssetPickerUIUXTest(EditorTestHelper):
x, y = initial_position.x() + 5, initial_position.y() + 5 x, y = initial_position.x() + 5, initial_position.y() + 5
widget.move(x, y) widget.move(x, y)
curr_position = widget.pos() curr_position = widget.pos()
move_success = curr_position.x() == x and curr_position.y() == y asset_picker_moved = (
self.test_success = move_success and self.test_success "Asset Picker widget moved successfully",
self.log(f"Widget Move Test: {move_success}") "Failed to move Asset Picker widget"
)
Report.result(asset_picker_moved, curr_position.x() == x and curr_position.y() == y)
# Resize the widget and verify size # Resize the widget and verify size
width, height = ( width, height = (
@ -99,9 +91,36 @@ class AssetPickerUIUXTest(EditorTestHelper):
widget.geometry().height() + 10, widget.geometry().height() + 10,
) )
widget.resize(width, height) widget.resize(width, height)
resize_success = widget.geometry().width() == width and widget.geometry().height() == height asset_picker_resized = (
self.test_success = resize_success and self.test_success "Resized Asset Picker widget successfully",
self.log(f"Widget Resize Test: {resize_success}") "Failed to resize Asset Picker widget"
)
Report.result(asset_picker_resized, widget.geometry().width() == width and widget.geometry().height() ==
height)
def verify_expand(model_index, tree):
initially_collapsed = (
"Folder initially collapsed",
"Folder unexpectedly expanded"
)
expanded = (
"Folder expanded successfully",
"Failed to expand folder"
)
# Check initial collapse
Report.result(initially_collapsed, not tree.isExpanded(model_index))
# Expand at the specified index
tree.expand(model_index)
# Verify expansion
Report.result(expanded, tree.isExpanded(model_index))
def verify_collapse(model_index, tree):
collapsed = (
"Folder hierarchy collapsed successfully",
"Failed to collapse folder hierarchy"
)
tree.collapse(model_index)
Report.result(collapsed, not tree.isExpanded(model_index))
def verify_files_appeared(model, allowed_asset_extensions, parent_index=QtCore.QModelIndex()): def verify_files_appeared(model, allowed_asset_extensions, parent_index=QtCore.QModelIndex()):
indices = [parent_index] indices = [parent_index]
@ -115,22 +134,20 @@ class AssetPickerUIUXTest(EditorTestHelper):
and (cur_data.lower().split(".")[-1] not in allowed_asset_extensions) and (cur_data.lower().split(".")[-1] not in allowed_asset_extensions)
and not cur_data[-1] == ")" and not cur_data[-1] == ")"
): ):
print(f"Incorrect file found: {cur_data}") Report.info(f"Incorrect file found: {cur_data}")
self.incorrect_file_found = True return False
indices = list()
break
indices.append(cur_index) indices.append(cur_index)
self.test_success = not self.incorrect_file_found and self.test_success return True
def print_message_prefix(message): async def asset_picker(allowed_asset_extensions, asset, interaction_option):
print(f"{self.prefix}: {message}")
async def asset_picker(prefix, allowed_asset_extensions, asset, interaction_option):
active_modal_widget = await pyside_utils.wait_for_modal_widget() active_modal_widget = await pyside_utils.wait_for_modal_widget()
if active_modal_widget and self.prefix == "": if active_modal_widget:
self.prefix = prefix
dialog = active_modal_widget.findChildren(QtWidgets.QDialog, "AssetPickerDialogClass")[0] dialog = active_modal_widget.findChildren(QtWidgets.QDialog, "AssetPickerDialogClass")[0]
print_message_prefix(f"Asset Picker title for Mesh: {dialog.windowTitle()}") asset_picker_title = (
"Asset Picker window is titled as expected",
"Asset Picker window has an unexpected title"
)
Report.result(asset_picker_title, dialog.windowTitle() == "Pick ModelAsset")
tree = dialog.findChildren(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")[0] tree = dialog.findChildren(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")[0]
scroll_area = tree.findChild(QtWidgets.QWidget, "qt_scrollarea_vcontainer") scroll_area = tree.findChild(QtWidgets.QWidget, "qt_scrollarea_vcontainer")
scroll_bar = scroll_area.findChild(QtWidgets.QScrollBar) scroll_bar = scroll_area.findChild(QtWidgets.QScrollBar)
@ -138,39 +155,42 @@ class AssetPickerUIUXTest(EditorTestHelper):
# a) Collapse all the files initially and verify if scroll bar is not visible # a) Collapse all the files initially and verify if scroll bar is not visible
tree.collapseAll() tree.collapseAll()
await pyside_utils.wait_for_condition(lambda: not scroll_bar.isVisible(), 0.5) await pyside_utils.wait_for_condition(lambda: not scroll_bar.isVisible(), 0.5)
print_message_prefix( scroll_bar_hidden = (
f"Scroll Bar is not visible before expanding the tree: {not scroll_bar.isVisible()}" "Scroll Bar is not visible before tree expansion",
"Scroll Bar is visible before tree expansion"
) )
Report.result(scroll_bar_hidden, not scroll_bar.isVisible())
# Get Model Index of the file paths # Get Model Index of the file paths
model_index_1 = pyside_utils.find_child_by_pattern(tree, self.file_path[0]) model_index_1 = pyside_utils.find_child_by_pattern(tree, file_path[0])
print(model_index_1.model()) model_index_2 = pyside_utils.find_child_by_pattern(model_index_1, file_path[1])
model_index_2 = pyside_utils.find_child_by_pattern(model_index_1, self.file_path[1])
# b) Expand/Verify Top folder of file path # b) Expand/Verify Top folder of file path
print_message_prefix(f"Top level folder initially collapsed: {not tree.isExpanded(model_index_1)}") verify_expand(model_index_1, tree)
tree.expand(model_index_1)
print_message_prefix(f"Top level folder expanded: {tree.isExpanded(model_index_1)}")
# c) Expand/Verify Nested folder of file path # c) Expand/Verify Nested folder of file path
print_message_prefix(f"Nested folder initially collapsed: {not tree.isExpanded(model_index_2)}") verify_expand(model_index_2, tree)
tree.expand(model_index_2)
print_message_prefix(f"Nested folder expanded: {tree.isExpanded(model_index_2)}")
# d) Verify if the ScrollBar appears after expanding folders # d) Verify if the ScrollBar appears after expanding folders
tree.expandAll() tree.expandAll()
await pyside_utils.wait_for_condition(lambda: scroll_bar.isVisible(), 0.5) await pyside_utils.wait_for_condition(lambda: scroll_bar.isVisible(), 0.5)
print_message_prefix(f"Scroll Bar appeared after expanding tree: {scroll_bar.isVisible()}") scroll_bar_visible = (
"Scroll Bar is visible after tree expansion",
"Scroll Bar is not visible after tree expansion"
)
Report.result(scroll_bar_visible, scroll_bar.isVisible())
# e) Collapse Nested and Top Level folders and verify if collapsed # e) Collapse Nested and Top Level folders and verify if collapsed
tree.collapse(model_index_2) verify_collapse(model_index_2, tree)
print_message_prefix(f"Nested folder collapsed: {not tree.isExpanded(model_index_2)}") verify_collapse(model_index_1, tree)
tree.collapse(model_index_1)
print_message_prefix(f"Top level folder collapsed: {not tree.isExpanded(model_index_1)}")
# f) Verify if the correct files are appearing in the Asset Picker # f) Verify if the correct files are appearing in the Asset Picker
verify_files_appeared(tree.model(), allowed_asset_extensions) asset_picker_correct_files_appear = (
print_message_prefix(f"Expected Assets populated in the file picker: {not self.incorrect_file_found}") "Expected assets populated in the file picker",
"Found unexpected assets in the file picker"
)
Report.result(asset_picker_correct_files_appear, verify_files_appeared(tree.model(),
allowed_asset_extensions))
# While we are here we can also check if we can resize and move the widget # While we are here we can also check if we can resize and move the widget
move_and_resize_widget(active_modal_widget) move_and_resize_widget(active_modal_widget)
@ -193,16 +213,10 @@ class AssetPickerUIUXTest(EditorTestHelper):
await pyside_utils.click_button_async(ok_button) await pyside_utils.click_button_async(ok_button)
elif interaction_option == "enter": elif interaction_option == "enter":
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier) QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
self.prefix = ""
# 1) Open an existing simple level
# 1) Open a new level helper.init_idle()
self.test_success = self.create_level( helper.open_level("Physics", "Base")
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 2) Create entity and add Mesh component # 2) Create entity and add Mesh component
entity_position = math.Vector3(125.0, 136.0, 32.0) entity_position = math.Vector3(125.0, 136.0, 32.0)
@ -222,7 +236,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
# Assign Mesh Asset via OK button # Assign Mesh Asset via OK button
pyside_utils.click_button_async(attached_button) pyside_utils.click_button_async(attached_button)
await asset_picker("Mesh Asset", ["azmodel", "fbx"], "cedar (ModelAsset)", "ok") await asset_picker(["azmodel", "fbx"], "cedar (ModelAsset)", "ok")
# 5) Verify if Mesh Asset is assigned # 5) Verify if Mesh Asset is assigned
try: try:
@ -231,7 +245,11 @@ class AssetPickerUIUXTest(EditorTestHelper):
except pyside_utils.EventLoopTimeoutException as err: except pyside_utils.EventLoopTimeoutException as err:
print(err) print(err)
mesh_success = False mesh_success = False
self.test_success = mesh_success and self.test_success mesh_asset_assigned_ok = (
"Successfully assigned Mesh asset via OK button",
"Failed to assign Mesh asset via OK button"
)
Report.result(mesh_asset_assigned_ok, mesh_success)
# Clear Mesh Asset # Clear Mesh Asset
hydra.get_set_test(entity, 0, "Controller|Configuration|Mesh Asset", None) hydra.get_set_test(entity, 0, "Controller|Configuration|Mesh Asset", None)
@ -242,7 +260,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
# Assign Mesh Asset via Enter # Assign Mesh Asset via Enter
pyside_utils.click_button_async(attached_button) pyside_utils.click_button_async(attached_button)
await asset_picker("Mesh Asset", ["azmodel", "fbx"], "cedar (ModelAsset)", "enter") await asset_picker(["azmodel", "fbx"], "cedar (ModelAsset)", "enter")
# 5) Verify if Mesh Asset is assigned # 5) Verify if Mesh Asset is assigned
try: try:
@ -251,8 +269,16 @@ class AssetPickerUIUXTest(EditorTestHelper):
except pyside_utils.EventLoopTimeoutException as err: except pyside_utils.EventLoopTimeoutException as err:
print(err) print(err)
mesh_success = False mesh_success = False
self.test_success = mesh_success and self.test_success mesh_asset_assigned_enter = (
"Successfully assigned Mesh asset via Enter button",
"Failed to assign Mesh asset via Enter button"
)
Report.result(mesh_asset_assigned_enter, mesh_success)
run_test()
if __name__ == "__main__":
test = AssetPickerUIUXTest() from editor_python_test_tools.utils import Report
test.run() Report.start_test(AssetPicker_UI_UX)

@ -5,36 +5,44 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C6351273: Create a new level
C6384955: Basic Workflow: Entity Manipulation in the Outliner
C16929880: Add Delete Components
C15167490: Save a level
C15167491: Export a level
"""
import os
import sys
from PySide2 import QtWidgets
import azlmbr.bus as bus class Tests:
import azlmbr.editor as editor level_created = (
import azlmbr.entity as entity "New level created successfully",
import azlmbr.math as math "Failed to create new level"
import azlmbr.paths )
new_entity_created = (
"New entity created successfully",
"Failed to create a new entity"
)
child_entity_created = (
"New child entity created successfully",
"Failed to create new child entity"
)
component_added = (
"Component added to entity successfully",
"Failed to add component to entity"
)
component_updated = (
"Component property updated successfully",
"Failed to update component property"
)
component_removed = (
"Component removed from entity successfully",
"Failed to remove component from entity"
)
level_saved_and_exported = (
"Level saved and exported successfully",
"Failed to save/export level"
)
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
import editor_python_test_tools.hydra_editor_utils as hydra
def BasicEditorWorkflows_LevelEntityComponentCRUD():
class TestBasicEditorWorkflows(EditorTestHelper): import editor_python_test_tools.pyside_utils as pyside_utils
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="BasicEditorWorkflows_LevelEntityComponent", args=["level"])
@pyside_utils.wrap_async @pyside_utils.wrap_async
async def run_test(self): async def run_test():
""" """
Summary: Summary:
Open O3DE editor and check if basic Editor workflows are completable. Open O3DE editor and check if basic Editor workflows are completable.
@ -55,6 +63,18 @@ class TestBasicEditorWorkflows(EditorTestHelper):
:return: None :return: None
""" """
import os
from PySide2 import QtWidgets
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.paths
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import Report
def find_entity_by_name(entity_name): def find_entity_by_name(entity_name):
search_filter = entity.SearchFilter() search_filter = entity.SearchFilter()
search_filter.names = [entity_name] search_filter.names = [entity_name]
@ -64,6 +84,7 @@ class TestBasicEditorWorkflows(EditorTestHelper):
return None return None
# 1) Create a new level # 1) Create a new level
level = "tmp_level"
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
new_level_action = pyside_utils.get_action_for_menu_path(editor_window, "File", "New Level") new_level_action = pyside_utils.get_action_for_menu_path(editor_window, "File", "New Level")
pyside_utils.trigger_action_async(new_level_action) pyside_utils.trigger_action_async(new_level_action)
@ -71,21 +92,17 @@ class TestBasicEditorWorkflows(EditorTestHelper):
new_level_dlg = active_modal_widget.findChild(QtWidgets.QWidget, "CNewLevelDialog") new_level_dlg = active_modal_widget.findChild(QtWidgets.QWidget, "CNewLevelDialog")
if new_level_dlg: if new_level_dlg:
if new_level_dlg.windowTitle() == "New Level": if new_level_dlg.windowTitle() == "New Level":
self.log("New Level dialog opened") Report.info("New Level dialog opened")
grp_box = new_level_dlg.findChild(QtWidgets.QGroupBox, "STATIC_GROUP1") grp_box = new_level_dlg.findChild(QtWidgets.QGroupBox, "STATIC_GROUP1")
level_name = grp_box.findChild(QtWidgets.QLineEdit, "LEVEL") level_name = grp_box.findChild(QtWidgets.QLineEdit, "LEVEL")
level_name.setText(self.args["level"]) level_name.setText(level)
button_box = new_level_dlg.findChild(QtWidgets.QDialogButtonBox, "buttonBox") button_box = new_level_dlg.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
button_box.button(QtWidgets.QDialogButtonBox.Ok).click() button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
# Verify new level was created successfully # Verify new level was created successfully
level_create_success = await pyside_utils.wait_for_condition(lambda: editor.EditorToolsApplicationRequestBus( level_create_success = await pyside_utils.wait_for_condition(lambda: editor.EditorToolsApplicationRequestBus(
bus.Broadcast, "GetCurrentLevelName") == self.args["level"], 5.0) bus.Broadcast, "GetCurrentLevelName") == level, 5.0)
self.test_success = level_create_success Report.critical_result(Tests.level_created, level_create_success)
self.log(f"Create and load new level: {level_create_success}")
# Execute EditorTestHelper setup since level was created outside of EditorTestHelper's methods
self.test_success = self.test_success and self.after_level_load()
# 2) Delete existing entities, and create and manipulate new entities via Entity Inspector # 2) Delete existing entities, and create and manipulate new entities via Entity Inspector
search_filter = azlmbr.entity.SearchFilter() search_filter = azlmbr.entity.SearchFilter()
@ -99,8 +116,7 @@ class TestBasicEditorWorkflows(EditorTestHelper):
# Find the new entity # Find the new entity
parent_entity_id = find_entity_by_name("Entity1") parent_entity_id = find_entity_by_name("Entity1")
parent_entity_success = await pyside_utils.wait_for_condition(lambda: parent_entity_id is not None, 5.0) parent_entity_success = await pyside_utils.wait_for_condition(lambda: parent_entity_id is not None, 5.0)
self.test_success = self.test_success and parent_entity_success Report.critical_result(Tests.new_entity_created, parent_entity_success)
self.log(f"New entity creation: {parent_entity_success}")
# TODO: Replace Hydra call to creates child entity and add components with context menu triggering - LYN-3951 # TODO: Replace Hydra call to creates child entity and add components with context menu triggering - LYN-3951
# Create a new child entity # Create a new child entity
@ -111,29 +127,27 @@ class TestBasicEditorWorkflows(EditorTestHelper):
# Verify entity hierarchy # Verify entity hierarchy
child_entity.get_parent_info() child_entity.get_parent_info()
self.test_success = self.test_success and child_entity.parent_id == parent_entity_id Report.result(Tests.child_entity_created, child_entity.parent_id == parent_entity_id)
self.log(f"Create entity hierarchy: {child_entity.parent_id == parent_entity_id}")
# 3) Add/configure a component on an entity # 3) Add/configure a component on an entity
# Add component and verify success # Add component and verify success
child_entity.add_component("Box Shape") child_entity.add_component("Box Shape")
component_add_success = self.wait_for_condition(lambda: hydra.has_components(child_entity.id, ["Box Shape"]), 5.0) component_add_success = await pyside_utils.wait_for_condition(lambda: hydra.has_components(child_entity.id,
self.test_success = self.test_success and component_add_success ["Box Shape"]), 5.0)
self.log(f"Add component: {component_add_success}") Report.result(Tests.component_added, component_add_success)
# Update the component # Update the component
dimensions_to_set = math.Vector3(16.0, 16.0, 16.0) dimensions_to_set = math.Vector3(16.0, 16.0, 16.0)
child_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", dimensions_to_set) child_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", dimensions_to_set)
box_shape_dimensions = hydra.get_component_property_value(child_entity.components[0], "Box Shape|Box Configuration|Dimensions") box_shape_dimensions = hydra.get_component_property_value(child_entity.components[0],
self.test_success = self.test_success and box_shape_dimensions == dimensions_to_set "Box Shape|Box Configuration|Dimensions")
self.log(f"Component update: {box_shape_dimensions == dimensions_to_set}") Report.result(Tests.component_updated, box_shape_dimensions == dimensions_to_set)
# Remove the component # Remove the component
child_entity.remove_component("Box Shape") child_entity.remove_component("Box Shape")
component_rem_success = self.wait_for_condition(lambda: not hydra.has_components(child_entity.id, ["Box Shape"]), component_rem_success = await pyside_utils.wait_for_condition(lambda: not hydra.has_components(child_entity.id,
5.0) ["Box Shape"]), 5.0)
self.test_success = self.test_success and component_rem_success Report.result(Tests.component_removed, component_rem_success)
self.log(f"Remove component: {component_rem_success}")
# 4) Save the level # 4) Save the level
save_level_action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save") save_level_action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save")
@ -143,12 +157,15 @@ class TestBasicEditorWorkflows(EditorTestHelper):
export_action = pyside_utils.get_action_for_menu_path(editor_window, "Game", "Export to Engine") export_action = pyside_utils.get_action_for_menu_path(editor_window, "Game", "Export to Engine")
pyside_utils.trigger_action_async(export_action) pyside_utils.trigger_action_async(export_action)
level_pak_file = os.path.join( level_pak_file = os.path.join(
"AutomatedTesting", "Levels", self.args["level"], "level.pak" "AutomatedTesting", "Levels", level, "level.pak"
) )
export_success = self.wait_for_condition(lambda: os.path.exists(level_pak_file), 5.0) export_success = await pyside_utils.wait_for_condition(lambda: os.path.exists(level_pak_file), 5.0)
self.test_success = self.test_success and export_success Report.result(Tests.level_saved_and_exported, export_success)
self.log(f"Save and Export: {export_success}")
run_test()
if __name__ == "__main__":
test = TestBasicEditorWorkflows() from editor_python_test_tools.utils import Report
test.run() Report.start_test(BasicEditorWorkflows_LevelEntityComponentCRUD)

@ -5,37 +5,39 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C16929880: Add Delete Components
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general class Tests:
import azlmbr.bus as bus entity_created = (
import azlmbr.editor as editor "Entity created successfully",
import azlmbr.entity as entity "Failed to create entity"
import azlmbr.math as math )
import azlmbr.paths box_component_added = (
"Box Shape component added to entity",
"Failed to add Box Shape component to entity"
)
mesh_component_added = (
"Mesh component added to entity",
"Failed to add Mesh component to entity"
)
mesh_component_deleted = (
"Mesh component removed from entity",
"Failed to remove Mesh component from entity"
)
mesh_component_delete_undo = (
"Mesh component removal was successfully undone",
"Failed to undo Mesh component removal"
)
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
def ComponentCRUD_Add_Delete_Components():
class AddDeleteComponentsTest(EditorTestHelper): import editor_python_test_tools.pyside_utils as pyside_utils
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="ComponentCRUD_Add_Delete_Components", args=["level"])
@pyside_utils.wrap_async @pyside_utils.wrap_async
async def run_test(self): async def run_test():
""" """
Summary: Summary:
Add/Delete Components to an entity. Add/Delete Components to/from an entity.
Expected Behavior: Expected Behavior:
1) Components can be added to an entity. 1) Components can be added to an entity.
@ -61,36 +63,43 @@ class AddDeleteComponentsTest(EditorTestHelper):
:return: None :return: None
""" """
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
async def add_component(component_name): async def add_component(component_name):
pyside_utils.click_button_async(add_comp_btn) pyside_utils.click_button_async(add_comp_btn)
popup = await pyside_utils.wait_for_popup_widget() popup = await pyside_utils.wait_for_popup_widget()
tree = popup.findChild(QtWidgets.QTreeView, "Tree") tree = popup.findChild(QtWidgets.QTreeView, "Tree")
component_index = pyside_utils.find_child_by_pattern(tree, component_name) component_index = pyside_utils.find_child_by_pattern(tree, component_name)
if component_index.isValid(): if component_index.isValid():
print(f"{component_name} found") Report.info(f"{component_name} found")
tree.expand(component_index) tree.expand(component_index)
tree.setCurrentIndex(component_index) tree.setCurrentIndex(component_index)
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier) QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
# 1) Open level # 1) Open an existing simple level
self.test_success = self.create_level( helper.init_idle()
self.args["level"], helper.open_level("Physics", "Base")
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 2) Create entity # 2) Create entity
entity_position = math.Vector3(125.0, 136.0, 32.0) entity_position = math.Vector3(125.0, 136.0, 32.0)
entity_id = editor.ToolsApplicationRequestBus( entity_id = editor.ToolsApplicationRequestBus(
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId() bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
) )
if entity_id.IsValid(): Report.critical_result(Tests.entity_created, entity_id.IsValid())
print("Entity Created")
# 3) Select the newly created entity # 3) Select the newly created entity
general.select_object("Entity2") general.select_object("Entity1")
# Give the Entity Inspector time to fully create its contents # Give the Entity Inspector time to fully create its contents
general.idle_wait(0.5) general.idle_wait(0.5)
@ -100,11 +109,11 @@ class AddDeleteComponentsTest(EditorTestHelper):
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector") entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
add_comp_btn = entity_inspector.findChild(QtWidgets.QPushButton, "m_addComponentButton") add_comp_btn = entity_inspector.findChild(QtWidgets.QPushButton, "m_addComponentButton")
await add_component("Box Shape") await add_component("Box Shape")
print(f"Box Shape Component added: {hydra.has_components(entity_id, ['Box Shape'])}") Report.result(Tests.box_component_added, hydra.has_components(entity_id, ['Box Shape']))
# 5) Add/verify Mesh component # 5) Add/verify Mesh component
await add_component("Mesh") await add_component("Mesh")
print(f"Mesh Component added: {hydra.has_components(entity_id, ['Mesh'])}") Report.result(Tests.mesh_component_added, hydra.has_components(entity_id, ['Mesh']))
# 6) Delete Mesh Component # 6) Delete Mesh Component
general.idle_wait(0.5) general.idle_wait(0.5)
@ -116,15 +125,17 @@ class AddDeleteComponentsTest(EditorTestHelper):
QtTest.QTest.mouseClick(mesh_frame, Qt.LeftButton, Qt.NoModifier) QtTest.QTest.mouseClick(mesh_frame, Qt.LeftButton, Qt.NoModifier)
QtTest.QTest.keyClick(mesh_frame, Qt.Key_Delete, Qt.NoModifier) QtTest.QTest.keyClick(mesh_frame, Qt.Key_Delete, Qt.NoModifier)
success = await pyside_utils.wait_for_condition(lambda: not hydra.has_components(entity_id, ['Mesh']), 5.0) success = await pyside_utils.wait_for_condition(lambda: not hydra.has_components(entity_id, ['Mesh']), 5.0)
if success: Report.result(Tests.mesh_component_deleted, success)
print(f"Mesh Component deleted: {not hydra.has_components(entity_id, ['Mesh'])}")
# 7) Undo deletion of component # 7) Undo deletion of component
QtTest.QTest.keyPress(entity_inspector, Qt.Key_Z, Qt.ControlModifier) QtTest.QTest.keyPress(entity_inspector, Qt.Key_Z, Qt.ControlModifier)
success = await pyside_utils.wait_for_condition(lambda: hydra.has_components(entity_id, ['Mesh']), 5.0) success = await pyside_utils.wait_for_condition(lambda: hydra.has_components(entity_id, ['Mesh']), 5.0)
if success: Report.result(Tests.mesh_component_delete_undo, success)
print(f"Mesh Component deletion undone: {hydra.has_components(entity_id, ['Mesh'])}")
run_test()
if __name__ == "__main__":
test = AddDeleteComponentsTest() from editor_python_test_tools.utils import Report
test.run() Report.start_test(ComponentCRUD_Add_Delete_Components)

@ -7,27 +7,32 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
C6376081: Basic Function: Docked/Undocked Tools C6376081: Basic Function: Docked/Undocked Tools
""" """
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general class Tests:
import azlmbr.bus as bus all_tools_docked = (
import azlmbr.editor as editor "The tools are all docked together in a tabbed widget",
import azlmbr.entity as entity "Failed to dock all tools together"
import azlmbr.paths )
docked_outliner_works = (
"Entity Outliner works when docked, can select an Entity",
"Failed to select an Entity in the Outliner while docked"
)
docked_inspector_works = (
"Entity Inspector works when docked, Entity name changed",
"Failed to change Entity name in the Inspector while docked"
)
docked_console_works = (
"Console works when docked, sent a Console Command",
"Failed to send Console Command in the Console while docked"
)
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
def Docking_BasicDockedTools():
class TestDockingBasicDockedTools(EditorTestHelper): import editor_python_test_tools.pyside_utils as pyside_utils
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Docking_BasicDockedTools", args=["level"])
@pyside_utils.wrap_async @pyside_utils.wrap_async
async def run_test(self): async def run_test():
""" """
Summary: Summary:
Test that tools still work as expected when docked together. Test that tools still work as expected when docked together.
@ -50,14 +55,19 @@ class TestDockingBasicDockedTools(EditorTestHelper):
:return: None :return: None
""" """
# Create a level since we are going to be dealing with an Entity. from PySide2 import QtWidgets, QtTest, QtCore
self.create_level(
self.args["level"], import azlmbr.legacy.general as general
heightmap_resolution=1024, import azlmbr.bus as bus
heightmap_meters_per_pixel=1, import azlmbr.editor as editor
terrain_texture_resolution=4096, import azlmbr.entity as entity
use_terrain=False,
) from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# Make sure the Entity Outliner, Entity Inspector and Console tools are open # Make sure the Entity Outliner, Entity Inspector and Console tools are open
general.open_pane("Entity Outliner (PREVIEW)") general.open_pane("Entity Outliner (PREVIEW)")
@ -101,12 +111,14 @@ class TestDockingBasicDockedTools(EditorTestHelper):
entity_inspector_parent = entity_inspector.parentWidget() entity_inspector_parent = entity_inspector.parentWidget()
entity_outliner_parent = entity_outliner.parentWidget() entity_outliner_parent = entity_outliner.parentWidget()
console_parent = console.parentWidget() console_parent = console.parentWidget()
print(f"Entity Inspector parent = {entity_inspector_parent}, Entity Outliner parent = {entity_outliner_parent}, Console parent = {console_parent}") Report.info(f"Entity Inspector parent = {entity_inspector_parent}, Entity Outliner parent = "
return isinstance(entity_inspector_parent, QtWidgets.QStackedWidget) and (entity_inspector_parent == entity_outliner_parent) and (entity_outliner_parent == console_parent) f"{entity_outliner_parent}, Console parent = {console_parent}")
return isinstance(entity_inspector_parent, QtWidgets.QStackedWidget) and \
(entity_inspector_parent == entity_outliner_parent) and \
(entity_outliner_parent == console_parent)
success = await pyside_utils.wait_for(check_all_panes_tabbed, timeout=3.0) success = await pyside_utils.wait_for(check_all_panes_tabbed, timeout=3.0)
if success: Report.result(Tests.all_tools_docked, success)
print("The tools are all docked together in a tabbed widget")
# 2.1,2) Select an Entity in the Entity Outliner. # 2.1,2) Select an Entity in the Entity Outliner.
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector") entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
@ -116,8 +128,7 @@ class TestDockingBasicDockedTools(EditorTestHelper):
test_entity_index = pyside_utils.find_child_by_pattern(object_tree, entity_original_name) test_entity_index = pyside_utils.find_child_by_pattern(object_tree, entity_original_name)
object_tree.clearSelection() object_tree.clearSelection()
object_tree.setCurrentIndex(test_entity_index) object_tree.setCurrentIndex(test_entity_index)
if object_tree.currentIndex(): Report.result(Tests.docked_outliner_works, object_tree.currentIndex() == test_entity_index)
print("Entity Outliner works when docked, can select an Entity")
# 2.3,4) Change the name of the selected Entity via the Entity Inspector. # 2.3,4) Change the name of the selected Entity via the Entity Inspector.
entity_inspector_name_field = entity_inspector.findChild(QtWidgets.QLineEdit, "m_entityNameEditor") entity_inspector_name_field = entity_inspector.findChild(QtWidgets.QLineEdit, "m_entityNameEditor")
@ -125,14 +136,23 @@ class TestDockingBasicDockedTools(EditorTestHelper):
entity_inspector_name_field.setText(expected_new_name) entity_inspector_name_field.setText(expected_new_name)
QtTest.QTest.keyClick(entity_inspector_name_field, QtCore.Qt.Key_Enter) QtTest.QTest.keyClick(entity_inspector_name_field, QtCore.Qt.Key_Enter)
entity_new_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id) entity_new_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
if entity_new_name == expected_new_name: Report.result(Tests.docked_inspector_works, entity_new_name == expected_new_name)
print(f"Entity Inspector works when docked, Entity name changed to {entity_new_name}")
# 2.5,6) Send a console command. # 2.5,6) Send a console command.
console_line_edit = console.findChild(QtWidgets.QLineEdit, "lineEdit") console_line_edit = console.findChild(QtWidgets.QLineEdit, "lineEdit")
console_line_edit.setText("Hello, world!") console_line_edit.setText("t_Scale 2")
QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter)
general.get_cvar("t_Scale")
Report.result(Tests.docked_console_works, general.get_cvar("t_Scale") == "2")
# Reset the altered cvar
console_line_edit.setText("t_Scale 1")
QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter) QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter)
run_test()
if __name__ == "__main__":
test = TestDockingBasicDockedTools() from editor_python_test_tools.utils import Report
test.run() Report.start_test(Docking_BasicDockedTools)

@ -5,32 +5,36 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C1506881: Adding/Removing Event Groups
"""
import os class Tests:
import sys asset_editor_opened = (
from PySide2 import QtWidgets "Successfully opened the Asset Editor",
"Failed to open the Asset Editor"
)
event_groups_added = (
"Successfully added event groups via +",
"Failed to add event groups"
)
single_event_group_deleted = (
"Successfully deleted an event group",
"Failed to delete event group"
)
all_event_groups_deleted = (
"Successfully deleted all event groups",
"Failed to delete all event groups"
)
asset_editor_closed = (
"Successfully closed the Asset Editor",
"Failed to close the Asset Editor"
)
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
class AddRemoveInputEventsTest(EditorTestHelper): def InputBindings_Add_Remove_Input_Events():
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="InputBindings_Add_Remove_Input_Events", args=["level"]) import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async @pyside_utils.wrap_async
async def run_test(self): async def run_test():
""" """
Summary: Summary:
Verify if we are able add/remove input events in inputbindings file. Verify if we are able add/remove input events in inputbindings file.
@ -42,7 +46,7 @@ class AddRemoveInputEventsTest(EditorTestHelper):
Test Steps: Test Steps:
1) Open a new level 1) Open an existing level
2) Open Asset Editor 2) Open Asset Editor
3) Access Asset Editor 3) Access Asset Editor
4) Create a new .inputbindings file and add event groups 4) Create a new .inputbindings file and add event groups
@ -61,6 +65,13 @@ class AddRemoveInputEventsTest(EditorTestHelper):
:return: None :return: None
""" """
from PySide2 import QtWidgets
import azlmbr.legacy.general as general
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
def open_asset_editor(): def open_asset_editor():
general.open_pane("Asset Editor") general.open_pane("Asset Editor")
return general.is_pane_visible("Asset Editor") return general.is_pane_visible("Asset Editor")
@ -69,17 +80,12 @@ class AddRemoveInputEventsTest(EditorTestHelper):
general.close_pane("Asset Editor") general.close_pane("Asset Editor")
return not general.is_pane_visible("Asset Editor") return not general.is_pane_visible("Asset Editor")
# 1) Open a new level # 1) Open an existing simple level
self.test_success = self.create_level( helper.init_idle()
self.args["level"], helper.open_level("Physics", "Base")
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 2) Open Asset Editor # 2) Open Asset Editor
print(f"Asset Editor opened: {open_asset_editor()}") Report.result(Tests.asset_editor_opened, open_asset_editor())
# 3) Access Asset Editor # 3) Access Asset Editor
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
@ -103,8 +109,7 @@ class AddRemoveInputEventsTest(EditorTestHelper):
# 5) Verify if there are 3 elements in the Input Event Groups label # 5) Verify if there are 3 elements in the Input Event Groups label
no_of_elements_label = input_event_groups.findChild(QtWidgets.QLabel, "DefaultLabel") no_of_elements_label = input_event_groups.findChild(QtWidgets.QLabel, "DefaultLabel")
success = await pyside_utils.wait_for_condition(lambda: "3 elements" in no_of_elements_label.text(), 2.0) success = await pyside_utils.wait_for_condition(lambda: "3 elements" in no_of_elements_label.text(), 2.0)
if success: Report.result(Tests.event_groups_added, success)
print("New Event Groups added when + is clicked")
# 6) Delete one event group # 6) Delete one event group
event = asset_editor_widget.findChildren(QtWidgets.QFrame, "<Unspecified Event>")[0] event = asset_editor_widget.findChildren(QtWidgets.QFrame, "<Unspecified Event>")[0]
@ -121,11 +126,11 @@ class AddRemoveInputEventsTest(EditorTestHelper):
input_event_group = input_event_groups[1] input_event_group = input_event_groups[1]
no_of_elements_label = input_event_group.findChild(QtWidgets.QLabel, "DefaultLabel") no_of_elements_label = input_event_group.findChild(QtWidgets.QLabel, "DefaultLabel")
return no_of_elements_label.text() return no_of_elements_label.text()
return ""
return ""; success = await pyside_utils.wait_for_condition(lambda: "2 elements" in
success = await pyside_utils.wait_for_condition(lambda: "2 elements" in get_elements_label_text(asset_editor_widget), 2.0) get_elements_label_text(asset_editor_widget), 2.0)
if success: Report.result(Tests.single_event_group_deleted, success)
print("Event Group deleted when the Delete button is clicked on an Event Group")
# 8) Click on Delete button to delete all the Event Groups # 8) Click on Delete button to delete all the Event Groups
# First QToolButton child of active input_event_groups is +, Second QToolButton is Delete # First QToolButton child of active input_event_groups is +, Second QToolButton is Delete
@ -141,13 +146,17 @@ class AddRemoveInputEventsTest(EditorTestHelper):
yes_button.click() yes_button.click()
# 9) Verify if all the elements are deleted # 9) Verify if all the elements are deleted
success = await pyside_utils.wait_for_condition(lambda: "0 elements" in get_elements_label_text(asset_editor_widget), 2.0) success = await pyside_utils.wait_for_condition(lambda: "0 elements" in
if success: get_elements_label_text(asset_editor_widget), 2.0)
print("All event groups deleted on clicking the Delete button") Report.result(Tests.all_event_groups_deleted, success)
# 10) Close Asset Editor # 10) Close Asset Editor
print(f"Asset Editor closed: {close_asset_editor()}") Report.result(Tests.asset_editor_closed, close_asset_editor())
run_test()
if __name__ == "__main__":
test = AddRemoveInputEventsTest() from editor_python_test_tools.utils import Report
test.run() Report.start_test(InputBindings_Add_Remove_Input_Events)

@ -5,25 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C24064529: Base Edit Menu Options
"""
import os
import sys
import azlmbr.paths def Menus_EditMenuOptions_Work():
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
class TestEditMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Menus_EditMenuOptions", args=["level"])
def run_test(self):
""" """
Summary: Summary:
Interact with Edit Menu options and verify if all the options are working. Interact with Edit Menu options and verify if all the options are working.
@ -32,7 +15,7 @@ class TestEditMenuOptions(EditorTestHelper):
The Edit menu functions normally. The Edit menu functions normally.
Test Steps: Test Steps:
1) Create a temp level 1) Open an existing level
2) Interact with Edit Menu options 2) Interact with Edit Menu options
Note: Note:
@ -42,6 +25,11 @@ class TestEditMenuOptions(EditorTestHelper):
:return: None :return: None
""" """
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
edit_menu_options = [ edit_menu_options = [
("Undo",), ("Undo",),
("Redo",), ("Redo",),
@ -67,31 +55,28 @@ class TestEditMenuOptions(EditorTestHelper):
("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"), ("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"),
] ]
# 1) Create and open the temp level # 1) Open an existing simple level
self.test_success = self.create_level( helper.init_idle()
self.args["level"], helper.open_level("Physics", "Base")
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with Edit Menu options # 2) Interact with Edit Menu options
try:
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
for option in edit_menu_options: for option in edit_menu_options:
try:
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", *option) action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger() action.trigger()
action.triggered.disconnect(trig_func) action_triggered = True
except Exception as e: except Exception as e:
self.test_success = False action_triggered = False
print(e) print(e)
menu_action_triggered = (
f"{action.iconText()} action triggered successfully",
f"Failed to trigger {action.iconText()} action"
)
Report.result(menu_action_triggered, action_triggered)
if __name__ == "__main__":
test = TestEditMenuOptions() from editor_python_test_tools.utils import Report
test.run() Report.start_test(Menus_EditMenuOptions_Work)

@ -5,21 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
import os
import sys
import azlmbr.paths def Menus_FileMenuOptions_Work():
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
class TestFileMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="file_menu_options: ", args=["level"])
def run_test(self):
""" """
Summary: Summary:
Interact with File Menu options and verify if all the options are working. Interact with File Menu options and verify if all the options are working.
@ -38,6 +25,11 @@ class TestFileMenuOptions(EditorTestHelper):
:return: None :return: None
""" """
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
file_menu_options = [ file_menu_options = [
("New Level",), ("New Level",),
("Open Level",), ("Open Level",),
@ -54,31 +46,28 @@ class TestFileMenuOptions(EditorTestHelper):
("Exit",), ("Exit",),
] ]
# 1) Open level # 1) Open an existing simple level
self.test_success = self.create_level( helper.init_idle()
self.args["level"], helper.open_level("Physics", "Base")
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with File Menu options # 2) Interact with File Menu options
try:
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
for option in file_menu_options: for option in file_menu_options:
try:
action = pyside_utils.get_action_for_menu_path(editor_window, "File", *option) action = pyside_utils.get_action_for_menu_path(editor_window, "File", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger() action.trigger()
action.triggered.disconnect(trig_func) action_triggered = True
except Exception as e: except Exception as e:
self.test_success = False action_triggered = False
print(e) print(e)
menu_action_triggered = (
f"{action.iconText()} action triggered successfully",
f"Failed to trigger {action.iconText()} action"
)
Report.result(menu_action_triggered, action_triggered)
if __name__ == "__main__":
test = TestFileMenuOptions() from editor_python_test_tools.utils import Report
test.run() Report.start_test(Menus_FileMenuOptions_Work)

@ -5,25 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT SPDX-License-Identifier: Apache-2.0 OR MIT
""" """
"""
C24064534: The View menu options function normally
"""
import os
import sys
import azlmbr.paths def Menus_ViewMenuOptions_Work():
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
class TestViewMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Menus_EditMenuOptions", args=["level"])
def run_test(self):
""" """
Summary: Summary:
Interact with View Menu options and verify if all the options are working. Interact with View Menu options and verify if all the options are working.
@ -32,7 +15,7 @@ class TestViewMenuOptions(EditorTestHelper):
The View menu functions normally. The View menu functions normally.
Test Steps: Test Steps:
1) Create a temp level 1) Open an existing level
2) Interact with View Menu options 2) Interact with View Menu options
Note: Note:
@ -42,6 +25,11 @@ class TestViewMenuOptions(EditorTestHelper):
:return: None :return: None
""" """
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
view_menu_options = [ view_menu_options = [
("Center on Selection",), ("Center on Selection",),
("Show Quick Access Bar",), ("Show Quick Access Bar",),
@ -55,31 +43,28 @@ class TestViewMenuOptions(EditorTestHelper):
("Refresh Style",), ("Refresh Style",),
] ]
# 1) Create and open the temp level # 1) Open an existing simple level
self.test_success = self.create_level( helper.init_idle()
self.args["level"], helper.open_level("Physics", "Base")
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with View Menu options # 2) Interact with View Menu options
try:
editor_window = pyside_utils.get_editor_main_window() editor_window = pyside_utils.get_editor_main_window()
for option in view_menu_options: for option in view_menu_options:
try:
action = pyside_utils.get_action_for_menu_path(editor_window, "View", *option) action = pyside_utils.get_action_for_menu_path(editor_window, "View", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger() action.trigger()
action.triggered.disconnect(trig_func) action_triggered = True
except Exception as e: except Exception as e:
self.test_success = False action_triggered = False
print(e) print(e)
menu_action_triggered = (
f"{action.iconText()} action triggered successfully",
f"Failed to trigger {action.iconText()} action"
)
Report.result(menu_action_triggered, action_triggered)
if __name__ == "__main__":
test = TestViewMenuOptions() from editor_python_test_tools.utils import Report
test.run() Report.start_test(Menus_ViewMenuOptions_Work)

@ -0,0 +1,43 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
import sys
import ly_test_tools.environment.file_system as file_system
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.fixture
def remove_test_level(request, workspace, project):
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
request.addfinalizer(teardown)
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, workspace, editor, launcher_platform,
remove_test_level):
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False)
@pytest.mark.REQUIRES_gpu
def test_BasicEditorWorkflows_GPU_LevelEntityComponentCRUD(self, request, workspace, editor, launcher_platform,
remove_test_level):
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False,
use_null_renderer=False)

@ -0,0 +1,75 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
import ly_test_tools.environment.file_system as file_system
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationNoAutoTestMode(EditorTestSuite):
# Disable -autotest_mode and -BatchMode. Tests cannot run in -BatchMode due to UI interactions, and these tests
# interact with modal dialogs
global_extra_cmdline_args = []
class test_BasicEditorWorkflows_LevelEntityComponentCRUD(EditorSingleTest):
# Custom teardown to remove slice asset created during test
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
True, True)
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
@pytest.mark.REQUIRES_gpu
class test_BasicEditorWorkflows_GPU_LevelEntityComponentCRUD(EditorSingleTest):
# Disable null renderer
use_null_renderer = False
# Custom teardown to remove slice asset created during test
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
True, True)
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
class test_InputBindings_Add_Remove_Input_Events(EditorSharedTest):
from .EditorScripts import InputBindings_Add_Remove_Input_Events as test_module
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
class test_AssetPicker_UI_UX(EditorSharedTest):
from .EditorScripts import AssetPicker_UI_UX as test_module
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationAutoTestMode(EditorTestSuite):
# Enable only -autotest_mode for these tests. Tests cannot run in -BatchMode due to UI interactions
global_extra_cmdline_args = ["-autotest_mode"]
class test_AssetBrowser_TreeNavigation(EditorSharedTest):
from .EditorScripts import AssetBrowser_TreeNavigation as test_module
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
class test_AssetBrowser_SearchFiltering(EditorSharedTest):
from .EditorScripts import AssetBrowser_SearchFiltering as test_module
class test_ComponentCRUD_Add_Delete_Components(EditorSharedTest):
from .EditorScripts import ComponentCRUD_Add_Delete_Components as test_module
class test_Menus_ViewMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_ViewMenuOptions as test_module
@pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208")
class test_Menus_FileMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_FileMenuOptions as test_module

@ -0,0 +1,62 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
import sys
import ly_test_tools.environment.file_system as file_system
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.fixture
def remove_test_level(request, workspace, project):
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
request.addfinalizer(teardown)
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_AssetBrowser_TreeNavigation(self, request, workspace, editor, launcher_platform):
from .EditorScripts import AssetBrowser_TreeNavigation as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
def test_AssetBrowser_SearchFiltering(self, request, workspace, editor, launcher_platform):
from .EditorScripts import AssetBrowser_SearchFiltering as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
def test_AssetPicker_UI_UX(self, request, workspace, editor, launcher_platform):
from .EditorScripts import AssetPicker_UI_UX as test_module
self._run_test(request, workspace, editor, test_module, autotest_mode=False, batch_mode=False)
def test_ComponentCRUD_Add_Delete_Components(self, request, workspace, editor, launcher_platform):
from .EditorScripts import ComponentCRUD_Add_Delete_Components as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
def test_InputBindings_Add_Remove_Input_Events(self, request, workspace, editor, launcher_platform):
from .EditorScripts import InputBindings_Add_Remove_Input_Events as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False)
def test_Menus_ViewMenuOptions_Work(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Menus_ViewMenuOptions as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208")
def test_Menus_FileMenuOptions_Work(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Menus_FileMenuOptions as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)

@ -0,0 +1,27 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_Menus_EditMenuOptions_Work(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Menus_EditMenuOptions as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
def test_Docking_BasicDockedTools(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Docking_BasicDockedTools as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)

@ -0,0 +1,27 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationAutoTestMode(EditorTestSuite):
# Enable only -autotest_mode for these tests. Tests cannot run in -BatchMode due to UI interactions
global_extra_cmdline_args = ["-autotest_mode"]
class test_Docking_BasicDockedTools(EditorSharedTest):
from .EditorScripts import Docking_BasicDockedTools as test_module
class test_Menus_EditMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_EditMenuOptions as test_module

@ -1,89 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13660195: Asset Browser - File Tree Navigation
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAssetBrowser(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13660195")
@pytest.mark.SUITE_periodic
def test_AssetBrowser_TreeNavigation(self, request, editor, level, launcher_platform):
expected_lines = [
"Collapse/Expand tests: True",
"Asset visibility test: True",
"Scrollbar visibility test: True",
"AssetBrowser_TreeNavigation: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetBrowser_TreeNavigation.py",
expected_lines,
run_python="--runpython",
cfg_args=[level],
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C13660194")
@pytest.mark.SUITE_periodic
def test_AssetBrowser_SearchFiltering(self, request, editor, level, launcher_platform):
expected_lines = [
"cedar.fbx asset is filtered in Asset Browser",
"Animation file type(s) is present in the file tree: True",
"FileTag file type(s) and Animation file type(s) is present in the file tree: True",
"FileTag file type(s) is present in the file tree after removing Animation filter: True",
]
unexpected_lines = [
"Asset Browser opened: False",
"Animation file type(s) is present in the file tree: False",
"FileTag file type(s) and Animation file type(s) is present in the file tree: False",
"FileTag file type(s) is present in the file tree after removing Animation filter: False",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetBrowser_SearchFiltering.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],
auto_test_mode=False,
run_python="--runpython",
timeout=log_monitor_timeout,
)

@ -1,74 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13751579: Asset Picker UI/UX
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 90
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAssetPicker(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13751579", "C1508814")
@pytest.mark.SUITE_periodic
@pytest.mark.xfail # ATOM-15493
def test_AssetPicker_UI_UX(self, request, editor, level, launcher_platform):
expected_lines = [
"TestEntity Entity successfully created",
"Mesh component was added to entity",
"Entity has a Mesh component",
"Mesh Asset: Asset Picker title for Mesh: Pick ModelAsset",
"Mesh Asset: Scroll Bar is not visible before expanding the tree: True",
"Mesh Asset: Top level folder initially collapsed: True",
"Mesh Asset: Top level folder expanded: True",
"Mesh Asset: Nested folder initially collapsed: True",
"Mesh Asset: Nested folder expanded: True",
"Mesh Asset: Scroll Bar appeared after expanding tree: True",
"Mesh Asset: Nested folder collapsed: True",
"Mesh Asset: Top level folder collapsed: True",
"Mesh Asset: Expected Assets populated in the file picker: True",
"Widget Move Test: True",
"Widget Resize Test: True",
"Asset assigned for ok option: True",
"Asset assigned for enter option: True",
"AssetPicker_UI_UX: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetPicker_UI_UX.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=False,
timeout=log_monitor_timeout,
)

@ -1,96 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestBasicEditorWorkflows(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C6351273", "C6384955", "C16929880", "C15167490", "C15167491")
@pytest.mark.SUITE_main
def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
expected_lines = [
"Create and load new level: True",
"New entity creation: True",
"Create entity hierarchy: True",
"Add component: True",
"Component update: True",
"Remove component: True",
"Save and Export: True",
"BasicEditorWorkflows_LevelEntityComponent: result=SUCCESS",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"BasicEditorWorkflows_LevelEntityComponentCRUD.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
auto_test_mode=False
)
@pytest.mark.test_case_id("C6351273", "C6384955", "C16929880", "C15167490", "C15167491")
@pytest.mark.SUITE_main
@pytest.mark.REQUIRES_gpu
def test_BasicEditorWorkflows_GPU_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
expected_lines = [
"Create and load new level: True",
"New entity creation: True",
"Create entity hierarchy: True",
"Add component: True",
"Component update: True",
"Remove component: True",
"Save and Export: True",
"BasicEditorWorkflows_LevelEntityComponent: result=SUCCESS",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"BasicEditorWorkflows_LevelEntityComponentCRUD.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
auto_test_mode=False,
null_renderer=False
)

@ -1,62 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C16929880: Add Delete Components
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestComponentCRUD(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C16929880", "C16877220")
@pytest.mark.SUITE_periodic
@pytest.mark.BAT
def test_ComponentCRUD_Add_Delete_Components(self, request, editor, level, launcher_platform):
expected_lines = [
"Entity Created",
"Box Shape found",
"Box Shape Component added: True",
"Mesh found",
"Mesh Component added: True",
"Mesh Component deleted: True",
"Mesh Component deletion undone: True",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"ComponentCRUD_Add_Delete_Components.py",
expected_lines,
cfg_args=[level],
auto_test_mode=False,
timeout=log_monitor_timeout
)

@ -1,55 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
C6376081: Basic Function: Docked/Undocked Tools
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestDocking(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C6376081")
@pytest.mark.SUITE_sandbox
def test_Docking_BasicDockedTools(self, request, editor, level, launcher_platform):
expected_lines = [
"The tools are all docked together in a tabbed widget",
"Entity Outliner works when docked, can select an Entity",
"Entity Inspector works when docked, Entity name changed to DifferentName",
"Hello, world!" # This line verifies the Console is working while docked
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Docking_BasicDockedTools.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
)

@ -1,66 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C1506881: Adding/Removing Event Groups
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestInputBindings(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C1506881")
@pytest.mark.SUITE_periodic
def test_InputBindings_Add_Remove_Input_Events(self, request, editor, level, launcher_platform):
expected_lines = [
"Asset Editor opened: True",
"New Event Groups added when + is clicked",
"Event Group deleted when the Delete button is clicked on an Event Group",
"All event groups deleted on clicking the Delete button",
"Asset Editor closed: True",
]
unexpected_lines = [
"Asset Editor opened: False",
"Asset Editor closed: False",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"InputBindings_Add_Remove_Input_Events.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=False,
timeout=log_monitor_timeout,
)

@ -1,132 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools.environment.process_utils as process_utils
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestMenus(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
process_utils.kill_processes_named("o3de", ignore_extensions=True) # Kill ProjectManager windows
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C16780783", "C2174438")
@pytest.mark.SUITE_sandbox
def test_Menus_EditMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"Undo Action triggered",
"Redo Action triggered",
"Duplicate Action triggered",
"Delete Action triggered",
"Select All Action triggered",
"Invert Selection Action triggered",
"Toggle Pivot Location Action triggered",
"Reset Entity Transform",
"Reset Manipulator",
"Reset Transform (Local) Action triggered",
"Reset Transform (World) Action triggered",
"Hide Selection Action triggered",
"Show All Action triggered",
"Snap angle Action triggered",
"Move Action triggered",
"Rotate Action triggered",
"Scale Action triggered",
"Global Preferences Action triggered",
"Editor Settings Manager Action triggered",
"Customize Keyboard Action triggered",
"Export Keyboard Settings Action triggered",
"Import Keyboard Settings Action triggered",
"Menus_EditMenuOptions: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_EditMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C16780807")
@pytest.mark.SUITE_periodic
def test_Menus_ViewMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"Center on Selection Action triggered",
"Show Quick Access Bar Action triggered",
"Configure Layout Action triggered",
"Go to Position Action triggered",
"Center on Selection Action triggered",
"Go to Location Action triggered",
"Remember Location Action triggered",
"Switch Camera Action triggered",
"Show/Hide Helpers Action triggered",
"Refresh Style Action triggered",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_ViewMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C16780778")
@pytest.mark.SUITE_sandbox
@pytest.mark.xfail # LYN-4208
def test_Menus_FileMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"New Level Action triggered",
"Open Level Action triggered",
"Import Action triggered",
"Save Action triggered",
"Save As Action triggered",
"Save Level Statistics Action triggered",
"Edit Project Settings Action triggered",
"Edit Platform Settings Action triggered",
"New Project Action triggered",
"Open Project Action triggered",
"Show Log File Action triggered",
"Resave All Slices Action triggered",
"Exit Action triggered",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_FileMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
timeout=log_monitor_timeout
)

@ -62,8 +62,11 @@ class EditorTestBase(ABC):
# Test that will be run alone in one editor # Test that will be run alone in one editor
class EditorSingleTest(EditorTestBase): class EditorSingleTest(EditorTestBase):
#- Configurable params -#
# Extra cmdline arguments to supply to the editor for the test # Extra cmdline arguments to supply to the editor for the test
extra_cmdline_args = [] extra_cmdline_args = []
# Whether to use null renderer, this will override use_null_renderer for the Suite if not None
use_null_renderer = None
# Custom setup function, will run before the test # Custom setup function, will run before the test
@staticmethod @staticmethod
@ -584,7 +587,7 @@ class EditorTestSuite():
test_spec : EditorTestBase, cmdline_args : List[str] = []): test_spec : EditorTestBase, cmdline_args : List[str] = []):
test_cmdline_args = self.global_extra_cmdline_args + cmdline_args test_cmdline_args = self.global_extra_cmdline_args + cmdline_args
if self.use_null_renderer: if test_spec.use_null_renderer or (test_spec.use_null_renderer is None and self.use_null_renderer):
test_cmdline_args += ["-rhi=null"] test_cmdline_args += ["-rhi=null"]
# Cycle any old crash report in case it wasn't cycled properly # Cycle any old crash report in case it wasn't cycled properly

Loading…
Cancel
Save