mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
UI: Add UI tests for Searching
UI simulation tests covering search/filter functionality (Ctrl + F), verifies search behavior in the following editors: - Properties Editor: Tests modifier search (Subdivision Surface) - Outliner: Tests object filtering using object name search - Dope Sheet: Tests F-Curve name filtering (location) - Graph Editor: Tests animation curve search/filter behavior - File Browser: Creates a temporary directory during runtime and Tests filename filtering through search. Added dedicated test blend file: `tests/files/ui_tests/test_search_in_editors.blend` `__search_test_cube__` a mesh object with Subdivision Surface modifier Pull Request: https://projects.blender.org/blender/blender/pulls/159720
This commit is contained in:
parent
59116e1c32
commit
c3be8ecb22
4 changed files with 213 additions and 0 deletions
|
|
@ -1686,6 +1686,11 @@ if(WITH_UI_TESTS)
|
|||
# `"${TEST_PYTHON_EXE}" "${CMAKE_CURRENT_LIST_DIR}/ui_simulate/run.py" --list-tests`
|
||||
# list explicitly so changes bisecting/updated are sure to re-run CMake.
|
||||
set(_ui_tests
|
||||
test_search_in_editors.test_properties_search
|
||||
test_search_in_editors.test_outliner_search
|
||||
test_search_in_editors.test_dopesheet_search
|
||||
test_search_in_editors.test_graph_editor_search
|
||||
test_search_in_editors.test_file_browser_search
|
||||
test_sculpt.asset_shelf_brush_selection
|
||||
test_sculpt.face_set_expand
|
||||
test_sculpt.face_set_gestures
|
||||
|
|
|
|||
|
|
@ -194,3 +194,14 @@ def cursor_motion_data_circle(center, radius):
|
|||
return [
|
||||
(int(center[0] + -radius * sin(phi)), int(center[1] + radius * cos(phi))) for phi in angles
|
||||
]
|
||||
|
||||
|
||||
# Grid helpers
|
||||
def largest_area(screen):
|
||||
"""
|
||||
Return the currently largest visible area in the screen.
|
||||
"""
|
||||
return max(
|
||||
screen.areas,
|
||||
key=lambda a: a.width * a.height
|
||||
)
|
||||
|
|
|
|||
194
tests/python/ui_simulate/test_search_in_editors.py
Normal file
194
tests/python/ui_simulate/test_search_in_editors.py
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
# SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
This file does not run anything; its methods are accessed by run_blender_setup.py.
|
||||
|
||||
Tests for search/filter functionality in:
|
||||
- Properties editor
|
||||
- Outliner
|
||||
- Dope Sheet
|
||||
- Graph Editor
|
||||
- File Browser
|
||||
|
||||
Requires: tests/files/ui_tests/test_search_in_editors.blend
|
||||
Objects expected in that file:
|
||||
__search_test_cube__ — mesh with a Subdivision Surface modifier
|
||||
"""
|
||||
|
||||
import os
|
||||
import modules.ui_test_utils as ui
|
||||
|
||||
_BLEND_FILE = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "files", "ui_tests", "test_search_in_editors.blend",
|
||||
)
|
||||
|
||||
|
||||
def _set_area_type(area, area_type):
|
||||
"""Switch *area* to *area_type*."""
|
||||
import bpy
|
||||
with bpy.context.temp_override(area=area):
|
||||
area.type = area_type
|
||||
|
||||
|
||||
def _load_blend():
|
||||
"""Load the test blend file; re-acquire and return (e, t, window, area)."""
|
||||
import bpy
|
||||
assert os.path.isfile(_BLEND_FILE), f"Test blend file not found: {_BLEND_FILE}"
|
||||
bpy.ops.wm.open_mainfile(filepath=_BLEND_FILE)
|
||||
yield # wait for file load to complete
|
||||
e, t, window = ui.test_window()
|
||||
area = ui.largest_area(window.screen)
|
||||
return e, t, window, area
|
||||
|
||||
|
||||
def test_properties_search():
|
||||
"""
|
||||
Properties editor — Ctrl+F → 'subdivision'.
|
||||
Verifies the search filter matches the Subdivision Surface modifier on
|
||||
__search_test_cube__ and that clearing the field resets it.
|
||||
"""
|
||||
import bpy
|
||||
|
||||
e, t, window, area = yield from _load_blend()
|
||||
|
||||
_set_area_type(area, 'PROPERTIES')
|
||||
|
||||
space = area.spaces.active
|
||||
t.assertIsInstance(space, bpy.types.SpaceProperties, "Area did not switch to Properties editor")
|
||||
t.assertIn("__search_test_cube__", bpy.data.objects, "Blend file is missing __search_test_cube__")
|
||||
|
||||
# Activate the object so its modifier panels are visible.
|
||||
bpy.context.view_layer.objects.active = bpy.data.objects["__search_test_cube__"]
|
||||
yield
|
||||
|
||||
e.cursor_position_set(*ui.get_area_center(area), move=True)
|
||||
yield e.ctrl.f()
|
||||
yield e.text("subdivision")
|
||||
yield e.ret()
|
||||
t.assertEqual(space.search_filter, "subdivision", "Properties: search_filter was not set by Ctrl+F")
|
||||
|
||||
yield e.ctrl.f()
|
||||
yield e.back_space()
|
||||
yield e.ret()
|
||||
t.assertEqual(space.search_filter, "", "Properties: search_filter should be empty after clearing")
|
||||
|
||||
|
||||
def test_outliner_search():
|
||||
"""
|
||||
Outliner — Ctrl+F → '__search_test_cube__'.
|
||||
Verifies filter_text is set and cleared correctly.
|
||||
"""
|
||||
import bpy
|
||||
|
||||
e, t, window, area = yield from _load_blend()
|
||||
|
||||
_set_area_type(area, 'OUTLINER')
|
||||
|
||||
space = area.spaces.active
|
||||
t.assertIsInstance(space, bpy.types.SpaceOutliner, "Area did not switch to Outliner")
|
||||
t.assertIn("__search_test_cube__", bpy.data.objects, "Blend file is missing __search_test_cube__")
|
||||
|
||||
e.cursor_position_set(*ui.get_area_center(area), move=True)
|
||||
yield e.ctrl.f()
|
||||
yield e.text("__search_test_cube__")
|
||||
yield e.ret()
|
||||
t.assertEqual(space.filter_text, "__search_test_cube__", "Outliner: filter_text was not set by Ctrl+F")
|
||||
|
||||
yield e.ctrl.f()
|
||||
yield e.back_space()
|
||||
yield e.ret()
|
||||
t.assertEqual(space.filter_text, "", "Outliner: filter_text was not cleared")
|
||||
|
||||
|
||||
def test_dopesheet_search():
|
||||
"""
|
||||
Dope Sheet — Ctrl+F → 'location'.
|
||||
"""
|
||||
import bpy
|
||||
|
||||
e, t, window, area = yield from _load_blend()
|
||||
|
||||
_set_area_type(area, 'DOPESHEET_EDITOR')
|
||||
with bpy.context.temp_override(area=area):
|
||||
area.spaces.active.ui_mode = 'DOPESHEET'
|
||||
yield # wait for mode switch
|
||||
|
||||
space = area.spaces.active
|
||||
t.assertIsInstance(space, bpy.types.SpaceDopeSheetEditor, "Area did not switch to Dope Sheet")
|
||||
|
||||
e.cursor_position_set(*ui.get_area_center(area), move=True)
|
||||
yield e.ctrl.f()
|
||||
yield e.text("location")
|
||||
yield e.ret()
|
||||
t.assertEqual(space.dopesheet.filter_text, "location",
|
||||
"Dope Sheet: filter_text was not set by Ctrl+F")
|
||||
|
||||
yield e.ctrl.f()
|
||||
yield e.back_space()
|
||||
yield e.ret()
|
||||
t.assertEqual(space.dopesheet.filter_text, "",
|
||||
"Dope Sheet: filter_text was not cleared")
|
||||
|
||||
|
||||
def test_graph_editor_search():
|
||||
"""
|
||||
Graph Editor — Ctrl+F → 'location'.
|
||||
"""
|
||||
import bpy
|
||||
|
||||
e, t, window, area = yield from _load_blend()
|
||||
|
||||
_set_area_type(area, 'GRAPH_EDITOR')
|
||||
|
||||
space = area.spaces.active
|
||||
t.assertIsInstance(space, bpy.types.SpaceGraphEditor, "Area did not switch to Graph Editor")
|
||||
|
||||
e.cursor_position_set(*ui.get_area_center(area), move=True)
|
||||
yield e.ctrl.f()
|
||||
yield e.text("location")
|
||||
yield e.ret()
|
||||
t.assertEqual(space.dopesheet.filter_text, "location",
|
||||
"Graph Editor: filter_text was not set by Ctrl+F")
|
||||
|
||||
yield e.ctrl.f()
|
||||
yield e.back_space()
|
||||
yield e.ret()
|
||||
t.assertEqual(space.dopesheet.filter_text, "",
|
||||
"Graph Editor: filter_text was not cleared")
|
||||
|
||||
|
||||
def test_file_browser_search():
|
||||
"""
|
||||
File Browser — Ctrl+F → 'search_target'.
|
||||
"""
|
||||
import bpy
|
||||
|
||||
e, t, window, area = yield from _load_blend()
|
||||
|
||||
_set_area_type(area, 'FILE_BROWSER')
|
||||
|
||||
space = area.spaces.active
|
||||
t.assertIsInstance(space, bpy.types.SpaceFileBrowser, "Area did not switch to File Browser")
|
||||
|
||||
blend_dir = os.path.dirname(_BLEND_FILE)
|
||||
with bpy.context.temp_override(area=area):
|
||||
bpy.ops.file.select_bookmark(dir=blend_dir)
|
||||
yield # wait for navigation to complete
|
||||
|
||||
params = space.params
|
||||
t.assertIsNotNone(params, "File Browser: params is None after navigation")
|
||||
|
||||
e.cursor_position_set(*ui.get_area_center(area), move=True)
|
||||
yield e.ctrl.f()
|
||||
yield e.text("search_target")
|
||||
yield e.ret()
|
||||
t.assertEqual(params.filter_search, "search_target",
|
||||
"File Browser: filter_search was not set by Ctrl+F")
|
||||
|
||||
yield e.ctrl.f()
|
||||
yield e.back_space()
|
||||
yield e.ret()
|
||||
t.assertEqual(params.filter_search, "", "File Browser: filter_search was not cleared")
|
||||
Loading…
Add table
Add a link
Reference in a new issue