Skip to content

Commit 4995ade

Browse files
committed
More complete playwright test
1 parent 24f05e5 commit 4995ade

File tree

4 files changed

+214
-126
lines changed

4 files changed

+214
-126
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import asyncio
2+
3+
from shiny import reactive
4+
from shiny.express import input, render, ui
5+
6+
SLEEP_TIME = 0.25
7+
8+
ui.page_opts(title="Hello chat message streams")
9+
10+
with ui.sidebar(style="height:100%"):
11+
ui.input_action_button("stream_1", "Stream 1")
12+
ui.input_action_button("stream_2", "Stream 2")
13+
ui.input_action_button("stream_3", "Stream 3")
14+
ui.input_action_button("stream_4", "Stream 4")
15+
ui.input_action_button("stream_5", "Stream 5")
16+
ui.input_action_button("stream_6", "Stream 6")
17+
18+
ui.h6("Message state:", class_="mt-auto mb-0")
19+
20+
@render.code
21+
def message_state():
22+
return str(chat.messages())
23+
24+
25+
chat = ui.Chat(id="chat")
26+
chat.ui()
27+
28+
29+
@chat.on_user_submit
30+
async def _(user_input: str):
31+
await chat.append_message(f"You said: {user_input}")
32+
33+
34+
@reactive.effect
35+
@reactive.event(input.stream_1)
36+
async def _():
37+
async with chat.append_message_context() as msg:
38+
await msg.append("Basic")
39+
await asyncio.sleep(SLEEP_TIME)
40+
await msg.append(" stream")
41+
42+
43+
@reactive.effect
44+
@reactive.event(input.stream_2)
45+
async def _():
46+
async with chat.append_message_context() as msg:
47+
await msg.append("Basic")
48+
await asyncio.sleep(SLEEP_TIME)
49+
await msg.append(" stream")
50+
await asyncio.sleep(SLEEP_TIME)
51+
await msg.restore()
52+
await asyncio.sleep(SLEEP_TIME)
53+
await msg.append("Finished")
54+
55+
56+
@reactive.effect
57+
@reactive.event(input.stream_3)
58+
async def _():
59+
async with chat.append_message_context() as outer:
60+
await outer.append("Outer start")
61+
await asyncio.sleep(SLEEP_TIME)
62+
async with chat.append_message_context() as inner:
63+
await inner.append("Inner start")
64+
await asyncio.sleep(SLEEP_TIME)
65+
await inner.append("Inner end")
66+
await asyncio.sleep(SLEEP_TIME)
67+
await outer.append("Outer end")
68+
69+
70+
@reactive.effect
71+
@reactive.event(input.stream_4)
72+
async def _():
73+
async with chat.append_message_context() as outer:
74+
await outer.append("Outer start")
75+
await asyncio.sleep(SLEEP_TIME)
76+
async with chat.append_message_context() as inner:
77+
await inner.append("Inner start")
78+
await asyncio.sleep(SLEEP_TIME)
79+
await inner.restore()
80+
await inner.append("Inner end")
81+
await asyncio.sleep(SLEEP_TIME)
82+
await outer.append("Outer end")
83+
84+
85+
@reactive.effect
86+
@reactive.event(input.stream_5)
87+
async def _():
88+
async with chat.append_message_context() as outer:
89+
await outer.append("Outer start")
90+
await asyncio.sleep(SLEEP_TIME)
91+
await outer.restore()
92+
async with chat.append_message_context() as inner:
93+
await inner.append("Inner start")
94+
await asyncio.sleep(SLEEP_TIME)
95+
await inner.append("Inner end")
96+
await asyncio.sleep(SLEEP_TIME)
97+
await outer.append("Outer end")
98+
99+
100+
@reactive.effect
101+
@reactive.event(input.stream_6)
102+
async def _():
103+
await chat.append_message_stream(outer_stream())
104+
105+
106+
async def outer_stream():
107+
yield "Outer start"
108+
await asyncio.sleep(SLEEP_TIME)
109+
await inner_stream()
110+
await asyncio.sleep(SLEEP_TIME)
111+
yield "Outer end"
112+
113+
114+
async def inner_stream():
115+
async with chat.append_message_context() as stream:
116+
await stream.append("Inner start")
117+
await asyncio.sleep(SLEEP_TIME)
118+
await stream.append("Inner progress")
119+
await stream.restore()
120+
await stream.append("Inner end")
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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_append_message_context(
10+
page: Page, local_app: ShinyAppProc
11+
) -> None:
12+
page.goto(local_app.url)
13+
14+
TIMEOUT = 30 * 1000
15+
16+
chat = controller.Chat(page, "chat")
17+
expect(chat.loc).to_be_visible(timeout=TIMEOUT)
18+
19+
stream_1 = controller.InputActionButton(page, "stream_1")
20+
expect(stream_1.loc).to_be_visible(timeout=TIMEOUT)
21+
stream_1.click()
22+
23+
chat.expect_latest_message("Basic stream", timeout=TIMEOUT)
24+
25+
stream_2 = controller.InputActionButton(page, "stream_2")
26+
expect(stream_2.loc).to_be_visible(timeout=TIMEOUT)
27+
stream_2.click()
28+
29+
chat.expect_latest_message("Finished", timeout=TIMEOUT)
30+
31+
chat.set_user_input("Hello")
32+
chat.send_user_input()
33+
chat.expect_latest_message("You said: Hello", timeout=TIMEOUT)
34+
35+
stream_3 = controller.InputActionButton(page, "stream_3")
36+
expect(stream_3.loc).to_be_visible(timeout=TIMEOUT)
37+
stream_3.click()
38+
39+
chat.expect_latest_message(
40+
"Outer startInner startInner endOuter end",
41+
timeout=TIMEOUT,
42+
)
43+
44+
stream_4 = controller.InputActionButton(page, "stream_4")
45+
expect(stream_4.loc).to_be_visible(timeout=TIMEOUT)
46+
stream_4.click()
47+
48+
chat.expect_latest_message(
49+
"Outer startInner endOuter end",
50+
timeout=TIMEOUT,
51+
)
52+
53+
stream_5 = controller.InputActionButton(page, "stream_5")
54+
expect(stream_5.loc).to_be_visible(timeout=TIMEOUT)
55+
stream_5.click()
56+
57+
chat.expect_latest_message(
58+
"Inner startInner endOuter end",
59+
timeout=TIMEOUT,
60+
)
61+
62+
stream_6 = controller.InputActionButton(page, "stream_6")
63+
expect(stream_6.loc).to_be_visible(timeout=TIMEOUT)
64+
stream_6.click()
65+
66+
chat.expect_latest_message(
67+
"Outer startInner endOuter end",
68+
timeout=TIMEOUT,
69+
)
70+
71+
chat.set_user_input("Goodbye")
72+
chat.send_user_input()
73+
chat.expect_latest_message("You said: Goodbye", timeout=TIMEOUT)
74+
75+
# Test server-side message state
76+
message_state = controller.OutputCode(page, "message_state")
77+
message_state_expected = tuple(
78+
[
79+
{"content": "Basic stream", "role": "assistant"},
80+
{"content": "Finished", "role": "assistant"},
81+
{"content": "Hello", "role": "user"},
82+
{"content": "You said: Hello", "role": "assistant"},
83+
{
84+
"content": "Outer startInner startInner endOuter end",
85+
"role": "assistant",
86+
},
87+
{"content": "Outer startInner endOuter end", "role": "assistant"},
88+
{"content": "Inner startInner endOuter end", "role": "assistant"},
89+
{"content": "Outer startInner endOuter end", "role": "assistant"},
90+
{"content": "Goodbye", "role": "user"},
91+
{"content": "You said: Goodbye", "role": "assistant"},
92+
]
93+
)
94+
message_state.expect_value(str(message_state_expected))

tests/playwright/shiny/components/chat/message-stream/app.py

Lines changed: 0 additions & 80 deletions
This file was deleted.

tests/playwright/shiny/components/chat/message-stream/test_chat_message_stream.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)