Skip to content

Commit c8dfdf6

Browse files
test: combination of an ipvue widget, ipyvue template and ipywidgets
Different combination of parent/child will trigger different code paths for ipyvue.
1 parent 02ac363 commit c8dfdf6

File tree

2 files changed

+156
-1
lines changed

2 files changed

+156
-1
lines changed

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def run(self):
180180
],
181181
extras_require={
182182
"test": [
183-
"solara[pytest]",
183+
"solara[pytest] @ https://github.com/widgetti/solara/archive/refs/heads/11-01-feat_testing_support_passing_local_variable_to_kernels.zip", # noqa: E501
184184
],
185185
"dev": [
186186
"pre-commit",

tests/ui/test_nested.py

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import pytest
2+
import sys
3+
import re
4+
5+
if sys.version_info < (3, 7):
6+
pytest.skip("requires python3.7 or higher", allow_module_level=True)
7+
8+
import ipyvue as vue
9+
import playwright.sync_api
10+
from playwright.sync_api import expect
11+
12+
from IPython.display import display
13+
from traitlets import default, Unicode, Instance
14+
import ipywidgets as widgets
15+
16+
17+
class MyTemplate(vue.VueTemplate):
18+
class_ = Unicode("template-parent").tag(sync=True)
19+
child = Instance(widgets.Widget, allow_none=True).tag(
20+
sync=True, **widgets.widget_serialization
21+
)
22+
text = Unicode(None, allow_none=True).tag(sync=True)
23+
24+
@default("template")
25+
def _default_vue_template(self):
26+
return """
27+
<template>
28+
<div :class="class_">
29+
<span v-if="text">{{text}}</span>
30+
<jupyter-widget v-if="child" :widget="child"></jupyter-widget>
31+
</div>
32+
</template>
33+
"""
34+
35+
36+
@pytest.mark.parametrize("parent_is_template", [True, False])
37+
def test_vue_with_vue_widget_child(
38+
ipywidgets_runner, page_session: playwright.sync_api.Page, parent_is_template
39+
):
40+
def kernel_code():
41+
from test_nested import MyTemplate
42+
import ipyvue as vue
43+
44+
child = vue.Html(tag="div", children=["I am a widget sibling"])
45+
46+
if parent_is_template:
47+
widget = MyTemplate(child=child)
48+
else:
49+
widget = vue.Html(
50+
tag="div",
51+
children=[child],
52+
class_="test-parent",
53+
)
54+
display(widget)
55+
56+
ipywidgets_runner(kernel_code, {"parent_is_template": parent_is_template})
57+
parent = page_session.locator(".test-parent")
58+
parent.wait_for()
59+
expect(parent.locator(":nth-child(1)")).to_contain_text("I am a widget sibling")
60+
61+
62+
@pytest.mark.parametrize("parent_is_template", [True, False])
63+
def test_vue_with_vue_template_child(
64+
ipywidgets_runner, page_session: playwright.sync_api.Page, parent_is_template
65+
):
66+
def kernel_code():
67+
# this import is need so when this code executes in the kernel,
68+
# the class is imported
69+
from test_nested import MyTemplate
70+
import ipyvue as vue
71+
72+
child = MyTemplate(class_="test-child", text="I am a child")
73+
74+
if parent_is_template:
75+
widget = MyTemplate(
76+
child=child,
77+
class_="test-parent",
78+
)
79+
else:
80+
widget = vue.Html(
81+
tag="div",
82+
children=[child],
83+
class_="test-parent",
84+
)
85+
display(widget)
86+
87+
ipywidgets_runner(kernel_code, {"parent_is_template": parent_is_template})
88+
parent = page_session.locator(".test-parent")
89+
parent.wait_for()
90+
expect(parent.locator(":nth-child(1) >> nth=0")).to_have_class("test-child")
91+
expect(parent.locator(".test-child >> :nth-child(1)")).to_contain_text(
92+
"I am a child"
93+
)
94+
95+
96+
@pytest.mark.parametrize("parent_is_template", [True, False])
97+
def test_vue_with_ipywidgets_child(
98+
ipywidgets_runner, page_session: playwright.sync_api.Page, parent_is_template
99+
):
100+
def kernel_code():
101+
from test_nested import MyTemplate
102+
import ipyvue as vue
103+
import ipywidgets as widgets
104+
105+
child = widgets.Label(value="I am a child")
106+
child.add_class("widget-child")
107+
108+
if parent_is_template:
109+
widget = MyTemplate(
110+
child=child,
111+
class_="test-parent",
112+
)
113+
else:
114+
widget = vue.Html(
115+
tag="div",
116+
children=[child],
117+
class_="test-parent",
118+
)
119+
display(widget)
120+
121+
ipywidgets_runner(kernel_code, {"parent_is_template": parent_is_template})
122+
parent = page_session.locator(".test-parent")
123+
parent.wait_for()
124+
# extra div is created by ipyvue
125+
expect(parent.locator(":nth-child(1) >> :nth-child(1)")).to_have_class(
126+
re.compile(".*widget-child.*")
127+
)
128+
expect(parent.locator(".widget-child")).to_contain_text("I am a child")
129+
130+
131+
@pytest.mark.parametrize("parent_is_template", [True, False])
132+
def test_vue_ipywidgets_vue(
133+
ipywidgets_runner, page_session: playwright.sync_api.Page, parent_is_template
134+
):
135+
# tests an interrupted vue hierarchy
136+
def kernel_code():
137+
import ipywidgets as widgets
138+
import ipyvue as vue
139+
140+
child = vue.Html(
141+
tag="div", children=["I am a widget sibling"], class_="test-child"
142+
)
143+
parent = widgets.VBox(children=[child])
144+
parent.add_class("ipywidgets-parent")
145+
grant_parent = vue.Html(
146+
tag="div",
147+
children=[child],
148+
class_="test-grandparent",
149+
)
150+
display(grant_parent)
151+
152+
ipywidgets_runner(kernel_code, {"parent_is_template": parent_is_template})
153+
grand_parent = page_session.locator(".test-grandparent")
154+
grand_parent.wait_for()
155+
expect(grand_parent.locator(".test-child")).to_contain_text("I am a widget sibling")

0 commit comments

Comments
 (0)