-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add $click()
method to MockSession
#2745
Comments
I think that If so, then this is might be related: can we trigger clicks from Setting input$my_button doesn't trigger eventReactivelibrary(shiny)
example_module_server <- function(id) {
moduleServer(
id,
function(input, output, session) {
eventReactive(input$my_button, {
print("Button was pressed")
})
}
)
}
testServer(example_module_server, {
# my_button should already be NULL, but for good measure:
session$setInputs(my_button = NULL)
# This should be what happens when the button is pressed, right?
session$setInputs(my_button = 0)
}) I expected some print output. For example, if this were just a reactive: library(shiny)
example_module_server <- function(id) {
moduleServer(
id,
function(input, output, session) {
myfun <- reactive({
print("Function was called")
})
}
)
}
testServer(example_module_server, {
myfun()
}) [1] "Function was called" Edit: @alandipert I would love to try to help with this, if possible, but I don't think I understand this enough yet to get started. You mentioned that you can't click an action button without knowing that buttons start at NULL and then transition to 0, but in the example above, it seems like setting a button from NULL to 0 does not trigger an eventReactive. Do you know why that is? Edit2: This is just because I was using an eventReactive, and nothing updated. Sorry for the confusion, I should've used observeEvent. |
Is there any solution to this? How do I simulate a click? |
Using the example from @julianstanley, this is how I would recommend testing a button "click" programmatically. For the first click, set the input to 0 (or any number, really). For clicks thereafter, set the input to library(shiny)
example_module_server <- function(id) {
moduleServer(
id,
function(input, output, session) {
my_reactive <- reactive(paste("Button was pressed:", input$my_button))
observe(message(my_reactive()))
}
)
}
testServer(example_module_server, {
# First programmatic 'click'
session$setInputs(my_button = 0)
stopifnot(my_reactive() == "Button was pressed: 0")
# Second programmatic 'click'
session$setInputs(my_button = input$my_button + 1)
stopifnot(my_reactive() == "Button was pressed: 1")
})
#> Button was pressed: 0
#> Button was pressed: 1 |
Since #3764 was closed as "not planned", does it mean this will also not be implemented? I'm fully aware of the workaround, but it still seems like a very incovenient way of doing a simple action. |
Hi @gadenbuie , Thank you for your assistance. I'm still not able to sort my issue out. I don't understand why the code below fails with the error: #' kwanza UI Function
#'
#' @description A shiny Module that contains code for the first tab.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_kwanza_ui <- function(id){
ns <- NS(id)
shiny::tagList(
shiny::fluidPage(
shiny::textInput(ns("firstname"), "First name", value = NULL),
shiny::br(),
shiny::textInput(ns("secondname"), "Second name", value = NULL),
shiny::br(),
shiny::numericInput(ns("yob"), "Year of birth", value = NULL),
shiny::br(),
shiny::actionButton(ns("go_button"), "Go"),
shiny::br(),
shiny::br(),
shiny::textOutput(ns("displayed_text")),
shiny::br(),
shiny::br(),
shiny::actionButton(ns("kwanza_next"), "Next"),
)
)
}
#' kwanza Server Functions
#'
#' @noRd
mod_kwanza_server <- function(id){
moduleServer( id, function(input, output, session){
ns <- session$ns
shiny::observeEvent(input$go_button, {
## activating this observeEvent makes the test fail with the error
##`Error in displayed_text_r() : could not find function "displayed_text_r"`
displayed_text_r <- shiny::reactive({
paste0("Hi ", input$firstname , " ", input$secondname ," ! " ,
"You are ", ceiling(lubridate::year(Sys.Date())- input$yob), " years old.")
})
output$displayed_text <- shiny::renderText({
displayed_text_r()
})
})
})
}
## Comment these lines if you want to view the app.
# # Shiny App
# ui <- fluidPage(
# mod_kwanza_ui("kwanza_1")
# )
#
# server <- function(input, output, session) {
# mod_kwanza_server("kwanza_1")
# }
#
# # Run the Shiny App
# shinyApp(ui, server)
# test function
testServer(
mod_kwanza_server,
# Add here your module params
args = list()
, {
ns <- session$ns
session$setInputs(firstname = "Shel")
session$setInputs(secondname = "Kariuki")
session$setInputs(yob = 2000)
session$setInputs(go_button = 0) ## Is this right?
print(displayed_text_r()) #for my own sanity
testthat::expect_true(grepl( "Shel", displayed_text_r()))
})
|
I think that's a reasonable conclusion. First: I recognize the friction identified and experienced around testing action buttons. I think we should do something to alleviate that friction and I propose we update the documentation of I understand the draw of wanting to solve this with a dead-simple helper method like Furthermore, Summarizing from my previous comment in #3746, I think its reasonable for users of |
Hi @Shelmith-Kariuki, thanks for sharing your app code. I think the problem with your module is that you define the Here's a smaller version that uses library(shiny)
example_module_server <- function(id) {
moduleServer(
id,
function(input, output, session) {
name <- reactive({
paste(input$first, input$last)
}) |>
bindEvent(input$button)
}
)
}
testServer(example_module_server, {
session$setInputs(first = "John", last = "Doe")
# click on the button (important because otherwise calling name() errors)
session$setInputs(button = 1)
stopifnot(name() == "John Doe")
session$setInputs(first = "Jane")
# The name() reactive should not have changed yet
stopifnot(name() == "John Doe")
session$setInputs(button = 2)
stopifnot(name() == "Jane Doe")
}) |
Hi @gadenbuie Thank you so much. That works. cc @arthur-shaw |
MockSession
exposes asetInputs()
method that can be used to programmatically set inputs, but we don't offer an easy way to click an action button programmatically without an understanding of the way button inputs transition from NULL to 0 first click and increase monotonically thereafter.I propose a new
$click()
method on MockSession that accepts a character vector of actionButton input names and "clicks" them, internally handling value transitions.The text was updated successfully, but these errors were encountered: