rstudio / shinytest

Automated testing for shiny apps
https://rstudio.github.io/shinytest/
Other
225 stars 55 forks source link

textAreaInput updated inside module cannot be tested #402

Open maxheld83 opened 3 years ago

maxheld83 commented 3 years ago

I want to updateTextAreaInput() inside a module, and test the resulting the change.

A simple reprex without module overhead works as expected:

# reprex w/o modules
library(shiny)
ui <- fluidPage(
  textAreaInput(inputId = "longtext", label = "longtext"),
  actionButton(inputId = "update", label = "update")
)
server <- function(input, output, session) {
  observeEvent(
    input$update,
    shiny::updateTextAreaInput(
      session = session,
      inputId = "longtext",
      value = "foo"
    )
  )
}
# shinyApp(ui, server)  # interactive use works fine
library(shinytest)
app <- ShinyDriver$new(shinyApp(ui, server))
app$getValue("longtext")
app$click("update")
app$getValue("longtext")  # works

This works as expected both when using the app, as well as testing it via shinyDriver.

(Weirdly, though, while this works interactively, inside reprex::reprex() the changed longtext field is not reflected ... maybe that's the same problem as below?)


Now, the same thing but inside modules:

# reprex with module
library(shiny)
moduleUI <- function(id) {
  ns <- shiny::NS(id)
  tagList(
    textAreaInput(inputId = ns("longtext"), label = "longtext"),
    actionButton(inputId = ns("update"), label = "update")
  )
}
moduleServ <- function(id) {
  shiny::moduleServer(
    id,
    module = function(input, output, session) {
      updateTextAreaInput(
        session = session,
        inputId = "longtext",
        value = "baz"
      )
      observeEvent(
        input$update,
        updateTextAreaInput(
          session = session,
          inputId = "longtext",
          value = "foo"
        )
      )
    }
  )
}
toyApp <- shinyApp(
  fluidPage(moduleUI(id = "toy")),
  function(input, output, session) moduleServ(id = "toy")
)
# toyApp  # works
library(shinytest)
app <- shinytest::ShinyDriver$new(toyApp)
app$getValue("toy-longtext")  # is not baz!
app$click("toy-update")
app$getValue("toy-update")  # counter and retrieving value works
app$getValue("toy-longtext")  # does not work
app$setValue("toy-longtext", "zap")
app$getValue("toy-longtext")  # manually setting/getting value also works

This also works fine when just playing around with the app in the browser, but the change when the update is triggered is not reflected in the ShinyDriver object.

This problem seems to be at the intersection of:

  1. modules
  2. updateTextAreaInput()

If I take one away, the problem disappears.

observeEvent() also doesn't seem to be the necessary (see above).