rshinytestthat

test output or observe elements in shiny using testthat


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?


Solution

  • 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'
    )
    })