rstudio / shinytest

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

Not rendered Plotly generates invalid char in 001.json when running mytest.R #417

Open FedericoTrifoglio opened 2 years ago

FedericoTrifoglio commented 2 years ago

To reproduce the error use this app

library(plotly)
shinyApp(
  ui = fluidPage(
    selectInput(inputId = "country",
                label = "Select country",
                choices = c("", "UK", "US", "China")),
    plotlyOutput("my_plot")
    ),
  server = function(input, output, session) {
      output$my_plot <- renderPlotly({
        req(input$country)
        data <- data.frame("Year" = 2016:2026,
                           "Value" = rnorm(11, 1000, 200))
        data %>%
          plot_ly(x = ~Year) %>%
          add_lines(y = ~Value)
      })
    }
)

Then record a test. Take a snapshot without interacting with the dropdown box. my_plot shouldn't be rendered. After closing, you should get this

Saved test code to your/path/tests/shinytest/mytest.R
Running mytest.R Query failed (500)----------------------
<html>

<head lang = "en">
  <title>An error has occurred</title>
</head>

<body>

<h1>An error has occurred!</h1>
<p>lexical error: invalid char in json text.
                                       NULL c("shiny.silent.error", "v
                     (right here) ------^
</p>

</body>
</html>

----------------------------------------
Error in httr_get(url) : Unable request data from server

The following two apps work fine.

library(plotly)
shinyApp(
  ui = fluidPage(
    selectInput(inputId = "country",
                label = "Select country",
                choices = c("","UK", "US", "China")),
    plotlyOutput("my_plot")
    ),
  server = function(input, output, session) {
    if (!session$options$testmode) {
      output$my_plot <- renderPlotly({
        req(input$country)
        data <- data.frame("Year" = 2016:2026,
                           "Value" = rnorm(11, 1000, 200))
        data %>%
          plot_ly(x = ~Year) %>%
          add_lines(y = ~Value)
      })
    }
    }
)

Not entirely sure why the above works, but I suppose it's like output$my_plot doesn't even exist when the app is loaded up.

library(ggplot2)
shinyApp(
  ui = fluidPage(
    selectInput(inputId = "country",
                label = "Select country",
                choices = c("","UK", "US", "China")),
    plotOutput("my_plot")
  ),
  server = function(input, output, session) {
    output$my_plot <- renderPlot({
      req(input$country)
      data <- data.frame("Year" = 2016:2026,
                         "Value" = rnorm(11, 1000, 200))
      data %>%
        ggplot(aes(x = Year, y = Value)) +
        geom_line()
    })
  }
)

This is is just to prove that the issue is isolated to Plotly.

FedericoTrifoglio commented 2 years ago

I've changed the title as I believe it describes the error better or at least my understanding of it.

harrismcgehee commented 2 years ago

We temporarily "circumvented" the issue by removing the req() from the renderPlotly. Instead, we added the req() condition to a shinyjs::toggle

library(plotly)
shinyApp(
  ui = fluidPage(
    shinyjs::useShinyjs(), ## added
    selectInput(inputId = "country",
                label = "Select country",
                choices = c("", "UK", "US", "China")),
    div(id = "plotly",  ## added
                plotlyOutput("my_plot")
    ) ## added
  ),
  server = function(input, output, session) {
    output$my_plot <- renderPlotly({
      # req(input$country) ## removed
      data <- data.frame("Year" = 2016:2026,
                         "Value" = rnorm(11, 1000, 200))
      data %>%
        plot_ly(x = ~Year) %>%
        add_lines(y = ~Value)
    })

    observe({
      shinyjs::toggle(id = "plotly", condition = (input$country != ""))
    })
  }
)