I am using R Shiny's shinytest2 package to automate testing my app. The app and tests work. However, the tests keep failing shinytest2's comparisons because of renderUI()
's auto-generated ids, e.g. out63cdc91c431ff1ea. I thought setting the driver's seed
would suffice, as it worked when I used shinytest
, but it doesn't.
Here's a pared-down version of my test script:
library(shinytest2)
test_that("{shinytest2} recording: test-good", {
print("Running test-good")
app <- AppDriver$new(
variant = platform_variant(),
name = "test-good",
seed = 1234,
load_timeout = 1e+05)
app$set_inputs(sidebarmenuid = "tabClientCount")
app$wait_for_idle(500) #wait until whole application is idle for 500ms
app$expect_values()
})
And here's some of the console failure:
Failure (test-good.R:20:1): {shinytest2} recording: test-good
Snapshot of `file` to 'good/test-good-001.json' has changed
So in good/test-good-001.json the ID is out63cdc91c431ff1ea and in good/test-good-001.new.json the ID is outcdc91c431ff1ea2a. And if I run it again, the IDs change again. I thought the random seed would work, but it's not. How can I stop these renderUI-auto-generated IDs from flagging failures, e.g. via an option to ignore these sorts of IDs, or via setting the ids myself. Also, I have many tests, so the solution needs to be scalable.
In case the renderUI code is helpful:
headerGeneric <- function(tabTitle, extraHTML = NULL) {
renderUI({
if(valid_file() == 1) {
list(h2(tabTitle),
h4(strong("Date Range of Current File: "),
paste(
format(Project0$start_date, "%m-%d-%Y"),
"to",
format(Project0$end_date, "%m-%d-%Y")
)),
extraHTML
)
} else {
h4("This is blank until your data has been validated.")
}
})
}
output$headerClientCounts <- headerGeneric("Client Counts Report",
renderUI({
organization <- Project0 %>%
filter(ProjectName == input$currentProviderList) %>%
pull(OrganizationName)
h4(organization, "|", input$currentProviderList)
})
)
UPDATE: The source of the problem was the nested-nature of the renderUI()
code. This must be because each renderUI()
call is essentially creating a new reactive context, and so it generates a new ID. shinytest2
's seed must only apply to the outer-most renderUI()
. But I'm not sure how best to avoid this. I created the headerGeneric()
function, because we reuse the main part of it over and over on each tab of our app. Is there a way to pass in a hard-coded ID to renderUI()
?
The source of the problem was the nested-nature of the renderUI code. It looks like I should be attaching all
renderUI()
s tooutput
s (whose names become the IDs), but, if I don't, Shiny is "smart" enough to generate a random ID for me. I do think this was not a problem with shinytest, but once I associated the innerrenderUI()
with an output, that fixed the problem.