insightsengineering / insightsengineering/teal.picks

[Feature Request]: Add `shinytest2` utils to package

Open
#114 1 comment 1 reaction 0 assignees View on GitHub
enhancement
Dominant language
R
Stars
4
Forks
0
Avg merge
6d 11h
Merged PRs (30d)
3

Description

### Feature description

Goal: Add utilities that modify picks in `shinytest2::AppDriver` to reuse on end-to-end tests and avoid having multiple definitions in other packages from frameworks

#### Details

Custom functions that make changes in `teal.picks` are being used and re-used in `teal.modules.clinical`, `teal.modules.general` and other packages

This may fit better in this package as the workflow is very specific to `teal.picks` and not general.

The workflow is implemented as:
- Modifications to input are only applied after a non-binding input changes from `TRUE` to `FALSE`
- For instance `var1-variables-selected` only changes when ``var1-variables-selected_open` is toggled
- The same for `var1-datasets-selected` and `var1-values-selected`
- This is part of `shinyWidgets::pickerInput` implementation, but the logic in `teal.picks` also uses this
- The idea is to only process changes to picks once the picker popup closes

A proposal from `teal.modules.general` that needs a slight modification to no longer rely on `TealAppDriver` (by using `id` as a fully formed namespace path, instead of the `app_driver$set_active_module_input()` and `app_driver$get_active_module_input()`)

```r
#' Set the selected value of a teal.picks slot in a teal app using shinytest2.
#'
#' It sets the value of picks of the currently active module.
#'
#' @param app_driver (`TealAppDriver`).
#' @param id (`character(1)`) `picks`` id.
#' @param slot_name (`character(1)`) The name of the slot. One of "variables", "datasets", or "values".
#' @param value The value to set using `AppDriver$set_input`
#' @param ... arguments passed to `AppDriver$set_input`.
#' @return `TRUE` if the value was set successfully, `FALSE` if the value was already set,
#' and a warning if the resolved value does not match the expected value.
.set_picks_slot_selected <- function(app_driver, id, value, slot_name = c("variables", "datasets", "values"), ...) {
slot_name <- match.arg(slot_name)
selected_open_id <- sprintf("%s-%s-selected_open", id, slot_name) # teal.picks implementation detail
selected_id <- sprintf("%s-%s-selected", id, slot_name)

if (isTRUE(app_driver$get_value(input = selected_open_id))) {
stop("Cannot set picks slot while the picker input is open. Please close the picker input first.")
}
if (isTRUE(all.equal(app_driver$get_value(input = selected_id), value, tolerance = 1e-15))) {
return(FALSE)
}

# Mock the opening of the picker input
app_driver$set_input(selected_open_id, TRUE, allow_no_input_binding_ = TRUE)
# Set the value

tryCatch(
.change_selectpicker(app_driver, selected_id, value),
error = function(e) warning(e)
)

# Mock the closing of the picker input
app_driver$set_input(selected_open_id, FALSE, allow_no_input_binding_ = TRUE)

# Validate change in picks
picks_export_id <- sprintf("%s-picks_resolved", id)
resolved_value <- app_driver$get_values(export = picks_export_id)$export[[picks_export_id]][[slot_name]]$selected
if (!isTRUE(all.equal(resolved_value, value, tolerance = 1e-15))) {
warning("Setting picks slot did not result in expected resolved value.")
}
TRUE
}
```

Additionally, the `shinyWidgets::pickerInput` does not allow consistent modification for its value using `shinytest2` api _(`AppDriver$set_inputs()`)_

And a custom Javascript needs to be used (code below is from `teal.modules.general`)

```r
change_selectpicker <- function(app_driver, id, value, wait_ = TRUE) {
app_driver$run_js(sprintf("$('select#%s').selectpicker('val', %s);", id, jsonlite::toJSON(value, auto_unbox = TRUE)))
if (wait_) {
app_driver$wait_for_idle()
}
return(all.equal(app_driver$get_values()$input[[id]], value, tolerance = 1e-15))
}
```

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct.

### Contribution Guidelines

- [x] I agree to follow this project's Contribution Guidelines.

### Security Policy

- [x] I agree to follow this project's Security Policy.

Contributor guide

Open the contributing guide

Research direction

Start by reading the proposed .set_picks_slot_selected and change_selectpicker entry points, then inspect the shinytest2::AppDriver calls and teal.picks picker IDs described in the issue. Done means reusable utilities can update variables, datasets, and values selections, handle the picker open/close state, and validate the resolved picks value.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, r
Domain
testing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.