Skip to content

Commit 064940a

Browse files
authored
test(express): Add kitchensink apps & tests (#1886)
1 parent c5f8a48 commit 064940a

File tree

84 files changed

+4358
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+4358
-5
lines changed

.github/workflows/pytest.yaml

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ jobs:
187187
- name: Install node.js
188188
uses: actions/setup-node@v4
189189
with:
190-
node-version: "18"
191190
cache: npm
192191
cache-dependency-path: examples/brownian/shinymediapipe/package-lock.json
193192
- name: Install node.js package
@@ -206,6 +205,49 @@ jobs:
206205
path: test-results/
207206
retention-days: 5
208207

208+
playwright-ai:
209+
if: github.event_name != 'release'
210+
runs-on: ubuntu-latest
211+
strategy:
212+
matrix:
213+
python-version: ["3.12", "3.11", "3.10", "3.9"]
214+
browser: ["chromium", "firefox", "webkit"]
215+
exclude:
216+
- python-version: ${{ github.event.pull_request.draft && '3.11' }}
217+
- python-version: ${{ github.event.pull_request.draft && '3.10' }}
218+
- python-version: ${{ github.event.pull_request.draft && '3.9' }}
219+
- browser: ${{ github.event.pull_request.draft && 'firefox' }}
220+
- browser: ${{ github.event.pull_request.draft && 'webkit' }}
221+
fail-fast: false
222+
223+
steps:
224+
- uses: actions/checkout@v4
225+
with:
226+
fetch-depth: 0
227+
- name: Setup py-shiny
228+
uses: ./.github/py-shiny/setup
229+
with:
230+
python-version: ${{ matrix.python-version }}
231+
- name: Determine browsers for testing
232+
uses: ./.github/py-shiny/pytest-browsers
233+
id: browsers
234+
with:
235+
browser: ${{ matrix.browser }}
236+
# If anything other than `true`, it will heavily reduce webkit performance
237+
# Related: https://github.com/microsoft/playwright/issues/18119
238+
disable-playwright-diagnostics: ${{ matrix.browser == 'webkit' || matrix.browser == 'firefox' }}
239+
240+
- name: Run playwright tests for AI generated apps
241+
timeout-minutes: 60
242+
run: |
243+
make playwright-ai SUB_FILE=". --numprocesses 3 ${{ steps.browsers.outputs.playwright-diagnostic-args }}" ${{ steps.browsers.outputs.browsers }}
244+
- uses: actions/upload-artifact@v4
245+
if: failure() && steps.browsers.outputs.has-playwright-diagnostics
246+
with:
247+
name: "playright-ai-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.browser }}-results"
248+
path: test-results/
249+
retention-days: 5
250+
209251
playwright-deploys-precheck:
210252
if: github.event_name != 'release'
211253
runs-on: ubuntu-latest

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323

2424
* Fixed an issue where the `.update_user_input()` method on `ui.Chat()` isn't working in shinylive. (#1891)
2525

26+
* Fixed an issue with the `.click()` method on InputActionButton controllers in `shiny.playwright.controllers` where the method would not work as expected. (#1886)
27+
2628
## [1.3.0] - 2025-03-03
2729

2830
### New features

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ TEST_FILE:=tests/playwright/$(SUB_FILE)
157157
DEPLOYS_TEST_FILE:=tests/playwright/deploys$(SUB_FILE)
158158
SHINY_TEST_FILE:=tests/playwright/shiny/$(SUB_FILE)
159159
EXAMPLES_TEST_FILE:=tests/playwright/examples/$(SUB_FILE)
160+
AI_TEST_FILE:=tests/playwright/ai_generated_apps/$(SUB_FILE)
160161

161162
install-playwright: FORCE
162163
playwright install --with-deps
@@ -187,6 +188,10 @@ playwright-deploys: FORCE
187188
playwright-examples: FORCE
188189
$(MAKE) playwright TEST_FILE="$(EXAMPLES_TEST_FILE)"
189190

191+
# end-to-end tests for all AI generated apps
192+
playwright-ai: FORCE
193+
$(MAKE) playwright TEST_FILE="$(AI_TEST_FILE)"
194+
190195
coverage: FORCE ## check combined code coverage (must run e2e last)
191196
pytest --cov-report term-missing --cov=shiny tests/pytest/ $(SHINY_TEST_FILE) $(PYTEST_BROWSERS)
192197
coverage html

pyrightconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"docs",
1111
"tests/playwright/deploys/*/app.py",
1212
"shiny/templates",
13-
"tests/playwright/shiny/tests_for_ai_generated_apps"
13+
"tests/playwright/ai_generated_apps",
1414
],
1515
"typeCheckingMode": "strict",
1616
"reportImportCycles": "none",

shiny/playwright/controller/_base.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,12 @@ def set_text(
123123

124124

125125
def _expect_multiple(loc: Locator, multiple: bool, timeout: Timeout = None) -> None:
126-
value = "True" if multiple else None
127-
_expect_style_to_have_value(loc, "multiple", value, timeout=timeout)
126+
_expect_attribute_to_have_value(
127+
loc,
128+
"multiple",
129+
value="multiple" if multiple else None,
130+
timeout=timeout,
131+
)
128132

129133

130134
######################################################

shiny/playwright/controller/_input_buttons.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def click(self, *, timeout: Timeout = None):
101101
timeout
102102
The maximum time to wait for the input dark mode to be clicked. Defaults to `None`.
103103
"""
104-
self.loc.click(timeout=timeout)
104+
self.loc.locator("button").click(timeout=timeout)
105105
return self
106106

107107
def expect_mode(self, value: str, *, timeout: Timeout = None):
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from shiny import App, render, ui
2+
3+
# Define the UI
4+
app_ui = ui.page_fillable(
5+
# Add Font Awesome CSS in the head section
6+
ui.tags.head(
7+
ui.tags.link(
8+
rel="stylesheet",
9+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css",
10+
)
11+
),
12+
# Card containing accordion
13+
ui.card(
14+
ui.accordion(
15+
# Basic Panel
16+
ui.accordion_panel(
17+
"Basic Panel",
18+
ui.markdown("This is a basic panel with just a title parameter"),
19+
),
20+
# Panel with title and value
21+
ui.accordion_panel(
22+
"Panel with Value",
23+
ui.markdown("This panel has both a title and a value parameter"),
24+
value="panel2",
25+
),
26+
# Panel with title, value, and icon
27+
ui.accordion_panel(
28+
"Panel with Icon",
29+
ui.markdown("This panel includes an icon parameter using Font Awesome"),
30+
value="panel3",
31+
icon=ui.tags.i(
32+
class_="fa-solid fa-shield-halved", style="font-size: 1rem;"
33+
),
34+
),
35+
# Panel with title, value, icon, and custom attributes
36+
ui.accordion_panel(
37+
"Panel with Custom Attributes",
38+
ui.markdown(
39+
"This panel demonstrates custom attributes (class and style)"
40+
),
41+
value="panel4",
42+
icon=ui.tags.i(class_="fa-solid fa-star", style="font-size: 1rem;"),
43+
class_="custom-panel",
44+
style="background-color: #f8f9fa;",
45+
),
46+
id="acc",
47+
open=True,
48+
multiple=True,
49+
),
50+
),
51+
# Output for selected panel
52+
ui.output_text("selected_panel"),
53+
)
54+
55+
56+
# Define the server
57+
def server(input, output, session):
58+
@output
59+
@render.text
60+
def selected_panel():
61+
return f"Currently selected panel: {input.acc()}"
62+
63+
64+
# Create the app
65+
app = App(app_ui, server)

0 commit comments

Comments
 (0)