rstudio / shinytest

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

Make shinytest work with other templates #369

Open DivadNojnarg opened 3 years ago

DivadNojnarg commented 3 years ago

I've been trying for a while to make {shinytest} work with other templates than classic {shiny} elements. I am missing something and can't figure out what. For instance, when you do:

remotes::install_github("RinteRface/bs4Dash")
library(shinytest)
app <- ShinyDriver$new(system.file(package = "bs4Dash", "examples/showcase"))
app$findElements("#sidebarToggle")[[1]]$getClass()

You get the "shiny-bound-input" class, telling the action button is bound ... After this you can do whatever you want with that button.

In {bs4Dash}, the left sidebar has a binding telling whether it is opened or closed. If we follow the same approach:

app$findElements("#sidebar")[[1]]$getClass()

We don't get any "shiny-bound-input" class, which it is not in line with the below screenshot where the input is clearly bound. This also prevents from doing anything else like app$setInputs(sidebar = FALSE), which yields Unable to find input binding for element with id ... raised by the flushItem function of shinytest.inputQueue.flush on the JS side.

Screenshot 2020-12-02 at 15 26 00

How to explain that the "shiny-bound-input" is not correctly added?

Additionally, I explored a bit {shinytest}, {webdriver} and according to the shiny-mapping.R file, there is a predefined list of mappings:

widget_names <- c(
    "shiny.actionButtonInput"  = "actionButton",
    "shiny.checkboxInput"      = "checkboxInput",
    "shiny.checkboxGroupInput" = "checkboxGroupInput",
    "shiny.dateInput"          = "dateInput",
    "shiny.dateRangeInput"     = "dateRangeInput",
    "shiny.fileInputBinding"   = "fileInput",
    "shiny.numberInput"        = "numericInput",
    "shiny.radioInput"         = "radioButtons",
    "shiny.selectInput"        = "selectInput",
    "shiny.sliderInput"        = "sliderInput",
    "shiny.textInput"          = "textInput",
    "shiny.passwordInput"      = "passwordInput",
    "shiny.bootstrapTabInput"  = "tabsetPanel",

    "shiny.textOutput"         = "textOutput",
    "shiny.verbatimTextOutput" = "verbatimTextOutput",
    "shiny.htmlOutput"         = "htmlOutput",
    "shiny.imageOutput"        = "plotOutput",
    "datatables"               = "tableOutput"
  )

which lists all (or almost all) vanilla shiny input bindings by their name. I imagine I'll also have to insert bs4Dash binding following the same convention (bs4Dash.bindingName), am I right?

Regarding my first issue (missing "shiny bound input" class), I am wondering what I am missing and appreciate any insights.

DivadNojnarg commented 3 years ago

I made a simple test with {webdriver}:

library(webdriver)
pjs <- run_phantomjs()
ses <- Session$new(port = pjs$port)
ses$go(<bs4Dash-app-url>)
ses$takeScreenshot()

Rplot

Actually it's just because the page does not load properly, but I don't really know why.

DivadNojnarg commented 3 years ago

I did further checks on AdminLTE 2 (shinydashboard): 11bd0d6f-b9ae-43b7-9363-3f697e1d6ba1

and AdminLTE3 (bs4Dash): 6ec27328-59b4-4d4d-99ba-524a5b80cf7d

It seems that Bootstrap 4 is not well handled (grid, ...) by phantomjs but this is not the only problem.