Integrating latest 47acbe8
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C17211213: Assign Dynamic Slice
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17211213
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.entity as entity
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as editor_utils
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtTest import QTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class AssignDynamicSlice(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="assign dynamic slice", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Dynamic slice can be assigned to a spawner on an entity
|
||||
|
||||
Expected Behavior:
|
||||
Dynamic slice is present in the file picker, can be added to
|
||||
components, and is visible in game mode when spawned
|
||||
|
||||
Test Steps:
|
||||
0) Open temporary test level
|
||||
1) Create an entity with a spawner component
|
||||
2) Add dynamic slice to the spawner component C17211213_visual_thunderbolt
|
||||
3) Set Spawn on activate to enabled
|
||||
4) Enter game mode
|
||||
5) Verify that the dynamic slice spawned and is visible in game mode
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def set_dynamic_slice_by_asset_path(entity_obj, asset_path):
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', asset_path, math.Uuid(), False)
|
||||
entity_obj.get_set_test(0, "Dynamic slice", asset_id)
|
||||
|
||||
def set_spawn_checkbox_enabled():
|
||||
general.idle_wait(0.5)
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
entity_inspector = editor_window.findChildren(QtWidgets.QDockWidget, "Entity Inspector")[0]
|
||||
spawn_activate_frame = entity_inspector.findChildren(QtWidgets.QFrame, "Spawn on activate")[0]
|
||||
checkbox = spawn_activate_frame.findChildren(QtWidgets.QCheckBox)[0]
|
||||
checkbox.click()
|
||||
|
||||
# 0) Open temporary test level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 1) Create an entity with a spawner component
|
||||
entity_postition = math.Vector3(125.0, 136.0, 32.0)
|
||||
components_to_add = ["Spawner"]
|
||||
|
||||
spawner_entity = editor_utils.Entity("Spawner")
|
||||
spawner_entity.create_entity(entity_postition, components_to_add)
|
||||
|
||||
# 2) Add dynamic slice to the spawner component C17211213_visual_thunderbolt
|
||||
thunderbolt_path = os.path.join("slices", "Test", "C17211213_visual_thunderbolt.dynamicslice")
|
||||
set_dynamic_slice_by_asset_path(spawner_entity, thunderbolt_path)
|
||||
|
||||
# 3) Set Spawn on activate to enabled
|
||||
set_spawn_checkbox_enabled()
|
||||
|
||||
# 4) Enter game mode
|
||||
general.enter_game_mode()
|
||||
general.idle_wait(0.5)
|
||||
|
||||
# 5) Verify that the dynamic slice spawned and is visible in game mode
|
||||
slice_name = "thunderbolt"
|
||||
thunderbolt_id = general.find_game_entity(slice_name)
|
||||
check_valid = thunderbolt_id.IsValid()
|
||||
assert check_valid, f"No entity found for {slice_name}"
|
||||
if check_valid:
|
||||
print(f"Entity found for {slice_name}")
|
||||
|
||||
general.exit_game_mode()
|
||||
|
||||
|
||||
|
||||
test = AssignDynamicSlice()
|
||||
test.run()
|
||||
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C6376081: Basic Function: Docked/Undocked Tools
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6376081
|
||||
"""
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
|
||||
from PySide2 import QtCore, QtWidgets, QtTest
|
||||
|
||||
|
||||
class TestBasicDockedTools(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_docked_tools: ", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Test that tools still work as expected when docked together.
|
||||
|
||||
Expected Behavior:
|
||||
Multiple tools can be docked together.
|
||||
Tools function while docked together and the main editor responds appropriately.
|
||||
|
||||
Test Steps:
|
||||
1) Open the tools and dock them together in a floating tabbed widget.
|
||||
2) Perform actions in the docked tools to verify they still work as expected.
|
||||
2.1) Select the Entity Outliner in the floating window.
|
||||
2.2) Select an Entity in the Entity Outliner.
|
||||
2.3) Select the Entity Inspector in the floating window.
|
||||
2.4) Change the name of the selected Entity via the Entity Inspector.
|
||||
2.5) Select the Console inside the floating window.
|
||||
2.6) Send a console command.
|
||||
2.7) Check the Editor to verify all changes were made.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# Create a level since we are going to be dealing with an Entity.
|
||||
self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# Make sure the Entity Outliner, Entity Inspector and Console tools are open
|
||||
general.open_pane("Entity Outliner (PREVIEW)")
|
||||
general.open_pane("Entity Inspector")
|
||||
general.open_pane("Console")
|
||||
|
||||
# Create an Entity to test with
|
||||
entity_original_name = 'MyTestEntity'
|
||||
entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
|
||||
editor.EditorEntityAPIBus(bus.Event, 'SetName', entity_id, entity_original_name)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
|
||||
# 1) Open the tools and dock them together in a floating tabbed widget.
|
||||
# We drag/drop it over the viewport since it doesn't allow docking, so this will undock it
|
||||
render_overlay = editor_window.findChild(QtWidgets.QWidget, "renderOverlay")
|
||||
pyside_utils.drag_and_drop(entity_outliner, render_overlay)
|
||||
|
||||
# We need to grab a new reference to the Entity Outliner QDockWidget because when it gets moved
|
||||
# to the floating window, its parent changes so the wrapped intance we had becomes invalid
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
|
||||
# Dock the Entity Inspector tabbed with the floating Entity Outliner
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
pyside_utils.drag_and_drop(entity_inspector, entity_outliner)
|
||||
|
||||
# We need to grab a new reference to the Entity Inspector QDockWidget because when it gets moved
|
||||
# to the floating window, its parent changes so the wrapped intance we had becomes invalid
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
|
||||
# Dock the Console tabbed with the floating Entity Inspector
|
||||
console = editor_window.findChild(QtWidgets.QDockWidget, "Console")
|
||||
pyside_utils.drag_and_drop(console, entity_inspector)
|
||||
|
||||
# Check to ensure all the tools are parented to the same QStackedWidget
|
||||
def check_all_panes_tabbed():
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
console = editor_window.findChild(QtWidgets.QDockWidget, "Console")
|
||||
entity_inspector_parent = entity_inspector.parentWidget()
|
||||
entity_outliner_parent = entity_outliner.parentWidget()
|
||||
console_parent = console.parentWidget()
|
||||
print(f"Entity Inspector parent = {entity_inspector_parent}, Entity Outliner parent = {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)
|
||||
if success:
|
||||
print("The tools are all docked together in a tabbed widget")
|
||||
|
||||
# 2.1,2) Select an Entity in the Entity Outliner.
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
console = editor_window.findChild(QtWidgets.QDockWidget, "Console")
|
||||
object_tree = entity_outliner.findChild(QtWidgets.QTreeView, "m_objectTree")
|
||||
test_entity_index = pyside_utils.find_child_by_pattern(object_tree, entity_original_name)
|
||||
object_tree.clearSelection()
|
||||
object_tree.setCurrentIndex(test_entity_index)
|
||||
selected_object_names = general.get_names_of_selected_objects()
|
||||
if len(selected_object_names) == 1 and selected_object_names[0] == entity_original_name:
|
||||
print("Entity Outliner works when docked, can select an Entity")
|
||||
|
||||
# 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")
|
||||
expected_new_name = "DifferentName"
|
||||
entity_inspector_name_field.setText(expected_new_name)
|
||||
QtTest.QTest.keyClick(entity_inspector_name_field, QtCore.Qt.Key_Enter)
|
||||
entity_new_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
|
||||
if 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.
|
||||
console_line_edit = console.findChild(QtWidgets.QLineEdit, "lineEdit")
|
||||
console_line_edit.setText("e_Vegetation=1")
|
||||
QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter)
|
||||
|
||||
|
||||
test = TestBasicDockedTools()
|
||||
test.run()
|
||||
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C24064529: Base Edit Menu Options
|
||||
https://testrail.agscollab.com/index.php?/cases/view/24064529
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestEditMenuOptions(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="edit_menu_options", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Edit Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The Edit menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Create a temp level
|
||||
2) Interact with Edit Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
edit_menu_options = [
|
||||
("Undo",),
|
||||
("Redo",),
|
||||
("Duplicate",),
|
||||
("Delete",),
|
||||
("Select All",),
|
||||
("Invert Selection",),
|
||||
("Hide Selection",),
|
||||
("Show Selection",),
|
||||
("Show Last Hidden",),
|
||||
("Unhide All",),
|
||||
("Modify", "Parent"),
|
||||
("Modify", "Un-Parent"),
|
||||
("Modify", "Align", "Align to grid"),
|
||||
("Modify", "Align", "Align to object"),
|
||||
("Modify", "Align", "Align object to surface"),
|
||||
("Modify", "Constrain", "Constrain to X axis"),
|
||||
("Modify", "Constrain", "Constrain to Y axis"),
|
||||
("Modify", "Constrain", "Constrain to Z axis"),
|
||||
("Modify", "Constrain", "Constrain to XY plane"),
|
||||
("Modify", "Constrain", "Constrain to terrain/geometry"),
|
||||
("Modify", "Snap", "Snap To Grid"),
|
||||
("Modify", "Snap", "Snap angle"),
|
||||
("Modify", "Fast Rotate", "Rotate X Axis"),
|
||||
("Modify", "Fast Rotate", "Rotate Y Axis"),
|
||||
("Modify", "Fast Rotate", "Rotate Z Axis"),
|
||||
("Modify", "Fast Rotate", "Rotate Angle"),
|
||||
("Modify", "Transform Mode", "Select mode"),
|
||||
("Modify", "Transform Mode", "Move"),
|
||||
("Modify", "Transform Mode", "Rotate"),
|
||||
("Modify", "Transform Mode", "Scale"),
|
||||
("Modify", "Transform Mode", "Select terrain"),
|
||||
("Lock selection",),
|
||||
("Unlock all",),
|
||||
("Editor Settings", "Global Preferences"),
|
||||
("Editor Settings", "Graphics Settings"),
|
||||
("Editor Settings", "Editor Settings Manager"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "High"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "High"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "High"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "High"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "Apple TV"),
|
||||
("Editor Settings", "Keyboard Customization", "Customize Keyboard"),
|
||||
("Editor Settings", "Keyboard Customization", "Export Keyboard Settings"),
|
||||
("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"),
|
||||
]
|
||||
|
||||
# 1) Create and open the temp level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 2) Interact with Edit Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
for option in edit_menu_options:
|
||||
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.triggered.disconnect(trig_func)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
test = TestEditMenuOptions()
|
||||
test.run()
|
||||
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C16780783: Base Edit Menu Options (New Viewport Interaction Model)
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16780783
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestEditMenuOptionsNewViewport(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="edit_menu_options: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Edit Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The Edit menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Create a temp level
|
||||
2) Interact with Edit Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
edit_menu_options = [
|
||||
("Undo",),
|
||||
("Redo",),
|
||||
("Duplicate",),
|
||||
("Delete",),
|
||||
("Select All",),
|
||||
("Invert Selection",),
|
||||
("Toggle Pivot Location",),
|
||||
("Reset Entity Transform",),
|
||||
("Reset Manipulator",),
|
||||
("Hide Selection",),
|
||||
("Show All",),
|
||||
("Modify", "Snap", "Snap angle"),
|
||||
("Modify", "Transform Mode", "Move"),
|
||||
("Modify", "Transform Mode", "Rotate"),
|
||||
("Modify", "Transform Mode", "Scale"),
|
||||
("Lock Selection",),
|
||||
("Unlock All Entities",),
|
||||
("Editor Settings", "Global Preferences"),
|
||||
("Editor Settings", "Graphics Settings"),
|
||||
("Editor Settings", "Editor Settings Manager"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "High"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "PC", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "High"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "OSX Metal", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "High"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "Android", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "Very High"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "High"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "Medium"),
|
||||
("Editor Settings", "Graphics Performance", "iOS", "Low"),
|
||||
("Editor Settings", "Graphics Performance", "Apple TV"),
|
||||
("Editor Settings", "Keyboard Customization", "Customize Keyboard"),
|
||||
("Editor Settings", "Keyboard Customization", "Export Keyboard Settings"),
|
||||
("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"),
|
||||
]
|
||||
|
||||
# 1) Create and open the temp level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 2) Interact with Edit Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
for option in edit_menu_options:
|
||||
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.triggered.disconnect(trig_func)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
test = TestEditMenuOptionsNewViewport()
|
||||
test.run()
|
||||
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C24064528: The File menu options function normally
|
||||
https://testrail.agscollab.com/index.php?/cases/view/24064528
|
||||
C16780778: The File menu options function normally-New view interaction Model enabled
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16780778
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestFileMenuOptions(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="file_menu_options: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with File Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The File menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Interact with File Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
file_menu_options = [
|
||||
("New Level",),
|
||||
("Open Level",),
|
||||
("Import",),
|
||||
("Save",),
|
||||
("Save As",),
|
||||
("Save Level Statistics",),
|
||||
("Project Settings", "Switch Projects"),
|
||||
("Project Settings", "Configure Gems"),
|
||||
("Show Log File",),
|
||||
("Resave All Slices",),
|
||||
("Upgrade Legacy Entities",),
|
||||
]
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 2) Interact with File Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
for option in file_menu_options:
|
||||
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.triggered.disconnect(trig_func)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
test = TestFileMenuOptions()
|
||||
test.run()
|
||||
@@ -0,0 +1,168 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C17218881: Basic Function: Locking & Hiding
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17218881
|
||||
"""
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.editor as editor
|
||||
from PySide2 import QtWidgets
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class BasicFunctionLockHideTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_function_lock_hide", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Basic Function: Locking & Hiding
|
||||
|
||||
Expected Behavior:
|
||||
1) Entities can be hidden.
|
||||
2) Hiding a parent entity hides its children.
|
||||
3) Entities can be shown.
|
||||
4) Showing a parent entity shows its children.
|
||||
5) Entities can be locked.
|
||||
6) Locking a parent entity locks its children.
|
||||
7) Locked entities cannot be interacted with in the Viewport.
|
||||
8) Entities can be unlocked.
|
||||
9) Unlocking a parent entity unlocks its children.
|
||||
10)Unlocked entities can be interacted with in the Viewport.
|
||||
11)Entities can be reordered even when locked or hidden.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create an entity and 3 child entity
|
||||
3) Click on show/hide button to hide entities and verify if they are hidden
|
||||
4) Click on show/hide button to show entities and verify if they are hidden
|
||||
5) Click on lock/unlock entities to lock entities and verify if they are locked
|
||||
6) Click on lock/unlock entities to unlock entities and verify if they are unlocked
|
||||
7) Create 2 new entities
|
||||
8) Hide/Lock the newly created entities
|
||||
9) Move the newly created entites under parent entity
|
||||
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def is_hidden(id):
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", id)
|
||||
|
||||
def is_locked(id):
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsLocked", id)
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
outliner_widget = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)").widget()
|
||||
|
||||
# 2) Create an entity and 3 child entity
|
||||
entity_position = math.Vector3(200.0, 200.0, 38.0)
|
||||
component_to_add = ["Mesh"]
|
||||
parent = hydra.Entity("Entity2")
|
||||
parent.create_entity(entity_position, component_to_add)
|
||||
|
||||
child_1 = hydra.Entity("Entity3")
|
||||
child_1.create_entity(entity_position, component_to_add, parent.id)
|
||||
|
||||
child_2 = hydra.Entity("Entity4")
|
||||
child_2.create_entity(entity_position, component_to_add, parent.id)
|
||||
|
||||
child_3 = hydra.Entity("Entity5")
|
||||
child_3.create_entity(entity_position, component_to_add, parent.id)
|
||||
|
||||
# 3) Click on show/hide button to hide entities and verify if they are hidden
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 0).data() == "Entity2")
|
||||
parent_model_index = pyside_utils.find_child_by_pattern(tree, "Entity2")
|
||||
show_hide_parent = parent_model_index.siblingAtColumn(1)
|
||||
pyside_utils.item_view_index_mouse_click(tree, show_hide_parent)
|
||||
self.wait_for_condition(lambda: is_hidden(parent.id))
|
||||
entities_hidden = (
|
||||
is_hidden(parent.id) and is_hidden(child_1.id) and is_hidden(child_2.id) and is_hidden(child_3.id)
|
||||
)
|
||||
print(f"Child entities are hidden when parent entity is hidden: {entities_hidden}")
|
||||
|
||||
# 4) Click on show/hide button to show entities and verify if they are hidden
|
||||
pyside_utils.item_view_index_mouse_click(tree, show_hide_parent)
|
||||
self.wait_for_condition(lambda: not is_hidden(parent.id))
|
||||
entities_hidden = (
|
||||
not is_hidden(parent.id)
|
||||
and not is_hidden(child_1.id)
|
||||
and not is_hidden(child_2.id)
|
||||
and not is_hidden(child_3.id)
|
||||
)
|
||||
print(f"Child entities are shown when parent entity is shown: {entities_hidden}")
|
||||
|
||||
# 5) Click on lock/unlock entities to lock entities and verify if they are locked
|
||||
lock_unlock_parent = parent_model_index.siblingAtColumn(2)
|
||||
pyside_utils.item_view_index_mouse_click(tree, lock_unlock_parent)
|
||||
self.wait_for_condition(lambda: is_locked(parent.id))
|
||||
entities_locked = (
|
||||
is_locked(parent.id) and is_locked(child_1.id) and is_locked(child_2.id) and is_locked(child_3.id)
|
||||
)
|
||||
print(f"Child entities are locked when parent entity is locked: {entities_locked}")
|
||||
|
||||
# 6) Click on lock/unlock entities to unlock entities and verify if they are unlocked
|
||||
pyside_utils.item_view_index_mouse_click(tree, lock_unlock_parent)
|
||||
self.wait_for_condition(lambda: not is_locked(parent.id))
|
||||
entities_unlocked = (
|
||||
not is_locked(parent.id)
|
||||
and not is_locked(child_1.id)
|
||||
and not is_locked(child_2.id)
|
||||
and not is_locked(child_3.id)
|
||||
)
|
||||
print(f"Child entities are unlocked when parent entity is unlocked: {entities_unlocked}")
|
||||
|
||||
# 7) Create 2 new entities
|
||||
new_entity_1 = hydra.Entity("Entity6")
|
||||
new_entity_1.create_entity(entity_position, component_to_add)
|
||||
new_entity_2 = hydra.Entity("Entity7")
|
||||
new_entity_2.create_entity(entity_position, component_to_add)
|
||||
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 0).data() == "Entity6")
|
||||
|
||||
# 8) Hide/Lock the newly created entities
|
||||
new_entity_1_mi = pyside_utils.find_child_by_pattern(tree, "Entity6")
|
||||
show_hide_new_entity = new_entity_1_mi.siblingAtColumn(1)
|
||||
|
||||
new_entity_2_mi = pyside_utils.find_child_by_pattern(tree, "Entity7")
|
||||
lock_unlock_new_entity = new_entity_2_mi.siblingAtColumn(2)
|
||||
|
||||
pyside_utils.item_view_index_mouse_click(tree, show_hide_new_entity)
|
||||
pyside_utils.item_view_index_mouse_click(tree, lock_unlock_new_entity)
|
||||
|
||||
# 9) Move the newly created entites under parent entity
|
||||
new_entity_1.set_test_parent_entity(parent)
|
||||
new_entity_2.set_test_parent_entity(parent)
|
||||
|
||||
|
||||
test = BasicFunctionLockHideTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6321491: Basic Function: Global Preferences
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6321491
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class BasicGlobalPreferencesTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_global_preferences: ")
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify if we can change some value in the Global Preferences in Editor Settings
|
||||
|
||||
Expected Behavior:
|
||||
Global preferences can be changed and saved.
|
||||
|
||||
Test Steps:
|
||||
1) Change Toolbar Icon size in Global Preferences
|
||||
2) Verify if the Toolbar Icon size changed
|
||||
3) Reset the Toolbar Icon Size
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
async def change_tool_button_size(size):
|
||||
action = pyside_utils.get_action_for_menu_path(
|
||||
editor_window, "Edit", "Editor Settings", "Global Preferences"
|
||||
)
|
||||
print(f"Global Preferences action triggered")
|
||||
pyside_utils.trigger_action_async(action)
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
combo_box = await pyside_utils.wait_for_child_by_hierarchy(
|
||||
active_modal_widget,
|
||||
"EditorPreferencesDialog",
|
||||
...,
|
||||
"propertyEditor",
|
||||
...,
|
||||
dict(type=QtWidgets.QFrame, text="Toolbar Icon Size"),
|
||||
...,
|
||||
QtWidgets.QComboBox
|
||||
)
|
||||
combo_box.setCurrentIndex(combo_box.findText(size))
|
||||
button_box = active_modal_widget.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
print(f"Toolbar Icon size set to {size}")
|
||||
await pyside_utils.wait_for_destroyed(active_modal_widget)
|
||||
|
||||
# 1) Change Toolbar Icon size in Global Preferences
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
play_game_button = await pyside_utils.wait_for_child_by_hierarchy(
|
||||
editor_window,
|
||||
...,
|
||||
"EditMode",
|
||||
...,
|
||||
dict(type=QtWidgets.QToolButton, text="Play Game")
|
||||
)
|
||||
|
||||
# First, make sure the toolbar icon size is the Default
|
||||
await change_tool_button_size("Default")
|
||||
initial_size = play_game_button.size()
|
||||
|
||||
await change_tool_button_size("Large")
|
||||
def check_size():
|
||||
current_size = play_game_button.size()
|
||||
return initial_size.height() < current_size.height() and initial_size.width() < current_size.width()
|
||||
|
||||
# 2) Verify if the Toolbar Icon size changed
|
||||
await pyside_utils.wait_for_condition(check_size)
|
||||
print("Toolbar Icon size changed in Global Preferences")
|
||||
|
||||
# 3) Reset the Toolbar Icon Size
|
||||
await change_tool_button_size("Default")
|
||||
|
||||
|
||||
test = BasicGlobalPreferencesTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C6351301: Basic Function: Toolbars
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6351301
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestBasicToolBarFunction(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_toolbar_function: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Enable all menu toolbars and click between options in each of the toolbars and then disable all the toolbars.
|
||||
|
||||
Expected Behavior:
|
||||
All menu toolbars can be enabled and disbled with each toolbar is functional and options can be selected.
|
||||
|
||||
Test Steps:
|
||||
1) Create new level with an Entity
|
||||
2) Enable each of the toolbars in the list.
|
||||
3) Verify options from toolbars can be selected
|
||||
3.1) "Play Game" option from EditMode toolbar
|
||||
3.2) "Go to selected object" option from Object toolbar
|
||||
4) Disable each of the toolbars in the list.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
def fetch_vector3_parts(vec3):
|
||||
x = vec3.get_property("x")
|
||||
y = vec3.get_property("y")
|
||||
z = vec3.get_property("z")
|
||||
return (x, y, z)
|
||||
|
||||
def enable_disable_toolbar(toolbar, enable=True):
|
||||
toolbar = editor_window.findChild(QtWidgets.QToolBar, i)
|
||||
action = toolbar.toggleViewAction()
|
||||
if enable:
|
||||
# Enable the toolbar
|
||||
if not toolbar.isVisible():
|
||||
action.trigger()
|
||||
if toolbar.isVisible():
|
||||
print(f"{i} toolbar is enabled")
|
||||
|
||||
else:
|
||||
# Disable the toolbar
|
||||
if toolbar.isVisible():
|
||||
action.trigger()
|
||||
if not toolbar.isVisible():
|
||||
print(f"{i} toolbar is disbaled")
|
||||
|
||||
menu_toolbar_list = [
|
||||
"EditMode",
|
||||
"Object",
|
||||
"debugViewsToolbar",
|
||||
"environmentModesToolbar",
|
||||
"viewModesToolbar",
|
||||
]
|
||||
|
||||
# 1) Create new level with an Entity
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId.EntityId())
|
||||
|
||||
# 2) Enable each of the toolbars in the list.
|
||||
for i in menu_toolbar_list:
|
||||
enable_disable_toolbar(i)
|
||||
|
||||
# 3) Select options from toolbar
|
||||
# 3.1) "Play Game" option from EditMode toolbar
|
||||
editors_toolbar = editor_window.findChild(QtWidgets.QToolBar, "EditMode")
|
||||
for i in editors_toolbar.children():
|
||||
if isinstance(i, QtWidgets.QToolButton) and i.text() == "Play Game":
|
||||
play_game_button = i
|
||||
break
|
||||
# Click on the tool button to verify ToolBar functionality
|
||||
play_game_button.click()
|
||||
general.idle_wait(1.0)
|
||||
|
||||
if general.is_in_game_mode():
|
||||
print("In game mode: Play game ToolButton is responsive")
|
||||
general.exit_game_mode()
|
||||
|
||||
# 3.2) "Go to selected object" option from Object toolbar
|
||||
position = fetch_vector3_parts(general.get_current_view_position())
|
||||
|
||||
# Click on the tool button to verify ToolBar functionality
|
||||
object_toolbar = editor_window.findChild(QtWidgets.QToolBar, "Object")
|
||||
for i in object_toolbar.children():
|
||||
if isinstance(i, QtWidgets.QToolButton) and i.text() == "Go to selected object":
|
||||
general.select_object(editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entityId))
|
||||
general.idle_wait(1.0)
|
||||
i.click()
|
||||
break
|
||||
general.idle_wait(1.0)
|
||||
new_pos = fetch_vector3_parts(general.get_current_view_position())
|
||||
if new_pos != position:
|
||||
print("Go to selected object option is responsive")
|
||||
|
||||
# 4) Disable each of the toolbars in the list.
|
||||
for i in menu_toolbar_list:
|
||||
enable_disable_toolbar(i, False)
|
||||
|
||||
|
||||
test = TestBasicToolBarFunction()
|
||||
test.run()
|
||||
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6317014: Basic UI Appearance & Function
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6317014
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestBasicUIAppearence(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_ui_appearence_function: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Open Lumberyard editor and check if basic UI components are loaded and responsive.
|
||||
|
||||
Expected Behavior:
|
||||
Elements below of the UI are loaded and responsive.
|
||||
Menus
|
||||
Toolbars
|
||||
Tools
|
||||
Viewport
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Verify if Tools are responsive - Opens some tool by triggering the Tool Menu actions and
|
||||
verifies if the tool has been opened and active.
|
||||
3) Verify if Menu items are responsive - Triggers the MenuBar actions of the Editor window.
|
||||
4) Verify if Viewport is responsive - Simulates right-click on the viewport to create a new Entity.
|
||||
5) Verify if Toolbars are responsive - Uses the "EditMode" toolbar to click on the Play Game
|
||||
ToolButton, and then verifies if the editor is in game mode.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
def on_action_trigger():
|
||||
print("Tools Action triggered")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
# 2) Verify if Tools are responsive
|
||||
tool_action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Script Canvas")
|
||||
tool_action.triggered.connect(on_action_trigger)
|
||||
tool_action.trigger()
|
||||
tool_action.triggered.disconnect(on_action_trigger)
|
||||
# Verify if the tool is opened
|
||||
def is_script_canvas_active_window():
|
||||
tool = editor_window.findChild(QtWidgets.QWidget, "Script Canvas")
|
||||
if tool:
|
||||
return tool.isActiveWindow()
|
||||
|
||||
return False
|
||||
if self.wait_for_condition(is_script_canvas_active_window, 2.0):
|
||||
print("Tool opened")
|
||||
|
||||
# 3) Verify if Menu items are responsive
|
||||
menu_bar = editor_window.menuBar()
|
||||
for action in menu_bar.actions():
|
||||
trig_func = lambda: on_action_triggered(action.iconText())
|
||||
action.triggered.connect(trig_func)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(trig_func)
|
||||
|
||||
# 4) Verify if Viewport is responsive
|
||||
# Clear the current selection and create a new Entity via the viewport right-click menu
|
||||
render_overlay = editor_window.findChild(QtWidgets.QWidget, "renderOverlay")
|
||||
general.clear_selection()
|
||||
pyside_utils.trigger_context_menu_entry(render_overlay.parent(), "Create entity")
|
||||
selected_entities = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
|
||||
if len(selected_entities) == 1:
|
||||
entity_id = selected_entities[0]
|
||||
name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
|
||||
if name == "Entity2":
|
||||
print("Viewport is responsive")
|
||||
|
||||
# 5) Verify if Toolbars are responsive
|
||||
editors_toolbar = editor_window.findChild(QtWidgets.QToolBar, "EditMode")
|
||||
play_game_button = pyside_utils.find_child_by_pattern(editors_toolbar, "Play Game")
|
||||
|
||||
# Click on the tool button to verify ToolBar functionality
|
||||
play_game_button.click()
|
||||
|
||||
if self.wait_for_condition(lambda: general.is_in_game_mode()):
|
||||
print("In game mode: Play game ToolButton is responsive")
|
||||
general.exit_game_mode()
|
||||
|
||||
|
||||
test = TestBasicUIAppearence()
|
||||
test.run()
|
||||
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6317020: Basic UI Scaling
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6317020
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestBasicUIScalingFunction(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_ui_scaling: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Resize the editor window and verify if the editor scaling works.
|
||||
|
||||
Expected Behavior:
|
||||
The editor window/docked widgets is scalable/resizable into windowed mode.
|
||||
|
||||
Test Steps:
|
||||
1) Resize the editor window couple of times
|
||||
2) Resize the docked widget
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def check_size(widget, widget_name, width, height):
|
||||
if widget.geometry().width() == width and widget.geometry().height() == height:
|
||||
print(f"{widget_name} size is {width} X {height}")
|
||||
else:
|
||||
print("Widget size not equal to expected value")
|
||||
|
||||
# 1) Resize the editor window couple of times
|
||||
# wait util the editor opens
|
||||
general.idle_wait(3.0)
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
editor_window.resize(1000, 500)
|
||||
check_size(editor_window, "Editor", 1000, 500)
|
||||
|
||||
editor_window.resize(2000, 1000)
|
||||
check_size(editor_window, "Editor", 2000, 1000)
|
||||
|
||||
# 2) Resize the docked widget
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
asset_browser = main_window.findChild(QtWidgets.QDockWidget, "Asset Browser")
|
||||
asset_browser.resize(100, 100)
|
||||
check_size(asset_browser, "Docked Widget", 100, 100)
|
||||
|
||||
|
||||
test = TestBasicUIScalingFunction()
|
||||
test.run()
|
||||
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6317035: Basic Viewport Configuration
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6317035
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtTest import QTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class BasicViewportConfigurationTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_viewport_configuration", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify id the basic viewport configuration works as expected.
|
||||
|
||||
Expected Behavior:
|
||||
1) Layout Configuration dialog opens.
|
||||
2) Layout configuration can be changed.
|
||||
3) All viewports function properly and independently of one another.
|
||||
4) The viewport is reverted to a single, large window.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Configure the viewport layer to a different layout
|
||||
3) Verify if viewport 1 is functional
|
||||
4) Verify if viewport 2 is functional
|
||||
5) Reset the layout back to original
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def verify_viewport_function(viewport_main_window_object):
|
||||
"""
|
||||
To check if the viewport camera controls are working, we can use the key press 'Left Arrow'
|
||||
which manuallly would have moved the camera to its left. So by simulating the Left Arrow press and
|
||||
comparing the current view position before and after the key press, we can verify if the view has indeed
|
||||
been modified and there by confirming if viewport is active.
|
||||
"""
|
||||
viewport = viewport_main_window_object.findChildren(QtWidgets.QWidget, "renderOverlay")[0].parent()
|
||||
initial_x = general.get_current_view_position().x
|
||||
viewport.setFocus()
|
||||
QTest.keyPress(viewport, Qt.Key_Left, Qt.NoModifier)
|
||||
general.idle_wait(0.5)
|
||||
QTest.keyRelease(viewport, Qt.Key_Left, Qt.NoModifier, delay=2)
|
||||
current_x = general.get_current_view_position().x
|
||||
return current_x < initial_x
|
||||
|
||||
async def select_layout(layout_index):
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "View", "Viewport", "Configure Layout")
|
||||
pyside_utils.trigger_action_async(action)
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
layout_config_dialog = active_modal_widget.findChild(QtWidgets.QDialog, "CLayoutConfigDialog")
|
||||
list_view = layout_config_dialog.findChild(QtWidgets.QListView, "m_layouts")
|
||||
pyside_utils.item_view_mouse_click(list_view, layout_index)
|
||||
button_box = layout_config_dialog.findChild(QtWidgets.QDialogButtonBox, "m_buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
print(f"Layout set to {layout_index}")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# 2) Configure the viewport layer to a different layout
|
||||
# In this case layout with 2 viewports placed side by side is selected
|
||||
await select_layout(1)
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow).findChild(QtWidgets.QMainWindow)
|
||||
central_widget = main_window.centralWidget()
|
||||
await pyside_utils.wait_for_condition(lambda: central_widget.findChild(QtWidgets.QSplitter) is not None)
|
||||
splitter = central_widget.findChild(QtWidgets.QSplitter)
|
||||
|
||||
# 3) Verify if viewport 1 is functional
|
||||
await pyside_utils.wait_for_condition(lambda: verify_viewport_function(splitter.children()[0]), 3.0)
|
||||
print(f"Viewport 1 camera controls are functional: {verify_viewport_function(splitter.children()[0])}")
|
||||
|
||||
# 4) Verify if viewport 2 is functional
|
||||
await pyside_utils.wait_for_condition(lambda: verify_viewport_function(splitter.children()[1]), 3.0)
|
||||
print(f"Viewport 2 camera controls are functional: {verify_viewport_function(splitter.children()[1])}")
|
||||
|
||||
# 5) Reset the layout back to original
|
||||
await select_layout(0)
|
||||
|
||||
test = BasicViewportConfigurationTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C18668804: Basic Window Docking System Tests
|
||||
https://testrail.agscollab.com/index.php?/cases/view/18668804
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
|
||||
from PySide2 import QtCore, QtWidgets
|
||||
|
||||
|
||||
class TestBasicWindowDocking(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_window_docking: ")
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Test basic docking behavior by undocking the Entity Outliner, and
|
||||
then docking on the edges around the main Editor window.
|
||||
|
||||
Expected Behavior:
|
||||
The window becomes undocked and floats on its own.
|
||||
The window can be docked to the main Editor's edges and is resized to fit.
|
||||
|
||||
Test Steps:
|
||||
1) Click on the Entity Outliner's title bar and drag it away to undock it.
|
||||
2) Click and drag the Entity Outliner to empty borders along the main Editor (top/bottom/left/right)
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# Make sure the Entity Outliner is open
|
||||
general.open_pane("Entity Outliner (PREVIEW)")
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
|
||||
# 1) Click on the Entity Outliner's title bar and drag it away to undock it.
|
||||
# We drag/drop it over the viewport since it doesn't allow docking, so this will undock it
|
||||
render_overlay = editor_window.findChild(QtWidgets.QWidget, "renderOverlay")
|
||||
pyside_utils.drag_and_drop(entity_outliner, render_overlay)
|
||||
|
||||
# Make sure the Entity Outliner is in a different QMainWindow than the main Editor QMainWindow,
|
||||
# which means it has been properly undocked (in a floating window)
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
if entity_outliner.parentWidget() != main_window:
|
||||
print("Entity Outliner is in a floating window")
|
||||
|
||||
# 2) Click and drag the Entity Outliner to empty borders along the main Editor (top/bottom/left/right)
|
||||
|
||||
# We need to grab a new reference to the Entity Outliner QDockWidget because when it gets moved
|
||||
# to the floating window, its parent changes so the wrapped intance we had becomes invalid
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
|
||||
# Dock to absolute top of main window
|
||||
edge_offset = 10 # The absolute drop zones are 25px wide, chose 10px as an in between
|
||||
main_window_rect = main_window.rect()
|
||||
main_window_center = main_window.rect().center()
|
||||
top_center = QtCore.QPoint(main_window_center.x(), edge_offset)
|
||||
pyside_utils.drag_and_drop(entity_outliner, main_window, QtCore.QPoint(), top_center)
|
||||
|
||||
# Make sure the Entity Outliner is now in the top area of the main Editor window
|
||||
if main_window.dockWidgetArea(entity_outliner) == QtCore.Qt.DockWidgetArea.TopDockWidgetArea:
|
||||
print("Entity Outliner docked in top area")
|
||||
|
||||
# Dock to absolute right of main window
|
||||
right_center = QtCore.QPoint(main_window_rect.right() - edge_offset, main_window_center.y())
|
||||
pyside_utils.drag_and_drop(entity_outliner, main_window, QtCore.QPoint(), right_center)
|
||||
|
||||
# Make sure the Entity Outliner is now in the right area of the main Editor window
|
||||
if main_window.dockWidgetArea(entity_outliner) == QtCore.Qt.DockWidgetArea.RightDockWidgetArea:
|
||||
print("Entity Outliner docked in right area")
|
||||
|
||||
# Dock to absolute bottom of main window
|
||||
bottom_center = QtCore.QPoint(main_window_center.x(), main_window_rect.bottom() - edge_offset)
|
||||
pyside_utils.drag_and_drop(entity_outliner, main_window, QtCore.QPoint(), bottom_center)
|
||||
|
||||
# Make sure the Entity Outliner is now in the bottom area of the main Editor window
|
||||
if main_window.dockWidgetArea(entity_outliner) == QtCore.Qt.DockWidgetArea.BottomDockWidgetArea:
|
||||
print("Entity Outliner docked in bottom area")
|
||||
|
||||
# Dock to absolute left of main window
|
||||
left_center = QtCore.QPoint(edge_offset, main_window_center.y())
|
||||
pyside_utils.drag_and_drop(entity_outliner, main_window, QtCore.QPoint(), left_center)
|
||||
|
||||
# Make sure the Entity Outliner is now in the left area of the main Editor window
|
||||
if main_window.dockWidgetArea(entity_outliner) == QtCore.Qt.DockWidgetArea.LeftDockWidgetArea:
|
||||
print("Entity Outliner docked in left area")
|
||||
|
||||
|
||||
test = TestBasicWindowDocking()
|
||||
test.run()
|
||||
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6384949: Basic Workflow: Layers
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6384949
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as editor_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.layers as layers
|
||||
import azlmbr.math as math
|
||||
from typing import Optional
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtGui import QContextMenuEvent
|
||||
from PySide2.QtCore import QObject, QEvent, QPoint
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestBasicWorkflowLayers(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="basic_workflow_layers: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Basic Workflow: Layers.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create layer in the Entity Outliner
|
||||
3) Create entity and Drag the entity into the layer
|
||||
4) Create another entity and Drag entities out of the layer
|
||||
5) Create a second layer and Drag the second layer into the first layer
|
||||
6) Save layer
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_entity_count_name(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
def verify_parent(
|
||||
entity_to_check, expected_parent_entity, child_name, parent_name, additional_pretext: Optional[str] = ""
|
||||
):
|
||||
actual_parent_id = editor.EditorEntityInfoRequestBus(bus.Event, "GetParent", entity_to_check)
|
||||
if actual_parent_id.ToString() == expected_parent_entity.ToString():
|
||||
print(f"{additional_pretext} The parent entity of {child_name} is : {parent_name}")
|
||||
|
||||
def set_parent(chilld_entity, parent_entity):
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetParent", chilld_entity, parent_entity)
|
||||
|
||||
class EventFilter(QObject):
|
||||
def eventFilter(self, obj, event):
|
||||
if event.type() == QEvent.Type.ChildPolished:
|
||||
print("ChildPolished event received")
|
||||
menu = obj.children()[-1]
|
||||
action = pyside_utils.find_child_by_property(menu, QtWidgets.QAction, "text", "Save layer")
|
||||
action.trigger()
|
||||
menu.clear()
|
||||
return False
|
||||
return False
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
active_modal_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
general.idle_wait(1.0)
|
||||
button_box = active_modal_widget.findChild(QtWidgets.QDialogButtonBox, "qt_msgbox_buttonbox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Save).click()
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Create layer in the Entity Outliner
|
||||
first_layer_entity_id = layers.EditorLayerComponent_CreateLayerEntityFromName("Layer1")
|
||||
if get_entity_count_name("Layer1*"):
|
||||
print("First Layer is created")
|
||||
|
||||
# 3) Create entity and Drag the entity into the layer
|
||||
entity_postition = math.Vector3(125.0, 136.0, 32.0)
|
||||
first_entity = editor_utils.Entity("Entity1")
|
||||
first_entity.create_entity(entity_postition, [])
|
||||
if get_entity_count_name("Entity1"):
|
||||
print("First Entity is created")
|
||||
set_parent(first_entity.id, first_layer_entity_id)
|
||||
verify_parent(first_entity.id, first_layer_entity_id, first_entity.name, "Layer1", "Original Check:")
|
||||
|
||||
# 4) Create another entity and Drag entities out of the layer
|
||||
second_entity = editor_utils.Entity("Entity2")
|
||||
second_entity.create_entity(entity_postition, [])
|
||||
if get_entity_count_name("Entity2"):
|
||||
print("Second Entity is created")
|
||||
set_parent(second_entity.id, first_layer_entity_id)
|
||||
verify_parent(second_entity.id, first_layer_entity_id, second_entity.name, "Layer1", "Original Check:")
|
||||
# Drag entities out of the layer
|
||||
set_parent(first_entity.id, entity.EntityId())
|
||||
set_parent(second_entity.id, entity.EntityId())
|
||||
verify_parent(first_entity.id, entity.EntityId(), first_entity.name, "", "After Drag:")
|
||||
verify_parent(second_entity.id, entity.EntityId(), second_entity.name, "", "After Drag:")
|
||||
|
||||
# 5) Create a second layer and Drag the second layer into the first layer
|
||||
second_layer_entity_id = layers.EditorLayerComponent_CreateLayerEntityFromName("Layer2")
|
||||
if get_entity_count_name("Layer2*"):
|
||||
print("Second Layer is created")
|
||||
set_parent(second_layer_entity_id, first_layer_entity_id)
|
||||
verify_parent(second_layer_entity_id, first_layer_entity_id, "Layer2", "Layer1", "After Drag:")
|
||||
|
||||
# 6) Save layer
|
||||
app = QtWidgets.QApplication.instance()
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
entity_outliner = main_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
outliner_main_window = entity_outliner.findChild(QtWidgets.QMainWindow)
|
||||
wid_1 = outliner_main_window.findChild(QtWidgets.QWidget)
|
||||
wid_2 = wid_1.findChild(QtWidgets.QWidget)
|
||||
tree = outliner_main_window.findChildren(QtWidgets.QTreeView, "m_objectTree")[0]
|
||||
general.clear_selection()
|
||||
general.select_object(editor.EditorEntityInfoRequestBus(bus.Event, "GetName", first_layer_entity_id))
|
||||
event_filter = EventFilter()
|
||||
try:
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
wid_2.installEventFilter(event_filter)
|
||||
context_menu_event = QContextMenuEvent(QContextMenuEvent.Mouse, QPoint(0, 0))
|
||||
app.sendEvent(tree, context_menu_event)
|
||||
general.idle_wait(1.0)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
wid_2.removeEventFilter(event_filter)
|
||||
|
||||
|
||||
test = TestBasicWorkflowLayers()
|
||||
test.run()
|
||||
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C17219007: Camera Component
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17219007
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as editor_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestCameraComponentHelper(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="camera_component: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Ensure that the camera component behaves properly in the editor and the
|
||||
proper camera settings are being populated.
|
||||
|
||||
Expected Behavior:
|
||||
Camera fov is visible in the Viewport
|
||||
The Camera entity is populated in the Viewport Selector
|
||||
The Viewport perspective is changed to the camera
|
||||
The Viewport perspective is switched back to the default editor camera
|
||||
|
||||
Test Steps:
|
||||
1) Create or open any level
|
||||
2) Create an entity with a Camera component
|
||||
3) Click "Be this camera"
|
||||
4) Save the position of the floating camera viewport and compare against entity
|
||||
5) Click "Return to default editor camera"
|
||||
6) Save the position of the current viewport and compare against entity
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_button(button_text):
|
||||
return pyside_utils.find_child_by_pattern(entity_inspector, button_text)
|
||||
|
||||
# 1) Create or open any level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
entity_inspector = editor_window.findChildren(QtWidgets.QDockWidget, "Entity Inspector")[0]
|
||||
|
||||
# 2) Create an entity with a Camera component
|
||||
entity_postition = math.Vector3(200.0, 200.0, 32.0)
|
||||
components_to_add = ["Camera"]
|
||||
|
||||
test_entity = editor_utils.Entity("Temp_Entity")
|
||||
test_entity.create_entity(entity_postition, components_to_add)
|
||||
if test_entity.id.isValid():
|
||||
print("Entity created with camera component")
|
||||
|
||||
# 3) Click "Be this camera"
|
||||
button_text = "Be this camera"
|
||||
self.wait_for_condition(lambda: get_button(button_text) is not None, 2.0)
|
||||
button = get_button(button_text)
|
||||
if button:
|
||||
button.click()
|
||||
print("Button 'Be this camera' clicked")
|
||||
|
||||
# 4) Save the position of the floating camera viewport and compare against entity
|
||||
self.wait_for_condition(lambda: general.get_current_view_position() == entity_postition, 1.0)
|
||||
camera_position = general.get_current_view_position()
|
||||
assert camera_position == entity_postition, "Camera positions did not change upon clicking 'Be this camera'"
|
||||
print("Camera has shifted after clicking 'Be this camera' button")
|
||||
|
||||
# 5) Click "Return to default editor camera"
|
||||
button_text = "Return to default editor camera"
|
||||
self.wait_for_condition(lambda: get_button(button_text) is not None, 2.0)
|
||||
button = get_button(button_text)
|
||||
if button:
|
||||
button.click()
|
||||
print("Button 'Return to default editor camera' clicked")
|
||||
|
||||
# 6) Save the position of the current viewport and compare against entity
|
||||
self.wait_for_condition(lambda: general.get_current_view_position() != entity_postition, 1.0)
|
||||
camera_position = general.get_current_view_position()
|
||||
assert camera_position != entity_postition, "Camera positions did not change upon clicking 'Return to default editor camera'"
|
||||
print("Camera has shifted after clicking 'Return to default editor camera' button")
|
||||
|
||||
|
||||
test = TestCameraComponentHelper()
|
||||
test.run()
|
||||
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C16798661: Component List Contents
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16798661
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class ComponentListContentsTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="component_list_contents", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Select an entity. Click "Add Component" in the Entity Inspector.
|
||||
Verify components are sorted into categories.
|
||||
Expand / collapse component categories.
|
||||
|
||||
Expected Behavior:
|
||||
Component categories are expanded / collapsed as expected.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create entity
|
||||
3) Select the newly created entity
|
||||
4) Click "Add Component" in the Entity Inspector.
|
||||
5) Verify list of components are sorted into categories.
|
||||
6) Collapse the first category.
|
||||
7) Expand the category which was just collapsed.
|
||||
8) Add a valid component to the entity.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# Make sure the Entity Inspector is open
|
||||
general.open_pane('Entity Inspector')
|
||||
|
||||
# 2) Create entity
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
if entity_id.IsValid():
|
||||
print("Entity Created")
|
||||
|
||||
# 3) Select the newly created entity
|
||||
general.clear_selection()
|
||||
general.select_object("Entity2")
|
||||
|
||||
# Get the component type ID for our Box Shape
|
||||
component_name = "Box Shape"
|
||||
type_ids = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [component_name],
|
||||
EntityId.EntityType().Game)
|
||||
component_type_id = type_ids[0]
|
||||
|
||||
# Sanity check to make sure our Entity didn't already have the Box Shape component for some reason
|
||||
had_component = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', entity_id, component_type_id)
|
||||
if had_component:
|
||||
print("Box Shape already existed on Entity.")
|
||||
|
||||
# 4) Click Add Component
|
||||
general.idle_wait(0.5)
|
||||
add_comp_btn = pyside_utils.find_child_by_hierarchy(
|
||||
pyside_utils.get_editor_main_window(), ..., "Entity Inspector", ..., "m_addComponentButton")
|
||||
add_comp_btn.click()
|
||||
# Wait 0.5s to ensure component is added and rendered, especially when adding components
|
||||
# continuously to the entity
|
||||
general.idle_wait(0.5)
|
||||
|
||||
popup = None
|
||||
search_frame = None
|
||||
def hasPopup():
|
||||
nonlocal popup
|
||||
nonlocal search_frame
|
||||
popup = QtWidgets.QApplication.activePopupWidget()
|
||||
focus = QtWidgets.QApplication.focusWidget()
|
||||
if isinstance(focus, QtWidgets.QLineEdit) and popup:
|
||||
search_frame = popup.findChild(QtWidgets.QFrame, "SearchFrame")
|
||||
if search_frame is not None:
|
||||
return True
|
||||
await pyside_utils.wait_for_condition(hasPopup)
|
||||
|
||||
# To ensure we get an updated tree after the component name is set
|
||||
general.idle_wait(0)
|
||||
tree = popup.findChild(QtWidgets.QTreeView, "Tree")
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Down, Qt.NoModifier)
|
||||
while tree.indexBelow(tree.currentIndex()) != QtCore.QModelIndex():
|
||||
# 6) Collapse the first category (which is "AI")
|
||||
# "Behavior Tree" is the first component in category "AI"
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "Behavior Tree":
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Left, Qt.NoModifier)
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Left, Qt.NoModifier)
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "AI":
|
||||
print("Successfully collapsed category.")
|
||||
|
||||
# 7) Expand the category which was just collapsed.
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Right, Qt.NoModifier)
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Right, Qt.NoModifier)
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "Behavior Tree":
|
||||
print("Successfully expanded category.")
|
||||
break
|
||||
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Down, Qt.NoModifier)
|
||||
|
||||
# 8) Add the component (based on passed "component_name" variable) to entity
|
||||
component_index = pyside_utils.find_child_by_pattern(tree, component_name)
|
||||
tree.setCurrentIndex(component_index)
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
|
||||
|
||||
# After selecting the Box Shape from the component palette, make sure the component exists on our Entity now
|
||||
has_component = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', entity_id, component_type_id)
|
||||
if has_component:
|
||||
print("Box Shape successfully added.")
|
||||
|
||||
test = ComponentListContentsTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,144 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C16877221: Component List Filtering
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16877221
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.math as math
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class ComponentListFilteringTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="component_list_filtering", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Select an entity. Click "Add Component" in the Entity Inspector.
|
||||
Type the name of a valid component in the component search field, clear the search field and finally
|
||||
type an invalid component name.
|
||||
The test verifies the component list is filtered correctly in all these cases.
|
||||
|
||||
Expected Behavior:
|
||||
1) Components are filtered as you type narrowing down to the desired component.
|
||||
2) Components are filtered with each character deleted, eventually restoring the entire component list when the
|
||||
field is empty.
|
||||
3) Components are filtered until there are no entries present.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create entity
|
||||
3) Select the newly created entity
|
||||
4) Click "Add Component" in the Entity Inspector.
|
||||
5) Type component name in search field.
|
||||
6) Verify list of components are filtered per the typed component name.
|
||||
7) Delete text in search field.
|
||||
8) Verify the list is restored.
|
||||
9) Type an invalid component name in search field.
|
||||
10) Verify the component list is empty as expected.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
async def search_component(component_name, expected_row_count=None):
|
||||
# Click the "Add Component" button in the Entity Inspector and
|
||||
# then enter the specified `component_name` into its search field
|
||||
pyside_utils.click_button_async(add_comp_btn)
|
||||
popup = await pyside_utils.wait_for_popup_widget()
|
||||
search_frame = popup.findChild(QtWidgets.QFrame, "SearchFrame")
|
||||
search_text = search_frame.findChild(QtWidgets.QLineEdit, "SearchText")
|
||||
search_text.setText(component_name)
|
||||
|
||||
# To ensure we get an updated tree after the component name is set, we
|
||||
# need to wait until the rowCount matches what we expect, since the
|
||||
# ComponentPaletteWidget::UpdateSearch is queued.
|
||||
def row_count_matches():
|
||||
tree = popup.findChild(QtWidgets.QTreeView, "Tree")
|
||||
row_count = tree.model().rowCount()
|
||||
if expected_row_count is not None:
|
||||
return row_count == expected_row_count
|
||||
|
||||
# Else, if expected_row_count was left as None, then just wait until
|
||||
# the tree model has been populated with anything
|
||||
return row_count > 0
|
||||
|
||||
await pyside_utils.wait_for_condition(row_count_matches)
|
||||
|
||||
# Print out the result based on what is populated in the component palette tree
|
||||
tree = popup.findChild(QtWidgets.QTreeView, "Tree")
|
||||
row_count = tree.model().rowCount()
|
||||
component_index = pyside_utils.find_child_by_pattern(tree, text=component_name, type=QtCore.QModelIndex)
|
||||
if component_index and component_index.isValid():
|
||||
print(f"{component_name} : Valid filtered component list")
|
||||
elif row_count == 0:
|
||||
print(f"{component_name} : Empty component list")
|
||||
else:
|
||||
print("Full component list")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# Make sure the Entity Inspector is open
|
||||
general.open_pane('Entity Inspector')
|
||||
|
||||
# 2) Create entity
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntity", entity.EntityId()
|
||||
)
|
||||
|
||||
# 3) Select the newly created entity
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [entity_id])
|
||||
# Give the Entity Inspector time to fully create its contents
|
||||
general.idle_wait(0.0)
|
||||
|
||||
# 4) Click Add Component
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
add_comp_btn = entity_inspector.findChild(QtWidgets.QPushButton, "m_addComponentButton")
|
||||
|
||||
# 5,6) Search for a valid component name, verify list is properly filtered
|
||||
component_name_to_search = "Box Shape"
|
||||
await search_component(component_name_to_search, 1)
|
||||
|
||||
# 7,8) Delete the search box, verify full list is loaded
|
||||
component_name_to_search = ""
|
||||
await search_component(component_name_to_search)
|
||||
|
||||
# 9,10) Search for an invalid component name, verify the list is empty
|
||||
component_name_to_search = "Invalid Component Name !@#$"
|
||||
await search_component(component_name_to_search, 0)
|
||||
|
||||
test = ComponentListFilteringTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,293 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
16929884: Conflicting Components
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16929884
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.entity as entity
|
||||
|
||||
from azlmbr.entity import EntityId
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestConflictingComponents(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="conflicting_components: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create conflicting components on an entity, test activating and deactivated each.
|
||||
|
||||
Expected Behavior:
|
||||
Conflicting compoennts are deactivated when appropriate.
|
||||
|
||||
Test Steps:
|
||||
1) Create new level
|
||||
2) Create an entity
|
||||
3) Create a box shape component on the entity
|
||||
4) Create a cylinder shape component on the entity
|
||||
5) Check both components have warnings and activate/delete buttons
|
||||
6) Select Activate on the cylinder shape
|
||||
7) Check that the cylinder is active and the box is not active
|
||||
8) Right click on the box shape and enable it
|
||||
9) Check delete/activate options exist on both components
|
||||
10) delete the cylinder shape
|
||||
11) Check that the cylinder is deleted and the box is enabled
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_component_type_id(component_type_name):
|
||||
# Generate List of Component Types
|
||||
component_list = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentTypeNameList')
|
||||
|
||||
if len(component_list) == 0:
|
||||
print("Component List returned incorrectly.")
|
||||
return False, 0
|
||||
|
||||
# Get Component Types for Mesh and Comment
|
||||
type_ids_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType',
|
||||
[component_type_name], entity.EntityType().Game)
|
||||
|
||||
if len(type_ids_list) == 0:
|
||||
print("Type Ids List returned incorrectly.")
|
||||
return False, 0
|
||||
|
||||
return True, type_ids_list[0]
|
||||
|
||||
def create_component_of_type(entity_id, component_type_name):
|
||||
result, component_type_id = get_component_type_id(component_type_name)
|
||||
if not result:
|
||||
print("Failed to get " + component_type_name + " component id.")
|
||||
return None
|
||||
|
||||
has_component_before_add = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', entity_id,
|
||||
component_type_id)
|
||||
|
||||
if not has_component_before_add:
|
||||
print("Entity does not have " + component_type_name + " component before add.")
|
||||
|
||||
# Add an ActorComponent to the entity.
|
||||
component_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entity_id,
|
||||
[component_type_id])
|
||||
|
||||
if component_outcome.IsSuccess():
|
||||
print(component_type_name + " component added to entity.")
|
||||
else:
|
||||
return None
|
||||
|
||||
components = component_outcome.GetValue()
|
||||
component = components[0]
|
||||
|
||||
has_component_after_add = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', entity_id,
|
||||
component_type_id)
|
||||
|
||||
if has_component_after_add and len(components) == 1:
|
||||
print("Entity has " + component_type_name + " component after add.")
|
||||
else:
|
||||
return None
|
||||
|
||||
return component
|
||||
|
||||
def get_inspector_component_by_index(index):
|
||||
inspector_dock = editor_window.findChild(QtWidgets.QWidget, "Entity Inspector")
|
||||
entity_inspector = inspector_dock.findChild(QtWidgets.QMainWindow)
|
||||
|
||||
child_widget = entity_inspector.findChild(QtWidgets.QWidget)
|
||||
if child_widget is None:
|
||||
return False, None
|
||||
|
||||
general.idle_wait(1.0)
|
||||
comp_list_contents = (
|
||||
child_widget.findChild(QtWidgets.QScrollArea, "m_componentList")
|
||||
.findChild(QtWidgets.QWidget, "qt_scrollarea_viewport")
|
||||
.findChild(QtWidgets.QWidget, "m_componentListContents")
|
||||
)
|
||||
|
||||
if comp_list_contents is None or index >= len(comp_list_contents.children()):
|
||||
return False, None
|
||||
|
||||
return True, comp_list_contents.children()[index]
|
||||
|
||||
def get_box_and_cylinder_component_inspector():
|
||||
result, box_frame = get_inspector_component_by_index(2)
|
||||
|
||||
result, cylinder_frame = get_inspector_component_by_index(3)
|
||||
|
||||
return box_frame, cylinder_frame
|
||||
|
||||
def is_just_first_component_enabled(component1, component2):
|
||||
c1_active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', component1)
|
||||
c2_active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', component2)
|
||||
|
||||
if c1_active and not c2_active:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def fail_test(msg):
|
||||
print(msg)
|
||||
print("Test Failed.")
|
||||
sys.exit()
|
||||
|
||||
create_level_result = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
if not create_level_result:
|
||||
fail_test("New level failed.")
|
||||
|
||||
EditorTestHelper.after_level_load(self)
|
||||
|
||||
# Create a new entity.
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
|
||||
|
||||
if not new_entity_id.IsValid():
|
||||
print("Failed to create new entity.")
|
||||
|
||||
# Select the entity so that it appears in the inspector.
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [new_entity_id])
|
||||
|
||||
# Create both shape components.
|
||||
box_component = create_component_of_type(new_entity_id, "Box Shape")
|
||||
if box_component is None:
|
||||
fail_test("Failed to create Box Shape component.")
|
||||
|
||||
cylinder_component = create_component_of_type(new_entity_id, "Cylinder Shape")
|
||||
if cylinder_component is None:
|
||||
fail_test("Failed to create Box Shape component.")
|
||||
|
||||
# Check inspector windows exist for both shapes
|
||||
box_frame, cylinder_frame = get_box_and_cylinder_component_inspector()
|
||||
if box_frame is None:
|
||||
fail_test("Could not find inspector for box shape.")
|
||||
if cylinder_frame is None:
|
||||
fail_test("Could not find inspector for cylinder shape.")
|
||||
|
||||
# Check both shape inspectors have delete and activate buttons.
|
||||
box_del_btn = pyside_utils.find_child_by_pattern(box_frame, "Delete component")
|
||||
box_activate_btn = pyside_utils.find_child_by_pattern(box_frame, "Activate this component")
|
||||
if box_del_btn is None or box_activate_btn is None:
|
||||
fail_test("Failed to find buttons on box component.")
|
||||
|
||||
cylinder_del_btn = pyside_utils.find_child_by_pattern(cylinder_frame, "Delete component")
|
||||
cylinder_activate_btn = pyside_utils.find_child_by_pattern(cylinder_frame, "Activate this component")
|
||||
if cylinder_del_btn is None or cylinder_activate_btn is None:
|
||||
fail_test("Failed to find buttons on cylinder component.")
|
||||
|
||||
# Check that just the box shape is enabled.
|
||||
just_box_enabled = is_just_first_component_enabled(box_component, cylinder_component)
|
||||
if not just_box_enabled:
|
||||
fail_test("Incorrectly enabled components.")
|
||||
|
||||
# Press Activate on cylinder
|
||||
QtTest.QTest.mouseClick(cylinder_activate_btn, Qt.LeftButton, Qt.NoModifier)
|
||||
|
||||
# Re-get the inspector windows to ensure they're up to date.
|
||||
box_frame, cylinder_frame = get_box_and_cylinder_component_inspector()
|
||||
|
||||
# Check that neither shape inspector now has delete or activate buttons.
|
||||
|
||||
box_del_btn = pyside_utils.find_child_by_pattern(box_frame, "Delete component")
|
||||
box_activate_btn = pyside_utils.find_child_by_pattern(box_frame, "Activate this component")
|
||||
if box_del_btn is not None or box_activate_btn is not None:
|
||||
fail_test("Found buttons on box component when disabled.")
|
||||
|
||||
cylinder_del_btn = pyside_utils.find_child_by_pattern(cylinder_frame, "Delete component")
|
||||
cylinder_activate_btn = pyside_utils.find_child_by_pattern(cylinder_frame, "Activate this component")
|
||||
if cylinder_del_btn is not None or cylinder_activate_btn is not None:
|
||||
fail_test("Found buttons on cylinder component when active.")
|
||||
|
||||
# Check that the cylinder is now enabled and not the box.
|
||||
just_cylinder_enabled = is_just_first_component_enabled(cylinder_component, box_component)
|
||||
if not just_cylinder_enabled:
|
||||
fail_test("Incorrectly enabled components.")
|
||||
|
||||
# Click on the box frame to activate it or we might get the wrong context menu
|
||||
QtTest.QTest.mouseClick(box_frame, Qt.LeftButton, Qt.NoModifier)
|
||||
|
||||
general.idle_wait(1.0)
|
||||
|
||||
# Pop up box component context menu and select the Enable component option
|
||||
pyside_utils.trigger_context_menu_entry(box_frame, "Enable component")
|
||||
|
||||
# Check that both components have the buttons again
|
||||
box_frame, cylinder_frame = get_box_and_cylinder_component_inspector()
|
||||
|
||||
box_del_btn = pyside_utils.find_child_by_pattern(box_frame, "Delete component")
|
||||
box_activate_btn = pyside_utils.find_child_by_pattern(box_frame, "Activate this component")
|
||||
if box_del_btn is None or box_activate_btn is None:
|
||||
fail_test("Failed to find buttons on box component.")
|
||||
|
||||
cylinder_del_btn = pyside_utils.find_child_by_pattern(cylinder_frame, "Delete component")
|
||||
cylinder_activate_btn = pyside_utils.find_child_by_pattern(cylinder_frame, "Activate this component")
|
||||
if cylinder_del_btn is None or cylinder_activate_btn is None:
|
||||
fail_test("Failed to find buttons on cylinder component.")
|
||||
|
||||
# Press "Delete component" on the Cylinder Shape.
|
||||
QtTest.QTest.mouseClick(cylinder_del_btn, Qt.LeftButton, Qt.NoModifier)
|
||||
|
||||
general.idle_wait(1.0)
|
||||
|
||||
# Check it's gone.
|
||||
result, component_type_id = get_component_type_id("Cylinder Shape")
|
||||
if not result:
|
||||
fail_test("Failed to get Cylinder Shape component id.")
|
||||
|
||||
has_component_after_delete = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', new_entity_id,
|
||||
component_type_id)
|
||||
|
||||
if has_component_after_delete:
|
||||
fail_test("Cylinder Shape still exists.")
|
||||
|
||||
box_frame, cylinder_frame = get_box_and_cylinder_component_inspector()
|
||||
|
||||
# Ensure the activate and delete buttons are gone from the box inspector.
|
||||
box_del_btn = pyside_utils.find_child_by_pattern(box_frame, "Delete component")
|
||||
box_activate_btn = pyside_utils.find_child_by_pattern(box_frame, "Activate this component")
|
||||
if box_del_btn is not None or box_activate_btn is not None:
|
||||
fail_test("Found buttons on box component when active.")
|
||||
|
||||
# Check the box is now enabled.
|
||||
box_active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', box_component)
|
||||
if not box_active:
|
||||
fail_test("Box not active.")
|
||||
|
||||
print("Conflicting components test successful.")
|
||||
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
app = QtWidgets.QApplication.instance()
|
||||
test = TestConflictingComponents()
|
||||
test.run()
|
||||
@@ -0,0 +1,368 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C2603859: Parent Slice should still load on map if a child slice is corrupted.
|
||||
https://testrail.agscollab.com/index.php?/cases/view/2603859
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import azlmbr.qt_helpers
|
||||
|
||||
import azlmbr
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.math as math
|
||||
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest, QtCore, QtGui
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
from azlmbr.entity import EntityId
|
||||
|
||||
class TestCorruptChildSlice(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="corrupt_child_slice: ", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Carry out various operations to ensure a corrupt child slice does not
|
||||
prevent a parent slice from loading.
|
||||
|
||||
Expected Behavior:
|
||||
Parent layer of corrupt slice can be loaded.
|
||||
|
||||
Test Steps:
|
||||
1) Create a new entity named "CorruptC".
|
||||
2) Save as a slice.
|
||||
3) Create a new entity named "CorruptB".
|
||||
4) Make CorruptC a child of CorruptB.
|
||||
5) Save CorruptB as a slice.
|
||||
6) Create a new entity named CorruptA.
|
||||
7) Make CorruptB a child of CorruptA.
|
||||
8) Save CorruptA as a slice.
|
||||
9) Instantiate an instance of CorruptB.
|
||||
10) Save the level and close the editor.
|
||||
11) Rename the CorruptC slice to CorruptC.slice.backup.
|
||||
12) Make a copy of CorruptB.slice named CorruptB.slice.backup.
|
||||
13) Open the editor and level.
|
||||
14) Check that an error is displayed when loading the level.
|
||||
15) Check that CorruptB and A have loaded but CorruptA is absent.
|
||||
16) Check that CorruptA has a blue icon.
|
||||
17) Check that CorruptB is orange.
|
||||
18) Close the error message.
|
||||
19) Use the context menu of CorruptB to enter the Advanced Save dialog.
|
||||
20) Check there is a warning message in the dialog.
|
||||
21) Check that either CorruptB has "changed" next to it or CorruptB is listed as
|
||||
having invalid references removed.
|
||||
22) Press "Save Selected Overrides".
|
||||
23) Close the editor and reopen the same level again.
|
||||
24) Check there are no warnings and the level loads correctly.
|
||||
25) Create a second instance of CorruptA.
|
||||
26) Check there are no errors.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
Outliner_Name = "Entity Outliner (PREVIEW)"
|
||||
Console_Name = "Console"
|
||||
|
||||
def fail_test(msg):
|
||||
print(msg)
|
||||
print("Test failed.")
|
||||
sys.exit()
|
||||
|
||||
async def save_level_as(main_editor_window, level_name_text):
|
||||
save_action = pyside_utils.get_action_for_menu_path(main_editor_window, "File", "Save As")
|
||||
pyside_utils.trigger_action_async(save_action)
|
||||
active_widget = await pyside_utils.wait_for_modal_widget()
|
||||
|
||||
save_level_as_dialogue = active_widget.findChild(QtWidgets.QWidget, "LevelFileDialog")
|
||||
level_name = await pyside_utils.wait_for_child_by_hierarchy(
|
||||
save_level_as_dialogue,
|
||||
...,
|
||||
dict(type=QtWidgets.QLineEdit, objectName="nameLineEdit"),
|
||||
)
|
||||
level_name.setText(level_name_text)
|
||||
|
||||
button_box = save_level_as_dialogue.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
await pyside_utils.close_modal(active_widget)
|
||||
|
||||
async def open_level_check_for_warning(level_name):
|
||||
general.open_level_no_prompt(level_name)
|
||||
|
||||
try:
|
||||
dialog = await pyside_utils.wait_for_child_by_hierarchy(None,
|
||||
{"objectName": "ErrorLogDialog", "type": QtWidgets.QDialog},
|
||||
timeout=2.0)
|
||||
|
||||
if dialog is None:
|
||||
return False
|
||||
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
|
||||
button = active_widget.findChild(QtWidgets.QPushButton, "okButton")
|
||||
if button is not None:
|
||||
button.click()
|
||||
except pyside_utils.EventLoopTimeoutException:
|
||||
# The assertion is a timeout while waiting for the dialog.
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
async def push_slice_confirm_overwrite(button):
|
||||
# If a confirm dialog pops up, press the confirm button.
|
||||
pyside_utils.click_button_async(button)
|
||||
|
||||
try:
|
||||
dialog = await pyside_utils.wait_for_child_by_hierarchy(None,
|
||||
{"objectName": "SliceUtilities.warningMessageBox",
|
||||
"type": QtWidgets.QMessageBox},
|
||||
timeout=1.0)
|
||||
confirm_button = pyside_utils.find_child_by_pattern(dialog, "Confirm")
|
||||
pyside_utils.click_button_async(confirm_button)
|
||||
await pyside_utils.close_modal(dialog)
|
||||
except pyside_utils.EventLoopTimeoutException:
|
||||
# No overwrite dialog appeared.
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
async def push_slice_to_file(slice_entity_id):
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [slice_entity_id])
|
||||
general.idle_wait(0.0)
|
||||
pyside_utils.run_soon(lambda: slice.SliceRequestBus(bus.Broadcast, "ShowPushDialog", [slice_entity_id]))
|
||||
active_widget = await pyside_utils.wait_for_modal_widget()
|
||||
|
||||
tree_widget = active_widget.findChild(QtWidgets.QTreeWidget, "SlicePushWidget.m_fieldTree")
|
||||
if tree_widget is None:
|
||||
return False
|
||||
|
||||
# Check warning message
|
||||
warning_message = active_widget.findChild(QtWidgets.QLabel, "SlicePushWidget.m_warningTitle")
|
||||
if warning_message is None:
|
||||
fail_test("Failed to find warning message in push dialog.")
|
||||
|
||||
if not warning_message.text().startswith("1 missing reference(s)"):
|
||||
fail_test("Failed to find Invalid References warning message.")
|
||||
|
||||
# Check for CorruptB in the field selection.
|
||||
found_corrupt_b_message = False
|
||||
iterator = QtWidgets.QTreeWidgetItemIterator(tree_widget)
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
# Check it has one of the two possible messages.
|
||||
if item.text(0) == "CorruptB (invalid references will be removed)" or item.text(
|
||||
0) == "CorruptB (changed)":
|
||||
found_corrupt_b_message = True
|
||||
iterator += 1
|
||||
|
||||
if not found_corrupt_b_message:
|
||||
fail_test("Failed to find CorruptB invalid reference removal message.")
|
||||
|
||||
# Press the save button.
|
||||
save_button = pyside_utils.find_child_by_pattern(active_widget, "Save Selected Overrides")
|
||||
|
||||
overwrite_result = await push_slice_confirm_overwrite(save_button)
|
||||
|
||||
await pyside_utils.close_modal(active_widget)
|
||||
|
||||
return overwrite_result
|
||||
|
||||
def create_entity_with_name(entity_name):
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
|
||||
if not new_entity_id.IsValid():
|
||||
fail_test("Failed to create new entity.")
|
||||
editor.EditorEntityAPIBus(bus.Event, 'SetName', new_entity_id, entity_name)
|
||||
name = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', new_entity_id)
|
||||
return new_entity_id
|
||||
|
||||
def path_is_valid_asset(asset_path):
|
||||
tmp_asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
|
||||
return tmp_asset_id.invoke("IsValid")
|
||||
|
||||
def save_entity_as_slice(entity_id, slice_name):
|
||||
current_level_name = editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName")
|
||||
slice_file = slice_name + ".slice"
|
||||
slice_dir = os.path.join("Levels", current_level_name)
|
||||
full_path = os.path.join(slice_dir, slice_file)
|
||||
slice_created = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", entity_id, full_path)
|
||||
self.wait_for_condition(lambda: path_is_valid_asset(full_path), 10.0)
|
||||
if not slice_created:
|
||||
fail_test("Failed to create slice.")
|
||||
general.idle_wait(0.0)
|
||||
|
||||
return slice_dir, slice_file
|
||||
|
||||
def check_log_for_text_absence(console_text_edit, text_to_check):
|
||||
# Grab the log text
|
||||
text = console_text_edit.toPlainText()
|
||||
|
||||
# Scan it for failed save lines.
|
||||
lines = text.split('\n')
|
||||
|
||||
for line in lines:
|
||||
if line.find(text_to_check) >= 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
EditorTestHelper.after_level_load(self)
|
||||
|
||||
app = QtWidgets.QApplication.instance()
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
|
||||
# Make sure the outliner and console are open.
|
||||
general.open_pane(Outliner_Name)
|
||||
entity_outliner = editor_window.findChild(QtWidgets.QDockWidget, Outliner_Name)
|
||||
if entity_outliner is None:
|
||||
fail_test("Failed to find the outliner.")
|
||||
|
||||
outliner_main_window = entity_outliner.findChild(QtWidgets.QMainWindow)
|
||||
if outliner_main_window is None:
|
||||
fail_test("Failed to find the outliner main window.")
|
||||
|
||||
outliner_tree_view = outliner_main_window.findChild(QtWidgets.QTreeView, "m_objectTree")
|
||||
if outliner_tree_view is None:
|
||||
fail_test("Failed to find the outliner tree view.")
|
||||
|
||||
general.open_pane(Console_Name)
|
||||
console = main_window.findChild(QtWidgets.QDockWidget, Console_Name)
|
||||
if console is None:
|
||||
fail_test("Failed to find the console.")
|
||||
|
||||
text_edit = console.findChild(QtWidgets.QPlainTextEdit, "textEdit")
|
||||
if text_edit is None:
|
||||
fail_test("Failed to find console textEdit.")
|
||||
|
||||
# Create a level.
|
||||
result = general.create_level_no_prompt("test_level_1", 1024, 1, 4096, True)
|
||||
if result != 0:
|
||||
fail_test("Failed to create level")
|
||||
general.idle_wait(2.0)
|
||||
|
||||
# Save as a different level name so we can switch between them.
|
||||
await save_level_as(editor_window, "test_level_2")
|
||||
|
||||
# Create the entities.
|
||||
corrupt_a_id = create_entity_with_name("CorruptA")
|
||||
corrupt_b_id = create_entity_with_name("CorruptB")
|
||||
corrupt_c_id = create_entity_with_name("CorruptC")
|
||||
|
||||
# Make C a slice.
|
||||
slice_file_path, slice_c_file = save_entity_as_slice(corrupt_c_id, "CorruptC")
|
||||
|
||||
# Make C a child of B.
|
||||
azlmbr.components.TransformBus(bus.Event, "SetParent", corrupt_c_id, corrupt_b_id)
|
||||
|
||||
# Make B a slice.
|
||||
slice_file_path, slice_b_file = save_entity_as_slice(corrupt_b_id, "CorruptB")
|
||||
|
||||
# Make B a child of A.
|
||||
azlmbr.components.TransformBus(bus.Event, "SetParent", corrupt_b_id, corrupt_a_id)
|
||||
|
||||
# Make A a slice.
|
||||
slice_file_path, slice_a_file = save_entity_as_slice(corrupt_a_id, "CorruptA")
|
||||
|
||||
# Instantiate another B
|
||||
slice_path = os.path.join(slice_file_path, slice_b_file)
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False)
|
||||
transform = math.Transform_CreateIdentity()
|
||||
slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform)
|
||||
general.idle_wait(0.0)
|
||||
|
||||
# Save.
|
||||
general.save_level()
|
||||
|
||||
# Switch levels while the files are manipulated.
|
||||
general.open_level_no_prompt("test_level_1")
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") != "test_level_1":
|
||||
fail_test("Failed to reload test_level_1")
|
||||
|
||||
# Rename the slice C file.
|
||||
game_folder = editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'GetGameFolder')
|
||||
src = os.path.join(game_folder, slice_file_path, slice_c_file)
|
||||
dest = src + ".backup"
|
||||
os.rename(src, dest)
|
||||
|
||||
# Duplicate the slice B file and rename that.
|
||||
src = os.path.join(game_folder, slice_file_path, slice_b_file)
|
||||
dest = src + ".backup"
|
||||
shutil.copyfile(src, dest)
|
||||
|
||||
# Switch back to the level with the slice instances in and check for error messages.
|
||||
seen_error_dialog = await open_level_check_for_warning("test_level_2")
|
||||
|
||||
if not seen_error_dialog:
|
||||
fail_test("Failed to find error message dialog.")
|
||||
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") != "test_level_2":
|
||||
fail_test("Failed to reload test_level_2")
|
||||
|
||||
# Check that A and B are present but not C
|
||||
corrupt_a_id = general.find_editor_entity("CorruptA")
|
||||
if not corrupt_a_id.isValid():
|
||||
fail_test("No CorruptA entity found after reload")
|
||||
corrupt_b_id = general.find_editor_entity("CorruptB")
|
||||
if not corrupt_b_id.isValid():
|
||||
fail_test("No CorruptB entity found after reload")
|
||||
corrupt_c_id = general.find_editor_entity("CorruptC")
|
||||
if corrupt_c_id.isValid():
|
||||
fail_test("CorruptC entity found after reload")
|
||||
|
||||
# Pop up the advanced push dialog for CorruptB and push it.
|
||||
push_success = await push_slice_to_file(corrupt_b_id)
|
||||
if not push_success:
|
||||
fail_test("Failed to push slice.")
|
||||
|
||||
# Switch levels again so we can reload level2.
|
||||
general.open_level_no_prompt("test_level_1")
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") != "test_level_1":
|
||||
fail_test("Failed to reload test_level_1")
|
||||
|
||||
# Switch back to level 2 and check the error dialog did not appear.
|
||||
seen_error_dialog = await open_level_check_for_warning("test_level_2")
|
||||
|
||||
if seen_error_dialog:
|
||||
fail_test("Level failed to load without errors.")
|
||||
|
||||
# Instantiate another CorruptA and check there are no errors.
|
||||
# Any errors will appear in the console so we need to check that.
|
||||
text_edit.clear()
|
||||
|
||||
slice_path = os.path.join(slice_file_path, slice_a_file)
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False)
|
||||
transform = math.Transform_CreateIdentity()
|
||||
slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform)
|
||||
general.idle_wait(0.0)
|
||||
|
||||
if not check_log_for_text_absence(text_edit, "could not be loaded"):
|
||||
fail_test("Error occurred instantiating CorruptA.")
|
||||
|
||||
print("Corrupt child slice test complete.")
|
||||
|
||||
|
||||
test = TestCorruptChildSlice()
|
||||
test.run()
|
||||
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
C17219006: Create Camera Entity from view
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17219006
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class CreateCameraComponentFromViewTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="create_camera_comp_from_view", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create Camera Entity from view - This can be verified by checking if the entity is created with
|
||||
Camera component and if the Camera is listed in Viewport Camera Selector
|
||||
|
||||
Expected Behavior:
|
||||
An entity is created with a Camera Component attached from the current viewport perspective.
|
||||
The camera entity is added to the Viewport Camera Selector.
|
||||
The Camera entity is labeled "Camera #" where # is replaced by the #number of camera entities in the level.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Trigger the action 'Create camera entity from view' from viewport context menu
|
||||
3) Verify if the entity is created with the name Camera# (Ex: Camera1)
|
||||
4) Verify if the entity has Camera component added
|
||||
5) Verify if Camera1 is listed in the Viewport Camera Selector
|
||||
6) Close Viewport Camera Selector
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Trigger the action 'Create camera entity from view' from viewport context menu
|
||||
# Get the editor window, main window, viewport objects
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
view_port = pyside_utils.find_child_by_hierarchy(main_window, ..., "renderOverlay")
|
||||
view_port = main_window.findChildren(QtWidgets.QWidget, "renderOverlay")[0]
|
||||
|
||||
# Trigger the action
|
||||
pyside_utils.trigger_context_menu_entry(view_port, "Create camera entity from view")
|
||||
|
||||
# 3) Verify if the entity is created with the name Camera# (Ex: Camera1)
|
||||
camera_entity_id = general.find_editor_entity("Camera1")
|
||||
assert camera_entity_id.isValid(), "Entity with Camera component is not created"
|
||||
|
||||
# 4) Verify if the entity has Camera component added
|
||||
assert hydra.has_components(camera_entity_id, ["Camera"]), "Entity do not have a Camera component"
|
||||
|
||||
# 5) Verify if Camera1 is listed in the Viewport Camera Selector
|
||||
# Open Viewport Camera Selector if not opened already
|
||||
if not general.is_pane_visible("Viewport Camera Selector"):
|
||||
general.open_pane("Viewport Camera Selector")
|
||||
if general.is_pane_visible("Viewport Camera Selector"):
|
||||
print("Viewport Camera Selector is opened")
|
||||
|
||||
# Get the Camera Selector object and the list of cameras
|
||||
camera_selector = editor_window.findChildren(QtWidgets.QDockWidget, "Viewport Camera Selector")[0]
|
||||
list_view = camera_selector.findChildren(QtWidgets.QListView)[0]
|
||||
|
||||
# Verify if the Camera1 is present in the list
|
||||
assert pyside_utils.find_child_by_pattern(
|
||||
list_view, "Camera1"
|
||||
), "Camera1 is not listed in the Viewport Camera Selector"
|
||||
|
||||
# 6) Close Viewport Camera Selector
|
||||
camera_selector.close()
|
||||
if not general.is_pane_visible("Viewport Camera Selector"):
|
||||
print("Viewport Camera Selector is closed")
|
||||
|
||||
|
||||
test = CreateCameraComponentFromViewTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
C1519572: Create a dynamic slice
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1519572
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.math as math
|
||||
import azlmbr.slice as slice
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class CreateDynamicSliceTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="create_dynamic_slice", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create a dynamic slice
|
||||
|
||||
Expected Behavior:
|
||||
Dynamic slices can be set/unset
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create new entity
|
||||
3) Create new slice from the newly created entity
|
||||
4) Set an existing slice to dynamic
|
||||
5) Unset the dynamic slice
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def is_slice_dynamic(asset_id):
|
||||
if slice.SliceRequestBus(bus.Broadcast, "IsSliceDynamic", asset_id):
|
||||
return "Dynamic"
|
||||
return "Not Dynamic"
|
||||
|
||||
def path_is_valid_asset(asset_path):
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
|
||||
return asset_id.invoke("IsValid")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Create new entity
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
|
||||
# 3) Create new slice from the newly created entity
|
||||
slice_path = os.path.join("slices", "TestSlice.slice")
|
||||
slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", entity_id, slice_path)
|
||||
self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 10.0)
|
||||
|
||||
# 4) Set an existing slice to dynamic
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False)
|
||||
print(f"Slice Status (Before setting to dynamic): {is_slice_dynamic(asset_id)}")
|
||||
slice.SliceRequestBus(bus.Broadcast, "SetSliceDynamic", asset_id, True)
|
||||
self.wait_for_condition(lambda: slice.SliceRequestBus(bus.Broadcast, "IsSliceDynamic", asset_id), 5.0)
|
||||
print(f"Slice Status (After setting to dynamic): {is_slice_dynamic(asset_id)}")
|
||||
|
||||
# 5) Unset the dynamic slice
|
||||
print(f"Slice Status (Before unsetting to dynamic): {is_slice_dynamic(asset_id)}")
|
||||
slice.SliceRequestBus(bus.Broadcast, "SetSliceDynamic", asset_id, False)
|
||||
self.wait_for_condition(lambda: not slice.SliceRequestBus(bus.Broadcast, "IsSliceDynamic", asset_id), 5.0)
|
||||
print(f"Slice Status (After unsetting to dynamic): {is_slice_dynamic(asset_id)}")
|
||||
|
||||
|
||||
test = CreateDynamicSliceTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6317058: Viewport Entity Creation
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6317058
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.components as components
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
class ViewportEntityCreation(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="viewport_entity_creation: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify if creating new entities via the viewport context menu works correctly.
|
||||
|
||||
Expected Behavior:
|
||||
Right clicking the viewport and selecting the option in the context menu creates an entity under the cursor.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Move the cursor on the viewport
|
||||
3) Copy the position on the level pointed at by the cursor from the viewport's toolbar
|
||||
4) Create a new entity via the context menu
|
||||
5) Verify the entity has been created at the right position
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
|
||||
# Grab the necessary widgets
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
viewport_window = main_window.findChild(QtWidgets.QMainWindow)
|
||||
overlay = viewport_window.findChild(QtWidgets.QWidget, "renderOverlay")
|
||||
posCtrl = viewport_window.findChild(QtWidgets.QWidget, "m_posCtrl")
|
||||
labels = ["X", "Y", "Z"]
|
||||
pos = [0.0, 0.0, 0.0]
|
||||
|
||||
# 2) Click on the Viewport to focus
|
||||
QtTest.QTest.mouseClick(overlay, Qt.LeftButton)
|
||||
|
||||
# Trigger a Move to update position in viewport toolbar
|
||||
QtTest.QTest.mouseMove(overlay)
|
||||
|
||||
# 3) Get position values
|
||||
for i, label in enumerate(labels):
|
||||
vector_element = posCtrl.findChild(QtWidgets.QWidget, label)
|
||||
line_edit = vector_element.findChild(QtWidgets.QLineEdit)
|
||||
pos[i] = float(line_edit.text())
|
||||
|
||||
# 4) Trigger Context Menu and click Create Entity
|
||||
pyside_utils.trigger_context_menu_entry(overlay.parent(), "Create entity")
|
||||
|
||||
# Get Selected Entity (it will be the newly created one)
|
||||
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
|
||||
newEntityId = selectedTestEntityIds[0]
|
||||
|
||||
# Get Position of new Entity
|
||||
position = components.TransformBus(bus.Event, "GetWorldTranslation", newEntityId)
|
||||
|
||||
# 5) Verify the positions match (tolerance threshold is 1.0 since this is based on mouseClick
|
||||
# right-click position which has some room for error)
|
||||
POSITION_TOLERANCE = 1.0
|
||||
if (math.Math_IsClose(pos[0], position.x, POSITION_TOLERANCE) and
|
||||
math.Math_IsClose(pos[1], position.y, POSITION_TOLERANCE) and
|
||||
math.Math_IsClose(pos[2], position.z, POSITION_TOLERANCE)):
|
||||
print("New Entity created in the correct position")
|
||||
|
||||
|
||||
test = ViewportEntityCreation()
|
||||
test.run()
|
||||
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C1506874: Create Input Bindings File
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1506874
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class CreateInputBindingFileTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="create_inputbindings_file", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create a new inputbinding file
|
||||
|
||||
Expected Behavior:
|
||||
The newly created inputbindings file is loaded into the Asset Editor.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create new inputbindings file
|
||||
3) Verify if file is created
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
INPUTBINDING_FILE_PATH = "SamplesProject/temp.inputbindings"
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Create new inputbindings file
|
||||
input_bindings_type_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetTypeByDisplayName", "Input Bindings"
|
||||
)
|
||||
editor.AssetEditorRequestsBus(bus.Broadcast, "CreateNewAsset", input_bindings_type_id)
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", INPUTBINDING_FILE_PATH)
|
||||
|
||||
# 3) Verify if file is created
|
||||
self.wait_for_condition(lambda: os.path.exists(INPUTBINDING_FILE_PATH), 0.5)
|
||||
print(f"New inputbindings file created: {os.path.exists(INPUTBINDING_FILE_PATH)}")
|
||||
|
||||
|
||||
test = CreateInputBindingFileTest()
|
||||
test.run_test()
|
||||
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6351273: Create a new level
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6351273
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestCreateNewLevel(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="create_new_level: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create a new level and verify if the level is loaded properly.
|
||||
|
||||
Expected Behavior:
|
||||
A new level is created and loaded into the editor.
|
||||
|
||||
Test Steps:
|
||||
1) Create new level
|
||||
2) Verify if the new level is loaded
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
print("focus Changed")
|
||||
active_modal_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_modal_widget:
|
||||
new_level_dlg = active_modal_widget.findChild(QtWidgets.QWidget, "CNewLevelDialog")
|
||||
if new_level_dlg:
|
||||
if new_level_dlg.windowTitle() == "New Level":
|
||||
print("New Level dialog opened")
|
||||
grp_box = new_level_dlg.findChild(QtWidgets.QGroupBox, "STATIC_GROUP1")
|
||||
level_name = grp_box.findChild(QtWidgets.QLineEdit, "LEVEL")
|
||||
level_name.setText(self.args["level"])
|
||||
level_folders = grp_box.findChild(QtWidgets.QComboBox, "LEVEL_FOLDERS")
|
||||
level_folders.setCurrentText("Levels/")
|
||||
button_box = new_level_dlg.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
def on_action_triggered():
|
||||
print("New Level Action triggered")
|
||||
|
||||
try:
|
||||
# 1) Create new level
|
||||
# Wait 2.0s for editor to load
|
||||
general.idle_wait(2.0)
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "File", "New Level")
|
||||
action.triggered.connect(on_action_triggered)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(on_action_triggered)
|
||||
|
||||
# 2) Verify if the new level is loaded
|
||||
general.idle_wait(3.0)
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") == self.args["level"]:
|
||||
print("Create and load new level: SUCCESS")
|
||||
else:
|
||||
print("Create and load new level: FAILED")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
print("Disconnecting focusChanged signal")
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
|
||||
test = TestCreateNewLevel()
|
||||
test.run()
|
||||
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C6321576: Basic Function: Customize Keyboard
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6321576
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtGui, QtTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestCustomizeKeyboard(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="customize_keyboard: ")
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Assign any new shortcut keys to menu command.
|
||||
|
||||
Expected Behavior:
|
||||
Keyboard customizations can be changed, saved, and function properly.
|
||||
|
||||
Test Steps:
|
||||
1) Open the Customize Keyboard dialog and Assign any button combination as new shortcut.
|
||||
2) Use the newly assigned hotkey.
|
||||
3) Restore the settings to default
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Open the Customize Keyboard dialog and Assign any button combination as new shortcut
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
action = pyside_utils.find_child_by_pattern(
|
||||
editor_window, {"text": "Customize &Keyboard...", "type": QtWidgets.QAction}
|
||||
)
|
||||
pyside_utils.trigger_action_async(action)
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
if active_modal_widget:
|
||||
keyboard_customizer = active_modal_widget.findChild(QtWidgets.QDialog, "CustomizeKeyboardDialog")
|
||||
if keyboard_customizer:
|
||||
print("Customize keyboard window opened successfully")
|
||||
keySequenceEdit = pyside_utils.find_child_by_pattern(keyboard_customizer, "keySequenceEdit")
|
||||
assign_button = pyside_utils.find_child_by_pattern(keyboard_customizer, "assignButton")
|
||||
categories = keyboard_customizer.findChild(QtWidgets.QComboBox, "categories")
|
||||
commandsView = keyboard_customizer.findChild(QtWidgets.QListView, "commandsView")
|
||||
|
||||
# Assign a shortcut to the Tools -> Asset Editor action
|
||||
categories.setCurrentText("Tools")
|
||||
asset_editor_index = pyside_utils.find_child_by_pattern(commandsView, "Asset Editor")
|
||||
commandsView.setCurrentIndex(asset_editor_index)
|
||||
keySequenceEdit.setKeySequence(QtGui.QKeySequence(Qt.CTRL + Qt.Key_M))
|
||||
|
||||
assign_button.setEnabled(True)
|
||||
if assign_button.isEnabled():
|
||||
app = QtWidgets.QApplication.instance()
|
||||
pyside_utils.click_button_async(assign_button)
|
||||
|
||||
# We need to handle in case this test had failed previously, the shortcut might
|
||||
# already be assigned, in which case there will be a second modal dialog
|
||||
# confirmation to overwrite it
|
||||
try:
|
||||
await pyside_utils.wait_for_condition(lambda: app.activeModalWidget() and app.activeModalWidget() != active_modal_widget, timeout=0.1)
|
||||
confirmation_popup = app.activeModalWidget()
|
||||
message_box = confirmation_popup.findChild(QtWidgets.QMessageBox)
|
||||
button = message_box.button(QtWidgets.QMessageBox.Yes)
|
||||
pyside_utils.click_button_async(button)
|
||||
await pyside_utils.wait_for_destroyed(confirmation_popup)
|
||||
except pyside_utils.EventLoopTimeoutException:
|
||||
# If this timed out, it just means that the shortcut wasn't already assigned
|
||||
pass
|
||||
|
||||
# "Close" button acts as "Save and Close" in this widget
|
||||
button_box = pyside_utils.find_child_by_pattern(keyboard_customizer, "buttonBox")
|
||||
button = button_box.button(QtWidgets.QDialogButtonBox.Close)
|
||||
pyside_utils.click_button_async(button)
|
||||
await pyside_utils.wait_for_destroyed(active_modal_widget)
|
||||
|
||||
# 2) Use the newly assigned hotkey.
|
||||
general.close_pane("Asset Editor")
|
||||
QtTest.QTest.keyPress(editor_window, Qt.Key_M, Qt.ControlModifier)
|
||||
success = await pyside_utils.wait_for_condition(lambda: general.is_pane_visible("Asset Editor"))
|
||||
if success:
|
||||
print("New shortcut works : Asset Editor opened")
|
||||
|
||||
# Close it now since we are going to verify the shortcut no longer works
|
||||
# after restoring the default settings
|
||||
general.close_pane("Asset Editor")
|
||||
|
||||
# 3) Restore the settings to default
|
||||
pyside_utils.trigger_action_async(action)
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
if active_modal_widget:
|
||||
button_box = pyside_utils.find_child_by_pattern(active_modal_widget, "buttonBox")
|
||||
restore_defaults = pyside_utils.find_child_by_pattern(button_box, "Restore Defaults")
|
||||
pyside_utils.click_button_async(restore_defaults)
|
||||
confirmation_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
if confirmation_modal_widget:
|
||||
message_box = confirmation_modal_widget.findChild(QtWidgets.QMessageBox)
|
||||
button = message_box.button(QtWidgets.QMessageBox.Yes)
|
||||
button.click()
|
||||
|
||||
# "Close" button acts as "Save and Close" in this widget
|
||||
close_button = button_box.button(QtWidgets.QDialogButtonBox.Close)
|
||||
pyside_utils.click_button_async(close_button)
|
||||
await pyside_utils.wait_for_destroyed(active_modal_widget)
|
||||
|
||||
# Verify if setting restored
|
||||
QtTest.QTest.keyClick(editor_window, Qt.Key_M, Qt.ControlModifier)
|
||||
if not general.is_pane_visible("Asset Editor"):
|
||||
print("Default shortcuts restored : Asset Editor stays closed")
|
||||
|
||||
|
||||
test = TestCustomizeKeyboard()
|
||||
test.run()
|
||||
@@ -0,0 +1,155 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C1510643: Deleting Entities in the Entity Outliner
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1510643
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestDeletingEntitiesFromOutliner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="deleting_entities_from_outliner: ", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create a nested group of Entities with parent and 2 children.
|
||||
Right click on each of the entities and select "Delete".
|
||||
Undo the deletion of those entites.
|
||||
|
||||
Expected Behavior:
|
||||
Deleting a Child entity does not delete the parent.
|
||||
The child entity is restored as part of the hierarchy.
|
||||
Deleting the Parent entity deletes all child entities linked to it.
|
||||
The entity hierarchy is restored.
|
||||
|
||||
Test Steps:
|
||||
1) Create a nested group of Entities and verify deleting the child does not destroy the parent
|
||||
1.1) Create group of entities
|
||||
1.2) Delete child
|
||||
1.3) Verify parent exists
|
||||
2) Undo the deletion of the child entity and verify the same is restored
|
||||
2.1) Undo the deletion
|
||||
2.2) verify child entity exists
|
||||
3) Delete the parent entity and verify all child entities deleted
|
||||
3.1) Delete parent
|
||||
3.2) Verify all child entities deleted
|
||||
4) Undo the deletion of the parent entity and verify hierarchy is restored
|
||||
4.1) Undo the deletion
|
||||
4.2) Verify all entities exist
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_entity_count_by_id(entity_id):
|
||||
entity_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
|
||||
searchFilter = EntityId.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = EntityId.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
async def delete_entity(entity_id, entity_name):
|
||||
"""
|
||||
Delete an entity using PySide Right-Click and Delete.
|
||||
:param entity_id: used to find and delete the entity
|
||||
:param entity_name: not dynamically grabbed from entity or used in delete code but is used for printing out a comment statement for testrunner
|
||||
:return None
|
||||
"""
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
entity_outliner = main_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
object_tree = entity_outliner.findChild(QtWidgets.QTreeView, "m_objectTree")
|
||||
index_to_delete = pyside_utils.find_child_by_pattern(object_tree, entity_name)
|
||||
object_tree.setCurrentIndex(index_to_delete)
|
||||
await pyside_utils.trigger_context_menu_entry(object_tree, "Delete", index=index_to_delete)
|
||||
|
||||
if get_entity_count_by_id(entity_id) == 0:
|
||||
print(f"{entity_name} deleted succesfully")
|
||||
|
||||
# Create a level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 1) Create a nested group of Entities and verify deleting the child does not destroy the parent
|
||||
# 1.1) Create group of entities
|
||||
parent_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId.EntityId())
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", parent_entity_id, "Parent entity")
|
||||
if get_entity_count_by_id(parent_entity_id) ==1:
|
||||
print("Parent Entity created")
|
||||
|
||||
child_entity_1 = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", parent_entity_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_entity_1, "Child entity 1")
|
||||
child_entity_2 = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", parent_entity_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_entity_2, "Child entity 2")
|
||||
if get_entity_count_by_id(child_entity_1) == 1 and get_entity_count_by_id(child_entity_1) == 1:
|
||||
print("Child Entities created")
|
||||
|
||||
# 1.2) Delete child
|
||||
await delete_entity(child_entity_1, "Child entity 1")
|
||||
|
||||
# 1.3) Verify parent exists
|
||||
if get_entity_count_by_id(parent_entity_id) != 0:
|
||||
print("Deleting a Child entity does not delete the parent")
|
||||
|
||||
# 2) Undo the deletion of the child entity and verify the same is restored
|
||||
# 2.1) Undo the deletion
|
||||
general.undo()
|
||||
|
||||
# 2.2) verify child entity exists
|
||||
success = await pyside_utils.wait_for_condition(lambda: get_entity_count_by_id(child_entity_1) != 0)
|
||||
if success:
|
||||
print("Child entity restored successfully")
|
||||
|
||||
# 3) Delete the parent entity and verify all child entities deleted
|
||||
# 3.1) Delete parent
|
||||
await delete_entity(parent_entity_id, "Parent entity")
|
||||
|
||||
# 3.2) Verify all child entities deleted
|
||||
if get_entity_count_by_id(child_entity_1) == 0 and get_entity_count_by_id(child_entity_1) == 0:
|
||||
print("Deleting the Parent entity deletes all child entities linked to it")
|
||||
|
||||
# 4) Undo the deletion of the parent entity and verify hierarchy is restored
|
||||
# 4.1) Undo the deletion
|
||||
general.undo()
|
||||
|
||||
# 4.2) Verify all entities exist
|
||||
success = await pyside_utils.wait_for_condition(lambda:
|
||||
(get_entity_count_by_id(parent_entity_id) != 0
|
||||
and get_entity_count_by_id(child_entity_1) != 0
|
||||
and get_entity_count_by_id(child_entity_2) != 0))
|
||||
if success:
|
||||
print("Entity hierarchy is restored")
|
||||
|
||||
|
||||
test = TestDeletingEntitiesFromOutliner()
|
||||
test.run()
|
||||
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C1564083 : Edit Mode Toolbar
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1564083
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as editor_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestEditModeToolbar(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="edit_mode_toolbar_function: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Edit mode toolbar options and verify if all the options are functional.
|
||||
|
||||
Expected Behavior:
|
||||
All options available in the Edit Mode Toolbar function as intended.
|
||||
|
||||
Test Steps:
|
||||
1) Create/Open a level
|
||||
2) Open the Edit mode Toolbar
|
||||
3) Use every option in the toolbar.
|
||||
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
editors_toolbar = editor_window.findChild(QtWidgets.QToolBar, "EditMode")
|
||||
|
||||
def get_entity_count(entity_id):
|
||||
searchFilter = EntityId.SearchFilter()
|
||||
searchFilter.names = [editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)]
|
||||
entities = EntityId.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
def get_tool_button(option):
|
||||
button = pyside_utils.find_child_by_pattern(editors_toolbar, option)
|
||||
if button.text() == option:
|
||||
return button
|
||||
|
||||
def wait_condition_print(function, wait_time, print_message=""):
|
||||
self.wait_for_condition(function, wait_time)
|
||||
if function() and print_message != "":
|
||||
print(print_message)
|
||||
|
||||
# 1) Create new level with an Entity
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Open the Editors Toolbar
|
||||
if not editors_toolbar.isVisible():
|
||||
editors_toolbar.toggleViewAction().trigger()
|
||||
if editors_toolbar.isVisible():
|
||||
print("Editors tool bar opened successfully")
|
||||
|
||||
# 3) Use every option in the toolbar.
|
||||
# i) Undo
|
||||
entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId.EntityId())
|
||||
self.wait_for_condition(lambda: get_tool_button("Undo").isEnabled(), 2.0)
|
||||
initial_count = get_entity_count(entity_id)
|
||||
get_tool_button("Undo").click()
|
||||
wait_condition_print(lambda: get_entity_count(entity_id) != initial_count, 2.0, "Undo tool button is functional")
|
||||
|
||||
# ii) Redo
|
||||
self.wait_for_condition(lambda: get_tool_button("Redo").isEnabled(), 2.0)
|
||||
get_tool_button("Redo").click()
|
||||
wait_condition_print(lambda: get_entity_count(entity_id) == initial_count, 2.0, "Redo tool button is functional")
|
||||
|
||||
# iii) Move
|
||||
move_button = get_tool_button("Move")
|
||||
if not move_button.isChecked(): move_button.click()
|
||||
if move_button.isChecked(): print("Move tool button is accesible")
|
||||
|
||||
# iv) Rotate
|
||||
rotate_button = get_tool_button("Rotate")
|
||||
if not rotate_button.isChecked(): rotate_button.click()
|
||||
if rotate_button.isChecked(): print("Rotate tool button is accesible")
|
||||
|
||||
# v) Scale
|
||||
scale_button = get_tool_button("Scale")
|
||||
if not scale_button.isChecked(): scale_button.click()
|
||||
if scale_button.isChecked(): print("Scale tool button is accesible")
|
||||
|
||||
# vi) Play Game
|
||||
get_tool_button("Play Game").click()
|
||||
wait_condition_print(lambda : general.is_in_game_mode(), 3.0, "Play game tool button is responsive")
|
||||
general.exit_game_mode()
|
||||
|
||||
# vii) Snap to grid
|
||||
# Wait for the snap_to_grid_text to become enabled since in the previous step we are leaving game mode,
|
||||
# so it might still be disabled momentarily
|
||||
snap_to_grid = get_tool_button("Snap To Grid")
|
||||
snap_grid_widget = snap_to_grid.parent()
|
||||
snap_to_grid.setChecked(True)
|
||||
snap_to_grid_text = snap_grid_widget.findChild(QtWidgets.QDoubleSpinBox).findChild(QtWidgets.QLineEdit)
|
||||
self.wait_for_condition(lambda: snap_to_grid_text.isEnabled())
|
||||
if snap_to_grid.isChecked() == snap_to_grid_text.isEnabled():
|
||||
print("Snap to grid tool button is responsive")
|
||||
|
||||
# viii) Snap Angle
|
||||
# Wait for the snap_angle_text to become enabled since in the previous step we are leaving game mode,
|
||||
# so it might still be disabled momentarily
|
||||
snap_angle = get_tool_button("Snap angle")
|
||||
snap_angle_widget = snap_angle.parent()
|
||||
snap_angle.setChecked(True)
|
||||
snap_angle_text = snap_angle_widget.findChild(QtWidgets.QDoubleSpinBox).findChild(QtWidgets.QLineEdit)
|
||||
self.wait_for_condition(lambda: snap_angle_text.isEnabled())
|
||||
if snap_angle.isChecked() == snap_angle_text.isEnabled():
|
||||
print("Snap angle tool button is responsive")
|
||||
|
||||
|
||||
test = TestEditModeToolbar()
|
||||
test.run_test()
|
||||
@@ -0,0 +1,156 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C697735: Custom layouts can be saved
|
||||
C697736: Custom/Default layouts can be loaded
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestLoadLayout(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="load_layout")
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Creates a custom Editor layout, resets to the default options, and then reloads the custom layout.
|
||||
|
||||
Expected Behavior:
|
||||
Pane/tool layout matches expected results for both default and custom layout.
|
||||
|
||||
Test Steps:
|
||||
1) Open Editor
|
||||
2) Open a few tools and dock them/leave floating
|
||||
3) Save the custom layout
|
||||
4) Restore the default layout and verify proper tools/panes are open
|
||||
5) Load the custom layout and verify proper tools/panes are open
|
||||
6) Delete the custom layout to cleanup
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
custom_layout_name = "custom_layout_test"
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
menu_paths = [
|
||||
("Layouts", "Save Layout"),
|
||||
("Layouts", "Restore Default Layout"),
|
||||
("Layouts", custom_layout_name, "Load"),
|
||||
("Layouts", custom_layout_name, "Delete")
|
||||
]
|
||||
|
||||
def on_save_layout_trigger():
|
||||
active_modal_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_modal_widget:
|
||||
save_level_as_dialogue = active_modal_widget.findChild(QtWidgets.QInputDialog)
|
||||
if save_level_as_dialogue.windowTitle() == "Layout Name":
|
||||
print("The 'Layout Name' dialog appeared")
|
||||
layout_name_field = active_modal_widget.findChild(QtWidgets.QLineEdit)
|
||||
layout_name_field.setText(custom_layout_name)
|
||||
button_box = active_modal_widget.findChild(QtWidgets.QDialogButtonBox)
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
def on_restore_default_layout_trigger():
|
||||
active_modal_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_modal_widget:
|
||||
restore_default_layout_dialog = active_modal_widget.findChild(QtWidgets.QMessageBox)
|
||||
if restore_default_layout_dialog.windowTitle() == "Restore Default Layout":
|
||||
print("The 'Restore Default Layout' dialog appeared")
|
||||
button_box = active_modal_widget.findChildren(QtWidgets.QDialogButtonBox)[0]
|
||||
button_box.button(QtWidgets.QDialogButtonBox.RestoreDefaults).click()
|
||||
|
||||
def on_custom_layout_load_trigger():
|
||||
print("Restoring default layout")
|
||||
|
||||
def on_delete_custom_layout_trigger():
|
||||
print("Deleting custom layout")
|
||||
active_modal_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_modal_widget:
|
||||
delete_custom_layout_dialog_button_box = active_modal_widget.findChild(QtWidgets.QDialogButtonBox)
|
||||
if delete_custom_layout_dialog_button_box:
|
||||
print("The 'Delete Layout' dialog appeared")
|
||||
delete_custom_layout_dialog_button_box.button(QtWidgets.QDialogButtonBox.Yes).click()
|
||||
|
||||
def trigger_view_menu_option(menu_path, on_trigger):
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_trigger)
|
||||
try:
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "View", *menu_path)
|
||||
action.trigger()
|
||||
print(f"{action.iconText()} Action triggered")
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_trigger)
|
||||
|
||||
# Open a few floating tools
|
||||
general.open_pane('Landscape Canvas')
|
||||
general.open_pane('Track View')
|
||||
general.open_pane('UI Editor')
|
||||
|
||||
# Close a few open tools
|
||||
general.close_pane('Console')
|
||||
general.close_pane('Asset Browser')
|
||||
|
||||
# Verify proper tools are open in the Editor prior to saving layout
|
||||
landscape_canvas_open = general.is_pane_visible('Landscape Canvas')
|
||||
track_view_open = general.is_pane_visible('Track View')
|
||||
ui_editor_open = general.is_pane_visible('UI Editor')
|
||||
console_closed = not general.is_pane_visible('Console')
|
||||
asset_browser_closed = not general.is_pane_visible('Asset Browser')
|
||||
self.test_success = landscape_canvas_open and track_view_open and ui_editor_open and console_closed \
|
||||
and asset_browser_closed
|
||||
if self.test_success:
|
||||
print('Custom layout setup complete')
|
||||
|
||||
# Save layout
|
||||
trigger_view_menu_option(menu_paths[0], on_save_layout_trigger)
|
||||
|
||||
# Trigger Restore Default Layout option and click Restore Defaults on popup dialog
|
||||
trigger_view_menu_option(menu_paths[1], on_restore_default_layout_trigger)
|
||||
|
||||
# Verify proper panes are open with Default Layout
|
||||
console_open = general.is_pane_visible('Console')
|
||||
asset_browser_open = general.is_pane_visible('Asset Browser')
|
||||
self.test_success = self.test_success and console_open and asset_browser_open
|
||||
general.idle_wait(2.0)
|
||||
|
||||
# Trigger Load of saved custom layout
|
||||
trigger_view_menu_option(menu_paths[2], on_custom_layout_load_trigger)
|
||||
|
||||
# Verify proper panes are open with saved custom layout
|
||||
landscape_canvas_open = general.is_pane_visible('Landscape Canvas')
|
||||
track_view_open = general.is_pane_visible('Track View')
|
||||
ui_editor_open = general.is_pane_visible('UI Editor')
|
||||
self.test_success = self.test_success and landscape_canvas_open and track_view_open and ui_editor_open
|
||||
general.idle_wait(2.0)
|
||||
|
||||
# Restore to defaults and delete custom layout
|
||||
trigger_view_menu_option(menu_paths[1], on_restore_default_layout_trigger)
|
||||
trigger_view_menu_option(menu_paths[3], on_delete_custom_layout_trigger)
|
||||
|
||||
# Verify that custom layout has been cleaned up
|
||||
pyside_utils.get_action_for_menu_path(editor_window, "View", *menu_paths[2])
|
||||
|
||||
|
||||
test = TestLoadLayout()
|
||||
test.run()
|
||||
@@ -0,0 +1,103 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C2174442: Enter/Exit Component Mode
|
||||
https://testrail.agscollab.com/index.php?/cases/view/2174442
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as EntityId
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestEnterExitComponentMode(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="enter_exit_component_mode: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Enter/Exit Component Mode
|
||||
|
||||
Expected Behavior:
|
||||
Component Mode can be entered and exited.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create an entity with Box Shape component
|
||||
3) Click the "Edit" button on the component to enter into component mode
|
||||
4) Click the "Done" button on the component to exit from component mode
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def on_entered_component_mode(parameters):
|
||||
print("Entered component mode")
|
||||
|
||||
def on_left_component_mode(parameters):
|
||||
print("Left component mode")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# Setup the handler to listen for Editor Component Mode notifications
|
||||
context_id = editor.EditorEntityContextRequestBus(bus.Broadcast, "GetEditorEntityContextId")
|
||||
handler = bus.NotificationHandler("EditorComponentModeNotificationBus")
|
||||
handler.connect(context_id)
|
||||
handler.add_callback("EnteredComponentMode", on_entered_component_mode)
|
||||
handler.add_callback("LeftComponentMode", on_left_component_mode)
|
||||
|
||||
# 2) Create an entity with Box Shape component
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
general.clear_selection()
|
||||
general.select_object(editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id))
|
||||
hydra.add_component("Box Shape", entity_id)
|
||||
|
||||
# 3) Click the "Edit" button on the component to enter into component mode
|
||||
# Retrieve the TypeId for the Box Shape component
|
||||
type_ids = editor.EditorComponentAPIBus(bus.Broadcast, "FindComponentTypeIdsByEntityType", ["Box Shape"],
|
||||
EntityId.EntityType().Game)
|
||||
box_shape_type_id = type_ids[0]
|
||||
|
||||
# Enter component mode for the Box Shape (Same as pressing the "Edit" button on the Box Shape component)
|
||||
editor.ComponentModeSystemRequestBus(bus.Broadcast, "EnterComponentMode", box_shape_type_id)
|
||||
|
||||
# 4) Click the "Done" button on the component to exit from component mode
|
||||
# End component mode (Same as pressing the "Done" button on the Box Shape component)
|
||||
editor.ComponentModeSystemRequestBus(bus.Broadcast, "EndComponentMode")
|
||||
|
||||
|
||||
test = TestEnterExitComponentMode()
|
||||
test.run()
|
||||
@@ -0,0 +1,114 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C17218882: Entity duplication in Entity Outliner
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17218882
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest
|
||||
from PySide2.QtCore import Qt, QObject, QEvent, QPoint
|
||||
from PySide2.QtGui import QContextMenuEvent
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
from re import compile as regex
|
||||
|
||||
|
||||
class TestEntityDuplication(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="entity_duplication_entity_outliner: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify if the entities in the Entity Outliner can be duplicated.
|
||||
|
||||
Expected Behavior:
|
||||
Entities can be duplicated and can be undone.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create a new entity by clicking "New Entity"
|
||||
3) Duplicate entity using shortcut CTRL+D
|
||||
4) Undo entity duplication using CTRL+Z
|
||||
5) Duplicate entity using Right click "Duplicate" Action
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_entity_count_name(entity_name="Entity2"):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Create a new entity by clicking "New Entity"
|
||||
general.clear_selection()
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
outliner_widget = pyside_utils.find_child_by_hierarchy(editor_window,
|
||||
...,
|
||||
dict(windowTitle=regex("Entity Outliner.*")),
|
||||
...,
|
||||
"m_objectList").parent()
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
|
||||
action = pyside_utils.find_child_by_pattern(outliner_widget, "Create Entity")
|
||||
action.trigger()
|
||||
if get_entity_count_name() == 1:
|
||||
print("First entity created")
|
||||
|
||||
# 3) Duplicate entity using shortcut CTRL+D
|
||||
for index in range(3):
|
||||
QtTest.QTest.keyPress(outliner_widget, Qt.Key_D, Qt.ControlModifier)
|
||||
success = lambda: get_entity_count_name() == index+2
|
||||
self.wait_for_condition(success)
|
||||
print(f"Entity duplicated using shortcut - {index+1} success: {success()}")
|
||||
|
||||
# 4) Undo entity duplication using CTRL+Z
|
||||
QtTest.QTest.keyPress(outliner_widget, Qt.Key_Z, Qt.ControlModifier)
|
||||
success = lambda: get_entity_count_name() == 3
|
||||
self.wait_for_condition(success)
|
||||
print(f"Entity duplication Undo success: {success()}")
|
||||
|
||||
# 5) Duplicate entity using Right click "Duplicate" Action
|
||||
general.select_object("Entity2")
|
||||
for index in range(3):
|
||||
index_to_duplicate = pyside_utils.find_child_by_pattern(tree, "Entity2")
|
||||
pyside_utils.trigger_context_menu_entry(tree, "Duplicate", index=index_to_duplicate)
|
||||
success = lambda: get_entity_count_name() == index+4
|
||||
self.wait_for_condition(success)
|
||||
print(f"Entity duplication using right click - {index+1} success: {success()}")
|
||||
|
||||
|
||||
test = TestEntityDuplication()
|
||||
test.run()
|
||||
@@ -0,0 +1,121 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C6384955: Basic Workflow: Entity Manipulation in the Outliner
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6384955
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as editor_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class BasicWorkflow(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="entity_manipulation_in_outliner", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Manipulate entities in the Entity Outliner
|
||||
|
||||
Expected:
|
||||
Entities/Children can be created/restructured
|
||||
|
||||
Test Steps:
|
||||
0) Open new test level
|
||||
1) Create the Entities/Child Entities
|
||||
1.1) Create Parent Entity
|
||||
1.2) Create Child Entity
|
||||
1.3) Create Grandchild Entity
|
||||
1.4) Entities/Children can be created in Outliner and are displayed properly
|
||||
2) Move the grandchild entity (child of the child entity) to be a child of the Parent (top level) entity
|
||||
3) Verify Entity Heirarchies can be restructured from the Entity Outliner
|
||||
4) Undo Entity Restructure (Ctrl+Z)
|
||||
5) Verify Entity Hierarchy Restructure is undone
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def verify_parent(entity_to_check, expected_parent_entity, additional_pretext: Optional[str] = ""):
|
||||
entity_to_check.get_parent_info()
|
||||
actual_parent_id = entity_to_check.parent_id
|
||||
actual_parent_name = entity_to_check.parent_name
|
||||
|
||||
# fmt:off
|
||||
print(f"{additional_pretext} The parent entity of {entity_to_check.name}: Expected: {expected_parent_entity.name}; Actual: {actual_parent_name}")
|
||||
assert actual_parent_id == expected_parent_entity.id, \
|
||||
"The IDs of the actual and expected parent entities did not match"
|
||||
# fmt:on
|
||||
|
||||
# 0) Create or open any level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 1) Create the Entities/Child Entities
|
||||
entity_postition = math.Vector3(125.0, 136.0, 32.0)
|
||||
components_to_add = []
|
||||
|
||||
# 1.1) Create an entity called "Parent"
|
||||
parent_entity = editor_utils.Entity("Parent")
|
||||
parent_entity.create_entity(entity_postition, components_to_add)
|
||||
|
||||
# 1.2) Create a child entity for "Parent" named "Child"
|
||||
child_entity = editor_utils.Entity("Child")
|
||||
child_entity.create_entity(entity_postition, components_to_add, parent_entity.id)
|
||||
|
||||
# 1.3) Create a child entity for "Child" named "Grandchild"
|
||||
grandchild_entity = editor_utils.Entity("Grandchild")
|
||||
grandchild_entity.create_entity(entity_postition, components_to_add, child_entity.id)
|
||||
|
||||
# 1.4) Verify the hierarchy of the entities (Parent>Child>Grandchild)
|
||||
# Child should be a child to Parent
|
||||
verify_parent(child_entity, parent_entity, "Original Check:")
|
||||
# Grandchild should be a child to Child
|
||||
verify_parent(grandchild_entity, child_entity, "Original Check:")
|
||||
|
||||
# 2) Click and drag the Grandchild from the Child entity to the Parent entity
|
||||
grandchild_entity.set_test_parent_entity(parent_entity)
|
||||
|
||||
# 3) Verify the Granchild entity is now a child of the Parent Entity
|
||||
verify_parent(grandchild_entity, parent_entity, "After Move:")
|
||||
|
||||
# 4) Press Ctrl+Z using hydra utilities to undo the moving of the Grandchild
|
||||
general.undo()
|
||||
|
||||
# 5) Verify the hierarchy has returned to the original orientation
|
||||
verify_parent(grandchild_entity, child_entity, "After Undo:")
|
||||
|
||||
|
||||
test = BasicWorkflow()
|
||||
test.run()
|
||||
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
C2202976: Entity Selection - Entity Outliner
|
||||
https://testrail.agscollab.com/index.php?/cases/view/2202976
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.math as math
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
from re import compile as regex
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class EntitySelectionEntityOutlinerTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="entity_selection_entity_outliner", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Entity Selection - Entity Outliner - We need to verify if the Entity outliner works as expected
|
||||
for the entity selections by verifying the selected items.
|
||||
|
||||
Expected Behavior:
|
||||
Single clicking entities will swap selection between entities.
|
||||
CTRL+Clicking entities will add to/remove from the selection group.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create 3 new entities in the outliner
|
||||
3) Get Model Index for all the entities
|
||||
4) Verify single click
|
||||
5) Verify CTRL+click
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def verify_selected_index(expected_entity_list):
|
||||
# NOTE: selectedIndexes() seems to return 2 extra elements for each item seleted whose data() is None
|
||||
# So removing the items whose data is None and considering only the selected items having data.
|
||||
selected_indexes = [i.data() for i in tree.selectedIndexes() if i.data()]
|
||||
return sorted(selected_indexes) == sorted(expected_entity_list)
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# Get the editor window object
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# Get the outliner widget object based on the window title
|
||||
outliner_widget = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Outliner.*")), ..., "m_objectList"
|
||||
).parent()
|
||||
|
||||
# Get the object tree in the entity outliner
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
|
||||
# 2) Create 3 new entities in the outliner
|
||||
entity_postition = math.Vector3(125.0, 136.0, 32.0)
|
||||
entity_list = ["Entity2", "Entity3", "Entity4"]
|
||||
[hydra.Entity(name).create_entity(entity_postition, []) for name in entity_list]
|
||||
|
||||
# 3) Get Model Index for all the entities
|
||||
model_index_2, model_index_3, model_index_4 = [
|
||||
pyside_utils.find_child_by_pattern(tree, name) for name in entity_list
|
||||
]
|
||||
|
||||
# 4) Verify single click
|
||||
# click on Entity2 and verify if it is selected
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_2)
|
||||
print(f"Single entity selected on first click: {verify_selected_index(['Entity2'])}")
|
||||
|
||||
# click on Entity3 and verify if only that is selected
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_3)
|
||||
print(f"Single entity selected on second click: {verify_selected_index(['Entity3'])}")
|
||||
|
||||
# 5) Verify CTRL+click
|
||||
# CTRL+click on Entity2 and verify if Entity2 and Entity3 are selected as Entity is already selected
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_2, modifier=QtCore.Qt.ControlModifier)
|
||||
print(
|
||||
f"CTRL+click worked for adding selected elements (2 elements): {verify_selected_index(['Entity2', 'Entity3'])}"
|
||||
)
|
||||
|
||||
# CTRL+click on Entity4 and verify if Entity 2, 3, 4 are selected
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_4, modifier=QtCore.Qt.ControlModifier)
|
||||
print(
|
||||
f"CTRL+click worked for adding selected elements (3 elements): {verify_selected_index(['Entity2', 'Entity3', 'Entity4'])}"
|
||||
)
|
||||
|
||||
# CTRL+click on already selected element (Entity2) to verify if it is removed from selected items
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_2, modifier=QtCore.Qt.ControlModifier)
|
||||
print(
|
||||
f"CTRL+click worked for removing already selected elements: {verify_selected_index(['Entity3', 'Entity4'])}"
|
||||
)
|
||||
|
||||
test = EntitySelectionEntityOutlinerTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C15167491: Export a level
|
||||
https://testrail.agscollab.com/index.php?/cases/view/15167491
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestExportALevel(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="export_level: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Export a Level and verify if the level file is created.
|
||||
|
||||
Expected Behavior:
|
||||
The level is exported and the message "Export to the game was successfully done." appears in the console.
|
||||
The level.pak file is created after exporting.
|
||||
|
||||
Test Steps:
|
||||
1) Create new level
|
||||
2) Export level
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def on_action_triggered():
|
||||
print("Game->Export to Engine Action triggered")
|
||||
|
||||
# 1) Create new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Export level
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Game", "Export to Engine")
|
||||
action.triggered.connect(on_action_triggered)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(on_action_triggered)
|
||||
level_pak_file = os.path.join(
|
||||
"SamplesProject", "Levels", self.args["level"], "level.pak"
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
if os.path.exists(level_pak_file):
|
||||
print("level.pak file exists")
|
||||
|
||||
|
||||
test = TestExportALevel()
|
||||
test.run()
|
||||
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C24064530 : Game Menu Options
|
||||
https://testrail.agscollab.com/index.php?/cases/view/24064530
|
||||
|
||||
C16780793: Game Menu Options (New Viewport Interaction Model)
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16780793
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestGameMenuOptions(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="game_menu_options: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Game Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The Game menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Interact with Game Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
game_menu_options = [
|
||||
("Play Game",),
|
||||
("Simulate",),
|
||||
("Export to Engine",),
|
||||
("Export Occlusion Mesh",),
|
||||
("Enable Camera Terrain Collision",),
|
||||
("Move Player and Camera Separately",),
|
||||
("AI", "Request a full MNM rebuild",),
|
||||
("AI", "Show Navigation Areas",),
|
||||
("AI", "Continuous Update",),
|
||||
("AI", "Visualize Navigation Accessibility",),
|
||||
("AI", "View Agent Type",),
|
||||
("Audio", "Stop All Sounds",),
|
||||
("Audio", "Refresh Audio",),
|
||||
("Debugging", "Configure ToolBox Macros",),
|
||||
("Debugging", "ToolBox Macros",),
|
||||
("Debugging", "Error Report",),
|
||||
]
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
print("Focus Changed")
|
||||
QtWidgets.QApplication.activeModalWidget().close()
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
if action_name == "Simulate":
|
||||
general.exit_simulation_mode()
|
||||
elif action_name == "Play Game":
|
||||
general.exit_game_mode()
|
||||
|
||||
# 1) Create a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Interact with Game Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
for option in game_menu_options:
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Game", *option)
|
||||
if action.isVisible():
|
||||
print(f"{option} is visible in Game Menu")
|
||||
trig_func = lambda: on_action_triggered(action.iconText())
|
||||
action.triggered.connect(trig_func)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(trig_func)
|
||||
general.idle_wait(2.0)
|
||||
else:
|
||||
print(f"{option} is not visible in Game Menu")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
test = TestGameMenuOptions()
|
||||
test.run()
|
||||
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6321557: Basic Function: Graphics Settings
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6321557
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
from enum import Enum, auto
|
||||
|
||||
class FocusChangeState(Enum):
|
||||
IGNORE = auto() # We're not waiting for anything
|
||||
SETTINGS_WINDOW_APPEAR = auto() # Waiting for the settings window to appear
|
||||
WARNING_DIALOG_APPEAR = auto() # Waiting for the warning about risks of changing settings
|
||||
POST_WARNING_DIALOG = auto() # After that, it'll either be a log message or source control warning.
|
||||
SAVE_WARNING_APPEAR = auto() # Waiting for the "Could not save" dialog if source control stopped us.
|
||||
LOG_WINDOW_APPEAR = auto() # Waiting for the log window to appear
|
||||
CLOSE_WITHOUT_SAVING = auto() # Waiting for the close without saving dialog.
|
||||
|
||||
|
||||
class TestGraphicsSettings(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="graphics_settings: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Open the graphics settings, change a value and ensure the setting changes.
|
||||
|
||||
Expected Behavior:
|
||||
Graphics settings can be changed.
|
||||
|
||||
Test Steps:
|
||||
1) Open the graphics settings dialog.
|
||||
2) Check the Save button is disabled.
|
||||
3) Change a setting.
|
||||
4) Check the save button is enabled.
|
||||
5) Press the save button.
|
||||
6) Check a warning dialog has appeared.
|
||||
7) Press Yes.
|
||||
8) Check the dialog has closed.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def fail_test(msg):
|
||||
print(msg)
|
||||
print("Test failed.")
|
||||
sys.exit()
|
||||
|
||||
current_state = FocusChangeState.IGNORE
|
||||
settings_have_saved = False
|
||||
last_window_seen = None
|
||||
|
||||
def handle_settings_dialog():
|
||||
nonlocal current_state
|
||||
current_state = FocusChangeState.IGNORE
|
||||
|
||||
general.idle_wait(0.0)
|
||||
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
|
||||
if active_widget is None:
|
||||
fail_test("Failed to find graphics settings dialog.")
|
||||
|
||||
save_button = pyside_utils.find_child_by_pattern(active_widget, "Save")
|
||||
if save_button is None:
|
||||
fail_test("Failed to find Save button")
|
||||
|
||||
if type(save_button) != QtWidgets.QToolButton:
|
||||
fail_test("Failed to find Save button 2")
|
||||
|
||||
if save_button.isEnabled():
|
||||
fail_test("Save button is enabled before change.")
|
||||
|
||||
spin_box = pyside_utils.find_child_by_pattern(active_widget, {"objectName": "e_viewdistratiocustom"})
|
||||
if spin_box is None:
|
||||
fail_test("Failed to find spinbox.")
|
||||
|
||||
if type(spin_box) != QtWidgets.QDoubleSpinBox:
|
||||
fail_test("Failed to find spinbox.")
|
||||
|
||||
current_value = spin_box.value()
|
||||
spin_box.setValue(current_value * 2)
|
||||
|
||||
new_value = spin_box.value()
|
||||
if current_value == new_value:
|
||||
fail_test("Failed to change value.")
|
||||
|
||||
if not save_button.isEnabled():
|
||||
fail_test("Save button is not enabled after change.")
|
||||
|
||||
current_state = FocusChangeState.WARNING_DIALOG_APPEAR
|
||||
save_button.click()
|
||||
|
||||
if not settings_have_saved:
|
||||
current_state = FocusChangeState.CLOSE_WITHOUT_SAVING
|
||||
|
||||
active_widget.close()
|
||||
|
||||
def handle_warning_dialog():
|
||||
nonlocal current_state
|
||||
current_state = FocusChangeState.IGNORE
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
|
||||
if active_widget is None:
|
||||
fail_test("Failed to find warning dialog.")
|
||||
|
||||
msg_box = active_widget.findChild(QtWidgets.QMessageBox)
|
||||
if msg_box is None:
|
||||
fail_test("Unable to find message box in warning dialog")
|
||||
|
||||
if not msg_box.text().startswith("A non-tested setting could potentially crash the game"):
|
||||
fail_test("Unexpected text in warning dialog: " + msg_box.text())
|
||||
|
||||
yes_button = pyside_utils.find_child_by_pattern(active_widget, "&Yes")
|
||||
if yes_button is None:
|
||||
fail_test("Failed to find yes button.")
|
||||
|
||||
current_state = FocusChangeState.POST_WARNING_DIALOG
|
||||
yes_button.click()
|
||||
|
||||
def press_button_in_dialog(button_text, next_state):
|
||||
nonlocal current_state
|
||||
current_state = FocusChangeState.IGNORE
|
||||
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
|
||||
button = pyside_utils.find_child_by_pattern(active_widget, button_text)
|
||||
if button is None:
|
||||
fail_test("Failed to find " + button_text + " button.")
|
||||
|
||||
current_state = next_state
|
||||
button.click()
|
||||
|
||||
def check_for_save_success(log_dialog_widget):
|
||||
nonlocal settings_have_saved
|
||||
|
||||
msg_box = log_dialog_widget.findChild(QtWidgets.QMessageBox)
|
||||
if msg_box is None:
|
||||
return
|
||||
|
||||
if msg_box.text().startswith("Updated the graphics setting correctly"):
|
||||
settings_have_saved = True
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
nonlocal current_state, settings_have_saved, last_window_seen
|
||||
|
||||
if current_state == FocusChangeState.IGNORE:
|
||||
return
|
||||
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_widget is None:
|
||||
return
|
||||
|
||||
# Make sure the window has changed.
|
||||
if active_widget == last_window_seen:
|
||||
return
|
||||
|
||||
last_window_seen = active_widget
|
||||
|
||||
title = pyside_utils.find_child_by_pattern(active_widget, "title")
|
||||
if title is None:
|
||||
return
|
||||
|
||||
if current_state == FocusChangeState.SETTINGS_WINDOW_APPEAR:
|
||||
# We're waiting for the settings dialog, ensure the right one has appeared.
|
||||
if title.text() == "Graphics Settings":
|
||||
handle_settings_dialog()
|
||||
elif current_state == FocusChangeState.WARNING_DIALOG_APPEAR:
|
||||
if title.text() == "Warning":
|
||||
handle_warning_dialog()
|
||||
elif current_state == FocusChangeState.POST_WARNING_DIALOG:
|
||||
# This could be a source control dialog, or a log window if the settings file exists and is writable.
|
||||
if title.text() == "Source Control":
|
||||
# Just use overwrite for the project settings file.
|
||||
press_button_in_dialog("Overwrite", FocusChangeState.POST_WARNING_DIALOG)
|
||||
elif title.text() == "Log":
|
||||
# After this, there will be another log window for the file that did save.
|
||||
check_for_save_success(active_widget)
|
||||
press_button_in_dialog("OK", FocusChangeState.LOG_WINDOW_APPEAR)
|
||||
elif current_state == FocusChangeState.SAVE_WARNING_APPEAR:
|
||||
if title.text() == "Warning":
|
||||
press_button_in_dialog("OK", FocusChangeState.LOG_WINDOW_APPEAR)
|
||||
elif current_state == FocusChangeState.LOG_WINDOW_APPEAR:
|
||||
if title.text() == "Log":
|
||||
check_for_save_success(active_widget)
|
||||
press_button_in_dialog("OK", FocusChangeState.IGNORE)
|
||||
elif current_state == FocusChangeState.CLOSE_WITHOUT_SAVING:
|
||||
if title.text() == "Warning":
|
||||
press_button_in_dialog("&Yes", FocusChangeState.IGNORE)
|
||||
|
||||
EditorTestHelper.after_level_load(self)
|
||||
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", "Editor Settings", "Graphics Settings")
|
||||
if action is None:
|
||||
fail_test("Failed to find Graphics Settings action.")
|
||||
|
||||
current_state = FocusChangeState.SETTINGS_WINDOW_APPEAR
|
||||
action.trigger()
|
||||
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
if settings_have_saved:
|
||||
print("Graphics Settings test successful.")
|
||||
else:
|
||||
print("Graphics Settings test failed.")
|
||||
|
||||
|
||||
test = TestGraphicsSettings()
|
||||
test.run()
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
"""
|
||||
C1564080: Help Menu Function
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1564080
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestHelpMenuFunction(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="help_menu_function: ")
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Help Menu options that open Urls and verify if Urls are valid.
|
||||
|
||||
Expected Behavior:
|
||||
The Help menu Urls are valid.
|
||||
|
||||
Test Steps:
|
||||
1) Interact with Help Menu options that open Urls
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
url_help_menu_options = [
|
||||
("Getting Started",),
|
||||
("Tutorials",),
|
||||
("Documentation", "Glossary",),
|
||||
("Documentation", "Lumberyard Documentation",),
|
||||
("Documentation", "GameLift Documentation",),
|
||||
("Documentation", "Release Notes",),
|
||||
("GameDev Resources", "GameDev Blog",),
|
||||
("GameDev Resources", "GameDev Twitch Channel",),
|
||||
("GameDev Resources", "Forums",),
|
||||
("GameDev Resources", "AWS Support",),
|
||||
("About Lumberyard",),
|
||||
]
|
||||
|
||||
def validate_url_action(action_name, urlHandler):
|
||||
if urlHandler.last_opened_url.isEmpty():
|
||||
print(f"{action_name} didn't open a url with an expected scheme (http/https)")
|
||||
else:
|
||||
url_display_string = urlHandler.last_opened_url.toDisplayString()
|
||||
if urlHandler.last_opened_url.isValid():
|
||||
print(f"{action_name} triggered Url {url_display_string}")
|
||||
else:
|
||||
print(f"{action_name} triggered invalid Url {url_display_string}")
|
||||
urlHandler.last_opened_url.clear()
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_widget:
|
||||
active_widget.close()
|
||||
|
||||
# 1) Interact with the Help Menu options that open urls
|
||||
try:
|
||||
# Create a handler to open Urls
|
||||
class UrlHandler(QtCore.QObject):
|
||||
self.last_opened_url = QtCore.QUrl()
|
||||
@QtCore.Slot("QUrl")
|
||||
def open_url(self, url):
|
||||
self.last_opened_url = url
|
||||
urlHandler = UrlHandler()
|
||||
QtGui.QDesktopServices.setUrlHandler("https", urlHandler, "open_url")
|
||||
QtGui.QDesktopServices.setUrlHandler("http", urlHandler, "open_url")
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
# Check help menu actions that trigger Urls
|
||||
for option in url_help_menu_options:
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Help", *option)
|
||||
if action.isVisible():
|
||||
action.trigger()
|
||||
action_name = action.iconText()
|
||||
validate_url_action(f"{action_name} Action", urlHandler)
|
||||
else:
|
||||
print(f"{option} is not visible in Help Menu")
|
||||
# Check the documentation search field under the help menu
|
||||
menu_bar = editor_window.menuBar()
|
||||
menu_bar_actions = [index.iconText() for index in menu_bar.actions()]
|
||||
main_menu_item = "Help"
|
||||
if main_menu_item not in menu_bar_actions:
|
||||
print(f"QAction not found for main menu item '{main_menu_item}'")
|
||||
else:
|
||||
help_action = menu_bar.actions()[menu_bar_actions.index(main_menu_item)]
|
||||
# Get the first action in the help menu which should be the search action
|
||||
search_action = help_action.menu().actions()[0]
|
||||
# Get the search line edit from the search action
|
||||
search_line_widget = search_action.defaultWidget().findChild(QtWidgets.QLineEdit)
|
||||
search_string = "component"
|
||||
search_line_widget.setText(search_string)
|
||||
search_line_widget.returnPressed.emit()
|
||||
validate_url_action(f"Documentation search with '{search_string}' text", urlHandler)
|
||||
search_string = ""
|
||||
search_line_widget.setText(search_string)
|
||||
search_line_widget.returnPressed.emit()
|
||||
validate_url_action(f"Documentation Search with '{search_string}' text", urlHandler)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
QtGui.QDesktopServices.unsetUrlHandler("https")
|
||||
QtGui.QDesktopServices.unsetUrlHandler("http")
|
||||
|
||||
test = TestHelpMenuFunction()
|
||||
test.run()
|
||||
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
"""
|
||||
C24064533: The Help menu functions normally.
|
||||
https://testrail.agscollab.com/index.php?/cases/view/24064533
|
||||
|
||||
C16780815: Help Menu Options (New Viewport Interaction Model)
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16780815
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestHelpMenuOptions(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="help_menu_options: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Help Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The Help menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Interact with Help Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
help_menu_options = [
|
||||
("Getting Started",),
|
||||
("Tutorials",),
|
||||
("Documentation", "Glossary",),
|
||||
("Documentation", "Lumberyard Documentation",),
|
||||
("Documentation", "GameLift Documentation",),
|
||||
("Documentation", "Release Notes",),
|
||||
("GameDev Resources", "GameDev Blog",),
|
||||
("GameDev Resources", "GameDev Twitch Channel",),
|
||||
("GameDev Resources", "Forums",),
|
||||
("GameDev Resources", "AWS Support",),
|
||||
("Give Us Feedback",),
|
||||
("About Lumberyard",),
|
||||
]
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
QtWidgets.QApplication.activeModalWidget().close()
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 1) Create a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Interact with Help Menu options
|
||||
try:
|
||||
for option in help_menu_options:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Help", *option)
|
||||
if action.isVisible():
|
||||
print(f"{option} is visible in Help Menu")
|
||||
trig_func = lambda: on_action_triggered(action.iconText())
|
||||
action.triggered.connect(trig_func)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(trig_func)
|
||||
general.idle_wait(2.0)
|
||||
else:
|
||||
print(f"{option} is not visible in Help Menu")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
test = TestHelpMenuOptions()
|
||||
test.run()
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C1564610: LMB and RMB mouse functionality
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1564610
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestLeftAndRightMouseButtons(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="left_and_right_mouse_buttons: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Use left mouse button to select items in Editor and
|
||||
Right mouse button to open the item.
|
||||
|
||||
Expected Behavior:
|
||||
LMB interaction is correct and accurate.
|
||||
RMB functions normally and appropriate context menus are opened.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Test LMB and RMB on Viewport of editor to open context menus and select items.
|
||||
2.1) Create camera entity from view
|
||||
2.2) Create entity
|
||||
2.3) Create layer
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_entity_count_name(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Test RMB and LMB on Viewport of editor to open context menus and select items.
|
||||
# Note: pyside_utils.trigger_context_menu_entry(widget, pattern, pos=None) does same
|
||||
# functionality as Right click to open context menu and left click to select options in menu.
|
||||
|
||||
app = QtWidgets.QApplication.instance()
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
viewport = editor_window.findChildren(QtWidgets.QWidget, "renderOverlay")[0]
|
||||
|
||||
# 2.1) Create camera entity from view
|
||||
pyside_utils.trigger_context_menu_entry(viewport, "Create camera entity from view")
|
||||
if get_entity_count_name("Camera1"):
|
||||
print("Create camera entity from view option is selected using mouse buttons")
|
||||
# 2.2) Create entity
|
||||
pyside_utils.trigger_context_menu_entry(viewport, "Create entity")
|
||||
if get_entity_count_name("Entity3"):
|
||||
print("Create entity option is selected using mouse buttons")
|
||||
# 2.3) Create layer
|
||||
pyside_utils.trigger_context_menu_entry(viewport, "Create layer")
|
||||
if get_entity_count_name("Layer4*"):
|
||||
print("Create layer option is selected using mouse buttons")
|
||||
|
||||
|
||||
test = TestLeftAndRightMouseButtons()
|
||||
test.run()
|
||||
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C5436953: Loading a level with un-pushed slice changes does not effect editor stability
|
||||
https://testrail.agscollab.com/index.php?/cases/view/5436953
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.slice as slice
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class LoadLevelUnpushedSliceTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="load_level_unpushed_slice_changes", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Loading a level with un-pushed slice changes does not effect editor stability
|
||||
|
||||
Expected Behavior:
|
||||
The editor remains stable, level loads, and the slice still has pushable changes.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create an entity and add a component to it
|
||||
3) Create slice from the entity
|
||||
4) Delete component from the entity
|
||||
5) Save the level
|
||||
6) Reload the same level
|
||||
7) Verify changes after reload
|
||||
8) Instantiate slice and verify if it has a component
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
SLICE_NAME = "TestSlice.slice"
|
||||
|
||||
def search_entity(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return entities
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Create an entity and add a component to it
|
||||
new_entity = hydra.Entity("entity")
|
||||
new_entity.create_entity(math.Vector3(64.0, 64.0, 32.0), ["Mesh"])
|
||||
|
||||
# 3) Create slice from the entity
|
||||
success = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", new_entity.id, SLICE_NAME)
|
||||
print(f"Slice Created: {success}")
|
||||
|
||||
# 4) Delete component from the entity
|
||||
success = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", [new_entity.components[0]])
|
||||
print(f"Component removed successfully: {success}")
|
||||
|
||||
# 5) Save the level
|
||||
general.save_level()
|
||||
|
||||
# 6) Reload the same level
|
||||
general.reload_current_level()
|
||||
|
||||
# 7) Verify changes after reload
|
||||
# Entity should not have the component
|
||||
entity_id = search_entity("entity")[0]
|
||||
print(f"Entity found after level reload: {entity_id.IsValid()}")
|
||||
print(
|
||||
f"Level saved even if there are unpushed changes in slice: {not hydra.has_components(entity_id, ['Mesh'])}"
|
||||
)
|
||||
|
||||
# 8) Instantiate slice and verify if it has a component
|
||||
# Delete existing slice initially
|
||||
general.delete_object("entity")
|
||||
# Instantiate slice
|
||||
transform = math.Transform_CreateIdentity()
|
||||
position = math.Vector3(64.0, 64.0, 32.0)
|
||||
transform.SetPosition(position)
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", SLICE_NAME, math.Uuid(), False)
|
||||
slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform)
|
||||
self.wait_for_condition(lambda: len(search_entity("entity")) > 0, 2.0)
|
||||
entity_id = search_entity("entity")[0]
|
||||
print(f"Unpushed changes in Slice are not saved: {hydra.has_components(entity_id, ['Mesh'])}")
|
||||
|
||||
|
||||
test = LoadLevelUnpushedSliceTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
C1564082 : Object Toolbar
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1564082
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as editor_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestObjectToolbar(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="object_toolbar_function: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Object toolbar options and verify if all the options are functionnal.
|
||||
|
||||
Expected Behavior:
|
||||
All options available in the Object Toolbar function as intended.
|
||||
|
||||
Test Steps:
|
||||
1) Create/Open a level
|
||||
2) Open the Object Toolbar
|
||||
3) Verify 'Go to selected object' tool button functionality
|
||||
i) Create entity and find the entity in viewport
|
||||
ii) Change viewport position
|
||||
iii) Click on option and verify viewport position
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
object_toolbar = editor_window.findChild(QtWidgets.QToolBar, "Object")
|
||||
|
||||
def get_tool_button(option):
|
||||
button = pyside_utils.find_child_by_pattern(object_toolbar, option)
|
||||
if button.text() == option:
|
||||
return button
|
||||
|
||||
# 1) Create new level with an Entity
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Open the Object Toolbar
|
||||
if not object_toolbar.isVisible():
|
||||
object_toolbar.toggleViewAction().trigger()
|
||||
if object_toolbar.isVisible():
|
||||
print("Object tool bar opened successfully")
|
||||
|
||||
# 3) Verify 'Go to selected object' tool button functionality
|
||||
# i)Create entity and find the entity in viewport
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId.EntityId())
|
||||
|
||||
# Find entity in viewport and get current position
|
||||
entity_outliner = pyside_utils.find_child_by_pattern(editor_window, "Entity Outliner (PREVIEW)")
|
||||
action = pyside_utils.find_child_by_pattern(entity_outliner, "Find in viewport")
|
||||
default_pos = general.get_current_view_position()
|
||||
action.trigger()
|
||||
self.wait_for_condition(lambda: default_pos != general.get_current_view_position(), 2.0)
|
||||
old_pos = general.get_current_view_position()
|
||||
|
||||
# ii) Change viewport position
|
||||
general.set_current_view_position(old_pos.x + 10.0, old_pos.y + 10.0, old_pos.z + 10.0)
|
||||
self.wait_for_condition(lambda: old_pos != general.get_current_view_position(), 2.0)
|
||||
current_pos = general.get_current_view_position()
|
||||
|
||||
# iii) Click on option and verify viewport position
|
||||
button = get_tool_button("Go to selected object")
|
||||
button.click()
|
||||
self.wait_for_condition(lambda: current_pos != general.get_current_view_position(), 2.0)
|
||||
new_pos = general.get_current_view_position()
|
||||
if new_pos != current_pos and new_pos == old_pos:
|
||||
print("Go to selected object tool button is responsive")
|
||||
|
||||
|
||||
test = TestObjectToolbar()
|
||||
test.run_test()
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6351276: Open a level
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6351276
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestOpenLevel(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="open_level", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Open a level and verify if the level is loaded properly.
|
||||
|
||||
Expected Behavior:
|
||||
A level is opened and loaded into the editor.
|
||||
|
||||
Test Steps:
|
||||
1) Open an existing level
|
||||
2) Verify if the level is loaded
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self.focus_changed = False
|
||||
def on_focus_changed(old, new):
|
||||
if not self.focus_changed:
|
||||
self.focus_changed = True
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
open_level_as_dialogue = active_widget.findChild(QtWidgets.QWidget, "LevelFileDialog")
|
||||
if open_level_as_dialogue.windowTitle() == "Open a Level":
|
||||
print("Open a Level dialog opened")
|
||||
level_name = open_level_as_dialogue.findChild(QtWidgets.QLineEdit, "nameLineEdit")
|
||||
level_name.setText(self.args["level"])
|
||||
button_box = open_level_as_dialogue.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 1) Open an existing level
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Open Level")
|
||||
action_triggered = lambda: on_action_triggered("Open Level")
|
||||
action.triggered.connect(action_triggered)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(action_triggered)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
# 2) Verify if the new level is loaded
|
||||
general.idle_wait(2.0)
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") == "Audio_Sample":
|
||||
print("An existing level opened : SUCCESS")
|
||||
else:
|
||||
print("An existing level opened : FAILED")
|
||||
|
||||
|
||||
test = TestOpenLevel()
|
||||
test.run()
|
||||
@@ -0,0 +1,168 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C1506875: Open Input Bindings File
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1506875
|
||||
|
||||
C1506876: Save Input Bindings File
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1506876
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class OpenSaveInputBindingFileTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="open_save_input_binding_file", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify if we are able to open/save a .inputbindings file in Asset Editor
|
||||
|
||||
Expected Behavior:
|
||||
The .inputbindings asset is loaded into the Asset Editor, replacing any currently open files.
|
||||
The .inputbindings file is saved correctly.
|
||||
All changes from step 1. are present in the .inputbindings file.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Open Asset Editor
|
||||
3) Access Asset Editor
|
||||
4) Open .inputbindings file
|
||||
5) Verify if the file has loaded by verifying the status bar in Asset Editor
|
||||
6) Delete all input events initially
|
||||
7) Add an event and save the file
|
||||
8) Close Asset editor and reopen the inputbindings file
|
||||
9) Verify if changes are saved.
|
||||
10) Close Asset Editor
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
INPUTBINDING_FILE_NAME = "test.inputbindings"
|
||||
|
||||
def open_asset_editor():
|
||||
general.open_pane("Asset Editor")
|
||||
return general.is_pane_visible("Asset Editor")
|
||||
|
||||
def close_asset_editor():
|
||||
general.close_pane("Asset Editor")
|
||||
return not general.is_pane_visible("Asset Editor")
|
||||
|
||||
async def open_input_binding_file():
|
||||
# Trigger the open asynchronously, since it opens a modal dialog
|
||||
action = pyside_utils.find_child_by_pattern(asset_editor_widget, {"iconText": "Open"})
|
||||
pyside_utils.trigger_action_async(action)
|
||||
|
||||
# This is to deal with the file picker for .inputbinding
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
tree = active_modal_widget.findChild(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")
|
||||
# Make sure the folder structure tree is expanded so that after giving the searchtext the first
|
||||
# .inputbinding file is selected
|
||||
tree.expandAll()
|
||||
search_text = active_modal_widget.findChild(QtWidgets.QLineEdit, "textSearch")
|
||||
# Set the searchText so that the first .inputbinding file in the folder structure is selected
|
||||
search_text.setText(INPUTBINDING_FILE_NAME)
|
||||
model_index = pyside_utils.find_child_by_pattern(tree, INPUTBINDING_FILE_NAME)
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index)
|
||||
# Click OK
|
||||
button_box = active_modal_widget.findChild(QtWidgets.QDialogButtonBox, "m_buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Open Asset Editor
|
||||
print(f"Asset Editor opened: {open_asset_editor()}")
|
||||
|
||||
# 3) Access Asset Editor
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor")
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "m_assetEditorWidget")
|
||||
|
||||
# 4) Open .inputbindings file
|
||||
await open_input_binding_file()
|
||||
|
||||
# 5) Verify if the file has loaded by verifying the status bar in Asset Editor
|
||||
status_bar = asset_editor_widget.findChild(QtWidgets.QWidget, "AssetEditorStatusBar")
|
||||
text_edit = status_bar.findChild(QtWidgets.QLabel, "textEdit")
|
||||
success = await pyside_utils.wait_for_condition(lambda: f"{INPUTBINDING_FILE_NAME} - Asset loaded!" in text_edit.text(), 2.0)
|
||||
if success:
|
||||
print("Input Binding File opened in the Asset Editor")
|
||||
|
||||
# C1506876
|
||||
# 6) Delete all input events initially
|
||||
await pyside_utils.wait_for_condition(lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups") is not None)
|
||||
input_event_groups = asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups")
|
||||
delete_all_button = input_event_groups.findChildren(QtWidgets.QToolButton, "")[1]
|
||||
pyside_utils.click_button_async(delete_all_button)
|
||||
|
||||
# Clicking the Delete All button will prompt the user if they are sure they want to
|
||||
# delete all the entries, so we wait for this modal dialog and then accept it
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
message_box = active_modal_widget.findChild(QtWidgets.QMessageBox)
|
||||
yes_button = message_box.button(QtWidgets.QMessageBox.Yes)
|
||||
yes_button.click()
|
||||
|
||||
# 7) Add an event and save the file
|
||||
# First QToolButton is +, Second QToolButton is Delete
|
||||
await pyside_utils.wait_for_condition(lambda: len(asset_editor_widget.findChildren(QtWidgets.QFrame, "Input Event Groups")) > 1, 2.0)
|
||||
input_event_groups = asset_editor_widget.findChildren(QtWidgets.QFrame, "Input Event Groups")[1]
|
||||
add_button = input_event_groups.findChild(QtWidgets.QToolButton, "")
|
||||
add_button.click()
|
||||
action = pyside_utils.find_child_by_pattern(asset_editor_widget, {"text": "&Save"})
|
||||
action.trigger()
|
||||
await pyside_utils.wait_for_condition(lambda: "Asset saved!" in text_edit.text(), 2.0)
|
||||
|
||||
# 8) Close Asset editor and reopen the inputbindings file
|
||||
close_asset_editor()
|
||||
open_asset_editor()
|
||||
await open_input_binding_file()
|
||||
|
||||
# 9) Verify if changes are saved. (1 Event should be present)
|
||||
# We need to re-find the Asset Editor and all its child widgets since we
|
||||
# close/re-opened it, so it is brand new
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor")
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "m_assetEditorWidget")
|
||||
input_event_groups = asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups")
|
||||
no_of_elements_label = input_event_groups.findChild(QtWidgets.QLabel, "DefaultLabel")
|
||||
success = await pyside_utils.wait_for_condition(lambda: "1 elements" in no_of_elements_label.text(), 3.0)
|
||||
if success:
|
||||
print("Changes are saved successfully")
|
||||
|
||||
# 6) Close Asset Editor
|
||||
print(f"Asset Editor closed: {close_asset_editor()}")
|
||||
|
||||
|
||||
test = OpenSaveInputBindingFileTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C17218816: Entity Outliner Searching
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17218816
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest
|
||||
from PySide2.QtCore import Qt, QObject, QEvent, QPoint
|
||||
from PySide2.QtGui import QContextMenuEvent, QCursor
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
class TestEntityOutlinerSearching(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="outliner_search: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify the search function of the Entity Outliner works properly
|
||||
|
||||
Expected Behavior:
|
||||
Typing text on the Entity Outliner search field limits the number of entities shown in the tree view
|
||||
|
||||
Test Steps:
|
||||
1) Create new level
|
||||
2) Create some test entities
|
||||
3) Write in the Entity Outliner search field (different combinations) and validate
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=False,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# Grab the Outliner
|
||||
|
||||
app = QtWidgets.QApplication.instance()
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
entity_outliner = main_window.findChild(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")
|
||||
outliner_main_window = entity_outliner.findChild(QtWidgets.QMainWindow)
|
||||
tree = outliner_main_window.findChild(QtWidgets.QTreeView, "m_objectTree")
|
||||
search = outliner_main_window.findChild(QtWidgets.QLineEdit, "textSearch")
|
||||
|
||||
# Store number of starting entities, just in case
|
||||
startingEntityCount = tree.model().rowCount()
|
||||
|
||||
# 2) Create entities
|
||||
|
||||
def CreateEntityWithName(name):
|
||||
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
|
||||
editor.EditorEntityAPIBus(bus.Event, 'SetName', entityId, name)
|
||||
|
||||
CreateEntityWithName("Test_01")
|
||||
CreateEntityWithName("Test_02")
|
||||
CreateEntityWithName("Test_03")
|
||||
CreateEntityWithName("AnotherTest")
|
||||
CreateEntityWithName("Entity01")
|
||||
CreateEntityWithName("Entity02")
|
||||
|
||||
# Count rows in Outliner
|
||||
fullEntityCount = tree.model().rowCount()
|
||||
|
||||
if((fullEntityCount - startingEntityCount) == 6):
|
||||
print("Test Entities were set up correctly")
|
||||
|
||||
# 3) Write in the Entity Outliner search field (different combinations)
|
||||
|
||||
# Write "Test_0" in search box
|
||||
search.setText("Test_0")
|
||||
|
||||
entityCount = tree.model().rowCount()
|
||||
if(entityCount == 3):
|
||||
print("Searching Test_0 returns 3 entities")
|
||||
|
||||
# Write "Test" in search box
|
||||
search.setText("Test")
|
||||
|
||||
entityCount = tree.model().rowCount()
|
||||
if(entityCount == 4):
|
||||
print("Searching Test returns 4 entities")
|
||||
|
||||
# Write "asdfgh" in search box
|
||||
search.setText("asdfgh")
|
||||
|
||||
entityCount = tree.model().rowCount()
|
||||
if(entityCount == 0):
|
||||
print("Searching asdfgh returns 0 entities")
|
||||
|
||||
# Write "" in search box
|
||||
search.setText("")
|
||||
|
||||
entityCount = tree.model().rowCount()
|
||||
if(entityCount == fullEntityCount):
|
||||
print("Emptying the search returns all entities")
|
||||
|
||||
test = TestEntityOutlinerSearching()
|
||||
test.run()
|
||||
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C2669525: Adding and deleting entities to a slice are able to be quick pushed to slice
|
||||
https://testrail.agscollab.com/index.php?/cases/view/2669525
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.entity as EntityId
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from re import compile as regex
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class QuickPushSliceTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="quick_push_slice", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Adding and deleting entities to a slice are able to be quick pushed to slice
|
||||
|
||||
Expected Behavior:
|
||||
The slice is saved and the second instance of the slice is updated with the
|
||||
deletion of Child 1 and a addition of Child 2.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create 2 entities as parent and child
|
||||
3) Create slice from the parent entity
|
||||
4) Wait until slice is created
|
||||
5) Instantiate a newly created slice
|
||||
6) Delete child on original slice
|
||||
7) Add a child to the original slice entity
|
||||
8) Save slice overrides
|
||||
9) Verify if the instantiated slice has a new child
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
SLICE_NAME = "temp_slice.slice"
|
||||
|
||||
def path_is_valid_asset(asset_path):
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
|
||||
return asset_id.invoke("IsValid")
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Create 2 entities as parent and child
|
||||
parent_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId.EntityId())
|
||||
child_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", parent_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_id, "child1")
|
||||
|
||||
# 3) Create slice from the parent entity
|
||||
success = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", parent_id, SLICE_NAME)
|
||||
print(f"Slice Created: {success}")
|
||||
|
||||
# 4) Wait until slice is created
|
||||
self.wait_for_condition(lambda: path_is_valid_asset(SLICE_NAME), 3.0)
|
||||
|
||||
# 5) Instantiate a newly created slice
|
||||
transform = math.Transform_CreateIdentity()
|
||||
position = math.Vector3(64.0, 64.0, 32.0)
|
||||
transform.SetPosition(position)
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", SLICE_NAME, math.Uuid(), False)
|
||||
slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform)
|
||||
|
||||
# 6) Delete child on original slice
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", [child_id])
|
||||
|
||||
# 7) Add a child to the original slice entity
|
||||
child_2_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", parent_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_2_id, "child2")
|
||||
|
||||
# 8) Save slice overrides
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
outliner_widget = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Outliner.*")), ..., "m_objectList"
|
||||
).parent()
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
# Model index for the original slice
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 2) is not None, 2.0)
|
||||
model_index_1 = pyside_utils.get_item_view_index(tree, 1)
|
||||
pyside_utils.trigger_context_menu_entry(tree, SLICE_NAME.lower(), index=model_index_1)
|
||||
|
||||
# 9) Verify if the instantiated slice has a new child
|
||||
# model index for instantiated slice
|
||||
model_index_0 = pyside_utils.get_item_view_index(tree, 0)
|
||||
self.wait_for_condition(lambda: pyside_utils.find_child_by_pattern(model_index_0, "child1") is None, 2.0)
|
||||
if pyside_utils.find_child_by_pattern(model_index_0, "child2"):
|
||||
print("Newly created child is updated in the instantiated slice")
|
||||
if pyside_utils.find_child_by_pattern(model_index_0, "child1") is None:
|
||||
print("Child deletion is updated in the instantiated slice")
|
||||
|
||||
|
||||
test = QuickPushSliceTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C17123213: Quick Saving Changes to Slice
|
||||
https://testrail.agscollab.com/index.php?/cases/view/17123213
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.math as math
|
||||
import azlmbr.slice as slice
|
||||
from azlmbr.entity import EntityId
|
||||
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from re import compile as regex
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class QuickSaveSlice(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="quick_save_slice", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Quick Saving Changes to Slice
|
||||
|
||||
Expected:
|
||||
All changes made to the slice are saved
|
||||
|
||||
Test Steps:
|
||||
1) Create or open a level
|
||||
2) Create a slice
|
||||
3) Create child entity
|
||||
4) Add a component to the slice.
|
||||
5) Quick save the slice
|
||||
6) Delete the existing slice before verifying if it is saved
|
||||
7) Reinstantiate the slice to verify if the changes are saved.
|
||||
8) Verify the saved changes
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
SLICE_NAME = "TempSlice.slice"
|
||||
|
||||
def search_entity(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return entities
|
||||
|
||||
# 1) Create or open any level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Create a slice
|
||||
# Create an Entity to turn into a slice.
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId())
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", new_entity_id, "Entity2")
|
||||
success = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", new_entity_id, SLICE_NAME)
|
||||
print(f"Slice Created: {success}")
|
||||
|
||||
# 3) Create child entity
|
||||
child_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", new_entity_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_entity_id, "Entity3")
|
||||
print(f"Child entity created: {child_entity_id.IsValid()}")
|
||||
|
||||
# 4) Add a component to the slice.
|
||||
hydra.add_component("Mesh", new_entity_id)
|
||||
|
||||
# 5) Quick save the slice
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
outliner_widget = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Outliner.*")), ..., "m_objectList"
|
||||
).parent()
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
model_index = pyside_utils.find_child_by_pattern(tree, "Entity2")
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index)
|
||||
pyside_utils.trigger_context_menu_entry(tree, SLICE_NAME.lower())
|
||||
|
||||
# 6) Delete the existing slice before verifying if it is saved
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntities', [new_entity_id, child_entity_id])
|
||||
|
||||
# 7) Reinstantiate the slice to verify if the changes are saved.
|
||||
transform = math.Transform_CreateIdentity()
|
||||
position = math.Vector3(64.0, 64.0, 32.0)
|
||||
transform.SetPosition(position)
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", SLICE_NAME, math.Uuid(), False)
|
||||
slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform)
|
||||
|
||||
# 8) Verify the saved changes
|
||||
tree.expandAll()
|
||||
self.wait_for_condition(lambda: len(search_entity("Entity3")) > 0, 2.0)
|
||||
# Parent and child entities instantiated
|
||||
parent_id = search_entity("Entity2")[0]
|
||||
child_id = search_entity("Entity3")[0]
|
||||
# Parent child hierarchy
|
||||
parent_child_valid = parent_id.Equal(editor.EditorEntityInfoRequestBus(bus.Event, "GetParent", child_id))
|
||||
# Component in parent entity
|
||||
has_component = hydra.has_components(parent_id, ["Mesh"])
|
||||
changes_saved = parent_id.IsValid() and child_id.IsValid() and parent_child_valid and has_component
|
||||
print(f"Changes in the slice file are saved: {changes_saved}")
|
||||
|
||||
|
||||
test = QuickSaveSlice()
|
||||
test.run()
|
||||
@@ -0,0 +1,239 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6130788: Recover a layer
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6130788
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.layers as layers
|
||||
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestRecoverLayer(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="recover_layer: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create two layers, delete them and ensure they can be recovered correctly.
|
||||
|
||||
Expected Behavior:
|
||||
Layers can be recovered.
|
||||
|
||||
Test Steps:
|
||||
1) Create two new new levels
|
||||
2) Create two layers, one with "Save as binary" activated.
|
||||
3) Save the level.
|
||||
4) Delete the layers.
|
||||
5) Save the level again.
|
||||
6) Load the other level.
|
||||
7) Reload the first level.
|
||||
8) Reload the layers using the Asset Browser.
|
||||
9) Ensure the layers have recovered.
|
||||
9) Ensure the save options are correct.
|
||||
10) Undo, check the layers are removed
|
||||
11) Redo, check the layers are restored.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def fail_test(msg):
|
||||
print(msg)
|
||||
print("Test failed.")
|
||||
sys.exit()
|
||||
|
||||
def on_focus_changed_save_as(old, new):
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
save_level_as_dialogue = active_widget.findChild(QtWidgets.QWidget, "LevelFileDialog")
|
||||
if save_level_as_dialogue.windowTitle() == "Save Level As ":
|
||||
print("The 'Save Level As' dialog appeared")
|
||||
level_name = save_level_as_dialogue.findChild(QtWidgets.QLineEdit, "nameLineEdit")
|
||||
level_name.setText("test_level_2")
|
||||
button_box = save_level_as_dialogue.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
general.idle_wait(3.0) # wait for new level to load
|
||||
|
||||
level_to_load = ""
|
||||
|
||||
def get_inspector_window():
|
||||
nonlocal editor_window
|
||||
inspector_dock = editor_window.findChild(QtWidgets.QWidget, "Entity Inspector")
|
||||
entity_inspector = inspector_dock.findChild(QtWidgets.QMainWindow)
|
||||
|
||||
child_widget = entity_inspector.findChild(QtWidgets.QWidget)
|
||||
if child_widget is None:
|
||||
fail_test("Failed to find inspector window")
|
||||
|
||||
general.idle_wait(1.0)
|
||||
comp_list_contents = (
|
||||
child_widget.findChild(QtWidgets.QScrollArea, "m_componentList")
|
||||
.findChild(QtWidgets.QWidget, "qt_scrollarea_viewport")
|
||||
.findChild(QtWidgets.QWidget, "m_componentListContents")
|
||||
)
|
||||
|
||||
if comp_list_contents is None or len(comp_list_contents.children()) < 1:
|
||||
return None
|
||||
|
||||
return comp_list_contents.children()[1]
|
||||
|
||||
def get_binary_save_state_for_layer(layer_name):
|
||||
layer_id = general.find_editor_entity(layer_name)
|
||||
if not layer_id.isValid():
|
||||
fail_test("Failed to find " + " after recovery")
|
||||
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [layer_id])
|
||||
|
||||
layer_inspector = get_inspector_window()
|
||||
if layer_inspector is None:
|
||||
fail_test("Failed to find inspector window")
|
||||
|
||||
frame = layer_inspector.findChild(QtWidgets.QFrame, "Save as binary")
|
||||
check_box = frame.findChild(QtWidgets.QCheckBox)
|
||||
|
||||
return check_box.isChecked()
|
||||
|
||||
def set_binary_save_state_for_layer(layer_name, state):
|
||||
layer_id = general.find_editor_entity(layer_name)
|
||||
if not layer_id.isValid():
|
||||
fail_test("Failed to find " + " after recovery")
|
||||
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [layer_id])
|
||||
|
||||
layer_inspector = get_inspector_window()
|
||||
if layer_inspector is None:
|
||||
fail_test("Failed to find inspector window")
|
||||
|
||||
frame = layer_inspector.findChild(QtWidgets.QFrame, "Save as binary")
|
||||
check_box = frame.findChild(QtWidgets.QCheckBox)
|
||||
|
||||
check_box.setChecked(state)
|
||||
|
||||
EditorTestHelper.after_level_load(self)
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# Create new level.
|
||||
result = general.create_level_no_prompt("test_level_1", 1024, 1, 4096, True)
|
||||
if result != 0:
|
||||
fail_test("Failed to create level")
|
||||
|
||||
general.idle_wait(1.0)
|
||||
|
||||
# Create two layers
|
||||
layer1_id = layers.EditorLayerComponent_CreateLayerEntityFromName('Layer1')
|
||||
if layer1_id.isValid():
|
||||
print("Layer1 created.")
|
||||
else:
|
||||
fail_test("Layer1 creation failed.")
|
||||
|
||||
layer2_id = layers.EditorLayerComponent_CreateLayerEntityFromName('Layer2')
|
||||
if layer2_id.isValid():
|
||||
print("Layer2 created.")
|
||||
else:
|
||||
fail_test("Layer2 creation failed.")
|
||||
|
||||
# Set the binary save option on layer 1.
|
||||
set_binary_save_state_for_layer("Layer1", True)
|
||||
|
||||
# Save as a different level name
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed_save_as)
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save As")
|
||||
action.trigger()
|
||||
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed_save_as)
|
||||
|
||||
print("Saved level 2 with layers")
|
||||
|
||||
# Delete the layers.
|
||||
general.idle_wait(1.0)
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntities', [layer1_id, layer2_id])
|
||||
|
||||
# Save level 2 again.
|
||||
general.save_level()
|
||||
|
||||
print("Saved level 2 without layers")
|
||||
|
||||
# Reopen level 1.
|
||||
general.open_level_no_prompt("test_level_1")
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") != "test_level_1":
|
||||
fail_test("Failed to reload test_level_1")
|
||||
print("Reopened level 1")
|
||||
|
||||
# Reopen level 2.
|
||||
general.open_level_no_prompt("test_level_2")
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") != "test_level_2":
|
||||
fail_test("Failed to reload test_level_2")
|
||||
print("Reopened level 2")
|
||||
|
||||
# Recover the layers
|
||||
game_folder = editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'GetGameFolder')
|
||||
layer1_path = game_folder + "\\Levels\\test_level_2\\Layers\\Layer1.layer"
|
||||
layer2_path = game_folder + "\\Levels\\test_level_2\\Layers\\Layer2.layer"
|
||||
|
||||
layers.EditorLayerComponent_RecoverLayer(layer1_path)
|
||||
layers.EditorLayerComponent_RecoverLayer(layer2_path)
|
||||
|
||||
# Check the binary save states are correct.
|
||||
layer1_binary = get_binary_save_state_for_layer("Layer1")
|
||||
layer2_binary = get_binary_save_state_for_layer("Layer2")
|
||||
|
||||
if not layer1_binary:
|
||||
fail_test("Layer1 save not set to binary.")
|
||||
if layer2_binary:
|
||||
fail_test("Layer2 save set to binary.")
|
||||
|
||||
# Undo layer recovery.
|
||||
general.undo()
|
||||
general.undo()
|
||||
|
||||
id1 = general.find_editor_entity("Layer1")
|
||||
id2 = general.find_editor_entity("Layer2")
|
||||
|
||||
if id1.isValid() or id2.isValid():
|
||||
fail_test("Failed to undo layer recovery.")
|
||||
|
||||
# Redo layer recovery.
|
||||
general.redo()
|
||||
general.redo()
|
||||
|
||||
id1 = general.find_editor_entity("Layer1")
|
||||
id2 = general.find_editor_entity("Layer2")
|
||||
|
||||
if not id1.isValid() or not id2.isValid():
|
||||
fail_test("Failed to redo layer recovery.")
|
||||
|
||||
print("Recover Layer test complete.")
|
||||
|
||||
|
||||
test = TestRecoverLayer()
|
||||
test.run()
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6130896 : Recover a layer containing a deleted slice.
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6130896
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.layers as layers
|
||||
import azlmbr.slice as slice
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestRecoverLayerDeletedSlice(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="recover_layer_deleted_slice: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Recover a layer containing a deleted slice.
|
||||
|
||||
Expected Behavior:
|
||||
The layer is not recovered and a error is given:
|
||||
This layer contains a reference to a slice that can't be loaded. This layer can't be recovered.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create a layer on the level as Layer1
|
||||
3) Create an entity as Entity1
|
||||
4) Make Entity1 a slice named Slice1
|
||||
5) Make Slice1 a child of Layer1
|
||||
6) Save the level
|
||||
7) Delete Layer1 from the level
|
||||
8) On disk find Slice1 and delete it
|
||||
9) Find Layer1 and select the "Recover layer" option for Layer1 in the Asset Browser
|
||||
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
SLICE_NAME = "Slice1.slice"
|
||||
|
||||
def get_entity_count_name(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Create a layer on the level as Layer1
|
||||
layer_id = layers.EditorLayerComponent_CreateLayerEntityFromName("Layer1")
|
||||
if get_entity_count_name("Layer1*"):
|
||||
print("Layer1 is created")
|
||||
|
||||
# 3) Create an entity as Entity1
|
||||
entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", entity.EntityId())
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", entity_id, "Entity1")
|
||||
if get_entity_count_name("Entity1*"):
|
||||
print("Entity1 is created")
|
||||
|
||||
# 4) Make Entity1 a slice named Slice1
|
||||
success = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", entity_id, SLICE_NAME)
|
||||
print(f"Slice Created: {success}")
|
||||
|
||||
# 5) Make Slice1 a child of Layer1
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetParent", entity_id, layer_id)
|
||||
actual_parent_id = editor.EditorEntityInfoRequestBus(bus.Event, "GetParent", entity_id)
|
||||
if actual_parent_id.ToString() == layer_id.ToString():
|
||||
print("Parent of Entity1 is : Layer1")
|
||||
|
||||
# 6) Save the level
|
||||
general.save_level()
|
||||
|
||||
# 7) Delete Layer1 from the level
|
||||
general.idle_wait(1.0)
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntities ', [layer_id])
|
||||
|
||||
# 8) On disk find Slice1 and delete it
|
||||
os.remove(os.path.join("SamplesProject", "Slice1.slice"))
|
||||
|
||||
# 9) Find Layer1 and select the "Recover layer" option for Layer1 in the Asset Browser
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
general.open_pane("Asset Browser")
|
||||
asset_browser = editor_window.findChildren(QtWidgets.QDockWidget, "Asset Browser")[0]
|
||||
search_bar = asset_browser.findChildren(QtWidgets.QLineEdit, "textSearch")[0]
|
||||
search_bar.setText("Layer1.layer")
|
||||
asset_browser_tree = asset_browser.findChildren(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")[0]
|
||||
asset_browser_tree.expandAll()
|
||||
model_index = pyside_utils.find_child_by_pattern(asset_browser_tree, "Layer1.layer")
|
||||
asset_browser_tree.setCurrentIndex(model_index)
|
||||
pyside_utils.trigger_context_menu_entry(asset_browser_tree, "Recover layer", index=model_index)
|
||||
|
||||
test = TestRecoverLayerDeletedSlice()
|
||||
test.run()
|
||||
@@ -0,0 +1,211 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C16929882: Required Components
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16929882
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
from azlmbr.entity import EntityId
|
||||
import azlmbr.entity as entity
|
||||
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
class RequiredComponentsTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="required_components: ", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Add required components to an entity.
|
||||
|
||||
Expected Behavior:
|
||||
1) An entity inspector will show a warning if a required component is missing.
|
||||
2) It will allow that component to be added.
|
||||
3) The warning will disappear once the component is present..
|
||||
|
||||
Test Steps:
|
||||
1) Open level.
|
||||
2) Create entity.
|
||||
3) Add a tube shape.
|
||||
4) Check there is a required component warning and drop down in the inspector.
|
||||
5) Click "Add Required Component".
|
||||
6) Check that a list of valid components has appeared.
|
||||
7) Click "Spline in the list.
|
||||
8) Check that a spline component is added to the entity.
|
||||
9) Check that the warning drop down is gone.
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
def fail_test(msg):
|
||||
print(msg)
|
||||
print("Test failed.")
|
||||
sys.exit()
|
||||
|
||||
def get_component_type_id(component_type_name):
|
||||
# Get Component Types for required component.
|
||||
type_ids_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType',
|
||||
[component_type_name], entity.EntityType().Game)
|
||||
|
||||
if len(type_ids_list) == 0:
|
||||
print("Type Ids List returned incorrectly.")
|
||||
return False, 0
|
||||
|
||||
return True, type_ids_list[0]
|
||||
|
||||
def find_component_inspector(inspector_list, component_name):
|
||||
for item in inspector_list:
|
||||
title = item.findChild(QtWidgets.QLabel, "Title")
|
||||
if title is None:
|
||||
continue
|
||||
print("Checking " + title.text())
|
||||
if title.text() == component_name:
|
||||
return item
|
||||
return None
|
||||
|
||||
async def add_spine_to_tube_shape(button):
|
||||
pyside_utils.click_button_async(button)
|
||||
list_widget = await pyside_utils.wait_for_popup_widget()
|
||||
|
||||
tree = pyside_utils.find_child_by_pattern(list_widget, "Tree")
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Down, Qt.NoModifier)
|
||||
|
||||
while tree.indexBelow(tree.currentIndex()) != QtCore.QModelIndex():
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "Shape":
|
||||
# Expand the Shape category
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Right, Qt.NoModifier)
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Right, Qt.NoModifier)
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "Spline":
|
||||
# Add this component type
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
|
||||
general.idle_wait(0.0)
|
||||
return
|
||||
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Down, Qt.NoModifier)
|
||||
|
||||
|
||||
# Create level
|
||||
create_level_result = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
if not create_level_result:
|
||||
fail_test("New level failed.")
|
||||
|
||||
EditorTestHelper.after_level_load(self)
|
||||
|
||||
# Ensure the inspector window is open.
|
||||
general.open_pane('Entity Inspector')
|
||||
|
||||
# Create an entity
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
|
||||
|
||||
# Select the entity.
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [new_entity_id])
|
||||
|
||||
# Add a Tube Shape Component
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
|
||||
tube_component = hydra.add_component("Tube Shape", new_entity_id)
|
||||
general.idle_wait(0.0)
|
||||
result, tube_component_id = get_component_type_id("Tube Shape")
|
||||
if not result:
|
||||
fail_test("Failed to find Tube Shape id.")
|
||||
|
||||
result, spline_component_id = get_component_type_id("Spline")
|
||||
if not result:
|
||||
fail_test("Failed to find Spline id.")
|
||||
|
||||
if not editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_entity_id, tube_component_id):
|
||||
fail_test("Failed to add Tube Shape to entity.")
|
||||
|
||||
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', tube_component)
|
||||
if is_enabled:
|
||||
fail_test("Tube is enabled when first created.")
|
||||
|
||||
component_list = pyside_utils.find_child_by_hierarchy(entity_inspector, ..., {"objectName": "m_componentListContents"})
|
||||
if component_list is None:
|
||||
fail_test("Failed to find component list.")
|
||||
|
||||
# Find the add required component button. It's inside a lot of anonymous frames,
|
||||
# so find the header_frame and work down from its parent.
|
||||
tube_frame = find_component_inspector(component_list.children(), "Tube Shape")
|
||||
if tube_frame is None:
|
||||
fail_test("Failed to find tube shape inspector.")
|
||||
|
||||
header_frame = pyside_utils.find_child_by_hierarchy(tube_frame, ..., {"objectName": "HeaderFrame"})
|
||||
if header_frame is None:
|
||||
fail_test("Unable to find tube header frame")
|
||||
|
||||
container_frame = header_frame.parent()
|
||||
if container_frame is None:
|
||||
fail_test("Unable to find tube container frame")
|
||||
|
||||
add_button = container_frame.findChild(QtWidgets.QPushButton)
|
||||
if add_button is None:
|
||||
fail_test("Unable to find add required component button")
|
||||
|
||||
# Check there is no spline component yet
|
||||
if editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_entity_id, spline_component_id):
|
||||
fail_test("Spline component already exists.")
|
||||
|
||||
await add_spine_to_tube_shape(add_button)
|
||||
|
||||
if not editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_entity_id, spline_component_id):
|
||||
fail_test("Failed to add Spline component to entity.")
|
||||
|
||||
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', tube_component)
|
||||
if not is_enabled:
|
||||
fail_test("Tube is not enabled.")
|
||||
|
||||
# Check that the missing component warning is gone.
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [new_entity_id])
|
||||
|
||||
component_list = pyside_utils.find_child_by_hierarchy(entity_inspector, ...,
|
||||
{"objectName": "m_componentListContents"})
|
||||
if component_list is None:
|
||||
fail_test("Failed to find component list.")
|
||||
|
||||
tube_frame = find_component_inspector(component_list.children(), "Tube Shape")
|
||||
if tube_frame is None:
|
||||
fail_test("Failed to find tube shape inspector.")
|
||||
|
||||
header_frame = pyside_utils.find_child_by_hierarchy(tube_frame, ..., {"objectName": "HeaderFrame"})
|
||||
if header_frame is not None:
|
||||
fail_test("Missing component warning still exists")
|
||||
|
||||
print("Required Component test successful.")
|
||||
|
||||
|
||||
test = RequiredComponentsTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,111 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C3712672: Save a Layer with 50,000 entities.
|
||||
https://testrail.agscollab.com/index.php?/cases/view/3712672
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.layers as layers
|
||||
import azlmbr.paths
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtTest, QtWidgets
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class SaveLayer50000EntitiesTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="save_layer_50000_entities", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Save a Layer with 50,000 entities and verify if the editor is stable.
|
||||
|
||||
Expected Behavior:
|
||||
The level and layer are saved.
|
||||
The Editor remains stable.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Delete the DefaultLevelSetup initially to make the selection of entities easier
|
||||
3) Create a new layer
|
||||
4) Initially create 2000 entities using 'Duplicate' action
|
||||
5) Duplicate the already created entities
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def search_entity(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
def layer_saved():
|
||||
return os.path.exists(os.path.join(azlmbr.paths.devroot, "SamplesProject", "Levels", self.args["level"], "Layers", "Layer.layer"))
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
outliner_widget = editor_window.findChildren(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")[0].widget()
|
||||
|
||||
# 2) Delete the DefaultLevelSetup initially to make the selection of entities easier
|
||||
default_entity_id = general.find_editor_entity("DefaultLevelSetup")
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", [default_entity_id])
|
||||
|
||||
# 3) Create a new layer
|
||||
layer_id = layers.EditorLayerComponent_CreateLayerEntityFromName("Layer")
|
||||
print(f"New layer created: {layer_id.isValid()}")
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", layer_id)
|
||||
general.select_object("Entity2")
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", "Select All")
|
||||
|
||||
# 4) Initially create 2000 entities using 'Duplicate' action
|
||||
for _ in range(2000):
|
||||
QtTest.QTest.keyPress(outliner_widget, Qt.Key_D, Qt.ControlModifier)
|
||||
|
||||
# 5) Duplicate the already created entities
|
||||
action.trigger()
|
||||
for _ in range(25):
|
||||
QtTest.QTest.keyPress(outliner_widget, Qt.Key_D, Qt.ControlModifier)
|
||||
print(f"50000 entities created: {search_entity('Entity2')>=50000}")
|
||||
|
||||
# 6) Save/Verify if layer is saved
|
||||
general.clear_selection()
|
||||
general.select_object("Layer")
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save")
|
||||
action.trigger()
|
||||
self.wait_for_condition(layer_saved, 250.0)
|
||||
print(f"Layer saved: {layer_saved()}")
|
||||
|
||||
|
||||
test = SaveLayer50000EntitiesTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C15167490: Save a level
|
||||
https://testrail.agscollab.com/index.php?/cases/view/15167490
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestSaveALevel(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="save_level: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Create or open a level in editor. Create an entity and
|
||||
Save level with new name using File > Save As..
|
||||
|
||||
Expected Behavior:
|
||||
The "Save Level As" dialog appears.
|
||||
A new level file is created and saved with the name provided.
|
||||
The level is saved.
|
||||
|
||||
Test Steps:
|
||||
1) Create or open a level in the editor.
|
||||
2) Create an entity and Save Level with new name
|
||||
3) Make any changes to the level and click on save
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
active_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
save_level_as_dialogue = active_widget.findChild(QtWidgets.QWidget, "LevelFileDialog")
|
||||
if save_level_as_dialogue.windowTitle() == "Save Level As ":
|
||||
print("The 'Save Level As' dialog appeared")
|
||||
level_name = save_level_as_dialogue.findChild(QtWidgets.QLineEdit, "nameLineEdit")
|
||||
level_name.setText("tmp_new_level")
|
||||
button_box = save_level_as_dialogue.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
general.idle_wait(3.0) #wait for new level lo load
|
||||
|
||||
def on_action_triggered(action):
|
||||
print(f"{action} Action triggered")
|
||||
|
||||
# 1) Create or open a level in the editor.
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(4.0)
|
||||
|
||||
# 2) Create an entity and Save Level with new name
|
||||
newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId.EntityId())
|
||||
if newEntityId.IsValid():
|
||||
print("Entity created")
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save As")
|
||||
action.triggered.connect(on_action_triggered("Save As"))
|
||||
action.trigger()
|
||||
action.triggered.disconnect(on_action_triggered("Save As"))
|
||||
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
# Verify if the new level is loaded
|
||||
general.idle_wait(2.0)
|
||||
if editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName") == "tmp_new_level":
|
||||
print("A new level file is created and saved with the name provided.: SUCCESS")
|
||||
else:
|
||||
print("A new level file is created and saved with the name provided.: FAILED")
|
||||
|
||||
# 3) Make any changes to the level and click on save
|
||||
new_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId.EntityId())
|
||||
if new_entity.IsValid():
|
||||
print("Made a change in level")
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save")
|
||||
action.triggered.connect(on_action_triggered("Save"))
|
||||
action.trigger()
|
||||
action.triggered.disconnect(on_action_triggered("Save"))
|
||||
|
||||
|
||||
test = TestSaveALevel()
|
||||
test.run()
|
||||
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C2654251: Adding and deleting entities to a slice should be included on save overrides by default
|
||||
https://testrail.agscollab.com/index.php?/cases/view/2654251
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.math as math
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.entity as EntityId
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtCore import Qt
|
||||
from re import compile as regex
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class SaveOverridesDefaultTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="save_overrides_default", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Adding and deleting entities to a slice should be included on save overrides by default
|
||||
|
||||
Expected Behavior:
|
||||
Observe that the Adding of Child 2 and the Deletion of Child 1 are both checked by default
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Create 2 entities as parent and child
|
||||
3) Create slice from the parent entity
|
||||
4) Wait until slice is created
|
||||
5) Delete child on slice
|
||||
6) Add a new child to the slice
|
||||
7) Open Save Slice Overrides (Advanced) and verify if the changes are checked by default
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
SLICE_NAME = "temp_slice.slice"
|
||||
self.focus_changed_flag = False
|
||||
|
||||
def path_is_valid_asset(asset_path):
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
|
||||
return asset_id.invoke("IsValid")
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
active_modal_widget = QtWidgets.QApplication.activeModalWidget()
|
||||
if active_modal_widget and not self.focus_changed_flag:
|
||||
self.focus_changed_flag = True
|
||||
# verify the changes child1 (deleted) and child2 (added) are checked by default
|
||||
# if the Qt.CheckStateRole of the checkbox is 2, it means it is checked
|
||||
child1_deleted = pyside_utils.find_child_by_pattern(active_modal_widget, "child1 (deleted)").data(
|
||||
Qt.CheckStateRole
|
||||
)
|
||||
print(f"Child 1 deleted change checked by default: {child1_deleted == 2}")
|
||||
child2_added = pyside_utils.find_child_by_pattern(active_modal_widget, "child2 (added)").data(
|
||||
Qt.CheckStateRole
|
||||
)
|
||||
print(f"Child 2 added change checked by default: {child2_added == 2}")
|
||||
active_modal_widget.close()
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Create 2 entities as parent and child
|
||||
parent_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId.EntityId())
|
||||
child_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", parent_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_id, "child1")
|
||||
|
||||
# 3) Create slice from the parent entity
|
||||
success = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", parent_id, SLICE_NAME)
|
||||
print(f"Slice Created: {success}")
|
||||
|
||||
# 4) Wait until slice is created
|
||||
self.wait_for_condition(lambda: path_is_valid_asset(SLICE_NAME), 3.0)
|
||||
|
||||
# 5) Delete child on slice
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", [child_id])
|
||||
|
||||
# 6) Add a new child to the slice
|
||||
child_2_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", parent_id)
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetName", child_2_id, "child2")
|
||||
|
||||
# 7) Open Save Slice Overrides (Advanced) and verify if the changes are checked by default
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
outliner_widget = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Outliner.*")), ..., "m_objectList"
|
||||
).parent()
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 1) is not None)
|
||||
model_index = pyside_utils.get_item_view_index(tree, 0)
|
||||
app = QtWidgets.QApplication.instance()
|
||||
try:
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
await pyside_utils.trigger_context_menu_entry(tree, "Save Slice Overrides (Advanced)...", index=model_index)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
test = SaveOverridesDefaultTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C1508364 : Select over 1,000+ entities that are open in the Entity Outliner at one time
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1508364
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
from azlmbr.entity import EntityId
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtCore, QtTest, QtWidgets
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
from re import compile as regex
|
||||
|
||||
|
||||
class TestSelectMultipleEntitiesEntityOutliner(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="select_multiple_entities_entityoutliner", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Select over 1,000+ entities that are open in the Entity Outliner at one time
|
||||
|
||||
Expected Behavior:
|
||||
The engine remains stable while selecting a large number of entities.
|
||||
Selected entities are highlighted in the Entity Outliner.
|
||||
The Entity Inspector shows an accurate count of selected entities.
|
||||
The engine remains stable while selecting entities in the Outliner.
|
||||
Selected entities are highlighted in the outliner.
|
||||
The Entity Inspector shows an accurate count of selected entities.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Delete the DefaultLevelSetup initially to make the selection of entities easier
|
||||
3) Create 1000 entities using 'Duplicate' action
|
||||
4) Verify CTRL+click to select individual entities
|
||||
5) Select all entities and make sure selected entities are highlighted in the Entity Outliner
|
||||
6) Verify the count of selected entities in Entity Inspector
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_entity_count_name(entity_name):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return len(entities)
|
||||
|
||||
def verify_selected_index(expected_entity_list):
|
||||
# NOTE: selectedIndexes() seems to return 2 extra elements for each item seleted whose data() is None
|
||||
# So removing the items whose data is None and considering only the selected items having data.
|
||||
selected_indexes = [i for i in tree.selectedIndexes() if i.data()]
|
||||
return sorted(selected_indexes) == sorted(expected_entity_list)
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# Get the editor window object
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# Get the outliner widget object based on the window title
|
||||
outliner_widget = editor_window.findChildren(QtWidgets.QDockWidget, "Entity Outliner (PREVIEW)")[0].widget()
|
||||
|
||||
# Get the entity inspector object based on the window title
|
||||
entity_inspector_name_editor = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Inspector.*")), ..., "m_entityNameEditor"
|
||||
)
|
||||
|
||||
# Get the object tree in the entity outliner
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
|
||||
# 2) Delete the DefaultLevelSetup initially to make the selection of entities easier
|
||||
default_entity_id = general.find_editor_entity("DefaultLevelSetup")
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", [default_entity_id])
|
||||
|
||||
# 3) Create 1000 entities using 'Duplicate' action
|
||||
entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", EntityId())
|
||||
entity_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "SetSelectedEntities", [entity_id])
|
||||
for _ in range(999):
|
||||
QtTest.QTest.keyPress(outliner_widget, Qt.Key_D, Qt.ControlModifier)
|
||||
|
||||
if get_entity_count_name(entity_name) == 1000:
|
||||
print("1000 entities created")
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "SetSelectedEntities", [])
|
||||
|
||||
# 4) Verify CTRL+click to select individual entities
|
||||
# CTRL+click on First Entity and verify if First Entity is selected
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 1) is not None, 2.0)
|
||||
model_index_1 = pyside_utils.get_item_view_index(tree, 0)
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_1, modifier=QtCore.Qt.ControlModifier)
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "Entity1", 1.0)
|
||||
print(
|
||||
f"The Entity Inspector shows an accurate count of selected entities (1 element): {entity_inspector_name_editor.text() == 'Entity1'}"
|
||||
)
|
||||
print(f"CTRL+click worked for adding selected elements (1 element): {verify_selected_index([model_index_1])}")
|
||||
|
||||
# CTRL+click on Second Entity and verify if First Entity and Second Entity are selected
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 2) is not None, 2.0)
|
||||
model_index_2 = pyside_utils.get_item_view_index(tree, 1)
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_2, modifier=QtCore.Qt.ControlModifier)
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "2 entities selected", 1.0)
|
||||
print(
|
||||
f"The Entity Inspector shows an accurate count of selected entities (2 elements): {entity_inspector_name_editor.text() == '2 entities selected'}"
|
||||
)
|
||||
print(
|
||||
f"CTRL+click worked for adding selected elements (2 elements): {verify_selected_index([model_index_1, model_index_2])}"
|
||||
)
|
||||
|
||||
# CTRL+click on Third Entity and verify if First Entity, Second Entity and Third Entity are selected
|
||||
self.wait_for_condition(lambda: pyside_utils.get_item_view_index(tree, 3) is not None, 2.0)
|
||||
model_index_3 = pyside_utils.get_item_view_index(tree, 2)
|
||||
pyside_utils.item_view_index_mouse_click(tree, model_index_3, modifier=QtCore.Qt.ControlModifier)
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "3 entities selected", 1.0)
|
||||
print(
|
||||
f"The Entity Inspector shows an accurate count of selected entities (3 elements): {entity_inspector_name_editor.text() == '3 entities selected'}"
|
||||
)
|
||||
print(
|
||||
f"CTRL+click worked for adding selected elements (3 elements): {verify_selected_index([model_index_1, model_index_2, model_index_3])}"
|
||||
)
|
||||
|
||||
# 5) Select all entities and make sure selected entities are highlighted in the Entity Outliner
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", "Select All")
|
||||
action.trigger()
|
||||
if len(editor.ToolsApplicationRequestBus(bus.Broadcast, "GetSelectedEntities")) == 1000:
|
||||
print("Selected entities are highlighted in the Entity Outliner")
|
||||
|
||||
# 6) Verify the count of selected entities in Entity Inspector
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "1000 entities selected", 1.0)
|
||||
print(
|
||||
f"The Entity Inspector shows an accurate count of selected entities (1000 elements): {entity_inspector_name_editor.text() == '1000 entities selected'}"
|
||||
)
|
||||
|
||||
|
||||
test = TestSelectMultipleEntitiesEntityOutliner()
|
||||
test.run()
|
||||
@@ -0,0 +1,147 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
Test the Hydra API to access Editor Settings
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
class TestSettingsAPI(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="settings_get_set: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Tests the Hydra API for Settings.
|
||||
|
||||
Expected Behavior:
|
||||
Settings can be listed, accessed and set.
|
||||
|
||||
Test Steps:
|
||||
1) Build the list of all settings
|
||||
2) For each supported type (bool, int, float, string):
|
||||
2a) Get the current values
|
||||
2b) Set an altered values
|
||||
2c) Get the value again
|
||||
2d) Verify the value has changed
|
||||
2e) Restore original value
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# Get full list of Editor settings
|
||||
paths = editor.EditorSettingsAPIBus(bus.Broadcast, 'BuildSettingsList')
|
||||
|
||||
if(len(paths) > 0):
|
||||
print("BuildSettingsList returned a non-empty list")
|
||||
|
||||
|
||||
# Verify a boolean settings
|
||||
def ParseBoolValue(value):
|
||||
if(value == "0"):
|
||||
return False
|
||||
return True
|
||||
|
||||
boolOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|LoadLastLevelAtStartup')
|
||||
|
||||
if(boolOutcome.isSuccess()):
|
||||
startupValue = boolOutcome.GetValue()
|
||||
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|LoadLastLevelAtStartup', not(ParseBoolValue(startupValue)))
|
||||
|
||||
boolOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|LoadLastLevelAtStartup')
|
||||
|
||||
if(boolOutcome.isSuccess()):
|
||||
newStartupValue = boolOutcome.GetValue()
|
||||
|
||||
if not(ParseBoolValue(startupValue) == ParseBoolValue(newStartupValue)):
|
||||
print("Boolean Setting editing works")
|
||||
|
||||
# Restore previous value
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|LoadLastLevelAtStartup', ParseBoolValue(startupValue))
|
||||
|
||||
|
||||
# Verify an int settings
|
||||
intOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|UndoLevels')
|
||||
|
||||
if(intOutcome.isSuccess()):
|
||||
undoLevel = intOutcome.GetValue()
|
||||
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|UndoLevels', (int(undoLevel) + 10))
|
||||
|
||||
intOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|UndoLevels')
|
||||
|
||||
if(intOutcome.isSuccess()):
|
||||
newUndoLevel = intOutcome.GetValue()
|
||||
|
||||
if not(int(undoLevel) == int(newUndoLevel)):
|
||||
print("Int Setting editing works")
|
||||
|
||||
# Restore previous value
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|UndoLevels', int(undoLevel))
|
||||
|
||||
|
||||
# Verify a float settings
|
||||
floatOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|DeepSelectionNearness')
|
||||
|
||||
if(floatOutcome.isSuccess()):
|
||||
deepSelection = floatOutcome.GetValue()
|
||||
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|DeepSelectionNearness', (float(deepSelection) + 0.5))
|
||||
|
||||
floatOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|DeepSelectionNearness')
|
||||
|
||||
if(floatOutcome.isSuccess()):
|
||||
newDeepSelection = floatOutcome.GetValue()
|
||||
|
||||
if not(float(deepSelection) == float(newDeepSelection)):
|
||||
print("Float Setting editing works")
|
||||
|
||||
# Restore previous value
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|DeepSelectionNearness', float(deepSelection))
|
||||
|
||||
|
||||
# Verify a string settings
|
||||
stringOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|TemporaryDirectory')
|
||||
|
||||
if(stringOutcome.isSuccess()):
|
||||
tempDir = stringOutcome.GetValue()
|
||||
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|TemporaryDirectory', "SomeTempDirectory")
|
||||
|
||||
stringOutcome = editor.EditorSettingsAPIBus(bus.Broadcast, 'GetValue', 'Settings|TemporaryDirectory')
|
||||
|
||||
if(stringOutcome.isSuccess()):
|
||||
newTempDir = stringOutcome.GetValue()
|
||||
|
||||
if not(tempDir == newTempDir):
|
||||
print("String Setting editing works")
|
||||
|
||||
# Restore previous value
|
||||
editor.EditorSettingsAPIBus(bus.Broadcast, 'SetValue', 'Settings|TemporaryDirectory', tempDir)
|
||||
|
||||
|
||||
test = TestSettingsAPI()
|
||||
test.run()
|
||||
@@ -0,0 +1,188 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
C6312589: Tool Stability & Workflow: Asset Editor
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6312589
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class ToolStabilityAssetEditorTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="tool_stability_asset_editor", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Tool Stability & Workflow: Asset Editor
|
||||
|
||||
Expected Behavior:
|
||||
1) The Asset Editor can be opened/closed.
|
||||
2) New Input Bindings can be created.
|
||||
3) Created input bindings populate the Pick Input Bindings list.
|
||||
4) Input Bindings can be opened.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Open Asset Editor
|
||||
3) Create new Input Bindings
|
||||
4) Open Save As dialog
|
||||
5) Close the Asset Editor
|
||||
6) Create new entity and add a Input component
|
||||
7) Assign a .inputbindings file to the input component
|
||||
8) Open Asset Editor through the newly assigned inputbinding file
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def open_asset_editor():
|
||||
if general.is_pane_visible("Asset Editor"):
|
||||
return True
|
||||
general.open_pane("Asset Editor")
|
||||
return general.is_pane_visible("Asset Editor")
|
||||
|
||||
def close_asset_editor():
|
||||
asset_editor.close()
|
||||
return not general.is_pane_visible("Asset Editor")
|
||||
|
||||
class InputBinding:
|
||||
input_binding_name = None
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# 2) Open Asset Editor
|
||||
print(f"Asset Editor opened: {open_asset_editor()}")
|
||||
|
||||
# 3) Create new Input Bindings
|
||||
# Access Asset editor
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor")
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "m_assetEditorWidget")
|
||||
menu_bar = asset_editor_widget.findChild(QtWidgets.QMenuBar)
|
||||
# Get the action File->New->Input Bindings
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, "Input Bindings")
|
||||
# Trigger the action
|
||||
action.trigger()
|
||||
# wait until the trigger loads the frame
|
||||
await pyside_utils.wait_for_condition(lambda: len(asset_editor_widget.findChildren(QtWidgets.QFrame, "Input Event Groups")) == 1, 3.0)
|
||||
input_event_groups = asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups")
|
||||
# Click on + button to assign Input event groups
|
||||
input_event_groups.findChildren(QtWidgets.QToolButton)[1].click()
|
||||
# wait until the click action loads the frame
|
||||
await pyside_utils.wait_for_condition(lambda: len(asset_editor_widget.findChildren(QtWidgets.QFrame, "Event Name")) == 1, 3.0)
|
||||
new_event_frame = asset_editor_widget.findChild(QtWidgets.QFrame, "<Unspecified Event>")
|
||||
expander = new_event_frame.findChild(QtWidgets.QCheckBox, "")
|
||||
expander.click()
|
||||
event_name_frame = asset_editor_widget.findChild(QtWidgets.QFrame, "Event Name")
|
||||
event_name = event_name_frame.findChildren(QtWidgets.QLineEdit)[0]
|
||||
# Set some event name
|
||||
event_name.setText("tmp_input_binding")
|
||||
|
||||
# 4) Open Save As dialog
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, {"iconText": "Save As"})
|
||||
# We use trigger_action_async here since it will open a modal dialog (save as)
|
||||
pyside_utils.trigger_action_async(action)
|
||||
# This checks if the Save As dialog is opened
|
||||
# NOTE: At the moment since we are not able to give a name and save something using QFileDialog
|
||||
# widget and for this particular case it is not so important to actually save the file, we are
|
||||
# just checking if the Save As dialog is opened and then closing it immediately
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
if active_modal_widget and "Save As" in active_modal_widget.windowTitle():
|
||||
print("Save as dialog opened")
|
||||
active_modal_widget.close()
|
||||
|
||||
# 5) Close the Asset Editor
|
||||
print(f"Asset Editor closed: {close_asset_editor()}")
|
||||
|
||||
# 6) Create new entity and add a Input component
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
hydra.add_component("Input", entity_id)
|
||||
entity_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
|
||||
|
||||
# 7) Assign a .inputbindings file to the input component
|
||||
general.clear_selection()
|
||||
general.select_object(entity_name)
|
||||
general.open_pane("Entity Inspector")
|
||||
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
|
||||
await pyside_utils.wait_for_condition(lambda: len(entity_inspector.findChildren(QtWidgets.QPushButton, "attached-button")) == 1, 2.0)
|
||||
# Assess the file picker button of the "Input" component
|
||||
button = entity_inspector.findChild(QtWidgets.QPushButton, "attached-button")
|
||||
# Click on the file picker button and select a .inputbinding file
|
||||
# We use click_button_async here since it will open a modal dialog
|
||||
pyside_utils.click_button_async(button)
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
# This is to deal with the file picker for .inputbinding
|
||||
if active_modal_widget:
|
||||
tree = active_modal_widget.findChild(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")
|
||||
# Make sure the folder structure tree is expanded so that after giving the searchtext the first
|
||||
# .inputbinding file is selected
|
||||
tree.expandAll()
|
||||
search_text = active_modal_widget.findChild(QtWidgets.QLineEdit, "textSearch")
|
||||
# Set the searchText so that the first .inputbinding file in the folder structure is selected
|
||||
search_text.setText(".inputbindings")
|
||||
# Save the file name for later to check when we open the Asset Editor
|
||||
InputBinding.input_binding_name = tree.currentIndex().data(Qt.DisplayRole)
|
||||
# Ensure the currently selected item actually is a .inputbinding file
|
||||
await pyside_utils.wait_for_condition(lambda: ".inputbinding" in str(tree.currentIndex().data(Qt.DisplayRole)))
|
||||
if ".inputbinding" in str(tree.currentIndex().data(Qt.DisplayRole)):
|
||||
print(".inputbinding file is selected in the file picker")
|
||||
# Click OK
|
||||
button_box = active_modal_widget.findChild(QtWidgets.QDialogButtonBox, "m_buttonBox")
|
||||
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
|
||||
|
||||
# 8) Open Asset Editor through the newly assigned inputbinding file
|
||||
# Access the popup button to open the Asset Editor
|
||||
tool_button_parent = entity_inspector.findChild(QtWidgets.QFrame, "browse-edit").parent()
|
||||
tool_button = tool_button_parent.findChild(QtWidgets.QToolButton)
|
||||
initial_active_window = QtWidgets.QApplication.activeWindow()
|
||||
# Click on the "Open in Input Bindings Editor" button to open the selected .inputbindings file in the
|
||||
# Asset Editor
|
||||
tool_button.click()
|
||||
await pyside_utils.wait_for_condition(lambda: initial_active_window != QtWidgets.QApplication.activeWindow(), 3.0)
|
||||
current_active_window = QtWidgets.QApplication.activeWindow()
|
||||
# Verify if the newly opened window is actually the Asset Editor to edit the selected inputbinding
|
||||
if current_active_window.findChildren(QtWidgets.QDockWidget, InputBinding.input_binding_name):
|
||||
print("Asset Editor for the assigned inputbinding file is opened")
|
||||
|
||||
|
||||
test = ToolStabilityAssetEditorTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,94 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6308169: Tool Stability & Workflow: Console
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6308169
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from PySide2.QtTest import QTest
|
||||
from PySide2.QtCore import Qt
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class ToolStabilityConsoleTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="tool_stability_console: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Tool Stability & Workflow: Console
|
||||
|
||||
Expected Behavior:
|
||||
1) Console can be opened
|
||||
2) Commands can be entered in the console
|
||||
3) Console can be closed
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Open console
|
||||
3) Close the console
|
||||
4) Reopen console
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def open_console():
|
||||
general.open_pane("Console")
|
||||
return general.is_pane_visible("Console")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Open console
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
if main_window.findChild(QtWidgets.QDockWidget, "Console") is None:
|
||||
print(f"Console opened successfully: {open_console()}")
|
||||
console = main_window.findChild(QtWidgets.QDockWidget, "Console")
|
||||
console_widget = console.findChild(QtWidgets.QWidget, "Console")
|
||||
container = console_widget.findChild(QtWidgets.QWidget, "container2")
|
||||
line_edit = container.findChild(QtWidgets.QLineEdit, "lineEdit")
|
||||
line_edit.setText("r_GetScreenShot=2")
|
||||
QTest.keyClick(line_edit, Qt.Key_Enter, Qt.ControlModifier)
|
||||
general.idle_wait(1.0)
|
||||
print("Ran the command in console")
|
||||
|
||||
# 3) Close the console
|
||||
general.close_pane("Console")
|
||||
print(f"Console window closed: {not general.is_pane_visible('Console')}")
|
||||
|
||||
# 4) Reopen console
|
||||
print(f"Console reopened successfully: {open_console()}")
|
||||
|
||||
|
||||
test = ToolStabilityConsoleTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C6308162: Tool Stability: Entity Inspector
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6308162
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.math as math
|
||||
import azlmbr.asset as asset
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
from PySide2.QtCore import Qt
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestToolStabilityEntityInspector(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="tool_stability_entity_inspector: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Tool Stability: Entity Inspector
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create an Entity with Mesh component
|
||||
3) View the entity in the Viewport and Take screenshot
|
||||
4) Click on the filter icon in Entity Outliner and check the entities filtered by "Mesh" in Entity Outliner
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
print("focus changed")
|
||||
popup = QtWidgets.QApplication.activePopupWidget()
|
||||
if popup:
|
||||
while tree.indexBelow(tree.currentIndex()) != QtCore.QModelIndex():
|
||||
QtTest.QTest.keyClick(tree, Qt.Key_Down, Qt.NoModifier)
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "Mesh":
|
||||
break
|
||||
tree.model().setData(tree.currentIndex(), 2, Qt.CheckStateRole)
|
||||
outliner_tree = outliner_main_window.findChildren(QtWidgets.QTreeView, "m_objectTree")[0]
|
||||
# make sure only one entity with mesh component is filtered
|
||||
QtTest.QTest.keyClick(outliner_tree, Qt.Key_Down, Qt.NoModifier)
|
||||
if tree.currentIndex().data(Qt.DisplayRole) == "Mesh" and outliner_tree.indexBelow(outliner_tree.currentIndex()) == QtCore.QModelIndex():
|
||||
print("Entity with Mesh component is filtered by Entity outliner")
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# 2) Create an Entity with Mesh component
|
||||
entity_position = math.Vector3(125.0, 136.0, 32.0)
|
||||
entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
general.clear_selection()
|
||||
entity_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
|
||||
general.select_object(entity_name)
|
||||
Entity = hydra.Entity("Entity", entity_id)
|
||||
Entity.components = []
|
||||
Entity.components.append(hydra.add_component("Mesh", entity_id))
|
||||
|
||||
def get_asset_by_path(path):
|
||||
return asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", path, math.Uuid(), False)
|
||||
|
||||
# Add any valid mesh asset
|
||||
hydra.get_set_test(
|
||||
Entity,
|
||||
0,
|
||||
"MeshComponentRenderNode|Mesh asset",
|
||||
get_asset_by_path(os.path.join("Objects", "SamplesAssets", "mover_display_smooth.cgf")),
|
||||
)
|
||||
|
||||
# 3) View the entity in the Viewport and Take screenshot
|
||||
self.take_viewport_screenshot(125.00, 129.01, 34.90, 0.00, 0.00, 0.00)
|
||||
screenshot_path = os.path.join("Cache", "SamplesProject", "pc", "user", "screenshots", "screenshot0000.jpg")
|
||||
if os.path.isfile(screenshot_path):
|
||||
print("Screenshot Taken")
|
||||
|
||||
# 4) Click on the filter icon in Entity Outliner and check the entities filtered by "Mesh" in Entity Outliner
|
||||
general.idle_wait(2.0)
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
entity_outliner = pyside_utils.find_child_by_property(
|
||||
main_window, QtWidgets.QDockWidget, "objectName", "Entity Outliner (PREVIEW)"
|
||||
)
|
||||
outliner_main_window = entity_outliner.findChild(QtWidgets.QMainWindow)
|
||||
tool_button = (
|
||||
outliner_main_window.findChild(QtWidgets.QWidget)
|
||||
.findChild(QtWidgets.QWidget, "OutlinerWidgetUI")
|
||||
.findChild(QtWidgets.QFrame, "m_searchWidget")
|
||||
.findChild(QtWidgets.QFrame, "textSearchContainer")
|
||||
.findChild(QtWidgets.QToolButton, "assetTypeSelector")
|
||||
)
|
||||
try:
|
||||
menu = tool_button.findChild(QtWidgets.QMenu)
|
||||
tree = menu.findChild(QtWidgets.QTreeView)
|
||||
app = QtWidgets.QApplication.instance()
|
||||
line_edit = menu.findChild(QtWidgets.QLineEdit, "filteredSearchWidget")
|
||||
line_edit.setFocus()
|
||||
line_edit.setText("Mesh")
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
tree.setFocus()
|
||||
tool_button.click()
|
||||
general.idle_wait(1.0)
|
||||
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
|
||||
test = TestToolStabilityEntityInspector()
|
||||
test.run_test()
|
||||
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
C6308161: Tool Stability: Entity Outliner
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6308161
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.slice as slice
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.math as math
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from re import compile as regex
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class ToolStabilityEntityOutlinerTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="tool_stability_entity_outliner", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Tool Stability: Entity Outliner - This can be verified by creating entity, layer, slice and
|
||||
instantiating a slice.
|
||||
|
||||
Expected Behavior:
|
||||
1) Entities can be created in the Entity Outliner.
|
||||
2) Created entities populate in other tools properly.
|
||||
3) Entity creation can be undone and related tools are updated.
|
||||
4) Entity creation can be redone and related tools are updated.
|
||||
5) Layers can be created in the Entity Outliner.
|
||||
5) Created layers populate in the Entity Inspector properly.
|
||||
6) Slices can be created inside the Entity Outliner.
|
||||
7) Slices can be instantiated inside the Entity Outliner.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create Entity and verify if it is created
|
||||
3) Undo entity creation and verify if entity is deleted
|
||||
4) Redo the last operation
|
||||
5) Create layer and verify if it is created
|
||||
6) Create slice using the first entity
|
||||
7) Instantiate an existing slice
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def get_entities_by_name(entity_name="Entity2"):
|
||||
searchFilter = entity.SearchFilter()
|
||||
searchFilter.names = [entity_name]
|
||||
entities = entity.SearchBus(bus.Broadcast, "SearchEntities", searchFilter)
|
||||
return entities
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# Get the editor window object
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# Get the outliner widget object based on the window title
|
||||
outliner_widget = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Outliner.*")), ..., "m_objectList"
|
||||
).parent()
|
||||
|
||||
# Get the object tree in the entity outliner
|
||||
tree = pyside_utils.find_child_by_hierarchy(outliner_widget, ..., "m_objectTree")
|
||||
|
||||
# Get the entity inspector object based on the window title
|
||||
entity_inspector_name_editor = pyside_utils.find_child_by_hierarchy(
|
||||
editor_window, ..., dict(windowTitle=regex("Entity Inspector.*")), ..., "m_entityNameEditor"
|
||||
)
|
||||
|
||||
# 2) Create Entity and verify if it is created
|
||||
general.clear_selection()
|
||||
|
||||
# find Create Entity action and trigger it
|
||||
action = pyside_utils.find_child_by_pattern(outliner_widget, "Create Entity")
|
||||
action.trigger()
|
||||
|
||||
# ensure entity is created
|
||||
entities = get_entities_by_name()
|
||||
print(f"New entity created: {len(entities) == 1}")
|
||||
|
||||
# get the newly create entity id and check if it is valid
|
||||
entity_id = entities[0]
|
||||
print(f"Entity Id is valid: {entity_id.isValid()}")
|
||||
|
||||
# check in entity inspector that the newly created entity is present by verifying
|
||||
# the name populated in the name editor in entity inspector
|
||||
general.select_object("Entity2")
|
||||
general.idle_wait(1.0)
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "Entity2", 1.0)
|
||||
print(f"Entity name populated in Entity Inspector: {entity_inspector_name_editor.text() == 'Entity2'}")
|
||||
|
||||
# 3) Undo entity creation and verify if entity is deleted
|
||||
general.undo()
|
||||
self.wait_for_condition(lambda: len(get_entities_by_name()) == 0, 3.0)
|
||||
print(f"Entity creation undone: {len(get_entities_by_name())==0}")
|
||||
|
||||
# 4) Redo the last operation
|
||||
general.idle_wait(1.0)
|
||||
general.redo()
|
||||
self.wait_for_condition(lambda: len(get_entities_by_name()) == 1, 3.5)
|
||||
print(f"Entity appeared after redo: {len(get_entities_by_name())==1}")
|
||||
|
||||
# 5) Create layer and verify if it is created
|
||||
general.idle_wait(2.0)
|
||||
pyside_utils.trigger_context_menu_entry(tree, "Create layer")
|
||||
|
||||
# ensure entity is created
|
||||
self.wait_for_condition(lambda: len(get_entities_by_name("Layer3*")) == 1, 1.0)
|
||||
print(f"New layer created: {len(get_entities_by_name('Layer3*'))==1}")
|
||||
|
||||
# check in entity inspector that the newly created entity is present by verifying
|
||||
# the name populated in the name editor in entity inspector
|
||||
general.clear_selection()
|
||||
general.select_object("Layer3*")
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "Layer3", 1.0)
|
||||
print(f"Layer name populated in Entity Inspector: {entity_inspector_name_editor.text() == 'Layer3'}")
|
||||
|
||||
# 6) Create slice using the first entity
|
||||
current_level_name = editor.EditorToolsApplicationRequestBus(bus.Broadcast, "GetCurrentLevelName")
|
||||
slice_path = os.path.join("Levels", current_level_name, "TestSlice.slice")
|
||||
slice_created = slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", entity_id, slice_path)
|
||||
print(f"Slice created successfully: {slice_created}")
|
||||
|
||||
# 7) Instantiate an existing slice
|
||||
# ensure we clear the selection so that the newly instantiated slice is selected after instantiating
|
||||
# so that we can verify the name of the object in the entity inspector
|
||||
general.clear_selection()
|
||||
slice_path = os.path.join("EngineAssets", "Slices", "DefaultLevelSetup.slice")
|
||||
asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False)
|
||||
transform = math.Transform_CreateIdentity()
|
||||
position = math.Vector3(64.0, 64.0, 32.0)
|
||||
transform.SetPosition(position)
|
||||
slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform)
|
||||
self.wait_for_condition(lambda: entity_inspector_name_editor.text() == "DefaultLevelSetup", 2.0)
|
||||
print(
|
||||
f"Instantiated slice populated in Entity Inspector: {entity_inspector_name_editor.text() == 'DefaultLevelSetup'}"
|
||||
)
|
||||
|
||||
|
||||
test = ToolStabilityEntityOutlinerTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
C6308168: Tool Stability & Workflow: Viewport Camera Selector
|
||||
https://testrail.agscollab.com/index.php?/cases/view/6308168
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
import Tests.ly_shared.hydra_editor_utils as hydra
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class ToolStabilityViewportCameraSelectorTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="tool_stability_viewport_camera_selector", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Tool Stability & Workflow: Viewport Camera Selector. This can be verified by creating mutiple entities
|
||||
with Camera component and verifying their functionality by clicking each of them in the Viewport Camera
|
||||
Selector tool
|
||||
|
||||
Expected Behavior:
|
||||
The Viewport Camera Selector can be opened.
|
||||
Cameras added to a level will populate the Veiwport Camera Selector.
|
||||
Selecting cameras in the Viewport Camera Selector will change the perspective camera in the Viewport.
|
||||
The Viewport Camera Selector can be closed.
|
||||
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Create first Camera component entity
|
||||
3) Create second Camera component entity at different position
|
||||
4) Open Viewport Camera Selector
|
||||
5) Click on both the Cameras in Viewport Camera Selector and verify view position
|
||||
6) Close Viewport Camera Selector
|
||||
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
CAM_POSITION_1 = (512.0, 512.0, 34.0)
|
||||
CAM_POSITION_2 = (100.0, 100.0, 34.0)
|
||||
|
||||
def create_camera_verify(entity_name, camera_position):
|
||||
general.set_current_view_position(*camera_position)
|
||||
# Trigger the action
|
||||
pyside_utils.trigger_context_menu_entry(view_port, "Create camera entity from view")
|
||||
# Verify if the entity is created with the name Camera# (Ex: Camera1)
|
||||
camera_entity_id = general.find_editor_entity(entity_name)
|
||||
assert camera_entity_id.isValid(), f"Entity {entity_name} with Camera component is not created"
|
||||
# Verify if the entity has Camera component added
|
||||
assert hydra.has_components(camera_entity_id, ["Camera"]), "Entity do not have a Camera component"
|
||||
|
||||
def select_camera_verify_position(camera_index, expected_position):
|
||||
# Get the model index of the camera in the list view of Viewport Camera Selector
|
||||
model_index = pyside_utils.find_child_by_pattern(list_view, f"Camera{camera_index}")
|
||||
assert model_index, f"Camera{camera_index} not found in Camera View Selctor"
|
||||
# Click on the camera
|
||||
pyside_utils.item_view_index_mouse_click(list_view, model_index)
|
||||
self.wait_for_condition(
|
||||
lambda: general.get_current_view_position().x == expected_position[0]
|
||||
and general.get_current_view_position().y == expected_position[1]
|
||||
and general.get_current_view_position().z == expected_position[2],
|
||||
1.0,
|
||||
)
|
||||
current_position = general.get_current_view_position()
|
||||
assert (
|
||||
current_position.x == expected_position[0]
|
||||
and current_position.y == expected_position[1]
|
||||
and current_position.z == expected_position[2]
|
||||
), f"View position incorrect for Camera {camera_index}"
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
# Get the editor window, main window, viewport objects
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
main_window = editor_window.findChild(QtWidgets.QMainWindow)
|
||||
view_port = main_window.findChildren(QtWidgets.QWidget, "renderOverlay")[0]
|
||||
|
||||
# 2) Create first Camera component entity
|
||||
create_camera_verify("Camera1", CAM_POSITION_1)
|
||||
print("done")
|
||||
# 3) Create second Camera component entity at different position
|
||||
create_camera_verify("Camera2", CAM_POSITION_2)
|
||||
|
||||
# 4) Open Viewport Camera Selector
|
||||
if not general.is_pane_visible("Viewport Camera Selector"):
|
||||
general.open_pane("Viewport Camera Selector")
|
||||
# Get the Camera Selector object and the list of cameras
|
||||
camera_selector = editor_window.findChildren(QtWidgets.QDockWidget, "Viewport Camera Selector")[0]
|
||||
list_view = camera_selector.findChildren(QtWidgets.QListView)[0]
|
||||
|
||||
# 5) Click on both the Cameras in Viewport Camera Selector and verify view position
|
||||
select_camera_verify_position(1, CAM_POSITION_1)
|
||||
select_camera_verify_position(2, CAM_POSITION_2)
|
||||
|
||||
# 6) Close Viewport Camera Selector
|
||||
camera_selector.close()
|
||||
self.wait_for_condition(lambda: not general.is_pane_visible("Viewport Camera Selector"), 1.0)
|
||||
if not general.is_pane_visible("Viewport Camera Selector"):
|
||||
print("Viewport Camera Selector is closed")
|
||||
|
||||
|
||||
test = ToolStabilityViewportCameraSelectorTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C1564077: The Tools menu options function normally - New view interaction Model enabled
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1564077
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestToolsMenuOptionsAfterInteractionModelToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="tools_menu_after_interaction_model_toggle: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with Tools Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The Tools menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Interact with Tools Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
tools_menu_options = [
|
||||
("Animation Editor (PREVIEW)",),
|
||||
("Asset Browser",),
|
||||
("Asset Editor",),
|
||||
("Console",),
|
||||
("Entity Inspector",),
|
||||
("ImGui Editor",),
|
||||
("Landscape Canvas",),
|
||||
("Level Inspector",),
|
||||
("Lua Editor",),
|
||||
("Material Editor",),
|
||||
("Particle Editor",),
|
||||
("PhysX Configuration (PREVIEW)",),
|
||||
("Script Canvas",),
|
||||
("Slice Relationship View (PREVIEW)",),
|
||||
("UI Editor",),
|
||||
("Vegetation Editor",),
|
||||
("Other", "Audio Controls Editor"),
|
||||
("Other", "Console Variables"),
|
||||
("Other", "Lens Flare Editor"),
|
||||
("Other", "Measurement System Tool"),
|
||||
("Other", "Python Console"),
|
||||
("Other", "Python Scripts"),
|
||||
("Other", "Slice Favorites"),
|
||||
("Other", "Sun Trajectory Tool"),
|
||||
("Other", "Terrain Texture Layers"),
|
||||
("Other", "Time Of Day"),
|
||||
("Plug-Ins", "Substance Editor"),
|
||||
("Viewport", "Viewport Camera Selector"),
|
||||
]
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
print("Focus Changed")
|
||||
QtWidgets.QApplication.activeModalWidget().close()
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
|
||||
# 2) Interact with File Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
for option in tools_menu_options:
|
||||
action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", *option)
|
||||
trig_func = lambda: on_action_triggered(action.iconText())
|
||||
action.triggered.connect(trig_func)
|
||||
action.trigger()
|
||||
action.triggered.disconnect(trig_func)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
general.close_pane("Editor Settings Manager")
|
||||
|
||||
test = TestToolsMenuOptionsAfterInteractionModelToggle()
|
||||
test.run()
|
||||
@@ -0,0 +1,169 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C1506899: Unsaved Changes Pop-Up
|
||||
https://testrail.agscollab.com/index.php?/cases/view/1506899
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class UnsavedChangesPopupTest(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="unsaved_changes_popup", args=["level"])
|
||||
|
||||
@pyside_utils.wrap_async
|
||||
async def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Verify if the unsaved change popup appears and each of the buttons function appropriately.
|
||||
|
||||
Expected Behavior:
|
||||
A prompt appears informing the user there are unsaved changes, with 3 options present: Yes, No, and Cancel.
|
||||
All options function as expected.
|
||||
|
||||
Test Steps:
|
||||
1) Open a new level
|
||||
2) Access Editor window
|
||||
3) Open .inputbindings file in Asset Editor
|
||||
4) Delete All events initially
|
||||
5) Add an input event to make a change
|
||||
6) Click on close - verify CANCEL function
|
||||
7) Click on close - verify YES function
|
||||
8) Make a new change for verifying NO button (Add another input event group)
|
||||
9) Click on close - verify NO function
|
||||
10) Close Asset Editor
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
INPUTBINDING_FILE_NAME = "test.inputbindings"
|
||||
|
||||
def close_asset_editor():
|
||||
general.close_pane("Asset Editor")
|
||||
general.close_pane(INPUTBINDING_FILE_NAME)
|
||||
return not general.is_pane_visible("Asset Editor")
|
||||
|
||||
async def close_asset_editor_unsaved(button_type):
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, INPUTBINDING_FILE_NAME)
|
||||
|
||||
# Trigger the closing of the Asset Editor as async so we can listen for the modal dialog
|
||||
pyside_utils.run_soon(lambda: asset_editor.close())
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget(timeout=2.0)
|
||||
if active_modal_widget:
|
||||
print("Message Box opened")
|
||||
message_box = active_modal_widget.findChild(QtWidgets.QMessageBox, "")
|
||||
button = message_box.button(button_type)
|
||||
pyside_utils.click_button_async(button)
|
||||
|
||||
return await pyside_utils.wait_for_destroyed(active_modal_widget)
|
||||
|
||||
# 1) Open a new level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
|
||||
# 2) Access Editor window
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
|
||||
# 3) Open .inputbindings file in Asset Editor
|
||||
# Close Asset Editor initially
|
||||
close_asset_editor()
|
||||
input_bindings_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", INPUTBINDING_FILE_NAME, math.Uuid(), False
|
||||
)
|
||||
editor.AssetEditorRequestsBus(bus.Broadcast, "OpenAssetEditorById", input_bindings_id)
|
||||
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, INPUTBINDING_FILE_NAME)
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "m_assetEditorWidget")
|
||||
input_event_groups = await pyside_utils.wait_for(lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups"))
|
||||
|
||||
# 4) Delete All events initially
|
||||
delete_all_button = input_event_groups.findChildren(QtWidgets.QToolButton, "")[1]
|
||||
pyside_utils.click_button_async(delete_all_button)
|
||||
active_modal_widget = await pyside_utils.wait_for_modal_widget()
|
||||
if active_modal_widget:
|
||||
message_box = active_modal_widget.findChild(QtWidgets.QMessageBox, "")
|
||||
button = message_box.button(QtWidgets.QMessageBox.Yes)
|
||||
button.click()
|
||||
|
||||
# 5) Add an input event to make a change
|
||||
await pyside_utils.wait_for_condition(lambda: len(asset_editor_widget.findChildren(QtWidgets.QFrame, "Input Event Groups")) > 1, 2.0)
|
||||
input_event_groups = asset_editor_widget.findChildren(QtWidgets.QFrame, "Input Event Groups")[1]
|
||||
add_button = input_event_groups.findChild(QtWidgets.QToolButton, "")
|
||||
add_button.click()
|
||||
|
||||
# 6) Click on close - verify CANCEL function
|
||||
await close_asset_editor_unsaved(QtWidgets.QMessageBox.Cancel)
|
||||
# Cancel should not change anything and the Asset Editor should remain open
|
||||
print(f"'CANCEL' button working as expected: {general.is_pane_visible(INPUTBINDING_FILE_NAME)}")
|
||||
|
||||
# 7) Click on close - verify YES function
|
||||
await close_asset_editor_unsaved(QtWidgets.QMessageBox.Yes)
|
||||
# Yes option should save the changes and not close the Asset Editor
|
||||
print(f"Asset Editor is visible after clicking YES: {general.is_pane_visible(INPUTBINDING_FILE_NAME)}")
|
||||
status_bar = await pyside_utils.wait_for(lambda: asset_editor_widget.findChild(QtWidgets.QWidget, "AssetEditorStatusBar"))
|
||||
text_edit = status_bar.findChild(QtWidgets.QLabel, "textEdit")
|
||||
success = await pyside_utils.wait_for_condition(lambda: f"{INPUTBINDING_FILE_NAME} - Asset saved!" in text_edit.text(), 3.0)
|
||||
if success:
|
||||
print("'YES' button working as expected")
|
||||
|
||||
# 8) Make a new change for verifying NO button (Add another input event group)
|
||||
input_event_groups = await pyside_utils.wait_for(lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups"), 2.0)
|
||||
add_button = await pyside_utils.wait_for(lambda: input_event_groups.findChild(QtWidgets.QToolButton, ""), 2.0)
|
||||
add_button.click()
|
||||
|
||||
# 9) Click on close - verify NO function
|
||||
await close_asset_editor_unsaved(QtWidgets.QMessageBox.No)
|
||||
# No button should close the Asset Editor and changes should not be saved
|
||||
print(f"Asset Editor is not visible after clicking NO: {not general.is_pane_visible('Asset Editor')}")
|
||||
|
||||
# Reopen inputbindings file
|
||||
input_bindings_id = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", INPUTBINDING_FILE_NAME, math.Uuid(), False
|
||||
)
|
||||
editor.AssetEditorRequestsBus(bus.Broadcast, "OpenAssetEditorById", input_bindings_id)
|
||||
# Ensure there are no changes saved (only one event group should be there)
|
||||
asset_editor = await pyside_utils.wait_for(lambda: editor_window.findChild(QtWidgets.QDockWidget, INPUTBINDING_FILE_NAME), 2.0)
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "m_assetEditorWidget")
|
||||
input_event_groups = asset_editor_widget.findChild(QtWidgets.QFrame, "Input Event Groups")
|
||||
no_of_elements_label = input_event_groups.findChild(QtWidgets.QLabel, "DefaultLabel")
|
||||
success = await pyside_utils.wait_for_condition(lambda: "1 elements" in no_of_elements_label.text(), 2.0)
|
||||
if success:
|
||||
print("'NO' button working as expected")
|
||||
|
||||
# 10) Close Asset Editor
|
||||
print(f"Asset Editor closed: {close_asset_editor()}")
|
||||
|
||||
|
||||
test = UnsavedChangesPopupTest()
|
||||
test.run()
|
||||
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C16780807: The View menu options function normally - New view interaction Model enabled
|
||||
https://testrail.agscollab.com/index.php?/cases/view/16780807
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestViewMenuAfterInteractionModelToggle(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="view_menu_after_interaction_model_toggle: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with View Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The View menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Open level
|
||||
2) Interact with View Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
view_menu_options = [
|
||||
("Center on Selection",),
|
||||
("Show Quick Access Bar",),
|
||||
("Layouts", "Default Layout"),
|
||||
("Layouts", "User Legacy Layout"),
|
||||
("Layouts", "Default Layout"),
|
||||
("Layouts", "Save Layout"),
|
||||
("Layouts", "Restore Default Layout"),
|
||||
("Viewport", "Wireframe"),
|
||||
("Viewport", "Grid Settings"),
|
||||
("Viewport", "Configure Layout"),
|
||||
("Viewport", "Goto Coordinates"),
|
||||
("Viewport", "Center on Selection"),
|
||||
("Viewport", "Goto Location"),
|
||||
("Viewport", "Remember Location"),
|
||||
("Viewport", "Change Move Speed"),
|
||||
("Viewport", "Switch Camera"),
|
||||
("Viewport", "Show/Hide Helpers"),
|
||||
("Refresh Style",),
|
||||
]
|
||||
|
||||
# 1) Open level
|
||||
self.test_success = self.create_level(
|
||||
self.args["level"],
|
||||
heightmap_resolution=1024,
|
||||
heightmap_meters_per_pixel=1,
|
||||
terrain_texture_resolution=4096,
|
||||
use_terrain=True,
|
||||
)
|
||||
general.idle_wait(3.0)
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
print("Focus Changed")
|
||||
QtWidgets.QApplication.activeModalWidget().close()
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 2) Interact with View Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
for option in view_menu_options:
|
||||
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.triggered.disconnect(trig_func)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
test = TestViewMenuAfterInteractionModelToggle()
|
||||
test.run()
|
||||
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
"""
|
||||
C24064534: The View menu options function normally
|
||||
https://testrail.agscollab.com/index.php?/cases/view/24064534
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import Tests.ly_shared.pyside_utils as pyside_utils
|
||||
from PySide2 import QtWidgets
|
||||
from Tests.editor.editor_utils.editor_test_helper import EditorTestHelper
|
||||
|
||||
|
||||
class TestViewMenuOptions(EditorTestHelper):
|
||||
def __init__(self):
|
||||
EditorTestHelper.__init__(self, log_prefix="view_menu_options: ", args=["level"])
|
||||
|
||||
def run_test(self):
|
||||
"""
|
||||
Summary:
|
||||
Interact with View Menu options and verify if all the options are working.
|
||||
|
||||
Expected Behavior:
|
||||
The View menu functions normally.
|
||||
|
||||
Test Steps:
|
||||
1) Interact with View Menu options
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Lumberyard Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
view_menu_options = [
|
||||
("Center on Selection",),
|
||||
("Show Quick Access Bar",),
|
||||
("Layouts", "Default Layout"),
|
||||
("Layouts", "User Legacy Layout"),
|
||||
("Layouts", "Default Layout"),
|
||||
("Layouts", "Save Layout"),
|
||||
("Layouts", "Restore Default Layout"),
|
||||
("Viewport", "Wireframe"),
|
||||
("Viewport", "Ruler"),
|
||||
("Viewport", "Grid Settings"),
|
||||
("Viewport", "Configure Layout"),
|
||||
("Viewport", "Goto Coordinates"),
|
||||
("Viewport", "Center on Selection"),
|
||||
("Viewport", "Goto Location"),
|
||||
("Viewport", "Remember Location"),
|
||||
("Viewport", "Change Move Speed"),
|
||||
("Viewport", "Switch Camera"),
|
||||
("Viewport", "Show/Hide Helpers"),
|
||||
("Refresh Style",),
|
||||
]
|
||||
|
||||
general.idle_wait(3.0)
|
||||
|
||||
def on_focus_changed(old, new):
|
||||
print("Focus Changed")
|
||||
QtWidgets.QApplication.activeModalWidget().close()
|
||||
|
||||
def on_action_triggered(action_name):
|
||||
print(f"{action_name} Action triggered")
|
||||
|
||||
# 1) Interact with View Menu options
|
||||
try:
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
app.focusChanged.connect(on_focus_changed)
|
||||
for option in view_menu_options:
|
||||
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.triggered.disconnect(trig_func)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
app.focusChanged.disconnect(on_focus_changed)
|
||||
|
||||
test = TestViewMenuOptions()
|
||||
test.run()
|
||||
Reference in New Issue
Block a user