### Install shinytest2 Source: https://github.com/rstudio/shinytest2/blob/main/README.md Installation commands for the released version from CRAN or the development version from GitHub. ```r # Install the released version from CRAN install.packages("shinytest2") # Or the development version from GitHub: # install.packages("devtools") devtools::install_github("rstudio/shinytest2") ``` -------------------------------- ### Setup Testing Infrastructure Source: https://context7.com/rstudio/shinytest2/llms.txt Initialize the necessary files and configurations for shinytest2 in a project. ```r # Full setup (creates runner, setup file, gitignore entries) shinytest2::use_shinytest2() # Setup for a specific app directory shinytest2::use_shinytest2(app_dir = "inst/shinyapp") # Selective setup shinytest2::use_shinytest2( runner = TRUE, # Create tests/testthat.R setup = TRUE, # Create tests/testthat/setup-shinytest2.R ignore = TRUE, # Add *.new.png to .gitignore package = TRUE # Add shinytest2 to DESCRIPTION Suggests ) # Create a new test file shinytest2::use_shinytest2_test() shinytest2::use_shinytest2_test(open = TRUE) # Open in editor ``` -------------------------------- ### Example Workflow: Test app w/ DESCRIPTION Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md This is an example GitHub Actions workflow for testing a Shiny application that uses a DESCRIPTION file for dependency management. It sets up R, dependencies, and runs the test-app action. ```yaml # Workflow derived from https://github.com/rstudio/shinytest2/tree/main/actions/test-app/example-test-app-description.yaml # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: branches: [main, master] pull_request: branches: [main, master] name: Test app w/ DESCRIPTION jobs: test-app: runs-on: ${{ matrix.config.os }} name: ${{ matrix.config.os }} (${{ matrix.config.r }}) strategy: fail-fast: false matrix: config: - {os: ubuntu-latest, r: release} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes steps: - uses: actions/checkout@v2 - uses: r-lib/actions/setup-pandoc@v2 - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: shinytest2 - uses: rstudio/shinytest2/actions/test-app@actions/v1 with: app-dir: "." ``` -------------------------------- ### Install test-app-description Workflow Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md Use this R code snippet with usethis to install a GitHub Actions workflow for testing Shiny apps with DESCRIPTION file dependencies. ```r usethis::use_github_action( url = "https://github.com/rstudio/shinytest2/raw/main/actions/test-app/example-test-app-descrption.yaml", save_as = "test-app-description.yaml" ) ``` -------------------------------- ### Install GitHub Action Workflow Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md Use this command to add the test-app-package workflow to your repository. ```r usethis::use_github_action( url = "https://github.com/rstudio/shinytest2/raw/main/actions/test-app/example-test-app-package.yaml", save_as = "test-app-package.yaml" ) ``` -------------------------------- ### Install shinytest2 dependencies Source: https://github.com/rstudio/shinytest2/blob/main/cran-comments.md Run this command to install necessary dependencies for running tests in shinytest2. ```r shinytest::installDependencies() ``` -------------------------------- ### Example Workflow: Test app w/ {renv} Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md This is an example GitHub Actions workflow for testing a Shiny application that uses renv for dependency management. It includes steps for checking out code, setting up R, renv, and running the test-app action. ```yaml # Workflow derived from https://github.com/rstudio/shinytest2/tree/main/actions/test-app/example-test-app-renv.yaml # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: branches: [main, master] pull_request: branches: [main, master] name: Test app w/ {renv} jobs: test-app: runs-on: ${{ matrix.config.os }} name: ${{ matrix.config.os }} (${{ matrix.config.r }}) strategy: fail-fast: false matrix: config: - {os: ubuntu-latest, r: release} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes steps: - uses: actions/checkout@v2 - uses: r-lib/actions/setup-pandoc@v2 - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - uses: r-lib/actions/setup-renv@v2 - uses: rstudio/shinytest2/actions/test-app@actions/v1 with: app-dir: "." ``` -------------------------------- ### Install test-app-renv Workflow Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md Use this R code snippet with usethis to install a GitHub Actions workflow for testing Shiny apps where dependencies are managed by renv. ```r usethis::use_github_action( url = "https://github.com/rstudio/shinytest2/raw/main/actions/test-app/example-test-app-renv.yaml", save_as = "test-app-renv.yaml" ) ``` -------------------------------- ### use_shinytest2 - Setup Testing Infrastructure Source: https://context7.com/rstudio/shinytest2/llms.txt Initializes shinytest2 testing configuration for a Shiny application. ```APIDOC ## use_shinytest2 ### Description Sets up the necessary files and configuration for shinytest2 in a project directory. ### Parameters #### Request Body - **app_dir** (string) - Optional - Directory of the Shiny app. - **runner** (boolean) - Optional - Create test runner. - **setup** (boolean) - Optional - Create setup file. ``` -------------------------------- ### Get and Use Platform Variants Source: https://context7.com/rstudio/shinytest2/llms.txt Retrieve the current platform variant string or customize it by toggling OS name and R version inclusion. ```r # Get current platform variant variant <- platform_variant() # Returns: "mac-4.3" or "linux-4.2" or "windows-4.3" # Use in AppDriver app <- AppDriver$new( "path/to/app", variant = platform_variant() ) # Custom variant components platform_variant(os_name = TRUE, r_version = FALSE) # Returns: "mac" platform_variant(os_name = FALSE, r_version = TRUE) # Returns: "4.3" ``` -------------------------------- ### Test Shiny Application States and Interactions Source: https://context7.com/rstudio/shinytest2/llms.txt Examples of using AppDriver to verify initial states, handle form submissions, process file uploads, and validate error messages in a Shiny application. ```R library(shinytest2) library(testthat) test_that("Initial app state is correct", { app <- AppDriver$new( test_path("apps/myapp"), name = "myapp", variant = platform_variant() ) # Verify initial values app$expect_values() app$stop() }) ``` ```R test_that("User can submit form", { app <- AppDriver$new(test_path("apps/myapp")) # Fill out form app$set_inputs( name = "Jane Doe", email = "jane@example.com", department = "Engineering" ) # Submit form app$click(input = "submit") # Wait for confirmation app$wait_for_value(output = "confirmation") # Verify success message confirmation_text <- app$get_text("#confirmation") expect_match(confirmation_text, "Successfully submitted") # Snapshot final state app$expect_values(name = "after_submit") app$stop() }) ``` ```R test_that("File upload processes correctly", { app <- AppDriver$new(test_path("apps/myapp")) # Upload test file app$upload_file(data_file = test_path("data/sample.csv")) # Wait for processing app$wait_for_idle(timeout = 10000) # Verify data was loaded row_count <- app$get_value(output = "row_count") expect_equal(row_count, "100 rows") app$stop() }) ``` ```R test_that("Error handling works", { app <- AppDriver$new(test_path("apps/myapp")) # Trigger validation error app$set_inputs(email = "not-an-email") app$click(input = "submit") # Check error is displayed error_text <- app$get_text(".validation-error") expect_match(error_text, "valid email") app$stop() }) ``` -------------------------------- ### AppDriver - Create and Control a Shiny App Test Driver Source: https://context7.com/rstudio/shinytest2/llms.txt The AppDriver R6 class is the primary interface for testing Shiny applications. It starts a Shiny app in a background R process and connects a headless Chrome browser to simulate user interactions and capture application state. ```APIDOC ## AppDriver - Create and Control a Shiny App Test Driver ### Description The `AppDriver` R6 class is the primary interface for testing Shiny applications. It starts a Shiny app in a background R process and connects a headless Chrome browser to simulate user interactions and capture application state. ### Method `AppDriver$new(...) ### Parameters #### Path Parameters - **app_dir** (string) - Required - Path to the Shiny app directory. - **name** (string) - Optional - Prefix for snapshot files. - **variant** (any) - Optional - Platform-specific snapshots. - **seed** (numeric) - Optional - Random seed for reproducibility. - **load_timeout** (numeric) - Optional - Max time to wait for app load (ms). - **timeout** (numeric) - Optional - Default timeout for operations (ms). - **height** (numeric) - Optional - Browser window height. - **width** (numeric) - Optional - Browser window width. - **view** (boolean) - Optional - Open browser for debugging. - **check_names** (boolean) - Optional - Warn about duplicate input/output IDs. ### Request Example ```R library(shinytest2) # Create an AppDriver from a Shiny app directory app <- AppDriver$new( app_dir = "path/to/app", name = "myapp", variant = platform_variant(), seed = 12345, load_timeout = 15000, timeout = 4000, height = 800, width = 1200, view = FALSE, check_names = TRUE ) # Create from a Shiny app object directly library(shiny) shiny_app <- shinyApp( ui = fluidPage( numericInput("n", "N", value = 10), textOutput("result") ), server = function(input, output) { output$result <- renderText({ input$n * 2 }) } ) app <- AppDriver$new(shiny_app) # Create from a function (useful for package testing) app <- AppDriver$new(function() { library(mypackage) mypackage::run_app() }) # Always stop the app when done app$stop() ``` ### Response #### Success Response (200) - **AppDriver object** - An instance of the AppDriver R6 class. #### Response Example ```R # AppDriver object is returned upon successful creation ``` ``` -------------------------------- ### Retrieve App State Values Source: https://context7.com/rstudio/shinytest2/llms.txt Get current values of inputs, outputs, and exported test values from a running Shiny application. Can retrieve all values, specific categories, or individual named values. ```R library(shiny) shiny_app <- shinyApp( ui = fluidPage( numericInput("A", "A", 3), numericInput("B", "B", 4), verbatimTextOutput("C") ), server = function(input, output) { c_squared <- reactive({ input$A^2 + input$B^2 }) output$C <- renderText({ sqrt(c_squared()) }) # Export internal reactive values for testing exportTestValues( c_squared = { c_squared() } ) } ) app <- AppDriver$new(shiny_app) # Get all values (inputs, outputs, exports) all_values <- app$get_values() # Returns: list(input = list(A = 3, B = 4), # output = list(C = "5"), # export = list(c_squared = 25)) # Get specific categories input_values <- app$get_values(input = TRUE) output_values <- app$get_values(output = TRUE) export_values <- app$get_values(export = TRUE) # Get specific named values specific_values <- app$get_values(input = "A", output = "C") # Get a single value (shorthand) a_value <- app$get_value(input = "A") # Returns: 3 c_output <- app$get_value(output = "C") # Returns: "5" app$stop() ``` -------------------------------- ### Build and check package Source: https://github.com/rstudio/shinytest2/blob/main/CLAUDE.md Standard development workflow for building documentation, checking package integrity, and reloading code. ```r # Load package for development devtools::load_all() # Check package devtools::check() # Build documentation devtools::document() # Build website pkgdown::build_site() ``` -------------------------------- ### Test File Downloads with expect_download Source: https://context7.com/rstudio/shinytest2/llms.txt Use expect_download to test downloadButton/downloadLink outputs by downloading files and comparing them against snapshots. It supports explicit text comparison and custom snapshot names. ```r library(shinytest2) library(testthat) test_that("Download produces expected file", { app <- AppDriver$new("path/to/app") # Download and snapshot (auto-detects text vs binary) app$expect_download("download_csv") # Explicit text comparison app$expect_download( "download_report", compare = testthat::compare_file_text ) # Custom snapshot name app$expect_download("download_data", name = "exported_data.csv") app$stop() }) # Get download without snapshotting download_path <- app$get_download("download_csv") # Returns: "/tmp/RtmpXXX/rock.csv" # Save to specific location app$get_download("download_csv", filename = "output/my_data.csv") ``` -------------------------------- ### Record Interactive Tests Source: https://context7.com/rstudio/shinytest2/llms.txt Launch the interactive recorder to capture user actions and generate test scripts. ```r # Record tests for an app in the current directory shinytest2::record_test() # Record for a specific app shinytest2::record_test("path/to/app") # Record with specific options shinytest2::record_test( app = "inst/shinyapp", name = "mytest", seed = 12345, load_timeout = 30000, test_file = "test-custom-name.R", record_screen_size = TRUE, run_test = TRUE # Run test after recording ) # Don't run test automatically after recording shinytest2::record_test( "path/to/app", run_test = FALSE, open_test_file = TRUE ) ``` -------------------------------- ### Basic Usage of test-app Action Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md Use this step in your GitHub Actions workflow to test a single Shiny application. Specify the application directory using the 'app-dir' input. ```yaml - uses: rstudio/shinytest2/actions/test-app@actions/v1 with: app-dir: | dir/to/app ``` -------------------------------- ### expect_download - Test File Downloads Source: https://context7.com/rstudio/shinytest2/llms.txt Tests downloadButton/downloadLink outputs by downloading the file and comparing it against a saved snapshot. ```APIDOC ## expect_download ### Description Tests downloadButton/downloadLink outputs by downloading the file and comparing it against a saved snapshot. ### Parameters #### Query Parameters - **output_id** (character) - Required - The ID of the download button. - **compare** (function) - Optional - Comparison function. - **name** (character) - Optional - Custom snapshot name. ``` -------------------------------- ### expect_screenshot - Visual Regression Testing Source: https://context7.com/rstudio/shinytest2/llms.txt Takes a PNG screenshot of the application and compares it against a saved baseline image. ```APIDOC ## expect_screenshot ### Description Takes a PNG screenshot of the application (or a specific element) and compares it against a saved baseline image. Supports threshold-based fuzzy matching. ### Parameters #### Query Parameters - **selector** (character) - Optional - CSS selector for the element to capture. - **delay** (numeric) - Optional - Delay in seconds before taking the screenshot. - **threshold** (numeric) - Optional - Threshold for fuzzy matching. - **kernel_size** (numeric) - Optional - Kernel size for fuzzy matching. - **name** (character) - Optional - Custom name for the screenshot. ``` -------------------------------- ### record_test - Interactive Test Recording Source: https://context7.com/rstudio/shinytest2/llms.txt Launches an interactive recorder that captures user actions and generates test code automatically. ```APIDOC ## record_test ### Description Starts the interactive recording session for a Shiny application. ### Parameters #### Request Body - **app** (string) - Optional - Path to the Shiny app. - **name** (string) - Optional - Name of the test. - **run_test** (boolean) - Optional - Whether to run the test after recording. ``` -------------------------------- ### Run package tests Source: https://github.com/rstudio/shinytest2/blob/main/CLAUDE.md Execute tests using devtools or testthat. ```r # Run all package tests devtools::test() # Run specific test file testthat::test_file("tests/testthat/test-app-driver.R") # Run tests with filter devtools::test(filter = "screenshot") ``` -------------------------------- ### Manage Browser Window Size Source: https://context7.com/rstudio/shinytest2/llms.txt Control browser dimensions for responsive design testing and wait for re-renders after resizing. ```r app <- AppDriver$new("path/to/app", height = 800, width = 1200) # Get current window size size <- app$get_window_size() # Returns: list(width = 1200, height = 800) # Set new window size and wait for re-render app$set_window_size(width = 375, height = 667) # Mobile size # Set size without waiting app$set_window_size(width = 1920, height = 1080, wait = FALSE) app$wait_for_idle() # Test responsive design app$set_window_size(width = 768, height = 1024) # Tablet app$expect_screenshot(name = "tablet_view") app$set_window_size(width = 1920, height = 1080) # Desktop app$expect_screenshot(name = "desktop_view") app$stop() ``` -------------------------------- ### Load Application Support Files Source: https://context7.com/rstudio/shinytest2/llms.txt Load Shiny application helper files into the testing environment using scoped or permanent loading functions. ```r library(shinytest2) library(testthat) # For package testing: temporary scoped loading test_that("Module function works correctly", { # Load app's R/ folder temporarily local_app_support(test_path("apps/myapp")) # Now app helper functions are available result <- my_helper_function(x = 10) expect_equal(result, 20) }) # Support files automatically unloaded after test # Explicit scope with with_app_support test_that("Another test", { with_app_support(test_path("apps/myapp"), { # Helper functions available here expect_true(validate_input("test")) }) # Helper functions no longer available here }) # For standalone apps: permanent loading in setup-shinytest2.R # File: tests/testthat/setup-shinytest2.R shinytest2::load_app_support(test_path("../..")) ``` -------------------------------- ### Testing Multiple Apps with test-app Action Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md To test multiple Shiny applications, provide a newline-separated list of directories to the 'app-dir' input. ```yaml - uses: rstudio/shinytest2/actions/test-app@actions/v1 with: app-dir: | dir/to/app1 dir/to/app2 ``` -------------------------------- ### Migrate from shinytest Source: https://context7.com/rstudio/shinytest2/llms.txt Automate the migration of test files from the legacy shinytest package to the shinytest2 format. ```r # Migrate app tests from shinytest to shinytest2 shinytest2::migrate_from_shinytest( app_dir = "path/to/app", clean = TRUE, # Remove old shinytest files include_expect_screenshot = FALSE # Don't include screenshot tests ) # Keep old files for comparison shinytest2::migrate_from_shinytest( app_dir = "path/to/app", clean = FALSE, quiet = TRUE ) ``` -------------------------------- ### GitHub Action Workflow Configuration Source: https://github.com/rstudio/shinytest2/blob/main/actions/test-app/README.md The YAML configuration for running tests on a Shiny application within a package structure. ```yaml # Workflow derived from https://github.com/rstudio/shinytest2/tree/main/actions/test-app/example-test-app-package.yaml # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: branches: [main, master] pull_request: branches: [main, master] name: Test package app jobs: test-package-app: runs-on: ${{ matrix.config.os }} name: ${{ matrix.config.os }} (${{ matrix.config.r }}) strategy: fail-fast: false matrix: config: - {os: ubuntu-latest, r: release} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes steps: - uses: actions/checkout@v2 - uses: r-lib/actions/setup-pandoc@v2 - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: local::. shinytest2 - uses: rstudio/shinytest2/actions/test-app@actions/v1 with: app-dir: "." ``` -------------------------------- ### Run Application Tests Source: https://context7.com/rstudio/shinytest2/llms.txt Execute testthat suites for Shiny applications. ```r # In tests/testthat.R: shinytest2::test_app() # Test app in a specific directory shinytest2::test_app("path/to/app") # Run specific test file only shinytest2::test_app(filter = "shinytest2") # With custom reporter shinytest2::test_app(reporter = testthat::ProgressReporter$new()) ``` -------------------------------- ### Create AppDriver Instance Source: https://context7.com/rstudio/shinytest2/llms.txt Instantiate an AppDriver to control a Shiny application. Can be created from a directory, a Shiny app object, or a function. Ensure to stop the app when done. ```R library(shinytest2) # Create an AppDriver from a Shiny app directory app <- AppDriver$new( app_dir = "path/to/app", name = "myapp", # Prefix for snapshot files variant = platform_variant(), # Platform-specific snapshots seed = 12345, # Random seed for reproducibility load_timeout = 15000, # Max time to wait for app load (ms) timeout = 4000, # Default timeout for operations (ms) height = 800, # Browser window height width = 1200, # Browser window width view = FALSE, # Open browser for debugging check_names = TRUE # Warn about duplicate input/output IDs ) # Create from a Shiny app object directly library(shiny) shiny_app <- shinyApp( ui = fluidPage( numericInput("n", "N", value = 10), textOutput("result") ), server = function(input, output) { output$result <- renderText({ input$n * 2 }) } ) app <- AppDriver$new(shiny_app) # Create from a function (useful for package testing) app <- AppDriver$new(function() { library(mypackage) mypackage::run_app() }) # Always stop the app when done app$stop() ``` -------------------------------- ### Execute JavaScript in Browser Source: https://context7.com/rstudio/shinytest2/llms.txt Interact with the browser context using get_js to return values or run_js for side-effect execution. ```r app <- AppDriver$new("path/to/app") # Get a value from JavaScript title <- app$get_js("document.title") # Returns: "My Shiny App" # Execute JavaScript and get result result <- app$get_js("1 + 1") # Returns: 2 # Wait for a Promise to resolve data <- app$get_js(" fetch('/api/data') .then(response => response.json()) ") # Run JavaScript without getting result app$run_js("console.log('Test started')") # Set up JavaScript state for testing app$run_js("window.testCounter = 0") app$click(input = "increment") count <- app$get_js("window.testCounter") # Execute JavaScript from a file app$run_js(file = "tests/testthat/helpers/setup.js") # With escaped arguments selector <- "#myElement" app$get_js(paste0( "document.querySelector(", jsonlite::toJSON(selector, auto_unbox = TRUE), ").textContent" )) app$stop() ``` -------------------------------- ### Run package tests Source: https://github.com/rstudio/shinytest2/blob/main/cran-comments.md Execute the test suite for the shinytest2 package using testthat. ```r library(testthat) library(shinytest2) test_check("shinytest2") ``` -------------------------------- ### Perform interactive testing Source: https://github.com/rstudio/shinytest2/blob/main/CLAUDE.md Initialize an AppDriver instance to inspect and manipulate a Shiny application during development. ```r # Create an AppDriver for interactive testing library(shinytest2) app <- AppDriver$new("path/to/app") app$view() # Opens browser for visual inspection app$get_values() app$set_inputs(input_name = value) app$stop() ``` -------------------------------- ### Verify Greeting Output Source: https://github.com/rstudio/shinytest2/blob/main/tests/testthat/apps/hello/tests/testthat/_snaps/mac-4.5/app.md This snippet shows the expected output of a basic Shiny application test. It verifies that the greeting message 'Hello Hadley!' is rendered correctly in the HTML. ```text "Hello Hadley!" ``` ```html "