Driver
Driver.RdA layer extending shinytest2::AppDriver. Instead of relying on fragile Shiny IDs, this driver
uses semantic test identifiers that can change independently from application logic.
Details
The Driver class provides a reliable testing framework by:
Using
testidattributes for component identification instead of Shiny IDsAutomatically detecting component types via
testtypeattributesDispatching appropriate actions based on component type (
testtype)Providing error checking and user-observable state validation
Components should be wrapped with testable_component() to add the necessary
data attributes for this driver to work properly.
# Wrap a component used in the app in a function.
# Use testable_component() to attach test attrubutes.
dropdown <- function(id, label = NULL, choices, ..., testid) {
shinyWidgets::pickerInput(
inputId = id,
label = label,
choices = choices,
...
) |>
testable_component(
id = id,
testid = testid,
testtype = "dropdown"
)
}
app <- shiny::shinyApp(
ui = bslib::page_fluid(
# Attach a unique testid for each visible component
dropdown(
id = "test-picker",
label = "Letter",
choices = c("A", "B"),
testid = "Letter"
)
),
server = function(input, output) {}
)
d <- Driver$new(app)
# Dispatch an action to "Letter" component. It sets the value to "B".
# Custom action wasn't registered for `testtype = "dropdown"`,
# `shinytest2::AppDriver$set_inputs` will be used to set the value.
d$dispatch("Letter", value = "B")
# Get the value of "Letter" component.
d$get_value(testid = "Letter") # Will return "B"See also
testable_component() for preparing components for testing
shinytest2::AppDriver for the underlying driver functionality
Methods
Inherited methods
shinytest2::AppDriver$click()shinytest2::AppDriver$expect_download()shinytest2::AppDriver$expect_html()shinytest2::AppDriver$expect_js()shinytest2::AppDriver$expect_screenshot()shinytest2::AppDriver$expect_text()shinytest2::AppDriver$expect_unique_names()shinytest2::AppDriver$expect_values()shinytest2::AppDriver$get_chromote_session()shinytest2::AppDriver$get_dir()shinytest2::AppDriver$get_download()shinytest2::AppDriver$get_html()shinytest2::AppDriver$get_js()shinytest2::AppDriver$get_logs()shinytest2::AppDriver$get_screenshot()shinytest2::AppDriver$get_url()shinytest2::AppDriver$get_values()shinytest2::AppDriver$get_variant()shinytest2::AppDriver$get_window_size()shinytest2::AppDriver$initialize()shinytest2::AppDriver$log_message()shinytest2::AppDriver$run_js()shinytest2::AppDriver$set_inputs()shinytest2::AppDriver$set_window_size()shinytest2::AppDriver$stop()shinytest2::AppDriver$upload_file()shinytest2::AppDriver$view()shinytest2::AppDriver$wait_for_idle()shinytest2::AppDriver$wait_for_js()shinytest2::AppDriver$wait_for_value()
Method dispatch()
Dispatch an action to a component based on its type
This method automatically detects the component type using the testtype
attribute and dispatches the appropriate action. The action system uses S3
method dispatch to handle different component types appropriately.
You can register your own custom actions by extending the action class:
action.dropdown <- function(x, ...) {
# Open the dropdown
# Click on a choice
}If custom action isn't registered, it falls back to shinytest2::AppDriver$set_inputs.
Arguments
testidA character string identifying the component via its
testidattribute...Additional arguments passed to the component-specific action method. Common arguments include
valuefor setting input values.Arguments passed to custom
actionimplementation.
Details
The dispatch system works as follows:
Waits for the app to be idle
Validates that the target component is findable and visible
Extracts the Shiny ID and component type from data attributes
Creates an object with the specified class (component type)
Calls the appropriate
action.*method for that component type
Method get_value()
Get the current value of an input component
Retrieves the current value of a Shiny input either by testid or by direct input/output/export name.
Usage
Driver$get_value(
testid = missing_arg(),
input = missing_arg(),
output = missing_arg(),
export = missing_arg()
)Arguments
testidA character string identifying the component via its
testidattribute. If provided, other parameters are ignored.inputA character string specifying the input name directly. For compatibility with shinytest2.
outputA character string specifying the output name directly. For compatibility with shinytest2.
exportA character string specifying the export name directly. For compatibility with shinytest2.
Details
When testid is provided:
Waits for the app to be idle
Validates that the target component exists and is findable
Extracts the Shiny ID from the
testshinyidattributeReturns the value using the resolved ID
When direct names are provided, behaves like the standard shinytest2::AppDriver$get_value().
Returns
The current value of the specified input, output, or export. Return type depends on the component type (e.g., character, numeric, list).
Examples
\dontrun{
# Get value using testid (recommended)
current_text <- driver$get_value(testid = "Username")
# Get value using direct input name (not recommended)
current_text <- driver$get_value(input = "module-nested_module-username")
# Get value using testid (recommended)
plot_data <- driver$get_value(testid = "Scatterplot")
# Get output value (not recommended)
plot_data <- driver$get_value(output = "module-nested_module-main_plot")
}
Method get_text()
Get the text content of a component
Extracts the visible text content from a component, either by testid or by CSS selector. This is useful for reading labels, button text, output text, or any other textual content displayed in the app.
Arguments
testidA character string identifying the component via its
testidattribute. If provided, selector parameter is ignored.selectorA CSS selector string for directly targeting elements (alternative to testid)
Details
When testid is provided, the method:
Validates that the target component exists and is findable
Constructs a CSS selector using the testid
Extracts the text content from the matching element
When selector is provided directly, it's passed through to the underlying
shinytest2::AppDriver$get_text() method.
Method get()
Execute custom JavaScript code on a component
Runs arbitrary JavaScript code in the context of a specific component identified by testid. This provides a flexible way to interact with components or extract information that isn't available through other driver methods.
Arguments
testidA character string identifying the component via its
testidattributecodeA character string containing JavaScript code to execute. The code receives the jQuery element(s) matching the testid as its parameter.
Details
The method:
Waits for the app to be idle
Constructs a JavaScript call targeting the component with the specified testid
Executes the provided code with the component element(s) as context
Returns the result
The JavaScript code parameter receives a jQuery object containing the matching elements.
Returns
The result of the JavaScript code execution. Type depends on what the JavaScript code returns (could be character, numeric, logical, list, etc.).
Examples
\dontrun{
# Get a custom attribute value
custom_attr <- driver$get("Name", "(el) => el.attr('custom')")
# Check if element has a specific CSS class
has_class <- driver$get("Next step", "(el) => el.hasClass('active')")
# Count child elements
child_count <- driver$get("Results list", "(el) => el.children().length")
}
Method is_visible()
Check if a component is visible
Determines whether a component is currently visible in the DOM. This checks
CSS visibility, display properties, and jQuery's :visible pseudo-selector.
Hidden, collapsed, or display:none elements will return FALSE.
Details
The method:
Waits for the app to be idle
Executes JavaScript to check the jQuery
:visibleselector statusReturns the boolean result
This is particularly useful for:
Conditional UI elements that show/hide based on user input
Verifying that certain elements appear after actions
Testing responsive design behavior
Checking modal or popup visibility
Examples
\dontrun{
# Check if an error message is visible
if (driver$is_visible("Error message")) {
error_text <- driver$get_text(testid = "Error message")
}
# Verify a modal dialog appeared
expect_true(driver$is_visible("Confirm"))
# Check if conditional UI element is shown
driver$dispatch("Show advanced options", value = TRUE)
expect_true(driver$is_visible("Advanced options"))
}
Method is_disabled()
Check if a component is disabled
Determines whether a component is currently disabled. This checks the disabled
attribute and property of HTML elements, which prevents user interaction.
Details
The method:
Waits for the app to be idle
Executes JavaScript to check the jQuery
:disabledselector statusReturns the boolean result
This is useful for:
Verifying that form controls are properly disabled/enabled based on conditions
Testing input validation states
Checking button states during processing
Ensuring UI elements respond correctly to application state changes
Method expect_output_errors()
Verify the expected number of Shiny output errors
Checks for visible Shiny error messages on the page and fails the test if the actual number doesn't match the expected count. This is crucial for testing error handling and ensuring your app displays appropriate error messages.
Arguments
nAn integer specifying the expected number of visible Shiny output errors. Defaults to 0 (no errors expected).
Details
The method:
Counts visible Shiny output errors (elements with class
.shiny-output-error)Excludes validation errors (
.shiny-output-error-validation)Compares the count to the expected number
If counts match, the test succeeds silently
If counts don't match, provides detailed failure information including the IDs of outputs that produced errors
This is typically used to verify that:
No unexpected errors occur during normal operation (
n = 0)Expected errors appear when testing error conditions (
n > 0)Error recovery works properly (errors disappear after fixes)
Examples
\dontrun{
# Verify no errors during normal operation
driver$expect_output_errors() # expects 0 errors
# Test that invalid input produces exactly one error
driver$dispatch("Category", value = "invalid")
driver$expect_output_errors(n = 1) # expects 1 error
driver$dispatch("Category", value = "valid")
driver$expect_output_errors() # expects 0 errors
}
Examples
if (FALSE) { # \dontrun{
# Initialize a driver for testing
driver <- Driver$new(app_dir = "path/to/app")
# Interact with components using testid
driver$dispatch("Species", value = "Setosa")
# Check component state
driver$is_visible("Species distribution")
# Get component values
current_value <- driver$get_value(testid = "Species")
# Verify no errors are present
driver$expect_output_errors(n = 0)
} # }
## ------------------------------------------------
## Method `Driver$dispatch`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Set value for a text input
driver$dispatch("Username", value = "John Doe")
# Click a button (no additional arguments needed)
driver$dispatch("Submit")
# Set multiple selection for a picker input
driver$dispatch("Species", value = c("Setosa"))
} # }
## ------------------------------------------------
## Method `Driver$get_value`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Get value using testid (recommended)
current_text <- driver$get_value(testid = "Username")
# Get value using direct input name (not recommended)
current_text <- driver$get_value(input = "module-nested_module-username")
# Get value using testid (recommended)
plot_data <- driver$get_value(testid = "Scatterplot")
# Get output value (not recommended)
plot_data <- driver$get_value(output = "module-nested_module-main_plot")
} # }
## ------------------------------------------------
## Method `Driver$get_text`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Get text using testid (recommended)
title_text <- driver$get_text(testid = "Title")
# Get text using CSS selector (not recommended)
title_text <- driver$get_text(selector = "h1.main-title")
} # }
## ------------------------------------------------
## Method `Driver$get`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Get a custom attribute value
custom_attr <- driver$get("Name", "(el) => el.attr('custom')")
# Check if element has a specific CSS class
has_class <- driver$get("Next step", "(el) => el.hasClass('active')")
# Count child elements
child_count <- driver$get("Results list", "(el) => el.children().length")
} # }
## ------------------------------------------------
## Method `Driver$is_visible`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Check if an error message is visible
if (driver$is_visible("Error message")) {
error_text <- driver$get_text(testid = "Error message")
}
# Verify a modal dialog appeared
expect_true(driver$is_visible("Confirm"))
# Check if conditional UI element is shown
driver$dispatch("Show advanced options", value = TRUE)
expect_true(driver$is_visible("Advanced options"))
} # }
## ------------------------------------------------
## Method `Driver$is_disabled`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Check if submit button is disabled when form is invalid
expect_true(driver$is_disabled("Submit"))
# Verify input becomes enabled after conditions are met
driver$dispatch("Enable options", value = TRUE)
expect_false(driver$is_disabled("Options"))
} # }
## ------------------------------------------------
## Method `Driver$expect_output_errors`
## ------------------------------------------------
if (FALSE) { # \dontrun{
# Verify no errors during normal operation
driver$expect_output_errors() # expects 0 errors
# Test that invalid input produces exactly one error
driver$dispatch("Category", value = "invalid")
driver$expect_output_errors(n = 1) # expects 1 error
driver$dispatch("Category", value = "valid")
driver$expect_output_errors() # expects 0 errors
} # }