Cannot test export values if any of them fail a `req()`
This is possibly a {shiny} issue rather than a {shinytest2} issue. If it is, feel free to transfer it to that repo.
I discovered this when trying to test a shiny module that returns several reactives, and some of them may not pass a req() test. Here is a simpler example:
library(shiny)
app <- shinyApp(
fluidPage(actionButton("go", "go")),
function(input, output, session) {
num <- reactive({
req(input$go)
input$go
})
exportTestValues(
num = num()
)
}
)
driver <- shinytest2::AppDriver$new(app)
driver$get_values(export = TRUE)
Results in an error:
Error in `app_httr_get()`:
! Unable request data from server
I understand why this happens, because req() is technically an error. But it's meant to be a silent error that we can work with, so I think some special value should be used instead of failing.
Moving to Shiny. A status code of 500 is being thrown.
{shinytest2} query failed (500)----------------------
URL: http://127.0.0.1:7285/session/97ae9f276f6b95ffe6641e6205e9b9b8/dataobj/shinytest?w=&nonce=1eba28671&&&export=1&format=rds&sortC=1
<html>
<head lang = "en">
<title>An error has occurred</title>
</head>
<body>
<h1>An error has occurred!</h1>
<p></p>
</body>
</html>
I have dealt with this before and a simple workaround is decorating the exported values as shown below. When decorated the error is caught and returned safely by the get_values function.
This could be easily extended to decorate all the values inside export so all of them would be exported safely.
Let me know if this solution is interesting and I can see if I can submit a PR.
library(shiny)
app <- shinyApp(
fluidPage(actionButton("go", "go")),
function(input, output, session) {
num <- reactive({
req(input$go)
input$go
})
# Declared inside because otherwise driver does not see this function
safely_export <- function(r) {
r_quo <- rlang::enquo(r)
rlang::inject({
shiny::reactive({
tryCatch(
!!r_quo,
error = function(e) {
e
}
)
})
})
}
exportTestValues(
num = safely_export(num())
)
}
)
driver <- shinytest2::AppDriver$new(app)
x <- shiny::isolate(driver$get_values(export = TRUE)$export$num())
str(x)
# List of 1
# $ message: chr ""
# - attr(*, "class")= chr [1:4] "shiny.silent.error" "validation" "error" "condition"
Hi, I'm dealing with a similar issue. Basically, when you export multiple reactives, it's pretty problematic that a single req(F) stops the whole export. One value could be expected to fail given e.g. inappropriate combination of inputs, and currently you are unable to check if other values take expected values. So a solution like one proposed by @zsigmas would be appreciated. Since exportTestValues() is a Shiny function that's explicitly meant to be used with testthat/shinytest/shinytest2 (if I'm not mistaken), such functionality would be appropriate, perhaps as an optional parameter.