Search code examples
rshinyautomated-testsshinytest

How to avoid shinytest ambiguities with navbarMenu entries having identical names?


This is my very simple Shiny app.R. As you see, there are sub-menu entries having the same names under the two top menu entries:

library(shiny)
ui <- basicPage(
  navbarPage("App", id = "nav",
    navbarMenu("Top 1", # id = "top1",
      tabPanel("Sub 1", "Top 1, Sub 1"),
      tabPanel("Sub 2", "Top 1, Sub 2")
    ),
    navbarMenu("Top 2", # id = "top2",
      tabPanel("Sub 1", "Top 2, Sub 1"),
      tabPanel("Sub 2", "Top 2, Sub 2")
    )
  )
)
server <- function(input, output, session) {}
shinyApp(ui = ui, server = server)

I can run this app and access all submenu entries just fine using shiny::shinyAppDir(".").

However, when recording tests going through all tabs using shinytest::recordTest("."), the recorded script looks something like this:

app <- ShinyDriver$new("../../")
app$snapshotInit("mytest")

app$setInputs(nav = "Sub 2")
app$setInputs(nav = "Sub 1")
app$setInputs(nav = "Sub 2")
app$snapshot()

You see the problem immediately: from the calls, it is unclear which of the top-menu entries I chose (for the record, I chose Top 1, Top 2, Top 2).

How can I deal with this without renaming the sub-menu entries? I tried adding an id to the navbarMenus as you can see above, but that resulted only in

Tabs should all be unnamed arguments, but some are named: id


Solution

  • After some digging, I found this:

    value The value that should be sent when tabsetPanel reports that this tab is selected. If omitted and tabsetPanel has an id, then the title will be used.

    https://shiny.rstudio.com/reference/shiny/0.14/tabPanel.html

    So one solution is:

    library(shiny)
    ui <- basicPage(
      navbarPage("App", id = "nav",
        navbarMenu("Top 1",
          tabPanel("Sub 1", "Top 1, Sub 1", value = "top1/sub1"),
          tabPanel("Sub 2", "Top 1, Sub 2", value = "top1/sub2")
        ),
        navbarMenu("Top 2",
          tabPanel("Sub 1", "Top 2, Sub 1", value = "top2/sub1"),
          tabPanel("Sub 2", "Top 2, Sub 2", value = "top2/sub2")
        )
      )
    )
    server <- function(input, output, session) {}
    shinyApp(ui = ui, server = server)
    

    which gives

    app <- ShinyDriver$new("../../")
    app$snapshotInit("mytest")
    
    app$setInputs(nav = "top1/sub2")
    app$setInputs(nav = "top2/sub1")
    app$setInputs(nav = "top2/sub2")
    app$snapshot()