Agent-almanac test-shiny-app
git clone https://github.com/pjt222/agent-almanac
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/es/skills/test-shiny-app" ~/.claude/skills/pjt222-agent-almanac-test-shiny-app-45fd33 && rm -rf "$T"
i18n/es/skills/test-shiny-app/SKILL.mdTest Shiny App
Configurar tests completos para aplicaciones Shiny usando shinytest2 (extremo a extremo) y testServer() (tests unitarios).
Cuándo Usar
- Al añadir tests a una aplicación Shiny existente
- Al configurar una estrategia de tests para un nuevo proyecto Shiny
- Al escribir tests de regresión antes de refactorizar código Shiny
- Al integrar tests de apps Shiny en pipelines CI/CD
Entradas
- Requerido: Ruta a la aplicación Shiny
- Requerido: Alcance de los tests (tests unitarios, extremo a extremo, o ambos)
- Opcional: Si usar tests de snapshot (predeterminado: sí para e2e)
- Opcional: Plataforma CI (GitHub Actions, GitLab CI)
- Opcional: Módulos a probar en aislamiento
Procedimiento
Paso 1: Instalar las Dependencias de Test
install.packages("shinytest2") # Para apps golem, añadir como dependencia de Suggests usethis::use_package("shinytest2", type = "Suggests") # Configurar infraestructura testthat si no está presente usethis::use_testthat(edition = 3)
Esperado: shinytest2 instalado y estructura de directorios testthat en su lugar.
En caso de fallo: shinytest2 requiere chromote (Chrome sin cabeza). Instala Chrome/Chromium en el sistema. En WSL:
sudo apt install -y chromium-browser. Verifica con chromote::find_chrome().
Paso 2: Escribir Tests Unitarios testServer() para Módulos
Crea
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") ), { # Establecer entradas session$setInputs(column = "Species") session$setInputs(value_select = "setosa") session$setInputs(apply = 1) # Verificar salida 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") ), { # El módulo no debe dar error con datos vacíos expect_no_error(session$setInputs(column = "Species")) }) })
Patrones clave:
prueba la lógica del server del módulo sin un navegadortestServer()- Pasa argumentos reactivos a través de la lista
args - Usa
para simular interacciones del usuariosession$setInputs() - Accede a los valores de retorno reactivos directamente por nombre
- Prueba casos extremos: datos vacíos, entradas NULL, valores inválidos
Esperado: Los tests del módulo pasan con
devtools::test().
En caso de fallo: Si
testServer() da error con "not a module server function", asegúrate de que la función use moduleServer() internamente. Si session$setInputs() no activa los reactivos, añade session$flushReact() después de establecer las entradas.
Paso 3: Escribir Tests de Extremo a Extremo con shinytest2
Crea
tests/testthat/test-app-e2e.R:
test_that("app loads and displays initial state", { # Para apps golem app <- AppDriver$new( app_dir = system.file(package = "myapp"), name = "initial-load", height = 800, width = 1200 ) on.exit(app$stop(), add = TRUE) # Esperar a que la app cargue app$wait_for_idle(timeout = 10000) # Verificar que los elementos clave existen 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) # Interactuar con la app app$set_inputs(`filter1-column` = "cyl") app$wait_for_idle() app$set_inputs(`filter1-apply` = "click") app$wait_for_idle() # Tomar snapshot de los valores de salida app$expect_values(output = "table") })
Patrones clave:
lanza la app en Chrome sin cabezaAppDriver$new()- Siempre usa
para limpiaron.exit(app$stop()) - Los IDs de entrada del módulo usan el formato
"moduleId-inputId"
crea/compara archivos de snapshotapp$expect_values()
garantiza que las actualizaciones reactivas completenapp$wait_for_idle()
Esperado: Los tests de extremo a extremo crean archivos de snapshot en
tests/testthat/_snaps/.
En caso de fallo: Si Chrome no se encuentra, establece la variable de entorno
CHROMOTE_CHROME a la ruta del binario de Chrome. Si los snapshots fallan en CI pero pasan en local, verifica las diferencias de renderizado dependientes de la plataforma — usa app$expect_values() para snapshots de datos en lugar de app$expect_screenshot() para snapshots visuales.
Paso 4: Grabar un Test de Forma Interactiva (Opcional)
shinytest2::record_test("path/to/app")
Esto abre la app en un navegador con un panel de grabación. Interactúa con la app, luego haz clic en "Save test" para generar automáticamente el código del test.
Esperado: Un archivo de test generado en
tests/testthat/ con las interacciones grabadas.
En caso de fallo: Si la grabadora no abre, verifica que la app se ejecute exitosamente con
shiny::runApp() primero. La grabadora requiere una app funcional.
Paso 5: Configurar la Gestión de Snapshots
Para tests basados en snapshots, gestiona los valores esperados:
# Aceptar snapshots nuevos/modificados después de revisión testthat::snapshot_accept("test-app-e2e") # Revisar diferencias en snapshots testthat::snapshot_review("test-app-e2e")
Añade los directorios de snapshots al control de versiones:
tests/testthat/_snaps/ # Confirmado — contiene los valores esperados
Esperado: Archivos de snapshot rastreados en git para detección de regresiones.
En caso de fallo: Si los snapshots cambian inesperadamente, ejecuta
testthat::snapshot_review() para ver las diferencias. Acepta los cambios intencionales con testthat::snapshot_accept().
Paso 6: Integrar con CI
Añade a
.github/workflows/R-CMD-check.yaml o crea un workflow dedicado:
- 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()'
Para apps golem, asegúrate de que el paquete de la app esté instalado antes de las pruebas:
- name: Install app package run: Rscript -e 'devtools::install()'
Esperado: Los tests pasan en CI con Chrome sin cabeza.
En caso de fallo: Problemas comunes de CI: Chrome no instalado (añade el paso apt-get), servidor de visualización faltante (shinytest2 usa modo sin cabeza por defecto, por lo que normalmente no es un problema), o tiempo de espera excedido en runners lentos (aumenta
timeout en AppDriver$new()).
Validación
-
ejecuta todos los tests sin erroresdevtools::test() - Los tests testServer() cubren la lógica del server del módulo
- Los tests shinytest2 cubren los flujos de trabajo clave del usuario
- Los archivos de snapshot están confirmados en el control de versiones
- Los tests pasan en el entorno CI
- Se prueban los casos extremos (datos vacíos, entradas NULL, estados de error)
Errores Comunes
- Probar el renderizado de UI en lugar de la lógica: Prefiere
para la lógica ytestServer()
para los datos. Solo usaapp$expect_values()
cuando la apariencia visual importa — los screenshots son frágiles entre plataformas.app$expect_screenshot() - Formato de ID del módulo en tests e2e: Al establecer entradas de módulo via AppDriver, usa el formato
(separado por guión), no"moduleId-inputId"
."moduleId.inputId" - Tiempos frágiles: Siempre llama a
después deapp$wait_for_idle()
. Sin esto, las aserciones pueden ejecutarse antes de que las actualizaciones reactivas completen.app$set_inputs() - Deriva de snapshots: No confirmes snapshots generados en diferentes plataformas (Mac vs Linux). Estandariza en la plataforma CI para la generación de snapshots.
- Chrome faltante en CI: shinytest2 requiere Chrome/Chromium. Siempre incluye el paso de instalación en los workflows CI.
Habilidades Relacionadas
— crear módulos comprobables con interfaces clarasbuild-shiny-module
— configurar la estructura de la app con infraestructura de testsscaffold-shiny-app
— patrones generales de testthat para paquetes Rwrite-testthat-tests
— configuración CI/CD para paquetes R (apps golem)setup-github-actions-ci