Skip to content

Commit 80bacdc

Browse files
committed
tests: Add test for status messages
1 parent f4e2858 commit 80bacdc

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from shiny import reactive
2+
from shiny.express import input, ui
3+
4+
# Set some Shiny page options
5+
ui.page_opts(title="Hello Chat")
6+
7+
# Create a chat instance, with an initial message
8+
chat = ui.Chat(
9+
id="chat",
10+
messages=[
11+
{"content": "Hello! How can I help you today?", "role": "assistant"},
12+
],
13+
)
14+
15+
# Display the chat
16+
chat.ui()
17+
18+
with ui.card():
19+
ui.card_header("Status Message")
20+
21+
with ui.layout_columns():
22+
with ui.div():
23+
ui.input_text("content", "Message Content", "Using model <code>llama3.2</code>")
24+
ui.input_switch("content_is_html", "Raw HTML", True)
25+
26+
ui.input_radio_buttons("type", "Status type", choices=["dynamic", "static"])
27+
28+
ui.input_action_button("submit", "Send status message")
29+
30+
31+
# Define a callback to run when the user submits a message
32+
@chat.on_user_submit
33+
async def handle_user_input(user_input: str):
34+
await chat.append_message(f"You said: {user_input}")
35+
36+
37+
@reactive.effect
38+
@reactive.event(input.submit)
39+
async def send_status_message():
40+
content = input.content()
41+
if input.content_is_html.get():
42+
content = ui.HTML(content)
43+
44+
await chat.append_status_message(content, type = input.type())
45+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from playwright.sync_api import Page, expect
2+
from utils.deploy_utils import skip_on_webkit
3+
4+
from shiny.playwright import controller
5+
from shiny.run import ShinyAppProc
6+
7+
8+
@skip_on_webkit
9+
def test_validate_chat_basic(page: Page, local_app: ShinyAppProc) -> None:
10+
page.goto(local_app.url)
11+
12+
chat = controller.Chat(page, "chat")
13+
content = controller.InputText(page, "content")
14+
content_is_html = controller.InputSwitch(page, "content_is_html")
15+
status_type = controller.InputRadioButtons(page, "type")
16+
submit = controller.InputActionButton(page, "submit")
17+
18+
# Verify starting state
19+
expect(chat.loc).to_be_visible(timeout=30 * 1000)
20+
initial_message = "Hello! How can I help you today?"
21+
chat.expect_latest_message(initial_message, timeout=30 * 1000)
22+
23+
# Send a status message
24+
content.set("Using model <code>llama3.1</code>")
25+
content_is_html.set(True)
26+
status_type.set("dynamic")
27+
submit.click()
28+
chat.expect_latest_message("Using model llama3.1")
29+
expect(chat.loc_latest_message).to_have_attribute("content_type", "html")
30+
expect(chat.loc_latest_message).to_have_attribute("type", "dynamic")
31+
32+
33+
# Send a status message that updates the original message
34+
content.set("Using model <code>phi4</code>")
35+
submit.click()
36+
chat.expect_latest_message("Using model phi4")
37+
expect(chat.loc_latest_message).to_have_attribute("content_type", "html")
38+
expect(chat.loc_latest_message).to_have_attribute("type", "dynamic")
39+
40+
41+
# Send a new status message that is static (doesn't overwrite previous message)
42+
html_message='<div class="alert alert-warning">Lost connection with provider.</div>'
43+
content.set(html_message)
44+
status_type.set("static")
45+
submit.click()
46+
chat.expect_latest_message("Lost connection with provider.")
47+
expect(chat.loc_latest_message).to_have_attribute("content_type", "html")
48+
expect(chat.loc_latest_message).to_have_attribute("type", "static")
49+
expect(chat.loc_latest_message.locator("> :first-child")).to_have_class("alert alert-warning")
50+
# previous status message is still there
51+
expect(chat.loc_messages.locator("> :nth-last-child(2)")).to_have_text("Using model phi4")
52+
53+
# Now another message as raw text
54+
content.set("Using model <code>deepseek-r1</code>")
55+
status_type.set("dynamic")
56+
content_is_html.set(False)
57+
submit.click()
58+
chat.expect_latest_message("Using model <code>deepseek-r1</code>")
59+
expect(chat.loc_latest_message).to_have_attribute("content_type", "text")
60+
expect(chat.loc_latest_message).to_have_attribute("type", "dynamic")
61+
62+
# Overwrite this message with one with raw html
63+
content_is_html.set(True)
64+
submit.click()
65+
chat.expect_latest_message("Using model deepseek-r1")
66+
expect(chat.loc_latest_message).to_have_attribute("content_type", "html")
67+
expect(chat.loc_latest_message).to_have_attribute("type", "dynamic")
68+
69+
70+
chat.set_user_input("Hello")
71+
chat.send_user_input()
72+
chat.expect_latest_message("You said: Hello")
73+
content.set("Disconnecting. <strong>Goodbye!</strong>")
74+
submit.click()
75+
chat.expect_latest_message("Disconnecting. Goodbye!")
76+
expect(chat.loc_latest_message).to_have_attribute("content_type", "html")
77+
expect(chat.loc_latest_message).to_have_attribute("type", "dynamic")
78+
expect(chat.loc_messages.locator("> :nth-last-child(4)")).to_have_text("Using model deepseek-r1")

0 commit comments

Comments
 (0)