test-shiny-app
Acerca de
Esta habilidad ayuda a los desarrolladores a probar aplicaciones Shiny utilizando shinytest2 para pruebas de navegador de extremo a extremo y testServer() para pruebas unitarias de la lógica de los módulos. Cubre pruebas de instantáneas, integración en CI y simulación de servicios externos. Úsela al agregar pruebas a aplicaciones Shiny existentes, configurar pruebas para nuevos proyectos o integrar pruebas en pipelines de CI/CD.
Instalación rápida
Claude Code
Recomendadonpx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/test-shiny-appCopia y pega este comando en Claude Code para instalar esta habilidad
Documentación
Test Shiny App
Set up comprehensive testing for Shiny applications using shinytest2 (end-to-end) and testServer() (unit tests).
When to Use
- Adding tests to an existing Shiny application
- Setting up a testing strategy for a new Shiny project
- Writing regression tests before refactoring Shiny code
- Integrating Shiny app tests into CI/CD pipelines
Inputs
- Required: Path to the Shiny application
- Required: Test scope (unit tests, end-to-end, or both)
- Optional: Whether to use snapshot testing (default: yes for e2e)
- Optional: CI platform (GitHub Actions, GitLab CI)
- Optional: Modules to test in isolation
Procedure
Step 1: Install Testing Dependencies
install.packages("shinytest2")
# For golem apps, add as a Suggests dependency
usethis::use_package("shinytest2", type = "Suggests")
# Set up testthat infrastructure if not present
usethis::use_testthat(edition = 3)
Got: shinytest2 installed and testthat directory structure in place.
If fail: shinytest2 requires chromote (headless Chrome). Install Chrome/Chromium on the system. On WSL: sudo apt install -y chromium-browser. Verify with chromote::find_chrome().
Step 2: Write testServer() Unit Tests for Modules
Create tests/testthat/test-mod_dashboard.R:
test_that("dashboard module filters data correctly", {
testServer(dataFilterServer, args = list(
data = reactive(iris),
columns = c("Species", "Sepal.Length")
), {
# Set inputs
session$setInputs(column = "Species")
session$setInputs(value_select = "setosa")
session$setInputs(apply = 1)
# Check output
result <- filtered()
expect_equal(nrow(result), 50)
expect_true(all(result$Species == "setosa"))
})
})
test_that("dashboard module handles empty data", {
testServer(dataFilterServer, args = list(
data = reactive(iris[0, ]),
columns = c("Species")
), {
# Module should not error on empty data
expect_no_error(session$setInputs(column = "Species"))
})
})
Key patterns:
testServer()tests module server logic without a browser- Pass reactive arguments via the
argslist - Use
session$setInputs()to simulate user interactions - Access reactive return values directly by name
- Test edge cases: empty data, NULL inputs, invalid values
Got: Module tests pass with devtools::test().
If fail: If testServer() errors with "not a module server function", ensure the function uses moduleServer() internally. If session$setInputs() doesn't trigger reactives, add session$flushReact() after setting inputs.
Step 3: Write shinytest2 End-to-End Tests
Create tests/testthat/test-app-e2e.R:
test_that("app loads and displays initial state", {
# For golem apps
app <- AppDriver$new(
app_dir = system.file(package = "myapp"),
name = "initial-load",
height = 800,
width = 1200
)
on.exit(app$stop(), add = TRUE)
# Wait for app to load
app$wait_for_idle(timeout = 10000)
# Check that key elements exist
app$expect_values()
})
test_that("filter interaction updates the table", {
app <- AppDriver$new(
app_dir = system.file(package = "myapp"),
name = "filter-interaction"
)
on.exit(app$stop(), add = TRUE)
# Interact with the app
app$set_inputs(`filter1-column` = "cyl")
app$wait_for_idle()
app$set_inputs(`filter1-apply` = "click")
app$wait_for_idle()
# Snapshot the output values
app$expect_values(output = "table")
})
Key patterns:
AppDriver$new()launches the app in headless Chrome- Always use
on.exit(app$stop())to clean up - Module input IDs use the format
"moduleId-inputId" app$expect_values()creates/compares snapshot filesapp$wait_for_idle()ensures reactive updates complete
Got: End-to-end tests create snapshot files in tests/testthat/_snaps/.
If fail: If Chrome isn't found, set CHROMOTE_CHROME environment variable to the Chrome binary path. If snapshots fail on CI but pass locally, check for platform-dependent rendering differences — use app$expect_values() for data snapshots rather than app$expect_screenshot() for visual ones.
Step 4: Record a Test Interactively (Optional)
shinytest2::record_test("path/to/app")
This opens the app in a browser with a recording panel. Interact with the app, then click "Save test" to auto-generate test code.
Got: A test file is generated in tests/testthat/ with recorded interactions.
If fail: If the recorder doesn't open, check that the app runs successfully with shiny::runApp() first. The recorder requires a working app.
Step 5: Set Up Snapshot Management
For snapshot-based tests, manage expected values:
# Accept new/changed snapshots after review
testthat::snapshot_accept("test-app-e2e")
# Review snapshot differences
testthat::snapshot_review("test-app-e2e")
Add snapshot directories to version control:
tests/testthat/_snaps/ # Committed — contains expected values
Got: Snapshot files tracked in git for regression detection.
If fail: If snapshots change unexpectedly, run testthat::snapshot_review() to see the diffs. Accept intentional changes with testthat::snapshot_accept().
Step 6: Integrate with CI
Add to .github/workflows/R-CMD-check.yaml or create a dedicated workflow:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y chromium-browser
- name: Set Chrome path
run: echo "CHROMOTE_CHROME=$(which chromium-browser)" >> $GITHUB_ENV
- name: Run tests
run: |
Rscript -e 'devtools::test()'
For golem apps, ensure the app package is installed before testing:
- name: Install app package
run: Rscript -e 'devtools::install()'
Got: Tests pass in CI with headless Chrome.
If fail: Common CI issues: Chrome not installed (add the apt-get step), display server missing (shinytest2 uses headless mode by default so this usually isn't an issue), or timeout on slow runners (increase timeout in AppDriver$new()).
Validation
-
devtools::test()runs all tests without errors - testServer() tests cover module server logic
- shinytest2 tests cover key user workflows
- Snapshot files are committed to version control
- Tests pass in CI environment
- Edge cases tested (empty data, NULL inputs, error states)
Pitfalls
- Testing UI rendering instead of logic: Prefer
testServer()for logic andapp$expect_values()for data. Only useapp$expect_screenshot()when visual appearance matters — screenshots are brittle across platforms. - Module ID format in e2e tests: When setting module inputs via AppDriver, use
"moduleId-inputId"format (hyphen-separated), not"moduleId.inputId". - Flaky timing: Always call
app$wait_for_idle()afterapp$set_inputs(). Without it, assertions may run before reactive updates complete. - Snapshot drift: Don't commit snapshots generated on different platforms (Mac vs Linux). Standardize on the CI platform for snapshot generation.
- Missing Chrome on CI: shinytest2 requires Chrome/Chromium. Always include the installation step in CI workflows.
Related Skills
build-shiny-module— create testable modules with clear interfacesscaffold-shiny-app— set up app structure with testing infrastructurewrite-testthat-tests— general testthat patterns for R packagessetup-github-actions-ci— CI/CD setup for R packages (golem apps)
Repositorio GitHub
Habilidades relacionadas
evaluating-llms-harness
PruebasEsta Skill de Claude ejecuta el benchmark lm-evaluation-harness para evaluar modelos de lenguaje en más de 60 tareas académicas estandarizadas como MMLU y GSM8K. Está diseñada para que los desarrolladores comparen la calidad de los modelos, realicen seguimiento del progreso del entrenamiento o reporten resultados académicos. La herramienta admite varios backends, incluidos modelos de HuggingFace y vLLM.
cloudflare-cron-triggers
PruebasEsta habilidad proporciona conocimiento integral para implementar Cron Triggers de Cloudflare y programar Workers mediante expresiones cron. Cubre la configuración de tareas periódicas, trabajos de mantenimiento y flujos de trabajo automatizados, manejando problemas comunes como expresiones cron inválidas y inconvenientes de zonas horarias. Los desarrolladores pueden utilizarla para configurar manejadores programados, probar activadores cron e integrar con Workflows y Green Compute.
webapp-testing
PruebasEsta habilidad de Claude proporciona un kit de herramientas basado en Playwright para probar aplicaciones web locales mediante scripts de Python. Permite verificación de frontend, depuración de interfaz de usuario, captura de pantallas y visualización de registros, mientras gestiona los ciclos de vida del servidor. Úsela para tareas de automatización de navegadores, pero ejecute los scripts directamente en lugar de leer su código fuente para evitar contaminación del contexto.
finishing-a-development-branch
PruebasEsta habilidad ayuda a los desarrolladores a completar el trabajo terminado verificando que las pruebas pasen y luego presentando opciones estructuradas de integración. Guía el flujo de trabajo para fusionar, crear PRs o limpiar ramas después de que se completa la implementación. Úsala cuando tu código esté listo y probado para finalizar sistemáticamente el proceso de desarrollo.
