Summary
What are best practices for testing Streamlit apps at the UI level?
Background.
I am authoring fairly complex Streamlit apps and really should be testing the behavior. I don’t have any experience working with UI unit testing frameworks. Below is a small check box app that has a bit of logic that I’d like to make sure is correct:
import streamlit as st
st.title("Test")
def select_all(arg):
st.session_state.a = st.session_state[arg]
st.session_state.b = st.session_state[arg]
def update_star():
all_true = True
for selection in ['a', 'b']:
if not st.session_state[selection]:
all_true = False
st.session_state['star_sel'] = all_true
st.write('### Control')
st.checkbox('\*', key='star_sel', args=['star_sel'], on_change=select_all)
st.write('### main')
st.checkbox('a', key='a', on_change=update_star)
st.checkbox('b', key='b', on_change=update_star)
In testing this I finally settled on trying Playwright, Installation | Playwright Python, for my testing. I looked at the blog post at How to Create Automated Visual Tests [SeleniumBase Tutorial] but couldn’t get it to work.
My testing code is:
from playwright.sync_api import Page, expect
def test_tmp(page: Page):
page.goto("http://localhost:8501")
star_cb = page.locator("label").filter(has_text="*").locator("span")
a_cb = page.locator("label").filter(has_text="a").locator("span")
b_cb = page.locator("label").filter(has_text="b").locator("span")
assert not star_cb.is_checked()
assert not a_cb.is_checked()
assert not b_cb.is_checked()
star_cb.click()
assert star_cb.is_checked()
page.wait_for_timeout(50) #annoying
assert page.locator("label").filter(has_text="a").locator("span").is_checked()
assert b_cb.is_checked()
So I run the streamlit app as usual and then run the above using pytest test.py
after installing the relevant packages for Playwright for anyone replicating what I am doing:
- Installation | Playwright (I just ran the install via npm and ignored the rest of the instructions)
- Installation | Playwright Python (Installed the python packages and ran from command line)
The question
Does the above approach make sense or am I heading down some wrong rabbit hole?
The page.wait_for_timeout(50)
with an #annoying
comment is indeed annoying, but since the backend has to compute the values of the checkboxes it makes some sense. The auto-wait feature of Playwright does not handle it correctly–perhaps I am using it improperly?
thanks for any feedback
Breck