1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-03-09 18:27:52 +01:00

feat(advanced_dock_area): added ads based dock area with profiles

This commit is contained in:
2025-08-05 15:58:29 +02:00
parent 25f9b09027
commit e7f9919620
7 changed files with 1915 additions and 8 deletions

View File

@@ -0,0 +1,806 @@
# pylint: disable=missing-function-docstring, missing-module-docstring, unused-import
import os
import tempfile
from unittest import mock
from unittest.mock import MagicMock, patch
import pytest
from qtpy.QtCore import QSettings, Qt
from qtpy.QtGui import QAction
from qtpy.QtWidgets import QDialog, QMessageBox
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import (
AdvancedDockArea,
DockSettingsDialog,
SaveProfileDialog,
_profile_path,
_profiles_dir,
is_profile_readonly,
list_profiles,
open_settings,
read_manifest,
set_profile_readonly,
write_manifest,
)
from .client_mocks import mocked_client
@pytest.fixture
def advanced_dock_area(qtbot, mocked_client):
"""Create an AdvancedDockArea instance for testing."""
widget = AdvancedDockArea(client=mocked_client)
qtbot.addWidget(widget)
qtbot.waitExposed(widget)
yield widget
@pytest.fixture
def temp_profile_dir():
"""Create a temporary directory for profile testing."""
with tempfile.TemporaryDirectory() as temp_dir:
with patch.dict(os.environ, {"BECWIDGETS_PROFILE_DIR": temp_dir}):
yield temp_dir
class TestAdvancedDockAreaInit:
"""Test initialization and basic properties."""
def test_init(self, advanced_dock_area):
assert advanced_dock_area is not None
assert isinstance(advanced_dock_area, AdvancedDockArea)
assert hasattr(advanced_dock_area, "dock_manager")
assert hasattr(advanced_dock_area, "toolbar")
assert hasattr(advanced_dock_area, "dark_mode_button")
assert hasattr(advanced_dock_area, "state_manager")
def test_minimum_size_hint(self, advanced_dock_area):
size_hint = advanced_dock_area.minimumSizeHint()
assert size_hint.width() == 1200
assert size_hint.height() == 800
def test_rpc_and_plugin_flags(self):
assert AdvancedDockArea.RPC is True
assert AdvancedDockArea.PLUGIN is False
def test_user_access_list(self):
expected_methods = [
"new",
"widget_map",
"widget_list",
"lock_workspace",
"attach_all",
"delete_all",
]
for method in expected_methods:
assert method in AdvancedDockArea.USER_ACCESS
class TestDockManagement:
"""Test dock creation, management, and manipulation."""
def test_new_widget_string(self, advanced_dock_area, qtbot):
"""Test creating a new widget from string."""
initial_count = len(advanced_dock_area.dock_list())
# Create a widget by string name
widget = advanced_dock_area.new("Waveform")
# Wait for the dock to be created (since it's async)
qtbot.wait(200)
# Check that dock was actually created
assert len(advanced_dock_area.dock_list()) == initial_count + 1
# Check widget was returned
assert widget is not None
assert hasattr(widget, "name_established")
def test_new_widget_instance(self, advanced_dock_area):
"""Test creating dock with existing widget instance."""
from bec_widgets.widgets.plots.waveform.waveform import Waveform
initial_count = len(advanced_dock_area.dock_list())
# Create widget instance
widget_instance = Waveform(parent=advanced_dock_area, client=advanced_dock_area.client)
widget_instance.setObjectName("test_widget")
# Add it to dock area
result = advanced_dock_area.new(widget_instance)
# Should return the same instance
assert result == widget_instance
# No new dock created since we passed an instance, not a string
assert len(advanced_dock_area.dock_list()) == initial_count
def test_dock_map(self, advanced_dock_area, qtbot):
"""Test dock_map returns correct mapping."""
# Initially empty
dock_map = advanced_dock_area.dock_map()
assert isinstance(dock_map, dict)
initial_count = len(dock_map)
# Create a widget
advanced_dock_area.new("Waveform")
qtbot.wait(200)
# Check dock map updated
new_dock_map = advanced_dock_area.dock_map()
assert len(new_dock_map) == initial_count + 1
def test_dock_list(self, advanced_dock_area, qtbot):
"""Test dock_list returns list of docks."""
dock_list = advanced_dock_area.dock_list()
assert isinstance(dock_list, list)
initial_count = len(dock_list)
# Create a widget
advanced_dock_area.new("Waveform")
qtbot.wait(200)
# Check dock list updated
new_dock_list = advanced_dock_area.dock_list()
assert len(new_dock_list) == initial_count + 1
def test_widget_map(self, advanced_dock_area, qtbot):
"""Test widget_map returns widget mapping."""
widget_map = advanced_dock_area.widget_map()
assert isinstance(widget_map, dict)
initial_count = len(widget_map)
# Create a widget
advanced_dock_area.new("DarkModeButton")
qtbot.wait(200)
# Check widget map updated
new_widget_map = advanced_dock_area.widget_map()
assert len(new_widget_map) == initial_count + 1
def test_widget_list(self, advanced_dock_area, qtbot):
"""Test widget_list returns list of widgets."""
widget_list = advanced_dock_area.widget_list()
assert isinstance(widget_list, list)
initial_count = len(widget_list)
# Create a widget
advanced_dock_area.new("DarkModeButton")
qtbot.wait(200)
# Check widget list updated
new_widget_list = advanced_dock_area.widget_list()
assert len(new_widget_list) == initial_count + 1
def test_attach_all(self, advanced_dock_area, qtbot):
"""Test attach_all functionality."""
# Create multiple widgets
advanced_dock_area.new("DarkModeButton", start_floating=True)
advanced_dock_area.new("DarkModeButton", start_floating=True)
# Wait for docks to be created
qtbot.wait(200)
# Should have floating widgets
initial_floating = len(advanced_dock_area.dock_manager.floatingWidgets())
# Attach all floating docks
advanced_dock_area.attach_all()
# Wait a bit for the operation to complete
qtbot.wait(200)
# Should have fewer floating widgets (or none if all were attached)
final_floating = len(advanced_dock_area.dock_manager.floatingWidgets())
assert final_floating <= initial_floating
def test_delete_all(self, advanced_dock_area, qtbot):
"""Test delete_all functionality."""
# Create multiple widgets
advanced_dock_area.new("DarkModeButton")
advanced_dock_area.new("DarkModeButton")
# Wait for docks to be created
qtbot.wait(200)
initial_count = len(advanced_dock_area.dock_list())
assert initial_count >= 2
# Delete all
advanced_dock_area.delete_all()
# Wait for deletion to complete
qtbot.wait(200)
# Should have no docks
assert len(advanced_dock_area.dock_list()) == 0
class TestWorkspaceLocking:
"""Test workspace locking functionality."""
def test_lock_workspace_property_getter(self, advanced_dock_area):
"""Test lock_workspace property getter."""
# Initially unlocked
assert advanced_dock_area.lock_workspace is False
# Set locked state directly
advanced_dock_area._locked = True
assert advanced_dock_area.lock_workspace is True
def test_lock_workspace_property_setter(self, advanced_dock_area, qtbot):
"""Test lock_workspace property setter."""
# Create a dock first
advanced_dock_area.new("DarkModeButton")
qtbot.wait(200)
# Initially unlocked
assert advanced_dock_area.lock_workspace is False
# Lock workspace
advanced_dock_area.lock_workspace = True
assert advanced_dock_area._locked is True
assert advanced_dock_area.lock_workspace is True
# Unlock workspace
advanced_dock_area.lock_workspace = False
assert advanced_dock_area._locked is False
assert advanced_dock_area.lock_workspace is False
class TestDeveloperMode:
"""Test developer mode functionality."""
def test_setup_developer_mode_menu(self, advanced_dock_area):
"""Test developer mode menu setup."""
# The menu should be set up during initialization
assert hasattr(advanced_dock_area, "_developer_mode_action")
assert isinstance(advanced_dock_area._developer_mode_action, QAction)
assert advanced_dock_area._developer_mode_action.isCheckable()
def test_developer_mode_toggle(self, advanced_dock_area):
"""Test developer mode toggle functionality."""
# Check initial state
initial_editable = advanced_dock_area._editable
# Toggle developer mode
advanced_dock_area._on_developer_mode_toggled(True)
assert advanced_dock_area._editable is True
assert advanced_dock_area.lock_workspace is False
advanced_dock_area._on_developer_mode_toggled(False)
assert advanced_dock_area._editable is False
assert advanced_dock_area.lock_workspace is True
def test_set_editable(self, advanced_dock_area):
"""Test _set_editable functionality."""
# Test setting editable to True
advanced_dock_area._set_editable(True)
assert advanced_dock_area.lock_workspace is False
assert advanced_dock_area._editable is True
# Test setting editable to False
advanced_dock_area._set_editable(False)
assert advanced_dock_area.lock_workspace is True
assert advanced_dock_area._editable is False
class TestToolbarFunctionality:
"""Test toolbar setup and functionality."""
def test_toolbar_setup(self, advanced_dock_area):
"""Test toolbar is properly set up."""
assert hasattr(advanced_dock_area, "toolbar")
assert hasattr(advanced_dock_area, "_ACTION_MAPPINGS")
# Check that action mappings are properly set
assert "menu_plots" in advanced_dock_area._ACTION_MAPPINGS
assert "menu_devices" in advanced_dock_area._ACTION_MAPPINGS
assert "menu_utils" in advanced_dock_area._ACTION_MAPPINGS
def test_toolbar_plot_actions(self, advanced_dock_area):
"""Test plot toolbar actions trigger widget creation."""
plot_actions = [
"waveform",
"scatter_waveform",
"multi_waveform",
"image",
"motor_map",
"heatmap",
]
for action_name in plot_actions:
with patch.object(advanced_dock_area, "new") as mock_new:
menu_plots = advanced_dock_area.toolbar.components.get_action("menu_plots")
action = menu_plots.actions[action_name].action
# Get the expected widget type from the action mappings
widget_type = advanced_dock_area._ACTION_MAPPINGS["menu_plots"][action_name][2]
action.trigger()
mock_new.assert_called_once_with(widget=widget_type)
def test_toolbar_device_actions(self, advanced_dock_area):
"""Test device toolbar actions trigger widget creation."""
device_actions = ["scan_control", "positioner_box"]
for action_name in device_actions:
with patch.object(advanced_dock_area, "new") as mock_new:
menu_devices = advanced_dock_area.toolbar.components.get_action("menu_devices")
action = menu_devices.actions[action_name].action
# Get the expected widget type from the action mappings
widget_type = advanced_dock_area._ACTION_MAPPINGS["menu_devices"][action_name][2]
action.trigger()
mock_new.assert_called_once_with(widget=widget_type)
def test_toolbar_utils_actions(self, advanced_dock_area):
"""Test utils toolbar actions trigger widget creation."""
utils_actions = ["queue", "vs_code", "status", "progress_bar", "sbb_monitor"]
for action_name in utils_actions:
with patch.object(advanced_dock_area, "new") as mock_new:
menu_utils = advanced_dock_area.toolbar.components.get_action("menu_utils")
action = menu_utils.actions[action_name].action
# Skip log_panel as it's disabled
if action_name == "log_panel":
assert not action.isEnabled()
continue
# Get the expected widget type from the action mappings
widget_type = advanced_dock_area._ACTION_MAPPINGS["menu_utils"][action_name][2]
action.trigger()
mock_new.assert_called_once_with(widget=widget_type)
def test_attach_all_action(self, advanced_dock_area, qtbot):
"""Test attach_all toolbar action."""
# Create floating docks
advanced_dock_area.new("DarkModeButton", start_floating=True)
advanced_dock_area.new("DarkModeButton", start_floating=True)
qtbot.wait(200)
initial_floating = len(advanced_dock_area.dock_manager.floatingWidgets())
# Trigger attach all action
action = advanced_dock_area.toolbar.components.get_action("attach_all").action
action.trigger()
# Wait a bit for the operation
qtbot.wait(200)
# Should have fewer or same floating widgets
final_floating = len(advanced_dock_area.dock_manager.floatingWidgets())
assert final_floating <= initial_floating
def test_screenshot_action(self, advanced_dock_area, tmpdir):
"""Test screenshot toolbar action."""
# Create a test screenshot file path in tmpdir
screenshot_path = tmpdir.join("test_screenshot.png")
# Mock the QFileDialog.getSaveFileName to return a test filename
with mock.patch("bec_widgets.utils.bec_widget.QFileDialog.getSaveFileName") as mock_dialog:
mock_dialog.return_value = (str(screenshot_path), "PNG Files (*.png)")
# Mock the screenshot.save method
with mock.patch.object(advanced_dock_area, "grab") as mock_grab:
mock_screenshot = mock.MagicMock()
mock_grab.return_value = mock_screenshot
# Trigger the screenshot action
action = advanced_dock_area.toolbar.components.get_action("screenshot").action
action.trigger()
# Verify the dialog was called
mock_dialog.assert_called_once()
# Verify grab was called
mock_grab.assert_called_once()
# Verify save was called with the filename
mock_screenshot.save.assert_called_once_with(str(screenshot_path))
class TestDockSettingsDialog:
"""Test dock settings dialog functionality."""
def test_dock_settings_dialog_init(self, advanced_dock_area):
"""Test DockSettingsDialog initialization."""
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import (
DarkModeButton,
)
# Create a real widget
mock_widget = DarkModeButton(parent=advanced_dock_area)
dialog = DockSettingsDialog(advanced_dock_area, mock_widget)
assert dialog.windowTitle() == "Dock Settings"
assert dialog.isModal()
assert hasattr(dialog, "prop_editor")
def test_open_dock_settings_dialog(self, advanced_dock_area, qtbot):
"""Test opening dock settings dialog."""
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import (
DarkModeButton,
)
# Create real widget and dock
widget = DarkModeButton(parent=advanced_dock_area)
widget.setObjectName("test_widget")
# Create a real dock
dock = advanced_dock_area._make_dock(widget, closable=True, floatable=True, movable=True)
# Mock dialog exec to avoid blocking
with patch.object(DockSettingsDialog, "exec") as mock_exec:
mock_exec.return_value = QDialog.Accepted
# Call the method
advanced_dock_area._open_dock_settings_dialog(dock, widget)
# Verify dialog was created and exec called
mock_exec.assert_called_once()
class TestSaveProfileDialog:
"""Test save profile dialog functionality."""
def test_save_profile_dialog_init(self, qtbot):
"""Test SaveProfileDialog initialization."""
dialog = SaveProfileDialog(None, "test_profile")
qtbot.addWidget(dialog)
assert dialog.windowTitle() == "Save Workspace Profile"
assert dialog.isModal()
assert dialog.name_edit.text() == "test_profile"
assert hasattr(dialog, "readonly_checkbox")
def test_save_profile_dialog_get_values(self, qtbot):
"""Test getting values from SaveProfileDialog."""
dialog = SaveProfileDialog(None)
qtbot.addWidget(dialog)
dialog.name_edit.setText("my_profile")
dialog.readonly_checkbox.setChecked(True)
assert dialog.get_profile_name() == "my_profile"
assert dialog.is_readonly() is True
def test_save_button_enabled_state(self, qtbot):
"""Test save button is enabled/disabled based on name input."""
dialog = SaveProfileDialog(None)
qtbot.addWidget(dialog)
# Initially should be disabled (empty name)
assert not dialog.save_btn.isEnabled()
# Should be enabled when name is entered
dialog.name_edit.setText("test")
assert dialog.save_btn.isEnabled()
# Should be disabled when name is cleared
dialog.name_edit.setText("")
assert not dialog.save_btn.isEnabled()
class TestProfileManagement:
"""Test profile management functionality."""
def test_profiles_dir_creation(self, temp_profile_dir):
"""Test that profiles directory is created."""
profiles_dir = _profiles_dir()
assert os.path.exists(profiles_dir)
assert profiles_dir == temp_profile_dir
def test_profile_path(self, temp_profile_dir):
"""Test profile path generation."""
path = _profile_path("test_profile")
expected = os.path.join(temp_profile_dir, "test_profile.ini")
assert path == expected
def test_open_settings(self, temp_profile_dir):
"""Test opening settings for a profile."""
settings = open_settings("test_profile")
assert isinstance(settings, QSettings)
def test_list_profiles_empty(self, temp_profile_dir):
"""Test listing profiles when directory is empty."""
profiles = list_profiles()
assert profiles == []
def test_list_profiles_with_files(self, temp_profile_dir):
"""Test listing profiles with existing files."""
# Create some test profile files
profile_names = ["profile1", "profile2", "profile3"]
for name in profile_names:
settings = open_settings(name)
settings.setValue("test", "value")
settings.sync()
profiles = list_profiles()
assert sorted(profiles) == sorted(profile_names)
def test_readonly_profile_operations(self, temp_profile_dir):
"""Test read-only profile functionality."""
profile_name = "readonly_profile"
# Initially should not be read-only
assert not is_profile_readonly(profile_name)
# Set as read-only
set_profile_readonly(profile_name, True)
assert is_profile_readonly(profile_name)
# Unset read-only
set_profile_readonly(profile_name, False)
assert not is_profile_readonly(profile_name)
def test_write_and_read_manifest(self, temp_profile_dir, advanced_dock_area, qtbot):
"""Test writing and reading dock manifest."""
settings = open_settings("test_manifest")
# Create real docks
advanced_dock_area.new("DarkModeButton")
advanced_dock_area.new("DarkModeButton")
advanced_dock_area.new("DarkModeButton")
# Wait for docks to be created
qtbot.wait(1000)
docks = advanced_dock_area.dock_list()
# Write manifest
write_manifest(settings, docks)
settings.sync()
# Read manifest
items = read_manifest(settings)
assert len(items) >= 3
for item in items:
assert "object_name" in item
assert "widget_class" in item
assert "closable" in item
assert "floatable" in item
assert "movable" in item
class TestWorkspaceProfileOperations:
"""Test workspace profile save/load/delete operations."""
def test_save_profile_with_name(self, advanced_dock_area, temp_profile_dir, qtbot):
"""Test saving profile with provided name."""
profile_name = "test_save_profile"
# Create some docks
advanced_dock_area.new("DarkModeButton")
qtbot.wait(200)
# Save profile
advanced_dock_area.save_profile(profile_name)
# Check that profile file was created
profile_path = _profile_path(profile_name)
assert os.path.exists(profile_path)
def test_save_profile_readonly_conflict(self, advanced_dock_area, temp_profile_dir):
"""Test saving profile when read-only profile exists."""
profile_name = "readonly_profile"
# Create a read-only profile
set_profile_readonly(profile_name, True)
settings = open_settings(profile_name)
settings.setValue("test", "value")
settings.sync()
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.SaveProfileDialog"
) as mock_dialog_class:
mock_dialog = MagicMock()
mock_dialog.exec.return_value = QDialog.Accepted
mock_dialog.get_profile_name.return_value = profile_name
mock_dialog.is_readonly.return_value = False
mock_dialog_class.return_value = mock_dialog
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.QMessageBox.warning"
) as mock_warning:
mock_warning.return_value = QMessageBox.No
advanced_dock_area.save_profile()
mock_warning.assert_called_once()
def test_load_profile_with_manifest(self, advanced_dock_area, temp_profile_dir, qtbot):
"""Test loading profile with widget manifest."""
profile_name = "test_load_profile"
# Create a profile with manifest
settings = open_settings(profile_name)
settings.beginWriteArray("manifest/widgets", 1)
settings.setArrayIndex(0)
settings.setValue("object_name", "test_widget")
settings.setValue("widget_class", "DarkModeButton")
settings.setValue("closable", True)
settings.setValue("floatable", True)
settings.setValue("movable", True)
settings.endArray()
settings.sync()
initial_count = len(advanced_dock_area.widget_map())
# Load profile
advanced_dock_area.load_profile(profile_name)
# Wait for widget to be created
qtbot.wait(1000)
# Check widget was created
widget_map = advanced_dock_area.widget_map()
assert "test_widget" in widget_map
def test_delete_profile_readonly(self, advanced_dock_area, temp_profile_dir):
"""Test deleting read-only profile shows warning."""
profile_name = "readonly_profile"
# Create read-only profile
set_profile_readonly(profile_name, True)
settings = open_settings(profile_name)
settings.setValue("test", "value")
settings.sync()
with patch.object(advanced_dock_area.toolbar.components, "get_action") as mock_get_action:
mock_combo = MagicMock()
mock_combo.currentText.return_value = profile_name
mock_get_action.return_value.widget = mock_combo
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.QMessageBox.warning"
) as mock_warning:
advanced_dock_area.delete_profile()
mock_warning.assert_called_once()
# Profile should still exist
assert os.path.exists(_profile_path(profile_name))
def test_delete_profile_success(self, advanced_dock_area, temp_profile_dir):
"""Test successful profile deletion."""
profile_name = "deletable_profile"
# Create regular profile
settings = open_settings(profile_name)
settings.setValue("test", "value")
settings.sync()
with patch.object(advanced_dock_area.toolbar.components, "get_action") as mock_get_action:
mock_combo = MagicMock()
mock_combo.currentText.return_value = profile_name
mock_get_action.return_value.widget = mock_combo
with patch(
"bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area.QMessageBox.question"
) as mock_question:
mock_question.return_value = QMessageBox.Yes
with patch.object(advanced_dock_area, "_refresh_workspace_list") as mock_refresh:
advanced_dock_area.delete_profile()
mock_question.assert_called_once()
mock_refresh.assert_called_once()
# Profile should be deleted
assert not os.path.exists(_profile_path(profile_name))
def test_refresh_workspace_list(self, advanced_dock_area, temp_profile_dir):
"""Test refreshing workspace list."""
# Create some profiles
for name in ["profile1", "profile2"]:
settings = open_settings(name)
settings.setValue("test", "value")
settings.sync()
with patch.object(advanced_dock_area.toolbar.components, "get_action") as mock_get_action:
mock_combo = MagicMock()
mock_combo.refresh_profiles = MagicMock()
mock_get_action.return_value.widget = mock_combo
advanced_dock_area._refresh_workspace_list()
mock_combo.refresh_profiles.assert_called_once()
class TestCleanupAndMisc:
"""Test cleanup and miscellaneous functionality."""
def test_cleanup(self, advanced_dock_area):
"""Test cleanup functionality."""
with patch.object(advanced_dock_area.dark_mode_button, "close") as mock_close:
with patch.object(advanced_dock_area.dark_mode_button, "deleteLater") as mock_delete:
with patch(
"bec_widgets.widgets.containers.main_window.main_window.BECMainWindow.cleanup"
) as mock_super_cleanup:
advanced_dock_area.cleanup()
mock_close.assert_called_once()
mock_delete.assert_called_once()
mock_super_cleanup.assert_called_once()
def test_delete_dock(self, advanced_dock_area, qtbot):
"""Test _delete_dock functionality."""
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import (
DarkModeButton,
)
# Create a real widget and dock
widget = DarkModeButton(parent=advanced_dock_area)
widget.setObjectName("test_widget")
dock = advanced_dock_area._make_dock(widget, closable=True, floatable=True, movable=True)
initial_count = len(advanced_dock_area.dock_list())
# Delete the dock
advanced_dock_area._delete_dock(dock)
# Wait for deletion to complete
qtbot.wait(200)
# Verify dock was removed
assert len(advanced_dock_area.dock_list()) == initial_count - 1
def test_apply_dock_lock(self, advanced_dock_area, qtbot):
"""Test _apply_dock_lock functionality."""
# Create a dock first
advanced_dock_area.new("DarkModeButton")
qtbot.wait(200)
# Test locking
advanced_dock_area._apply_dock_lock(True)
# No assertion needed - just verify it doesn't crash
# Test unlocking
advanced_dock_area._apply_dock_lock(False)
# No assertion needed - just verify it doesn't crash
def test_make_dock(self, advanced_dock_area):
"""Test _make_dock functionality."""
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import (
DarkModeButton,
)
# Create a real widget
widget = DarkModeButton(parent=advanced_dock_area)
widget.setObjectName("test_widget")
initial_count = len(advanced_dock_area.dock_list())
# Create dock
dock = advanced_dock_area._make_dock(widget, closable=True, floatable=True, movable=True)
# Verify dock was created
assert dock is not None
assert len(advanced_dock_area.dock_list()) == initial_count + 1
assert dock.widget() == widget
def test_install_dock_settings_action(self, advanced_dock_area):
"""Test _install_dock_settings_action functionality."""
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import (
DarkModeButton,
)
# Create real widget and dock
widget = DarkModeButton(parent=advanced_dock_area)
widget.setObjectName("test_widget")
dock = advanced_dock_area._make_dock(widget, closable=True, floatable=True, movable=True)
# Verify dock has settings action
assert hasattr(dock, "setting_action")
assert dock.setting_action is not None
# Verify title bar actions were set
title_bar_actions = dock.titleBarActions()
assert len(title_bar_actions) >= 1