rshinygolemshinytest

shinytest2 with golem how to


I can't seem to figure out how to use shinytest2 for my golem app. And I think it really looks like a nice tool to improve my productivity.

Update:

I did overlook one vignette. I think I make progress. I added shinytest2 to Suggests, and called shinytest2::use_shinytest2() as recommended. Then I run devtools::install(), and then:

shiny_app <- run_app()
shinytest2::record_test(shiny_app, name = "ShinyGolem")

Now the app seems to try to start. I think the app doesn't pass along the values in golem::get_golem_options(), although I'm not sure how to confirm this. At least I see, the app is not making the database connections (while it works when I just call run_app().

I set those options by passing arguments like so: run_app(my_parameter = Sys.getenv('MY_PARAMETER'). and then pass them along in the run_app() function:

with_golem_options(
    app = shinyApp(
      ui = app_ui,
      server = app_server,
      onStart = onStart,
      options = options,
      enableBookmarking = enableBookmarking,
      uiPattern = uiPattern
    ),
        golem_opts = list(
            db_server = db_server,
            db_name = db_name,
            uid = uid,
            pwd = pwd,
            ...
        )

How can I fix this?

Original Post

I am using the recommended folder structure etc., so all the files are in R/. After running devtools::load_all() I can call run_app() and the app just works (interactively). I can build it, install the package in a different session, and use, and it works. But I have no idea how to use the shinytest2::record_test() function.

I get: The App dir must contain either app.R or server.R. This is of course not the case for golem apps.

in this thread it was suggested to simply add an app.R file that simply calls run_app() at the top level directory. If I do that, I get:

Warning in warn_if_app_dir_is_package(appDir) :
  Loading R/ subdirectory for Shiny application, but this directory appears to contain an R package. Sourcing files in R/ may cause unexpected behavior. See `?loadSupport` for more details.
Error in with_golem_options(app = shinyApp(ui = app_ui, server = app_server,  : 
  could not find function "with_golem_options"

The suggestion in the help ?loadSupport to add a _disable_autoload.R file doesn't help either.

I'm not sure how to proceed. It feels like there is a "magic command" that I'm overlooking. Any ideas?


Solution

  • Alright, I finally figured it out. The last hint was in this post. But I somehow needed to do it a bit differently than described there. Perhaps my solution may help others.

    run_app.R:

    run_app <- function(
      onStart = NULL,
      options = list(),
      enableBookmarking = NULL,
      uiPattern = "/",
      my_par = "my_test_value",
      ...
    ) {
      with_golem_options(
        app = shinyApp(
          ui = app_ui,
          server = app_server,
          onStart = onStart,
          options = options,
          enableBookmarking = enableBookmarking,
          uiPattern = uiPattern
        ),
        golem_opts = list(
          my_par = my_par,
          ...
          )
      )
    }
    

    app_ui.R:

    app_ui <- function(request) {
      tagList(
        # Leave this function for adding external resources
        golem_add_external_resources(),
        # Your application UI logic
        rintrojs::introjsUI(),
        fluidRow(textOutput("sel")),
        navbarPage(
          "Test",
          id = "navbar",
          mod_slow_load_ui('slow_load_1'),
          mod_slow_load_ui('slow_load_2')
        )
      )
    }
    

    app_server.R:

    app_server <- function(input, output, session) {
      # Your application server logic
      r_global <- reactiveValues(tab_id = NULL)
      observe({r_global$tab_id <- input$navbar})
      mod_slow_load_server('slow_load_1', r_global)
      mod_slow_load_server('slow_load_2', r_global)
    }
    

    mod_slow_load.R:

    my_slow_loading <- function(my_par) {
      Sys.sleep(1)
      data.frame(a = rep_len(my_par, 3))
    }
    
    mod_slow_load_ui <- function(id) {
      ns <- NS(id)
      tabPanel(
        id,
        verbatimTextOutput(ns('my_txt'))
      )
    }
    
    mod_slow_load_server <- function(id, r_global){
      moduleServer(id, function(input, output, session){
        ns <- session$ns
        r_local <- reactiveValues(df = NULL)
    
        observe({
          if (r_global$tab_id == id) {
            r_local$df <- my_slow_loading(golem::get_golem_options("my_par"))
          } else {
            r_local$df <- NULL
          }
        })
    
        output$my_txt <- renderPrint(r_local$df)
      })
    }
    

    To make the golem options available, I use the same as I need for testServer(). In tests > testthat I have setup.R:

    golem_options = list(
      my_par = "my_test_value"
    )
    
    shinyOptions("golem_options" = golem_options)
    

    and, finally, under tests > testthat > fixtures I have app.R:

    MyPackageName::run_app()
    

    I also add shinytest2 to Suggests and devtools::install() as recommended.

    Now I can use shinytest2, if I specify the location:

    shinytest2::record_test(
      testthat::test_path("fixtures"), 
      name = "MyName"
      )
    

    Note that I specify the folder path where app.R is located. It took me forever to realize that I should not specify the location of app.R (and it didn't work when I did that).

    tests can be done by instantiating an app object as follows:

    app <- AppDriver$new(testthat::test_path("fixtures"), name = "MyName")
    

    One final remark is that I can't get the tests to work interactively. Not a big problem, since I have to wrap everything in a test_that() call anyway. I can not run the test by running the test_that() call interactively, it only works when using test() & related functions.