Skip to content

Commit 85bed6b

Browse files
committed
Merge branch 'main' into df-style-cell
* main: tests(controls): Change API from controls to controller (#1481) fix(docs): Update path to reflect correct one (#1478) docs(testing): Add quarto page for testing (#1461) fix(test): Remove unused testrail reporting from nightly builds (#1476) chore(pyright): Remove version restriction and fix appropriate pyright errors (#1473)
2 parents 7e53a10 + 0155127 commit 85bed6b

File tree

88 files changed

+720
-550
lines changed

Some content is hidden

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

88 files changed

+720
-550
lines changed

.github/workflows/pytest.yaml

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -244,58 +244,3 @@ jobs:
244244
with:
245245
user: __token__
246246
password: ${{ secrets.PYPI_API_TOKEN }}
247-
248-
testrail-reporting-nightly:
249-
runs-on: ${{ matrix.os }}
250-
if: ${{ github.event_name == 'schedule' || startsWith(github.head_ref, 'testrail') }}
251-
strategy:
252-
matrix:
253-
python-version:
254-
- "3.12"
255-
- "3.11"
256-
- "3.10"
257-
- "3.9"
258-
# - "3.8" # Testrail has errors when running on python 3.8; Skipping
259-
os: [ubuntu-latest]
260-
fail-fast: false
261-
262-
steps:
263-
- uses: actions/checkout@v4
264-
- name: Setup py-shiny
265-
uses: ./.github/py-shiny/setup
266-
with:
267-
python-version: ${{ matrix.python-version }}
268-
269-
- name: Install node.js
270-
uses: actions/setup-node@v4
271-
with:
272-
node-version: "18"
273-
cache: npm
274-
cache-dependency-path: examples/brownian/shinymediapipe/package-lock.json
275-
- name: Install node.js package
276-
working-directory: examples/brownian/shinymediapipe
277-
run: |
278-
npm ci
279-
280-
- name: Run End-to-End tests
281-
timeout-minutes: 20
282-
run: |
283-
make testrail-junit
284-
- name: Report results to Testrail
285-
env:
286-
TESTRAIL_URL: "https://posit.testrail.io"
287-
TESTRAIL_PROJECT: "Shiny-Python"
288-
TESTRAIL_USER: "${{ secrets.TESTRAIL_USER }}"
289-
TESTRAIL_PASSWORD: "${{ secrets.TESTRAIL_PASSWORD }}"
290-
run: |
291-
CURRENT_DATE="$(date +'%Y-%m-%d %H:%M:%S') Nightly tests"
292-
trcli \
293-
--yes \
294-
--host "$TESTRAIL_URL" \
295-
--project "$TESTRAIL_PROJECT" \
296-
--username "$TESTRAIL_USER" \
297-
--password "$TESTRAIL_PASSWORD" \
298-
parse_junit \
299-
--file "report.xml" \
300-
--title "$CURRENT_DATE" \
301-
--close-run

CHANGELOG.md

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

2020
### New features
2121

22+
* Expose `shiny.playwright`, `shiny.run`, and `shiny.pytest` modules that allow users to testing their Shiny apps. (#1448, #1456, #1481)
23+
* `shiny.playwright` contains `controller` and `expect` submodules. `controller` will contain many classes to interact with (and verify!) your Shiny app using Playwright. `expect` contains expectation functions that enhance standard Playwright expectation methods.
24+
* `shiny.run` contains the `run_shiny_app` command and the return type `ShinyAppProc`. `ShinyAppProc` can be used to type the Shiny app pytest fixtures.
25+
* `shiny.pytest` contains pytest test fixtures. The `local_app` pytest fixture is automatically available and runs a sibling `app.py` file. Where as `create_app_fixture(PATH_TO_APP)` allows for a Shiny app to be instantiated from a different folder.
26+
27+
* Added CLI command `shiny add test` to add a test file to an existing Shiny app. (#1461)
28+
2229
* `@render.data_frame` has added a few new methods:
2330
* `.data_view_rows()` is a reactive value representing the sorted and filtered row numbers. This value wraps `input.<ID>_data_view_rows()`(#1374)
2431
* `.sort()` is a reactive value representing the sorted column information (dictionaries containing `col: int` and `desc: bool`). This value wraps `input.<ID>_sort()`. (#1374)
@@ -60,8 +67,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6067

6168
### New features
6269

63-
* Expose shiny.pytest, shiny.run and shiny.playwright modules that allow users to testing their Shiny apps. (#1448, #1456)
64-
6570
* Added busy indicators to provide users with a visual cue when the server is busy calculating outputs or otherwise serving requests to the client. More specifically, a spinner is shown on each calculating/recalculating output, and a pulsing banner is shown at the top of the page when the app is otherwise busy. Use the new `ui.busy_indicator.options()` function to customize the appearance of the busy indicators and `ui.busy_indicator.use()` to disable/enable them. (#918)
6671

6772
* Added support for creating modules using Shiny Express syntax, and using modules in Shiny Express apps. (#1220)

Makefile

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# https://www.gnu.org/software/make/manual/make.html#Phony-Targets
22
# Prerequisites of .PHONY are always interpreted as literal target names, never as patterns (even if they contain ‘%’ characters).
3-
# # .PHONY: help clean% check% format% docs% lint test pyright playwright% install% testrail% coverage release js-*
3+
# # .PHONY: help clean% check% format% docs% lint test pyright playwright% install% coverage release js-*
44
# Using `FORCE` as prerequisite to _force_ the target to always run; https://www.gnu.org/software/make/manual/make.html#index-FORCE
55
FORCE: ;
66

@@ -152,9 +152,6 @@ PYTEST_DEPLOYS_BROWSERS:= --browser chromium
152152
install-playwright: FORCE
153153
playwright install --with-deps
154154

155-
install-trcli: FORCE
156-
$(if $(shell which trcli), @echo -n, $(shell pip install trcli))
157-
158155
install-rsconnect: FORCE
159156
pip install git+https://github.com/rstudio/rsconnect-python.git#egg=rsconnect-python
160157

@@ -182,10 +179,6 @@ playwright-deploys: install-rsconnect
182179
playwright-examples: FORCE
183180
$(MAKE) playwright TEST_FILE="tests/playwright/examples/$(SUB_FILE)"
184181

185-
# end-to-end tests with playwright and generate junit report
186-
testrail-junit: install-playwright install-trcli
187-
pytest tests/playwright/shiny/$(SUB_FILE) --junitxml=report.xml $(PYTEST_BROWSERS)
188-
189182
coverage: FORCE ## check combined code coverage (must run e2e last)
190183
pytest --cov-report term-missing --cov=shiny tests/pytest/ tests/playwright/shiny/$(SUB_FILE) $(PYTEST_BROWSERS)
191184
coverage html

docs/.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ _sidebar.yml
55
/.quarto/
66
objects.json
77
site_libs/
8-
_objects_core.json
9-
_objects_express.json
8+
_objects_*.json

docs/Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ deps: $(PYBIN) dev-htmltools dev-shinylive ## Install build dependencies
4949
$(PYBIN)/pip install pip --upgrade
5050
$(PYBIN)/pip install ..[doc]
5151

52-
quartodoc: quartodoc_build_core quartodoc_build_express quartodoc_post ## Build quartodocs for express and core
52+
quartodoc: quartodoc_build_core quartodoc_build_express quartodoc_build_test quartodoc_post ## Build quartodocs for express and core
5353

5454
## Build interlinks for API docs
5555
quartodoc_interlinks: $(PYBIN)
@@ -78,6 +78,14 @@ quartodoc_build_express: $(PYBIN) quartodoc_interlinks
7878
&& mv objects.json _objects_express.json \
7979
&& echo "::endgroup::"
8080

81+
## Build test API docs
82+
quartodoc_build_test: $(PYBIN) quartodoc_interlinks
83+
. $(PYBIN)/activate \
84+
&& echo "::group::quartodoc build testing docs" \
85+
&& quartodoc build --config _quartodoc-testing.yml --verbose \
86+
&& mv objects.json _objects_test.json \
87+
&& echo "::endgroup::"
88+
8189
## Clean up after quartodoc build
8290
quartodoc_post: $(PYBIN)
8391
. $(PYBIN)/activate \

docs/_combine_objects_json.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ def write_objects_file(objects: QuartodocObject, path: str) -> None:
4040
print("\nCombining objects json files...")
4141
objects_core = read_objects_file("_objects_core.json")
4242
objects_express = read_objects_file("_objects_express.json")
43+
objects_test = read_objects_file("_objects_test.json")
4344

4445
items_map: dict[str, QuartodocObjectItem] = {}
4546

46-
for item in [*objects_core.items, *objects_express.items]:
47+
for item in [*objects_core.items, *objects_express.items, *objects_test.items]:
4748
if item.name in items_map:
4849
continue
4950
items_map[item.name] = item
@@ -58,6 +59,7 @@ def write_objects_file(objects: QuartodocObject, path: str) -> None:
5859

5960
print("Core:", objects_core.count)
6061
print("Express:", objects_express.count)
62+
print("Testing:", objects_test.count)
6163
print("Combined:", objects_ret.count)
6264

6365
# Save combined objects file info

docs/_quarto.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ website:
2222
file: api/express/index.qmd
2323
- text: "Core API"
2424
file: api/core/index.qmd
25+
- text: "Testing API"
26+
file: api/testing/index.qmd
2527
right:
2628
- icon: github
2729
href: https://github.com/posit-dev/py-shiny

docs/_quartodoc-testing.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
quartodoc:
2+
style: pkgdown
3+
dir: api/testing
4+
out_index: index.qmd
5+
package: shiny
6+
rewrite_all_pages: false
7+
sidebar: api/testing/_sidebar.yml
8+
dynamic: false
9+
renderer:
10+
style: _renderer.py
11+
show_signature_annotations: false
12+
sections:
13+
- title: UI Layouts
14+
desc: Methods for interacting with Shiny app multiple UI component controller.
15+
contents:
16+
- playwright.controller.Accordion
17+
- playwright.controller.AccordionPanel
18+
- playwright.controller.Card
19+
- playwright.controller.Popover
20+
- playwright.controller.Sidebar
21+
- playwright.controller.Tooltip
22+
- title: UI Inputs
23+
desc: Methods for interacting with Shiny app input value controller.
24+
contents:
25+
- playwright.controller.InputActionLink
26+
- playwright.controller.InputCheckbox
27+
- playwright.controller.InputCheckboxGroup
28+
- playwright.controller.InputDarkMode
29+
- playwright.controller.InputDate
30+
- playwright.controller.InputDateRange
31+
- playwright.controller.InputFile
32+
- playwright.controller.InputNumeric
33+
- playwright.controller.InputPassword
34+
- playwright.controller.InputRadioButtons
35+
- playwright.controller.InputSelect
36+
- playwright.controller.InputSelectize
37+
- playwright.controller.InputSlider
38+
- playwright.controller.InputSliderRange
39+
- playwright.controller.InputSwitch
40+
- playwright.controller.InputTaskButton
41+
- playwright.controller.InputText
42+
- playwright.controller.InputTextArea
43+
- title: Value boxes
44+
desc: Methods for interacting with Shiny app valuebox controller.
45+
contents:
46+
- playwright.controller.ValueBox
47+
- title: Navigation (tab) panels
48+
desc: Methods for interacting with Shiny app UI content controller.
49+
contents:
50+
- playwright.controller.NavItem
51+
- playwright.controller.NavsetBar
52+
- playwright.controller.NavsetCardPill
53+
- playwright.controller.NavsetCardTab
54+
- playwright.controller.NavsetCardUnderline
55+
- playwright.controller.NavsetHidden
56+
- playwright.controller.NavsetPill
57+
- playwright.controller.NavsetPillList
58+
- playwright.controller.NavsetTab
59+
- playwright.controller.NavsetUnderline
60+
- title: Upload and download
61+
desc: Methods for interacting with Shiny app uploading and downloading controller.
62+
contents:
63+
- playwright.controller.DownloadButton
64+
- playwright.controller.DownloadLink
65+
- title: Rendering outputs
66+
desc: Render output in a variety of ways.
67+
contents:
68+
- playwright.controller.OutputCode
69+
- playwright.controller.OutputDataFrame
70+
- playwright.controller.OutputImage
71+
- playwright.controller.OutputPlot
72+
- playwright.controller.OutputTable
73+
- playwright.controller.OutputText
74+
- playwright.controller.OutputTextVerbatim
75+
- playwright.controller.OutputUi
76+
- title: "Playwright Expect"
77+
desc: "Methods for testing the state of a locator within a Shiny app."
78+
contents:
79+
- playwright.expect.expect_to_change
80+
- playwright.expect.expect_attribute_to_have_value
81+
- playwright.expect.expect_to_have_class
82+
- playwright.expect.expect_not_to_have_class
83+
- playwright.expect.expect_to_have_style
84+
- title: "Pytest"
85+
desc: "Fixtures used for testing Shiny apps with Pytest."
86+
contents:
87+
- pytest.create_app_fixture
88+
- pytest.ScopeName
89+
- title: "Run"
90+
desc: "Methods for starting a local Shiny app in the background"
91+
contents:
92+
- run.run_shiny_app
93+
- run.ShinyAppProc

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ dev =
103103
flake8>=6.0.0
104104
flake8-bugbear>=23.2.13
105105
isort>=5.10.1
106-
pyright==1.1.365 # must be larger than 1.1.366; https://github.com/microsoft/pyright/issues/8087
106+
pyright>=1.1.367
107107
pre-commit>=2.15.0
108108
wheel
109109
matplotlib

shiny/_main.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,45 @@ def try_import_module(module: str) -> Optional[types.ModuleType]:
503503
}
504504

505505

506+
@main.group(help="""Add files to enhance your Shiny app.""")
507+
def add() -> None:
508+
pass
509+
510+
511+
@add.command(
512+
help="""Add a test file for a specified Shiny app.
513+
514+
Add an empty test file for a specified app. You will be prompted with a destination
515+
folder. If you don't provide a destination folder, it will be added in the current
516+
working directory based on the app name.
517+
518+
After creating the shiny app file, you can use `pytest` to run the tests:
519+
520+
pytest TEST_FILE
521+
"""
522+
)
523+
@click.option(
524+
"--app",
525+
"-a",
526+
type=str,
527+
help="Please provide the path to the app file for which you want to create a test file.",
528+
)
529+
@click.option(
530+
"--test-file",
531+
"-t",
532+
type=str,
533+
help="Please provide the name of the test file you want to create. The basename of the test file should start with `test_` and be unique across all test files.",
534+
)
535+
# Param for app.py, param for test_name
536+
def test(
537+
app: Path | None,
538+
test_file: Path | None,
539+
) -> None:
540+
from ._template_utils import add_test_file
541+
542+
add_test_file(app_file=app, test_file=test_file)
543+
544+
506545
@main.command(
507546
help="""Create a Shiny application from a template.
508547

0 commit comments

Comments
 (0)