tests/testthat/test-shinytest2-modules.R

testthat::skip_if_not_installed("shinytest2")
testthat::skip_if_not_installed("rvest")

testthat::test_that("e2e: the module server logic is only triggered when the teal module becomes active", {
  skip_if_too_deep(5)
  value_export_module <- function(label = "custom module", value) {
    module(
      label = label,
      server = function(id, data) {
        moduleServer(id, function(input, output, session) {
          shiny::exportTestValues(value = value)
        })
      },
      ui = function(id) {
        ns <- NS(id)
        h1("Module that exports a random value for testing")
      }
    )
  }

  app <- TealAppDriver$new(
    init(
      data = simple_teal_data(),
      modules = modules(
        value_export_module(label = "Module 1", value = 98),
        value_export_module(label = "Module 2", value = 99)
      )
    )
  )

  expected_values <- list(
    `teal-teal_modules-nav-module_1-value` = 98,
    `teal-teal_modules-nav-module_2-value` = 99
  )

  testthat::expect_identical(expected_values %in% app$get_values()$export, c(TRUE, FALSE))
  app$navigate_teal_tab("Module 2")
  testthat::expect_identical(expected_values %in% app$get_values()$export, c(TRUE, TRUE))
  app$stop()
})


testthat::test_that("e2e: filter panel only shows the data supplied using datanames", {
  skip_if_too_deep(5)
  app <- TealAppDriver$new(
    init(
      data = simple_teal_data(),
      modules = modules(
        example_module(label = "mtcars", datanames = "mtcars")
      )
    )
  )

  testthat::expect_identical(
    app$get_active_filter_vars(),
    "mtcars"
  )
  app$stop()
})

testthat::test_that("e2e: filter panel shows all the datasets when datanames is all", {
  skip_if_too_deep(5)
  app <- TealAppDriver$new(
    init(
      data = simple_teal_data(),
      modules = modules(
        example_module(label = "all", datanames = "all")
      )
    )
  )

  testthat::expect_identical(app$get_active_filter_vars(), c("iris", "mtcars"))
  app$stop()
})


testthat::test_that("e2e: nested modules layout in navigation respect order and keeps group names", {
  skip_if_too_deep(5)
  app <- TealAppDriver$new(
    init(
      data = simple_teal_data(),
      modules = modules(
        example_module(label = "Example Module"),
        modules(
          label = "Nested Modules",
          example_module(label = "Nested 1.1"),
          example_module(label = "Nested 1.2"),
          modules(
            label = "Sub Nested Modules",
            example_module(label = "Nested 2.1"),
            example_module(label = "Nested 2.2")
          )
        )
      )
    )
  )
  app_modules <- app$get_text(
    selector = sprintf("ul.teal-modules-tree li %s", c("a", "span.module-group-label"))
  )
  testthat::expect_identical(
    app_modules,
    c(
      "Example Module", # Depth: 1
      "Nested Modules", # Depth: 1
      "Nested 1.1", # Depth: 2
      "Nested 1.2", # Depth: 2
      "Sub Nested Modules", # Depth: 2
      "Nested 2.1", # Depth: 3
      "Nested 2.2" # Depth: 3
    )
  )
  app$stop()
})

testthat::test_that("e2e: active tab is reflected in URL query string after navigation", {
  skip_if_too_deep(5)
  app <- TealAppDriver$new(
    init(
      data = simple_teal_data(),
      modules = modules(
        example_module(label = "mod1"),
        example_module(label = "mod2")
      )
    ),
    teal_options = list(teal.enable_deep_linking = TRUE)
  )
  on.exit(app$stop())

  app$navigate_teal_tab("mod2")

  testthat::expect_match(app$get_js("window.location.href"), "active_module=mod2")
})

testthat::test_that("e2e: URL query string active_module switches to the specified tab", {
  skip_if_too_deep(5)
  app <- TealAppDriver$new(
    init(
      data = simple_teal_data(),
      modules = modules(
        example_module(label = "mod1"),
        example_module(label = "mod2")
      )
    ),
    teal_options = list(teal.enable_deep_linking = TRUE)
  )
  on.exit(app$stop())

  # Change URL without page reload and fire popstate so Shiny re-reads url_search.
  app$run_js("
    window.history.pushState({}, '', '?active_module=mod2');
    window.dispatchEvent(new PopStateEvent('popstate'));
  ")
  app$wait_for_idle()

  testthat::expect_equal(
    app$get_value(input = "teal-teal_modules-active_module_id"),
    "mod2"
  )
})

Try the teal package in your browser

Any scripts or data that you put into this service are public.

teal documentation built on June 30, 2026, 5:11 p.m.