Skip to content

Commit 2b30c5b

Browse files
committed
Add missing tests
1 parent 8b61f79 commit 2b30c5b

File tree

1 file changed

+395
-0
lines changed

1 file changed

+395
-0
lines changed

tests/streamlit/test_streamlit.py

Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
from __future__ import annotations
2+
3+
from contextlib import contextmanager
4+
from time import sleep
5+
6+
import pytest
7+
from playwright.sync_api import Page, Response, expect
8+
9+
LOCAL_TEST = False
10+
11+
PORT = "8503" if LOCAL_TEST else "8699"
12+
13+
14+
@pytest.fixture(scope="module", autouse=True)
15+
def before_module():
16+
# Run the streamlit app before each module
17+
with run_streamlit():
18+
yield
19+
20+
21+
@pytest.fixture(scope="function", autouse=True)
22+
def before_test(page: Page):
23+
page.goto(f"localhost:{PORT}")
24+
page.set_viewport_size({"width": 2000, "height": 2000})
25+
expect.set_options(timeout=5_000)
26+
27+
28+
# Take screenshot of each page if there are failures for this session
29+
@pytest.fixture(scope="function", autouse=True)
30+
def after_test(page: Page, request):
31+
yield
32+
if request.node.rep_call.failed:
33+
page.screenshot(path=f"screenshot-{request.node.name}.png", full_page=True)
34+
35+
36+
@contextmanager
37+
def run_streamlit():
38+
"""Run the streamlit app at examples/streamlit_app.py on port 8599"""
39+
import subprocess
40+
41+
if LOCAL_TEST:
42+
try:
43+
yield 1
44+
finally:
45+
pass
46+
else:
47+
p = subprocess.Popen(
48+
[
49+
"streamlit",
50+
"run",
51+
"examples/streamlit_app.py",
52+
"--server.port",
53+
PORT,
54+
"--server.headless",
55+
"true",
56+
]
57+
)
58+
59+
sleep(5)
60+
61+
try:
62+
yield 1
63+
finally:
64+
p.kill()
65+
66+
67+
def click_button_or_marker(page: Page, nth: int = 0, locator: str | None = None):
68+
"""For some reason, there's a discrepancy between how the map markers are
69+
selectable locally and on github actions, perhaps related some error in loading
70+
the actual marker images. This tries both ways to select a marker"""
71+
72+
frame = page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]')
73+
if locator is not None:
74+
frame = frame.locator(locator)
75+
try:
76+
frame.get_by_role("button", name="Marker").nth(nth).click(timeout=5_000)
77+
except Exception:
78+
frame.get_by_role("img").nth(nth).click(timeout=5_000)
79+
80+
81+
def test_marker_click(page: Page):
82+
def check_for_404(response: Response):
83+
if not response.ok:
84+
print(response)
85+
print(response.text())
86+
print(response.url)
87+
print(response.status)
88+
raise Exception("404")
89+
90+
page.on("response", check_for_404)
91+
92+
# Check page title
93+
expect(page).to_have_title("streamlit-folium documentation")
94+
95+
expect(page.get_by_text('"last_object_clicked":NULL')).to_be_visible()
96+
97+
# Click marker
98+
try:
99+
click_button_or_marker(page)
100+
except Exception as e:
101+
page.screenshot(path="screenshot-test-marker-click.png", full_page=True)
102+
raise e
103+
104+
expect(page.get_by_text('"last_object_clicked":NULL')).to_be_hidden()
105+
106+
107+
def test_draw(page: Page):
108+
# Test draw support
109+
page.get_by_role("link", name="draw support").click()
110+
# Click again to see if it resolves timeout issues
111+
page.get_by_role("link", name="draw support").click()
112+
113+
expect(page).to_have_title("streamlit-folium documentation: Draw Support")
114+
115+
page.frame_locator(
116+
'internal:attr=[title="streamlit_folium.st_folium"i]'
117+
).get_by_role("link", name="Draw a polygon").click()
118+
119+
# Should be no drawings
120+
expect(page.get_by_text('"all_drawings":NULL')).to_be_visible()
121+
122+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_role(
123+
"link", name="Draw a marker"
124+
).click()
125+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').locator(
126+
".leaflet-marker-icon"
127+
).first.click()
128+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').locator(
129+
"#map_div"
130+
).click()
131+
132+
# Should be one item in drawings after having placed a marker
133+
expect(page.get_by_text('"all_drawings":NULL')).to_be_hidden()
134+
135+
136+
def test_limit_data(page: Page):
137+
# Test limit data support
138+
page.get_by_role("link", name="limit data return").click()
139+
# Click again to see if it resolves timeout issues
140+
page.get_by_role("link", name="limit data return").click()
141+
142+
expect(page).to_have_title("streamlit-folium documentation: Limit Data Return")
143+
144+
expect(page.get_by_text('{"last_object_clicked":NULL}')).to_be_visible()
145+
146+
# Click marker
147+
click_button_or_marker(page, 2)
148+
149+
# Have to click a second time for some reason, maybe because it doesn't load right
150+
# away
151+
click_button_or_marker(page, 2)
152+
153+
expect(page.get_by_text('{"last_object_clicked":{"lat":39.96')).to_be_visible()
154+
155+
156+
def test_dual_map(page: Page):
157+
page.get_by_role("link", name="misc examples").click()
158+
# Click again to see if it resolves timeout issues
159+
page.get_by_role("link", name="misc examples").click()
160+
161+
expect(page).to_have_title("streamlit-folium documentation: Misc Examples")
162+
163+
page.locator("label").filter(has_text="Dual map").click()
164+
page.locator("label").filter(has_text="Dual map").click()
165+
166+
# Click marker on left map
167+
try:
168+
click_button_or_marker(page, 0, "#map_div")
169+
click_button_or_marker(page, 0, "#map_div2")
170+
except Exception as e:
171+
page.screenshot(path="screenshot-dual-map.png", full_page=True)
172+
raise e
173+
174+
175+
def test_vector_grid(page: Page):
176+
page.get_by_role("link", name="vector grid").click()
177+
page.get_by_role("link", name="vector grid").click()
178+
179+
expect(page).to_have_title("streamlit-folium documentation: Vector Grid")
180+
181+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').locator(
182+
".leaflet-marker-icon"
183+
).click()
184+
185+
186+
def test_tooltip_click(page: Page):
187+
expect(page.get_by_text('"last_object_clicked_tooltip":NULL')).to_be_visible()
188+
189+
# Click marker on map
190+
click_button_or_marker(page)
191+
192+
expect(
193+
page.get_by_text('"last_object_clicked_tooltip":"Liberty Bell"')
194+
).to_be_visible()
195+
196+
197+
def test_popup_text(page: Page):
198+
page.get_by_role("link", name="simple popup").click()
199+
page.get_by_role("link", name="simple popup").click()
200+
201+
expect(page.get_by_text("Popup: None")).to_be_visible()
202+
expect(page.get_by_text("Tooltip: None")).to_be_visible()
203+
204+
click_button_or_marker(page)
205+
206+
try:
207+
expect(page.get_by_text("Popup: Popup!")).to_be_visible()
208+
expect(page.get_by_text("Tooltip: Tooltip!")).to_be_visible()
209+
except Exception as e:
210+
page.screenshot(path="screenshot-popup.png")
211+
raise e
212+
213+
214+
def test_return_on_hover(page: Page):
215+
page.get_by_role("link", name="simple popup").click()
216+
page.get_by_role("link", name="simple popup").click()
217+
218+
expect(page.get_by_text("Popup: None")).to_be_visible()
219+
expect(page.get_by_text("Tooltip: None")).to_be_visible()
220+
221+
page.get_by_text("Return on hover?").click()
222+
223+
click_button_or_marker(page, 1)
224+
225+
try:
226+
expect(page.get_by_text("Popup: Popup 2!")).to_be_visible()
227+
expect(page.get_by_text("Tooltip: Tooltip 2!")).to_be_visible()
228+
except Exception as e:
229+
page.screenshot(path="screenshot-popup2.png")
230+
raise e
231+
232+
233+
def test_responsiveness(page: Page):
234+
page.get_by_role("link", name="responsive").click()
235+
page.get_by_role("link", name="responsive").click()
236+
237+
page.set_viewport_size({"width": 500, "height": 3000})
238+
239+
try:
240+
initial_bbox = (
241+
page.frame_locator("iframe").nth(2).locator("#map_div").bounding_box()
242+
)
243+
except Exception as e:
244+
page.screenshot(path="screenshot-responsive.png", full_page=True)
245+
raise e
246+
247+
page.set_viewport_size({"width": 1000, "height": 3000})
248+
249+
sleep(1)
250+
251+
new_bbox = page.query_selector_all("iframe")[2].bounding_box()
252+
253+
print(initial_bbox)
254+
print(new_bbox)
255+
256+
assert initial_bbox is not None
257+
258+
assert new_bbox is not None
259+
260+
assert new_bbox["width"] > initial_bbox["width"] + 300
261+
262+
# Check that the iframe is reasonably tall, which makes sure it hasn't failed to
263+
# render at all
264+
assert new_bbox["height"] > 100
265+
266+
page.set_viewport_size({"width": 2000, "height": 2000})
267+
268+
269+
def test_geojson_styles(page: Page):
270+
page.get_by_role("link", name="geojson styles").click()
271+
page.get_by_role("link", name="geojson styles").click()
272+
273+
page.get_by_text("Show generated code").click()
274+
expect(page.get_by_text('"fillOpacity"')).to_be_visible()
275+
276+
277+
def test_grouped_layer_control(page: Page):
278+
page.get_by_role("link", name="grouped layer control").click()
279+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').locator(
280+
"label"
281+
).filter(has_text="g2").click()
282+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_label(
283+
"g2"
284+
).check()
285+
286+
287+
def test_geojson_popup(page: Page):
288+
page.get_by_role("link", name="geojson popup").click()
289+
290+
expect(page.get_by_text("AttributeError")).to_be_hidden()
291+
292+
293+
@pytest.mark.skip(reason="too flaky")
294+
def test_dynamic_feature_group_update(page: Page):
295+
page.get_by_role("link", name="dynamic updates").click()
296+
page.get_by_text("Show generated code").click()
297+
298+
# Test showing only Parcel layer
299+
page.get_by_test_id("stRadio").get_by_text("Parcels").click()
300+
expect(
301+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
302+
.locator("path")
303+
.first
304+
).to_be_visible()
305+
expect(
306+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
307+
.get_by_role("img")
308+
.locator("svg")
309+
).to_be_hidden()
310+
expect(
311+
page.get_by_text('"fillColor"')
312+
).to_be_visible() # fillColor only present in parcel style
313+
expect(
314+
page.get_by_text('"dashArray"')
315+
).to_be_hidden() # dashArray only present in building style
316+
317+
# Test showing only Building layer
318+
page.get_by_test_id("stRadio").get_by_text("Buildings").click()
319+
expect(
320+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
321+
.locator("path")
322+
.first
323+
).to_be_visible()
324+
expect(
325+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
326+
.get_by_role("img")
327+
.locator("svg")
328+
).to_be_hidden()
329+
expect(page.get_by_text("fillColor")).to_be_hidden()
330+
expect(page.get_by_text("dashArray")).to_be_visible()
331+
332+
# Test showing no layers
333+
page.get_by_test_id("stRadio").get_by_text("None").click()
334+
expect(
335+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
336+
.get_by_role("img")
337+
.locator("svg")
338+
).to_be_hidden()
339+
expect(page.get_by_text("fillColor")).to_be_hidden()
340+
expect(page.get_by_text("dashArray")).to_be_hidden()
341+
342+
# Test showing both layers
343+
page.get_by_test_id("stRadio").get_by_text("Both").click()
344+
expect(
345+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
346+
.locator("path")
347+
.first
348+
).to_be_visible()
349+
expect(
350+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1')
351+
.locator("path")
352+
.nth(1)
353+
).to_be_visible()
354+
expect(page.get_by_text("fillColor")).to_be_visible()
355+
expect(page.get_by_text("dashArray")).to_be_visible()
356+
357+
358+
def test_layer_control_dynamic_update(page: Page):
359+
page.get_by_role("link", name="dynamic layer control").click()
360+
# page.get_by_text("Show generated code").click()
361+
362+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_text(
363+
"Parcels"
364+
).click()
365+
expect(
366+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_text(
367+
"Parcels"
368+
)
369+
).not_to_be_checked()
370+
expect(
371+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]')
372+
.get_by_role("img")
373+
.locator("svg")
374+
).to_be_hidden()
375+
expect(page.get_by_text("dashArray")).to_be_hidden()
376+
377+
page.get_by_test_id("stRadio").get_by_text("Both").click()
378+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_text(
379+
"Parcels"
380+
).click()
381+
expect(
382+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_text(
383+
"Parcels"
384+
)
385+
).not_to_be_checked()
386+
expect(
387+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_text(
388+
"Buildings"
389+
)
390+
).to_be_checked()
391+
expect(
392+
page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]')
393+
.get_by_role("img")
394+
.locator("path")
395+
).to_be_visible()

0 commit comments

Comments
 (0)