rstudio / shinytest2

https://rstudio.github.io/shinytest2/
Other
104 stars 16 forks source link

Any way to inspect the environment of the Shiny app that's running under AppDriver? #319

Open daattali opened 1 year ago

daattali commented 1 year ago

Suppose I have a shiny app that assigns to a global variable. (Bad practice, yes, but there are cases where that's desired 😃). Is there any way to look at the environment of the shiny app to see that the variable was created? In the example below, it'd be great to have something like driver$get_env()

Example:

app <- shinyApp(
  fluidPage(),
  function(input, output, session) {
    assign("foo", "bar", envir = globalenv())
  }
)

driver <- shinytest2::AppDriver$new(app)
driver$get_env()
schloerke commented 1 year ago

The shiny process is in a callr::r_bg(). Docs: https://callr.r-lib.org/reference/r_bg.html

I do not believe accessing the process directly is currently possible.

However, you can use exportTestValues(NAME = VALUE) within your app. This allows for the key NAME to be requested and returns the current value of VALUE for each request.

Ex:

Adding these lines within the geyser app's server function...

exportTestValues(
  time=Sys.time()
)

... and then making an AppDriver of it, the time can be requested.

driver <- AppDriver$new("01_hello")
driver$get_value(export = "time")
#> [1] "2023-01-24 13:19:11 EST"
Sys.sleep(2)
driver$get_value(export = "time")
#> [1] "2023-01-24 13:19:15 EST"

This approach will only expose the key/value pairs that you want and will only do this during testing runtime.

daattali commented 1 year ago

In general that approach would work, but it doesn't work if the app is already stopped.

For example (this is actually my real use case): a shiny app that has a "Done" button. When the done button is clicked, the app closes the browser and stops the app, and creates a variable in the globalenv. I don't have a way to test that this variable got created because driver$get_value() results in an error after the app is stopped.

I can get around this by mocking the function that kills my app, but that requires #301