I have a shiny app, where I test the server component using testthat
and testServer
. The server part of the app has a couple of reactive values but also renders some elements in an observe()
element (I group multiple renders together for performance reasons).
A simple server + testServer example function looks like this
library(shiny)
library(dplyr)
library(testthat)
server <- function(input, output, session) {
data <- reactive(mtcars)
observe({
print("Observe is active")
# do some further analysis on the data here
data2 <- data() |> filter(mpg > 20)
output$nrows <- renderUI(nrow(data2)) # 14
output$unique_mpgs <- renderUI(length(unique(data2$mpg))) # 10
})
}
testServer(server, {
expect_equal(data(), mtcars) # works because data() is a reactive() not observe()...
# how can I test here that nrows == 14 and unique_mpgs == 10
})
As mentioned earlier, I don't want to have multiple reactive values (eg one for nrows, then another for unique_mpgs) if possible.
Is there a way to check the value of an observe element in testServer?
Running session$flushReact()
seems to trigger the observe
part (the print part was helpful in identifying this). This forces manual refresh of all reactives. After that output$nrows
and output$unique_mpgs
become available.
testServer(server, {
expect_equal(data(), mtcars) # works because data() is a reactive() not observe()...
# manually force a flush of reactives
session$flushReact()
# check output is available
expect_error(output$nrows, NA)
expect_error(output$unique_mpgs, NA)
# or just
output$nrows
output$unique_mpgs
# since these are rendered as UI, so the output is HTML
expect_equal(
as.character(output$nrows$html),
'14'
)
expect_equal(
as.character(output$unique_mpgs$html),
'10'
)
})