test-shiny-app
О программе
Этот навык помогает разработчикам тестировать приложения Shiny с использованием shinytest2 для сквозного тестирования в браузере и testServer() для модульного тестирования серверной логики. Он охватывает снапшот-тестирование, интеграцию с CI и мокирование внешних сервисов. Используйте его при добавлении тестов к существующим приложениям, настройке тестирования для новых проектов, написании регрессионных тестов или интеграции тестов в CI/CD-пайплайны.
Быстрая установка
Claude Code
Рекомендуетсяnpx 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-appСкопируйте и вставьте эту команду в Claude Code для установки этого навыка
Документация
Test Shiny App
Set up comprehensive testing for Shiny applications using shinytest2 (end-to-end) and testServer() (unit tests).
When Use
- Add tests to existing Shiny application
- Set up testing strategy for new Shiny project
- Write regression tests before refactoring Shiny code
- Integrate Shiny app tests into CI/CD pipelines
Inputs
- Required: Path to 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
Steps
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, testthat directory structure in place.
If fail: shinytest2 needs chromote (headless Chrome). Install Chrome/Chromium on system. 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: testServer() errors with "not a module server function"? Ensure function uses moduleServer() internally. 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: Chrome not found? Set CHROMOTE_CHROME environment variable to Chrome binary path. Snapshots fail on CI but pass local? Check for platform-dependent rendering differences — use app$expect_values() for data snapshots rather than app$expect_screenshot() for visual ones.
Step 4: Record 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: Test file generated in tests/testthat/ with recorded interactions.
If fail: Recorder doesn't open? Check app runs successful with shiny::runApp() first. Recorder needs 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: Snapshots change unexpected? Run testthat::snapshot_review() to see 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 apt-get step), display server missing (shinytest2 uses headless mode default so usually not issue), or timeout on slow runners (increase timeout in AppDriver$new()).
Checks
-
devtools::test()runs all tests without errors - testServer() tests cover module server logic
- shinytest2 tests cover key user workflows
- Snapshot files committed to version control
- Tests pass in CI environment
- Edge cases tested (empty data, NULL inputs, error states)
Pitfalls
- Test UI rendering instead of logic: Prefer
testServer()for logic andapp$expect_values()for data. Only useapp$expect_screenshot()when visual appearance matters — screenshots brittle across platforms. - Module ID format in e2e tests: 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: Never commit snapshots generated on different platforms (Mac vs Linux). Standardize on CI platform for snapshot generation.
- Missing Chrome on CI: shinytest2 needs Chrome/Chromium. Always include installation step in CI workflows.
See Also
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)
GitHub репозиторий
Похожие навыки
evaluating-llms-harness
ТестированиеЭтот навык Claude запускает lm-evaluation-harness для тестирования LLM на более чем 60 стандартизированных академических задачах, таких как MMLU и GSM8K. Он предназначен для разработчиков, чтобы сравнивать качество моделей, отслеживать прогресс обучения или сообщать академические результаты. Инструмент поддерживает различные бэкенды, включая модели HuggingFace и vLLM.
cloudflare-cron-triggers
ТестированиеЭтот навык предоставляет обширные знания по реализации Cloudflare Cron Triggers для планирования запуска Workers с помощью cron-выражений. Он охватывает настройку периодических задач, заданий технического обслуживания и автоматизированных рабочих процессов, а также решение распространенных проблем, таких как неверные cron-выражения и ошибки часовых поясов. Разработчики могут использовать его для настройки планировщиков обработчиков, тестирования cron-триггеров и интеграции с Workflows и Green Compute.
webapp-testing
ТестированиеЭтот навык Claude предоставляет инструментарий на базе Playwright для тестирования локальных веб-приложений с помощью Python-скриптов. Он позволяет проводить проверку фронтенда, отладку интерфейса, создание скриншотов и просмотр логов, одновременно управляя жизненным циклом сервера. Используйте его для задач автоматизации браузера, но запускайте скрипты напрямую, вместо чтения их исходного кода, чтобы избежать загрязнения контекста.
finishing-a-development-branch
ТестированиеЭтот навык помогает разработчикам завершать готовую работу, проверяя прохождение тестов и предлагая структурированные варианты интеграции. Он направляет рабочий процесс по слиянию, созданию пул-реквестов или очистке веток после завершения реализации. Используйте его, когда ваш код готов и протестирован, чтобы систематически завершать процесс разработки.
