Tests and screenshots
app.screenshot(path) renders the app’s current state off-screen and saves a PNG.
It needs no window, display or GPU (it uses the software renderer), so it works in CI.
app = MyApp()app.items = ["one", "two"] # set up the state you want to showapp.screenshot("docs/list.png", size=(480, 320), scale=2)size: logical size; defaults toApp.size.scale: PNG pixel density (2 = retina).wait: seconds to wait before capturing, in caseon_startstarted some work.
Every image in this documentation is generated this way:
uv run python examples/screenshots.py # large screenshots (docs/screenshots)uv run python docs/scripts/component_shots.py # component illustrationspython examples/screenshots.py # large screenshots (docs/screenshots)python docs/scripts/component_shots.py # component illustrationspython3 examples/screenshots.py # large screenshots (docs/screenshots)python3 docs/scripts/component_shots.py # component illustrationspy examples/screenshots.py # large screenshots (docs/screenshots)py docs/scripts/component_shots.py # component illustrationsTesting the logic
Section titled “Testing the logic”Since the state lives in your object, update and callbacks are tested like plain Python:
def test_counter(): app = Counter() app.update("increment") app.update("increment") assert app.count == 2Testing that the view renders
Section titled “Testing that the view renders”view() must return a Widget without raising. A screenshot makes a good smoke test:
def test_view_renders(tmp_path): app = MyApp() app.screenshot(tmp_path / "ui.png", size=(800, 600)) assert (tmp_path / "ui.png").stat().st_size > 0If view() raises, the screenshot shows the traceback instead of the UI, just like the window.