Skip to content

Commit b74ae25

Browse files
committed
Update end-to-end-testing.qmd
1 parent 341d074 commit b74ae25

File tree

1 file changed

+118
-56
lines changed

1 file changed

+118
-56
lines changed

docs/end-to-end-testing.qmd

Lines changed: 118 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,199 @@
11
---
2-
title: End-to-end testing
2+
title: End-to-End Testing Your App
33
editor:
44
markdown:
55
wrap: sentence
66
---
77

8-
End-to-end testing is like checking your app from start to finish, just as a user would.
8+
### What is End-to-End Testing (and Why Should You Care)?
99

10-
Imagine you're using your Shiny app. You click buttons, enter data, and see results on a graph or a dashboard. End-to-end tests mimic these actions.
11-
Instead of manually clicking around, we write code to do this for us.
12-
The code interacts with your app like a user, checking if everything works as expected.
10+
Imagine you've built a beautiful, interactive Shiny app. You want to make sure everything works exactly as expected, every time, for every user. That's where end-to-end testing comes in.
1311

14-
#### Benefits
15-
- End-to-end tests find issues early, like broken links or unexpected behavior.
16-
- As your app grows, it becomes harder to keep track of all parts. Tests help ensure nothing breaks.
12+
**What it is:**
1713

14+
* End-to-end testing checks your *entire* Shiny app, from start to finish, as if a real person were using it.
15+
* It simulates user actions like clicking buttons, filling in forms, and navigating between different parts of your app.
16+
* It verifies that the app's outputs (like graphs, tables, and text) are correct based on those actions.
1817

19-
### Playwright
18+
**Why it's awesome:**
2019

21-
***Playwright*** is an open-source library developed by Microsoft. It enables developers to automate browser interactions and perform end-to-end testing of web applications.
20+
* **Early bug detection:** Find problems *before* your users do! No more embarrassing surprises.
21+
* **Confidence in changes:** When you update your app, tests make sure you haven't accidentally broken anything.
22+
* **Time saver:** Instead of manually clicking through your app every time you make a change, tests automate the process.
23+
* **Peace of mind:** Know that your app is working reliably, so you can focus on building new features.
2224

23-
Benefits of using Playwright for Shiny App testing
25+
### Introducing Playwright: Your Automated Testing Buddy
2426

25-
- **End-to-End Testing**: Playwright allows you to simulate real user interactions with your Shiny app, ensuring that the reactive components and user flows work as expected.
26-
- **Cross-Browser Testing**: Playwright supports multiple browsers like Chromium, Firefox, and Safari(Webkit), enabling you to test your Shiny app's compatibility across different browser environments.
27-
- **Dynamic wait times** Playwright provides dynamic wait times, automatically waiting for elements to be ready before interacting with them, which eliminates the need for explicit waits and reduces flakiness caused by timing issues.
27+
Playwright is a fantastic, free tool (made by Microsoft) that lets you automate web browsers. Think of it as a robot that can control Chrome, Firefox, or Safari and interact with your Shiny app just like a human would.
2828

29-
For detailed information and guidance, check out the [official Playwright documentation](https://playwright.dev/python/).
29+
**Why Playwright is perfect for Shiny:**
3030

31-
### How it works: a basic example
31+
* **Handles interactivity:** It can interact with all those cool Shiny widgets like sliders, dropdowns, and buttons.
32+
* **Cross-browser testing:** Make sure your app works flawlessly on different browsers.
33+
* **Smart waiting:** Playwright automatically waits for your app to load and for elements to be ready, so your tests are reliable.
34+
* **Easy to learn:** The code is relatively straightforward, and we'll walk you through it.
3235

33-
Consider the following app that simply displays a message with double the slider value:
36+
Learn more at the [official Playwright documentation](https://playwright.dev/python/).
3437

35-
```{.python filename="app.py"}
38+
### Let's Build and Test a Simple Shiny App!
39+
40+
We'll start with a super simple example to show you the basics. Follow along, and you'll be writing your own tests in no time!
41+
42+
#### Step 1: Create Your First Shiny App
43+
44+
First, let's create a tiny Shiny app with just a slider and some text.
45+
46+
1. **Create a new file:** Create a file named `app.py`.
47+
2. **Copy and paste this code:**
48+
49+
```python
3650
from shiny import render, ui
3751
from shiny.express import input
3852

3953
ui.panel_title("Hello Shiny!")
4054
ui.input_slider("n", "N", 0, 100, 20)
4155

56+
4257
@render.text
4358
def txt():
4459
return f"n*2 is {input.n() * 2}"
60+
4561
```
4662

47-
If we want to test that the shiny app works for the following scenario:
63+
3. **What this app does:** This app displays a slider (labeled "N") that goes from 0 to 100. Below the slider, it shows the text "n*2 is \[value]", where \[value] is twice the current slider value.
64+
65+
#### Step 2: What Are We Testing?
66+
67+
Our goal is to write a test that does the following:
4868

49-
1. Wait for the Shiny app to finish loading
50-
1. Drag the slider to value as `55`
51-
1. Verify the output text changes to reflect the value of `n*2 is 110`
69+
1. **Opens the app:** Starts the Shiny app in a browser.
70+
2. **Moves the slider:** Sets the slider to a specific value (*55* in this case).
71+
3. **Checks the output:** Verifies that the text below the slider displays the correct result ("n*2 is 110").
5272

53-
The test code to test the shiny app to emulate the above scenario would be as following:
73+
#### Step 3: Write Your First Test!
5474

55-
```{.python filename="test_basic_app.py"}
75+
Now for the exciting part – writing the test code!
76+
77+
1. **Create a new file:** Create a file named `test_basic_app.py` (test files *must* start with `test_`).
78+
2. **Copy and paste this code:**
79+
80+
```python
5681
from shiny.playwright import controller
5782
from shiny.run import ShinyAppProc
5883
from playwright.sync_api import Page
59-
from shiny.pytest import create_app_fixture
6084

61-
app = create_app_fixture("../app.py")
85+
def test_basic_app(page: Page, local_app: ShinyAppProc) -> None:
86+
# Navigate to the app URL when it's ready
87+
page.goto(local_app.url)
6288

63-
def test_basic_app(page: Page, app: ShinyAppProc):
64-
page.goto(app.url)
6589
txt = controller.OutputText(page, "txt")
6690
slider = controller.InputSlider(page, "n")
91+
92+
# Move the slider to position 55
6793
slider.set("55")
94+
95+
# Verify that the output text shows "n*2 is 110"
96+
# (since 55 * 2 = 110)
6897
txt.expect_value("n*2 is 110")
6998
```
7099

71-
Here's a breakdown of what's happening in the test code:
100+
1. **Understanding Fixtures**
101+
- `ShinyAppProc` class manages a Shiny web application as a subprocess, handling its lifecycle (startup, monitoring, and shutdown) while providing access to its output streams and status.
72102

73-
1. The code begins by importing the `controller` module. This module provides classes and methods for controlling Shiny [components](https://shiny.posit.co/py/components/). With these classes, you can mimic user interactions (e.g., `.set()`) and verify state (e.g., `.expect_value()`). [See here](https://shiny.posit.co/py/api/testing/) for more information on the available classes and methods.
103+
2. **Code Breakdown:** Let's go through the code line by line:
74104

75-
2. Defines ***test_basic_app*** function with ***page*** and ***app*** parameters. *page* is an instance of the Page class from the Playwright library, which represents a single tab in a browser, and *app* is an instance of the `ShinyAppProc` class, which represents the Shiny app being tested.
105+
* `from shiny.playwright import controller`: This imports the `controller` module, which gives us tools to interact with Shiny components.
76106

77-
3. Navigates to the app's URL.
107+
* `from shiny.run import ShinyAppProc`: This imports `ShinyAppProc` (which represents our running Shiny app)
78108

79-
4. Creates instances of `OutputText` and `InputSlider` for UI elements.
109+
* `def test_basic_app(page: Page, local_app: ShinyAppProc) -> None:`: This defines our test function. The `page` argument is a Playwright object representing the browser tab, and `local_app` represents our running Shiny app.
80110

81-
5. Sets the slider value to `55`.
111+
* `page.goto(local_app.url)`: This tells Playwright to open the Shiny app in the browser.
82112

83-
6. Checks if the output text displays `n*2 is 110` as expected.
113+
* `txt = controller.OutputText(page, "txt")`: This creates an object that lets us interact with the text output (which has the ID "txt" in our app).
84114

85-
And visually, this is what happens when the test runs:
115+
* `slider = controller.InputSlider(page, "n")`: This creates an object to control the slider (which has the ID "n").
116+
117+
* `slider.set("55")`: This moves the slider to the value 55.
118+
119+
* `txt.expect_value("n*2 is 110")`: This checks if the text output matches the expected value. If it doesn't, the test will fail.
86120

87121
![](assets/end-to-end-test-workflow.png)
88122

123+
#### Step 4: Run Your Test!
89124

90-
### Run the test
125+
Before you run the test, you need to install a couple of things:
91126

92-
To run end-to-end tests, you'll first want to make sure `pytest` and the `pytest-playwright` plugin are installed:
127+
1. **Install pytest and pytest-playwright:** Open your terminal (or command prompt) and type:
93128

94129
```bash
95130
pip install pytest pytest-playwright
96131
```
97132

98-
Now, if you have the `app.py` and `test_basic_app.py` files in the same directory, from that same directory, run the `pytest` command:
133+
2. **Navigate to your app's directory:** In the terminal, use the `cd` command to go to the folder where you saved `app.py` and `test_basic_app.py`.
134+
135+
3. **Run the test:** Type the following command and press Enter:
99136

100137
```bash
101138
pytest
139+
```
102140

141+
You should see output similar to this:
142+
143+
```text
103144
======== test session starts ========
104-
platform darwin -- Python 3.10.12, pytest-7.4.4, pluggy-1.4.0
105-
configfile: pytest.ini
106-
plugins: asyncio-0.21.0, timeout-2.1.0, Faker-20.1.0, cov-4.1.0, playwright-0.4.4, rerunfailures-11.1.2, xdist-3.3.1, base-url-2.1.0, hydra-core-1.3.2, anyio-3.7.0, syrupy-4.0.5, shiny-1.0.0
107-
asyncio: mode=strict
108-
12 workers [1 item]
145+
... (some details about your setup)
109146
.
147+
======== 1 passed in 3.05s ========
148+
```
110149

150+
What does this mean?
111151

112-
======== 1 passed in 3.05s ========
152+
- The `.` (dot) means your test passed!
153+
- If you see an `F`, it means the test failed. Double-check your code and make sure you followed all the steps.
154+
155+
#### Visualize Your Test (Optional)
156+
157+
If you want to see what Playwright is doing, you can run the test in "headed" mode. This will open a browser window and show you the interactions.
158+
159+
```bash
160+
pytest --headed
113161
```
114162

115-
Each test inside the file is shown by a single character in the output:
163+
You can also specify a particular browser:
116164

117-
- `.` for passing
118-
- `F` for failure.
165+
```bash
166+
pytest --browser firefox
167+
```
119168

120-
For more information on different options for running tests (like running tests in headful mode or in different browsers), check out the [Playwright documentation](https://playwright.dev/python/docs/test-runners).
169+
### Adding Tests to an Existing Shiny App
121170

122-
### Add tests an existing app
171+
If you already have a Shiny app, you can easily add tests:
123172

124-
If you already have a shiny app and want to add a test file to it, enter the following command in your terminal/console:
173+
1. Open your terminal: Navigate to your app's directory.
174+
1. Run the shiny add test command:
125175

126176
```bash
127177
shiny add test
128178
```
129179

130-
This command will ask you for a path to the app file as well as a name for the test file.
131-
Just make sure to follow `pytest` conventions for naming the test file (should start with `test_`).
132-
Note that the test file this command provides will need to be updated with the test logic you want to add.
180+
1. Answer the prompts: It will ask for the path to your app file (e.g., `app.py`) and a name for your test file (e.g., `test_myapp.py`). Remember, the test file name must start with `test_`.
181+
182+
1. Edit the generated test file: This command creates a basic test file. You'll need to modify it to add your specific test scenarios (like the slider example above).
183+
184+
### Troubleshooting Common Issues
185+
186+
- Test fails with an error about finding an element: Make sure the IDs you're using in your test code (e.g., "txt", "n") match the IDs in your Shiny app code. Inspect your app's HTML in the browser's developer tools if you're unsure.
187+
188+
- Test is flaky (sometimes passes, sometimes fails): This can happen if your app takes a while to load or if there are timing issues. Playwright has built-in waiting mechanisms, but you might need to add explicit waits in some cases. See the [Playwright documentation](https://playwright.dev/python/docs/events#waiting-for-event) on waiting.
189+
190+
### Keep Exploring!
191+
192+
You've taken your first steps into the world of Shiny app testing! Here are some resources to help you learn more:
133193

194+
- [Shiny testing API documentation](https://shiny.posit.co/py/api/testing/) - This is your go-to guide for all the available testing methods in Shiny.
195+
- [Playwright documentation](https://playwright.dev/python/) - Learn more about Playwright's powerful features.
196+
- [pytest documentation](https://docs.pytest.org/en/stable/)
134197

135-
### Learn more
136198

137-
For more information about the testing methods available to the user, read the reference documentation about shiny testing API [here](https://shiny.posit.co/py/api/testing/).
199+
Happy testing! You're now well-equipped to build more robust and reliable Shiny apps.

0 commit comments

Comments
 (0)