py10x-universe 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core_10x/__init__.py +42 -0
- core_10x/backbone/__init__.py +0 -0
- core_10x/backbone/backbone_store.py +59 -0
- core_10x/backbone/backbone_traitable.py +30 -0
- core_10x/backbone/backbone_user.py +66 -0
- core_10x/backbone/bound_data_domain.py +49 -0
- core_10x/backbone/namespace.py +101 -0
- core_10x/backbone/vault.py +38 -0
- core_10x/code_samples/__init__.py +0 -0
- core_10x/code_samples/_package_manifest.py +3 -0
- core_10x/code_samples/directories.py +181 -0
- core_10x/code_samples/person.py +76 -0
- core_10x/concrete_traits.py +356 -0
- core_10x/conftest.py +12 -0
- core_10x/curve.py +321 -0
- core_10x/data_domain.py +48 -0
- core_10x/data_domain_binder.py +45 -0
- core_10x/directory.py +250 -0
- core_10x/entity.py +8 -0
- core_10x/entity_filter.py +5 -0
- core_10x/environment_variables.py +147 -0
- core_10x/exec_control.py +84 -0
- core_10x/experimental/__init__.py +0 -0
- core_10x/experimental/data_protocol_ex.py +34 -0
- core_10x/global_cache.py +121 -0
- core_10x/manual_tests/__init__.py +0 -0
- core_10x/manual_tests/calendar_test.py +35 -0
- core_10x/manual_tests/ctor_update_bug.py +58 -0
- core_10x/manual_tests/debug_graph_on.py +17 -0
- core_10x/manual_tests/debug_graphoff_inside_graph_on.py +28 -0
- core_10x/manual_tests/enum_bits_test.py +17 -0
- core_10x/manual_tests/env_vars_trivial_test.py +12 -0
- core_10x/manual_tests/existing_traitable.py +33 -0
- core_10x/manual_tests/k10x_test1.py +13 -0
- core_10x/manual_tests/named_constant_test.py +121 -0
- core_10x/manual_tests/nucleus_trivial_test.py +42 -0
- core_10x/manual_tests/polars_test.py +14 -0
- core_10x/manual_tests/py_class_test.py +4 -0
- core_10x/manual_tests/rc_test.py +42 -0
- core_10x/manual_tests/rdate_test.py +12 -0
- core_10x/manual_tests/reference_serialization_bug.py +19 -0
- core_10x/manual_tests/resource_trivial_test.py +10 -0
- core_10x/manual_tests/store_uri_test.py +6 -0
- core_10x/manual_tests/trait_definition_test.py +19 -0
- core_10x/manual_tests/trait_filter_test.py +15 -0
- core_10x/manual_tests/trait_flag_modification_test.py +42 -0
- core_10x/manual_tests/trait_modification_bug.py +26 -0
- core_10x/manual_tests/traitable_as_of_test.py +82 -0
- core_10x/manual_tests/traitable_heir_test.py +39 -0
- core_10x/manual_tests/traitable_history_test.py +41 -0
- core_10x/manual_tests/traitable_serialization_test.py +54 -0
- core_10x/manual_tests/traitable_trivial_test.py +71 -0
- core_10x/manual_tests/trivial_graph_test.py +16 -0
- core_10x/manual_tests/ts_class_association_test.py +64 -0
- core_10x/manual_tests/ts_trivial_test.py +35 -0
- core_10x/named_constant.py +425 -0
- core_10x/nucleus.py +81 -0
- core_10x/package_manifest.py +85 -0
- core_10x/package_refactoring.py +153 -0
- core_10x/py_class.py +431 -0
- core_10x/rc.py +155 -0
- core_10x/rdate.py +339 -0
- core_10x/resource.py +189 -0
- core_10x/roman_number.py +67 -0
- core_10x/testlib/__init__.py +0 -0
- core_10x/testlib/test_store.py +240 -0
- core_10x/testlib/traitable_history_tests.py +787 -0
- core_10x/testlib/ts_tests.py +280 -0
- core_10x/trait.py +377 -0
- core_10x/trait_definition.py +176 -0
- core_10x/trait_filter.py +205 -0
- core_10x/trait_method_error.py +36 -0
- core_10x/traitable.py +1082 -0
- core_10x/traitable_cli.py +153 -0
- core_10x/traitable_heir.py +33 -0
- core_10x/traitable_id.py +31 -0
- core_10x/ts_store.py +172 -0
- core_10x/ts_store_type.py +26 -0
- core_10x/ts_union.py +147 -0
- core_10x/ui_hint.py +153 -0
- core_10x/unit_tests/test_concrete_traits.py +156 -0
- core_10x/unit_tests/test_converters.py +51 -0
- core_10x/unit_tests/test_curve.py +157 -0
- core_10x/unit_tests/test_directory.py +54 -0
- core_10x/unit_tests/test_documentation.py +172 -0
- core_10x/unit_tests/test_environment_variables.py +15 -0
- core_10x/unit_tests/test_filters.py +239 -0
- core_10x/unit_tests/test_graph.py +348 -0
- core_10x/unit_tests/test_named_constant.py +98 -0
- core_10x/unit_tests/test_rc.py +11 -0
- core_10x/unit_tests/test_rdate.py +484 -0
- core_10x/unit_tests/test_trait_method_error.py +80 -0
- core_10x/unit_tests/test_trait_modification.py +19 -0
- core_10x/unit_tests/test_traitable.py +959 -0
- core_10x/unit_tests/test_traitable_history.py +1 -0
- core_10x/unit_tests/test_ts_store.py +1 -0
- core_10x/unit_tests/test_ts_union.py +369 -0
- core_10x/unit_tests/test_ui_nodes.py +81 -0
- core_10x/unit_tests/test_xxcalendar.py +471 -0
- core_10x/vault/__init__.py +0 -0
- core_10x/vault/sec_keys.py +133 -0
- core_10x/vault/security_keys_old.py +168 -0
- core_10x/vault/vault.py +56 -0
- core_10x/vault/vault_traitable.py +56 -0
- core_10x/vault/vault_user.py +70 -0
- core_10x/xdate_time.py +136 -0
- core_10x/xnone.py +71 -0
- core_10x/xxcalendar.py +228 -0
- infra_10x/__init__.py +0 -0
- infra_10x/manual_tests/__init__.py +0 -0
- infra_10x/manual_tests/test_misc.py +16 -0
- infra_10x/manual_tests/test_prepare_filter_and_pipeline.py +25 -0
- infra_10x/mongodb_admin.py +111 -0
- infra_10x/mongodb_store.py +346 -0
- infra_10x/mongodb_utils.py +129 -0
- infra_10x/unit_tests/conftest.py +13 -0
- infra_10x/unit_tests/test_mongo_db.py +36 -0
- infra_10x/unit_tests/test_mongo_history.py +1 -0
- py10x_universe-0.1.3.dist-info/METADATA +406 -0
- py10x_universe-0.1.3.dist-info/RECORD +214 -0
- py10x_universe-0.1.3.dist-info/WHEEL +4 -0
- py10x_universe-0.1.3.dist-info/licenses/LICENSE +21 -0
- ui_10x/__init__.py +0 -0
- ui_10x/apps/__init__.py +0 -0
- ui_10x/apps/collection_editor_app.py +100 -0
- ui_10x/choice.py +212 -0
- ui_10x/collection_editor.py +135 -0
- ui_10x/concrete_trait_widgets.py +220 -0
- ui_10x/conftest.py +8 -0
- ui_10x/entity_stocker.py +173 -0
- ui_10x/examples/__init__.py +0 -0
- ui_10x/examples/_guess_word_data.py +14076 -0
- ui_10x/examples/collection_editor.py +17 -0
- ui_10x/examples/date_selector.py +14 -0
- ui_10x/examples/entity_stocker.py +18 -0
- ui_10x/examples/guess_word.py +392 -0
- ui_10x/examples/message_box.py +20 -0
- ui_10x/examples/multi_choice.py +17 -0
- ui_10x/examples/py_data_browser.py +66 -0
- ui_10x/examples/radiobox.py +29 -0
- ui_10x/examples/single_choice.py +31 -0
- ui_10x/examples/style_sheet.py +47 -0
- ui_10x/examples/trivial_entity_editor.py +18 -0
- ui_10x/platform.py +20 -0
- ui_10x/platform_interface.py +517 -0
- ui_10x/py_data_browser.py +249 -0
- ui_10x/qt6/__init__.py +0 -0
- ui_10x/qt6/conftest.py +8 -0
- ui_10x/qt6/manual_tests/__init__.py +0 -0
- ui_10x/qt6/manual_tests/basic_test.py +35 -0
- ui_10x/qt6/platform_implementation.py +275 -0
- ui_10x/qt6/utils.py +665 -0
- ui_10x/rio/__init__.py +0 -0
- ui_10x/rio/apps/examples/examples/__init__.py +22 -0
- ui_10x/rio/apps/examples/examples/components/__init__.py +3 -0
- ui_10x/rio/apps/examples/examples/components/collection_editor.py +15 -0
- ui_10x/rio/apps/examples/examples/pages/collection_editor.py +21 -0
- ui_10x/rio/apps/examples/examples/pages/login_page.py +88 -0
- ui_10x/rio/apps/examples/examples/pages/style_sheet.py +21 -0
- ui_10x/rio/apps/examples/rio.toml +14 -0
- ui_10x/rio/component_builder.py +497 -0
- ui_10x/rio/components/__init__.py +9 -0
- ui_10x/rio/components/group_box.py +31 -0
- ui_10x/rio/components/labeled_checkbox.py +18 -0
- ui_10x/rio/components/line_edit.py +37 -0
- ui_10x/rio/components/radio_button.py +32 -0
- ui_10x/rio/components/separator.py +24 -0
- ui_10x/rio/components/splitter.py +121 -0
- ui_10x/rio/components/tree_view.py +75 -0
- ui_10x/rio/conftest.py +35 -0
- ui_10x/rio/internals/__init__.py +0 -0
- ui_10x/rio/internals/app.py +192 -0
- ui_10x/rio/manual_tests/__init__.py +0 -0
- ui_10x/rio/manual_tests/basic_test.py +24 -0
- ui_10x/rio/manual_tests/splitter.py +27 -0
- ui_10x/rio/platform_implementation.py +91 -0
- ui_10x/rio/style_sheet.py +53 -0
- ui_10x/rio/unit_tests/test_collection_editor.py +68 -0
- ui_10x/rio/unit_tests/test_internals.py +630 -0
- ui_10x/rio/unit_tests/test_style_sheet.py +37 -0
- ui_10x/rio/widgets/__init__.py +46 -0
- ui_10x/rio/widgets/application.py +109 -0
- ui_10x/rio/widgets/button.py +48 -0
- ui_10x/rio/widgets/button_group.py +60 -0
- ui_10x/rio/widgets/calendar.py +23 -0
- ui_10x/rio/widgets/checkbox.py +24 -0
- ui_10x/rio/widgets/dialog.py +137 -0
- ui_10x/rio/widgets/group_box.py +27 -0
- ui_10x/rio/widgets/layout.py +34 -0
- ui_10x/rio/widgets/line_edit.py +37 -0
- ui_10x/rio/widgets/list.py +105 -0
- ui_10x/rio/widgets/message_box.py +70 -0
- ui_10x/rio/widgets/scroll_area.py +31 -0
- ui_10x/rio/widgets/spacer.py +6 -0
- ui_10x/rio/widgets/splitter.py +45 -0
- ui_10x/rio/widgets/text_edit.py +28 -0
- ui_10x/rio/widgets/tree.py +89 -0
- ui_10x/rio/widgets/unit_tests/test_button.py +101 -0
- ui_10x/rio/widgets/unit_tests/test_button_group.py +33 -0
- ui_10x/rio/widgets/unit_tests/test_calendar.py +114 -0
- ui_10x/rio/widgets/unit_tests/test_checkbox.py +109 -0
- ui_10x/rio/widgets/unit_tests/test_group_box.py +158 -0
- ui_10x/rio/widgets/unit_tests/test_label.py +43 -0
- ui_10x/rio/widgets/unit_tests/test_line_edit.py +140 -0
- ui_10x/rio/widgets/unit_tests/test_list.py +146 -0
- ui_10x/table_header_view.py +305 -0
- ui_10x/table_view.py +174 -0
- ui_10x/trait_editor.py +189 -0
- ui_10x/trait_widget.py +131 -0
- ui_10x/traitable_editor.py +200 -0
- ui_10x/traitable_view.py +131 -0
- ui_10x/unit_tests/conftest.py +8 -0
- ui_10x/unit_tests/test_platform.py +9 -0
- ui_10x/utils.py +661 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import rio.testing
|
|
4
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
5
|
+
from ui_10x.rio.widgets import CheckBox, GroupBox, Label, PushButton
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def test_group_box() -> None:
|
|
9
|
+
"""Test basic GroupBox widget functionality."""
|
|
10
|
+
widget = GroupBox(title='Test Group')
|
|
11
|
+
|
|
12
|
+
async with rio.testing.DummyClient(lambda: DynamicComponent(widget)) as test_client:
|
|
13
|
+
await asyncio.sleep(0.5)
|
|
14
|
+
|
|
15
|
+
# Test initial state
|
|
16
|
+
assert widget['title'] == 'Test Group'
|
|
17
|
+
|
|
18
|
+
# Test title change
|
|
19
|
+
widget.set_title('Updated Group')
|
|
20
|
+
await test_client.wait_for_refresh()
|
|
21
|
+
assert widget['title'] == 'Updated Group'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def test_group_box_with_children() -> None:
|
|
25
|
+
"""Test GroupBox widget with child widgets."""
|
|
26
|
+
label = Label('Label inside group')
|
|
27
|
+
checkbox = CheckBox('Checkbox inside group')
|
|
28
|
+
button = PushButton('Button inside group')
|
|
29
|
+
|
|
30
|
+
widget = GroupBox(None, 'Group with children', label, checkbox, button)
|
|
31
|
+
|
|
32
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
33
|
+
await asyncio.sleep(0.5)
|
|
34
|
+
|
|
35
|
+
# Test title
|
|
36
|
+
assert widget['title'] == 'Group with children'
|
|
37
|
+
|
|
38
|
+
# Test children
|
|
39
|
+
children = widget.get_children()
|
|
40
|
+
assert len(children) == 3
|
|
41
|
+
assert label in children
|
|
42
|
+
assert checkbox in children
|
|
43
|
+
assert button in children
|
|
44
|
+
assert 4 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
45
|
+
assert 1 == await test_client.execute_js('document.querySelectorAll(".rio-button").length')
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def test_group_box_add_remove_children() -> None:
|
|
49
|
+
"""Test GroupBox widget adding and removing children."""
|
|
50
|
+
widget = GroupBox(title='Dynamic Group')
|
|
51
|
+
label = Label('Dynamic Label')
|
|
52
|
+
button = PushButton('Dynamic Button')
|
|
53
|
+
|
|
54
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
55
|
+
await asyncio.sleep(0.5)
|
|
56
|
+
|
|
57
|
+
# Test initial empty state
|
|
58
|
+
assert len(widget.get_children()) == 0
|
|
59
|
+
assert 1 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
60
|
+
assert 0 == await test_client.execute_js('document.querySelectorAll(".rio-button").length')
|
|
61
|
+
|
|
62
|
+
# Test adding children
|
|
63
|
+
widget.add_children(label)
|
|
64
|
+
await test_client.wait_for_refresh()
|
|
65
|
+
assert len(widget.get_children()) == 1
|
|
66
|
+
assert label in widget.get_children()
|
|
67
|
+
assert 2 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
68
|
+
assert 0 == await test_client.execute_js('document.querySelectorAll(".rio-button").length')
|
|
69
|
+
|
|
70
|
+
widget.add_children(button)
|
|
71
|
+
await test_client.wait_for_refresh()
|
|
72
|
+
assert len(widget.get_children()) == 2
|
|
73
|
+
assert button in widget.get_children()
|
|
74
|
+
assert 3 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
75
|
+
assert 1 == await test_client.execute_js('document.querySelectorAll(".rio-button").length')
|
|
76
|
+
|
|
77
|
+
# Test removing children
|
|
78
|
+
widget._kwargs['children'] = [child for child in widget._kwargs['children'] if child is not label]
|
|
79
|
+
widget.force_update()
|
|
80
|
+
await test_client.wait_for_refresh()
|
|
81
|
+
assert len(widget.get_children()) == 1
|
|
82
|
+
assert label not in widget.get_children()
|
|
83
|
+
assert button in widget.get_children()
|
|
84
|
+
assert 2 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
85
|
+
assert 1 == await test_client.execute_js('document.querySelectorAll(".rio-button").length')
|
|
86
|
+
|
|
87
|
+
widget._kwargs['children'] = [child for child in widget._kwargs['children'] if child is not button]
|
|
88
|
+
widget.force_update()
|
|
89
|
+
await test_client.wait_for_refresh()
|
|
90
|
+
assert len(widget.get_children()) == 0
|
|
91
|
+
assert 1 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
92
|
+
assert 0 == await test_client.execute_js('document.querySelectorAll(".rio-button").length')
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# async def test_group_box_enabled_disabled() -> None:
|
|
96
|
+
# """Test GroupBox enabled/disabled state."""
|
|
97
|
+
# widget = GroupBox(title = 'Enabled Group')
|
|
98
|
+
# label = Label('Child Label')
|
|
99
|
+
# widget.add_widget(label)
|
|
100
|
+
#
|
|
101
|
+
# async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
102
|
+
# await asyncio.sleep(0.5)
|
|
103
|
+
#
|
|
104
|
+
# # Test initial enabled state
|
|
105
|
+
# assert widget['is_sensitive']
|
|
106
|
+
# assert label.is_enabled()
|
|
107
|
+
#
|
|
108
|
+
# # Test disabling group (should disable children)
|
|
109
|
+
# widget.set_enabled(False)
|
|
110
|
+
# await test_client.wait_for_refresh()
|
|
111
|
+
# assert not widget['is_sensitive']
|
|
112
|
+
# assert not label.is_enabled()
|
|
113
|
+
#
|
|
114
|
+
# # Test re-enabling
|
|
115
|
+
# widget.set_enabled(True)
|
|
116
|
+
# await test_client.wait_for_refresh()
|
|
117
|
+
# assert widget['is_sensitive']
|
|
118
|
+
# assert label.is_enabled()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def test_group_box_client_interaction() -> None:
|
|
122
|
+
"""Test GroupBox widget client interaction with timeout protection."""
|
|
123
|
+
widget = GroupBox(title='Client Test')
|
|
124
|
+
label = Label('Content')
|
|
125
|
+
widget.add_children(label)
|
|
126
|
+
|
|
127
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
128
|
+
await asyncio.sleep(0.5)
|
|
129
|
+
|
|
130
|
+
# Test initial state
|
|
131
|
+
assert widget['title'] == 'Client Test'
|
|
132
|
+
assert len(widget.get_children()) == 1
|
|
133
|
+
await check_title(widget, test_client)
|
|
134
|
+
await check_label(label, test_client)
|
|
135
|
+
|
|
136
|
+
# Test widget property changes
|
|
137
|
+
widget.set_title('Updated Title')
|
|
138
|
+
await test_client.wait_for_refresh()
|
|
139
|
+
assert widget['title'] == 'Updated Title'
|
|
140
|
+
|
|
141
|
+
# Verify client state reflects widget changes
|
|
142
|
+
await check_title(widget, test_client)
|
|
143
|
+
await check_label(label, test_client)
|
|
144
|
+
|
|
145
|
+
# Test empty title
|
|
146
|
+
widget.set_title('')
|
|
147
|
+
await test_client.wait_for_refresh()
|
|
148
|
+
assert widget['title'] == ''
|
|
149
|
+
await check_title(widget, test_client)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
async def check_label(label, test_client):
|
|
153
|
+
assert 2 == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text").length')
|
|
154
|
+
assert label['text'] == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text")[1].innerText')
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
async def check_title(widget, test_client):
|
|
158
|
+
assert widget['title'] == await test_client.execute_js('document.querySelectorAll(".rio-column .rio-text")[0].innerText')
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import rio.testing.browser_client
|
|
4
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
5
|
+
from ui_10x.rio.widgets import Label
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def check_text(widget, test_client, text):
|
|
9
|
+
assert widget['text'] == text
|
|
10
|
+
client_text = await test_client.execute_js('document.querySelector(".rio-text")?.children[0]?.innerText || ""')
|
|
11
|
+
assert client_text == text
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def test_label() -> None:
|
|
15
|
+
"""Test basic Label widget functionality with client interaction verification."""
|
|
16
|
+
widget = Label('Hello World')
|
|
17
|
+
|
|
18
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
19
|
+
await asyncio.sleep(0.5)
|
|
20
|
+
|
|
21
|
+
# Test initial text - verify widget state
|
|
22
|
+
assert widget['text'] == 'Hello World'
|
|
23
|
+
|
|
24
|
+
# Test text change - verify widget update
|
|
25
|
+
widget.set_text('Updated Text')
|
|
26
|
+
await test_client.wait_for_refresh()
|
|
27
|
+
await check_text(widget, test_client, 'Updated Text')
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def test_label_empty() -> None:
|
|
31
|
+
"""Test Label widget with empty text and client validation."""
|
|
32
|
+
widget = Label()
|
|
33
|
+
|
|
34
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
35
|
+
await asyncio.sleep(0.5)
|
|
36
|
+
|
|
37
|
+
# Test empty text
|
|
38
|
+
await check_text(widget, test_client, '')
|
|
39
|
+
|
|
40
|
+
# Test setting text
|
|
41
|
+
widget.set_text('New Text')
|
|
42
|
+
await test_client.wait_for_refresh()
|
|
43
|
+
await check_text(widget, test_client, 'New Text')
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import rio.testing
|
|
5
|
+
from ui_10x import platform_interface as i
|
|
6
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
7
|
+
from ui_10x.rio.widgets import LineEdit
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.async_timeout(10)
|
|
11
|
+
async def test_line_edit_comprehensive() -> None:
|
|
12
|
+
"""Test LineEdit with comprehensive client-widget interaction verification."""
|
|
13
|
+
widget = LineEdit('Initial Text')
|
|
14
|
+
find_input = 'document.querySelector(".rio-input-box").querySelector("input")'
|
|
15
|
+
find_tool_tip = 'document.querySelector(".rio-tooltip-popup").querySelector(".rio-text").children[0].innerText'
|
|
16
|
+
|
|
17
|
+
edited_calls = []
|
|
18
|
+
finished_calls = []
|
|
19
|
+
|
|
20
|
+
def edited_handler(text):
|
|
21
|
+
edited_calls.append(text)
|
|
22
|
+
|
|
23
|
+
def finished_handler():
|
|
24
|
+
finished_calls.append(True)
|
|
25
|
+
|
|
26
|
+
widget.text_edited_connect(edited_handler)
|
|
27
|
+
widget.editing_finished_connect(finished_handler)
|
|
28
|
+
|
|
29
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
30
|
+
await asyncio.sleep(0.5)
|
|
31
|
+
|
|
32
|
+
# 1) Verify client shows widget value
|
|
33
|
+
assert widget.text() == 'Initial Text'
|
|
34
|
+
assert widget.text() == await test_client.execute_js(find_input + '.value')
|
|
35
|
+
|
|
36
|
+
# 2) Modify client value (user typing)
|
|
37
|
+
await test_client.execute_js(find_input + '.focus();')
|
|
38
|
+
await test_client.execute_js(find_input + '.value = "User Typed Text";')
|
|
39
|
+
await test_client.execute_js(find_input + '.dispatchEvent(new Event("input"));')
|
|
40
|
+
await asyncio.sleep(1) # wait for change delay
|
|
41
|
+
|
|
42
|
+
# 3) Verify widget reflects client value
|
|
43
|
+
assert widget.text() == 'User Typed Text'
|
|
44
|
+
assert widget.text() == await test_client.execute_js(find_input + '.value')
|
|
45
|
+
assert len(edited_calls) == 1
|
|
46
|
+
assert widget.text() == edited_calls[0]
|
|
47
|
+
|
|
48
|
+
# Test editing finished
|
|
49
|
+
await test_client.execute_js(find_input + '.blur();')
|
|
50
|
+
assert len(finished_calls) == 1
|
|
51
|
+
assert widget.text() == await test_client.execute_js(find_input + '.value')
|
|
52
|
+
|
|
53
|
+
# Test widget changes propagate to client with timeout protection
|
|
54
|
+
widget.set_text('Widget Updated')
|
|
55
|
+
await test_client.wait_for_refresh()
|
|
56
|
+
client_value = await test_client.execute_js(find_input + '.value')
|
|
57
|
+
assert client_value == 'Widget Updated'
|
|
58
|
+
assert widget.text() == 'Widget Updated'
|
|
59
|
+
|
|
60
|
+
# Test tooltip functionality
|
|
61
|
+
widget.set_tool_tip('Helpful tip')
|
|
62
|
+
await test_client.wait_for_refresh()
|
|
63
|
+
await test_client._page.mouse.move(1, 1)
|
|
64
|
+
tooltip_text = await test_client.execute_js(find_tool_tip)
|
|
65
|
+
assert tooltip_text == 'Helpful tip'
|
|
66
|
+
|
|
67
|
+
# Test password mode with timeout protection
|
|
68
|
+
assert 'password' != await test_client.execute_js(find_input + '.type')
|
|
69
|
+
widget.set_password_mode()
|
|
70
|
+
await test_client.wait_for_refresh()
|
|
71
|
+
assert 'password' == await test_client.execute_js(find_input + '.type')
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
async def test_line_edit_disabled_interaction() -> None:
|
|
75
|
+
"""Test LineEdit disabled state blocks user interaction."""
|
|
76
|
+
|
|
77
|
+
right_button_presses = []
|
|
78
|
+
left_button_presses = []
|
|
79
|
+
|
|
80
|
+
class MyLineEdit(LineEdit):
|
|
81
|
+
def mouse_press_event(self, event: i.MouseEvent):
|
|
82
|
+
if event.is_right_button():
|
|
83
|
+
right_button_presses.append(event)
|
|
84
|
+
else:
|
|
85
|
+
left_button_presses.append(event)
|
|
86
|
+
|
|
87
|
+
widget = MyLineEdit('Initial Text')
|
|
88
|
+
find_input = 'document.querySelector(".rio-input-box input")'
|
|
89
|
+
|
|
90
|
+
edited_calls = []
|
|
91
|
+
|
|
92
|
+
def edited_handler(text):
|
|
93
|
+
edited_calls.append(text)
|
|
94
|
+
|
|
95
|
+
widget.text_edited_connect(edited_handler)
|
|
96
|
+
|
|
97
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
98
|
+
await asyncio.sleep(0.5)
|
|
99
|
+
|
|
100
|
+
# Test initial enabled state - typing should work
|
|
101
|
+
async def test_interaction(old_content, new_content, enabled=True):
|
|
102
|
+
initial_left = len(left_button_presses)
|
|
103
|
+
initial_right = len(right_button_presses)
|
|
104
|
+
initial_edited = len(edited_calls)
|
|
105
|
+
await test_client.click(10, 20, button='right') # handler
|
|
106
|
+
await test_client._page.click('.rio-input-box input', click_count=3, force=True) # select all
|
|
107
|
+
await test_client._page.keyboard.press(new_content)
|
|
108
|
+
await asyncio.sleep(1)
|
|
109
|
+
|
|
110
|
+
right, left, edited, content = (1, 3, 1, new_content) if enabled else (1, 3, 0, old_content)
|
|
111
|
+
|
|
112
|
+
assert len(right_button_presses) == right + initial_right
|
|
113
|
+
assert len(left_button_presses) == left + initial_left
|
|
114
|
+
assert len(edited_calls) == edited + initial_edited
|
|
115
|
+
assert edited_calls[-1] == content
|
|
116
|
+
assert widget.text() == content
|
|
117
|
+
|
|
118
|
+
await test_interaction(widget.text(), 'A')
|
|
119
|
+
|
|
120
|
+
# Disable widget
|
|
121
|
+
widget.set_enabled(False)
|
|
122
|
+
await test_client.wait_for_refresh()
|
|
123
|
+
|
|
124
|
+
# Verify client shows disabled state
|
|
125
|
+
client_disabled = await test_client.execute_js(find_input + '.disabled')
|
|
126
|
+
assert client_disabled is True
|
|
127
|
+
|
|
128
|
+
# Test that typing is blocked when disabled
|
|
129
|
+
await test_interaction(widget.text(), 'B', enabled=False)
|
|
130
|
+
|
|
131
|
+
# Re-enable widget
|
|
132
|
+
widget.set_enabled(True)
|
|
133
|
+
await test_client.wait_for_refresh()
|
|
134
|
+
|
|
135
|
+
# Verify client shows enabled state
|
|
136
|
+
client_disabled = await test_client.execute_js(find_input + '.disabled')
|
|
137
|
+
assert client_disabled is False
|
|
138
|
+
|
|
139
|
+
# Test that typing works again
|
|
140
|
+
await test_interaction(widget.text(), 'C')
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import rio.testing.browser_client
|
|
4
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
5
|
+
from ui_10x.rio.widgets import ListWidget
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def test_list_comprehensive() -> None:
|
|
9
|
+
"""Test ListWidget with comprehensive client-widget interaction verification."""
|
|
10
|
+
widget = ListWidget()
|
|
11
|
+
widget.add_items(['Item 1', 'Item 2', 'Item 3'])
|
|
12
|
+
|
|
13
|
+
find_list_items = 'document.querySelectorAll(".rio-selectable-item")'
|
|
14
|
+
find_selected_text = 'document.querySelector(".selected").querySelector(".rio-text").children[0].innerText'
|
|
15
|
+
|
|
16
|
+
clicked_calls = []
|
|
17
|
+
|
|
18
|
+
def clicked_handler(item):
|
|
19
|
+
clicked_calls.append(item)
|
|
20
|
+
|
|
21
|
+
widget.clicked_connect(clicked_handler)
|
|
22
|
+
|
|
23
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
24
|
+
await asyncio.sleep(0.5)
|
|
25
|
+
|
|
26
|
+
# 1) Verify client shows widget value (list items)
|
|
27
|
+
assert widget.child_count() == 3
|
|
28
|
+
client_items = await test_client.execute_js(f'{find_list_items}.length')
|
|
29
|
+
assert client_items == 3
|
|
30
|
+
|
|
31
|
+
# 2) Modify client value (user clicking first item)
|
|
32
|
+
await test_client.click(10, 1)
|
|
33
|
+
await asyncio.sleep(0.5)
|
|
34
|
+
|
|
35
|
+
# 3) Verify widget reflects client value
|
|
36
|
+
assert len(clicked_calls) == 1
|
|
37
|
+
assert clicked_calls[0]['text'] == 'Item 1'
|
|
38
|
+
assert widget['selected_items'] == [clicked_calls[0]['key']]
|
|
39
|
+
|
|
40
|
+
# Verify client shows selection
|
|
41
|
+
selected_text = await test_client.execute_js(find_selected_text)
|
|
42
|
+
assert selected_text == 'Item 1'
|
|
43
|
+
|
|
44
|
+
# Test clicking second item
|
|
45
|
+
await test_client.click(10, test_client.window_height_in_pixels - 1)
|
|
46
|
+
await asyncio.sleep(0.5)
|
|
47
|
+
assert len(clicked_calls) == 2
|
|
48
|
+
assert clicked_calls[1]['text'] == 'Item 3' # Last item
|
|
49
|
+
assert widget['selected_items'] == [clicked_calls[1]['key']]
|
|
50
|
+
|
|
51
|
+
# Test widget changes propagate to client (clearing list)
|
|
52
|
+
widget.clear()
|
|
53
|
+
assert not widget.get_children()
|
|
54
|
+
await test_client.wait_for_refresh()
|
|
55
|
+
assert not widget.subcomponent.selected_items
|
|
56
|
+
client_items = await test_client.execute_js(f'{find_list_items}.length')
|
|
57
|
+
assert client_items == 0
|
|
58
|
+
|
|
59
|
+
# Test adding item
|
|
60
|
+
widget.add_item('New Item')
|
|
61
|
+
await test_client.wait_for_refresh()
|
|
62
|
+
assert widget.child_count() == 1
|
|
63
|
+
client_items = await test_client.execute_js(f'{find_list_items}.length')
|
|
64
|
+
assert client_items == 1
|
|
65
|
+
|
|
66
|
+
# Test clicking new item
|
|
67
|
+
await test_client.click(10, 1)
|
|
68
|
+
await asyncio.sleep(0.5)
|
|
69
|
+
assert len(clicked_calls) == 3
|
|
70
|
+
assert clicked_calls[2]['text'] == 'New Item'
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def test_list_item_management() -> None:
|
|
74
|
+
"""Test ListWidget item management operations."""
|
|
75
|
+
widget = ListWidget()
|
|
76
|
+
widget.add_items(['A', 'B', 'C'])
|
|
77
|
+
|
|
78
|
+
find_list_items = 'document.querySelectorAll(".rio-selectable-item")'
|
|
79
|
+
|
|
80
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
81
|
+
await asyncio.sleep(0.5)
|
|
82
|
+
|
|
83
|
+
# Test initial state
|
|
84
|
+
assert widget.child_count() == 3
|
|
85
|
+
client_items = await test_client.execute_js(f'{find_list_items}.length')
|
|
86
|
+
assert client_items == 3
|
|
87
|
+
|
|
88
|
+
# Test removing item
|
|
89
|
+
removed_item = widget.take_item(1) # Remove 'B'
|
|
90
|
+
await test_client.wait_for_refresh()
|
|
91
|
+
assert widget.child_count() == 2
|
|
92
|
+
client_items = await test_client.execute_js(f'{find_list_items}.length')
|
|
93
|
+
assert client_items == 2
|
|
94
|
+
assert removed_item['text'] == 'B'
|
|
95
|
+
|
|
96
|
+
# Test adding another item with timeout protection
|
|
97
|
+
widget.add_item('Inserted')
|
|
98
|
+
await test_client.wait_for_refresh()
|
|
99
|
+
assert widget.child_count() == 3
|
|
100
|
+
client_items = await test_client.execute_js(f'{find_list_items}.length')
|
|
101
|
+
assert client_items == 3
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
async def test_list_disabled_interaction() -> None:
|
|
105
|
+
"""Test ListWidget disabled state blocks user interaction."""
|
|
106
|
+
widget = ListWidget()
|
|
107
|
+
widget.add_items(['Item 1', 'Item 2', 'Item 3'])
|
|
108
|
+
|
|
109
|
+
clicked_calls = []
|
|
110
|
+
|
|
111
|
+
def clicked_handler(item):
|
|
112
|
+
clicked_calls.append(item)
|
|
113
|
+
|
|
114
|
+
widget.clicked_connect(clicked_handler)
|
|
115
|
+
|
|
116
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
117
|
+
await asyncio.sleep(0.5)
|
|
118
|
+
|
|
119
|
+
# Test initial enabled state - clicks should work
|
|
120
|
+
await test_client.click(10, 1)
|
|
121
|
+
await asyncio.sleep(0.5)
|
|
122
|
+
assert len(clicked_calls) == 1
|
|
123
|
+
assert clicked_calls[0]['text'] == 'Item 1'
|
|
124
|
+
assert widget['selected_items'] == [id(widget.get_children()[0])]
|
|
125
|
+
|
|
126
|
+
# Disable widget
|
|
127
|
+
widget.set_enabled(False)
|
|
128
|
+
await test_client.wait_for_refresh()
|
|
129
|
+
|
|
130
|
+
# Test that clicks are blocked when disabled
|
|
131
|
+
initial_calls = len(clicked_calls)
|
|
132
|
+
await test_client.click(10, 1)
|
|
133
|
+
await asyncio.sleep(0.5)
|
|
134
|
+
assert len(clicked_calls) == initial_calls # No additional calls
|
|
135
|
+
assert widget['selected_items'] == [id(widget.get_children()[0])]
|
|
136
|
+
|
|
137
|
+
# Re-enable widget
|
|
138
|
+
widget.set_enabled(True)
|
|
139
|
+
await test_client.wait_for_refresh()
|
|
140
|
+
|
|
141
|
+
# Test that clicks work again
|
|
142
|
+
await test_client.click(10, 1)
|
|
143
|
+
await asyncio.sleep(0.5)
|
|
144
|
+
assert len(clicked_calls) == initial_calls + 1
|
|
145
|
+
assert clicked_calls[-1]['text'] == 'Item 1'
|
|
146
|
+
assert widget['selected_items'] == []
|