mirror of
https://github.com/rstudio/shiny.git
synced 2026-04-29 03:00:45 -04:00
Compare commits
38 Commits
main
...
fix/autoen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32847b98cc | ||
|
|
27f3cdfb74 | ||
|
|
2594e3e41b | ||
|
|
41dd9023f9 | ||
|
|
f737b4b7bb | ||
|
|
14e1a65b09 | ||
|
|
0a1c424a79 | ||
|
|
85da5b5a97 | ||
|
|
719886421d | ||
|
|
1d24bd47bc | ||
|
|
c9bc2418ae | ||
|
|
c16218b79d | ||
|
|
5948c66ec8 | ||
|
|
cee115e112 | ||
|
|
11c6a866b1 | ||
|
|
2483746d5f | ||
|
|
9366f5d72b | ||
|
|
48382c43b4 | ||
|
|
5e04142fef | ||
|
|
9b5a36d1aa | ||
|
|
35f71c4a76 | ||
|
|
c76e5663de | ||
|
|
3e57bb3c66 | ||
|
|
008efd7363 | ||
|
|
bc34f3443f | ||
|
|
958027cdfa | ||
|
|
a3f317c75d | ||
|
|
ebd085f3f8 | ||
|
|
4d12245112 | ||
|
|
6e834a757c | ||
|
|
c3a890fcef | ||
|
|
a28a325e7b | ||
|
|
12981caf25 | ||
|
|
ff829e929b | ||
|
|
9bf06b75b0 | ||
|
|
88888cf47a | ||
|
|
d25a8f17fb | ||
|
|
e93dea6c32 |
@@ -120,7 +120,7 @@ Suggests:
|
||||
testthat (>= 3.2.1),
|
||||
watcher,
|
||||
yaml
|
||||
Config/Needs/check: shinytest2
|
||||
Config/Needs/check: callr, devtools, httr, shinytest2
|
||||
Config/testthat/edition: 3
|
||||
Encoding: UTF-8
|
||||
Roxygen: list(markdown = TRUE)
|
||||
|
||||
4
NEWS.md
4
NEWS.md
@@ -10,6 +10,10 @@
|
||||
third-party tab components, and non-Bootstrap frameworks — without requiring
|
||||
custom event hooks. (#3682)
|
||||
|
||||
## Bug fixes and minor improvements
|
||||
|
||||
* `downloadButton()` and `downloadLink()` gain a new `enabled` parameter. Use `enabled = "auto"` (default) to automatically enable the button when the download is ready, `enabled = TRUE` to start the button already enabled, or `enabled = FALSE` to opt into manual state management. (#4119)
|
||||
|
||||
# shiny 1.13.0
|
||||
|
||||
## New features
|
||||
|
||||
@@ -1237,6 +1237,15 @@ uiOutput <- htmlOutput
|
||||
#' @param label The label that should appear on the button.
|
||||
#' @param class Additional CSS classes to apply to the tag, if any.
|
||||
#' @param icon An [icon()] to appear on the button. Default is `icon("download")`.
|
||||
#' @param enabled Controls the enabled/disabled behavior of the button.
|
||||
#' - `"auto"` (the default): the button starts disabled and is automatically
|
||||
#' enabled once the server has initialized the `downloadHandler`.
|
||||
#' - `TRUE`: the button starts enabled immediately, without waiting for the
|
||||
#' `downloadHandler`.
|
||||
#' - `FALSE`: the button starts disabled and Shiny will **never**
|
||||
#' automatically enable it, even after the `downloadHandler` is ready.
|
||||
#' You are responsible for managing the enabled/disabled state yourself
|
||||
#' (e.g., with `shinyjs::enable()` and `shinyjs::disable()`).
|
||||
#' @param ... Other arguments to pass to the container tag function.
|
||||
#'
|
||||
#' @examples
|
||||
@@ -1275,30 +1284,42 @@ downloadButton <- function(outputId,
|
||||
label="Download",
|
||||
class=NULL,
|
||||
...,
|
||||
enabled = c("auto", TRUE, FALSE),
|
||||
icon = shiny::icon("download")) {
|
||||
enabled <- match.arg(as.character(enabled), c("auto", "TRUE", "FALSE"))
|
||||
auto_enable <- identical(enabled, "auto")
|
||||
enabled <- identical(enabled, "TRUE")
|
||||
tags$a(id=outputId,
|
||||
class='btn btn-default shiny-download-link disabled',
|
||||
class="btn btn-default shiny-download-link",
|
||||
class=if (!enabled) "disabled",
|
||||
class=class,
|
||||
href='',
|
||||
target='_blank',
|
||||
download=NA,
|
||||
"aria-disabled"="true",
|
||||
tabindex="-1",
|
||||
"aria-disabled"=if (!enabled) "true",
|
||||
"data-shiny-disable-auto-enable"=if (!auto_enable) NA,
|
||||
tabindex=if (!enabled) "-1",
|
||||
validateIcon(icon),
|
||||
label, ...)
|
||||
}
|
||||
|
||||
#' @rdname downloadButton
|
||||
#' @export
|
||||
downloadLink <- function(outputId, label="Download", class=NULL, ...) {
|
||||
tags$a(id=outputId,
|
||||
class='shiny-download-link disabled',
|
||||
class=class,
|
||||
href='',
|
||||
target='_blank',
|
||||
download=NA,
|
||||
"aria-disabled"="true",
|
||||
tabindex="-1",
|
||||
downloadLink <- function(outputId, label = "Download", class = NULL, ...,
|
||||
enabled = c("auto", TRUE, FALSE)) {
|
||||
enabled <- match.arg(as.character(enabled), c("auto", "TRUE", "FALSE"))
|
||||
auto_enable <- identical(enabled, "auto")
|
||||
enabled <- identical(enabled, "TRUE")
|
||||
tags$a(id = outputId,
|
||||
class = "shiny-download-link",
|
||||
class = if (!enabled) "disabled",
|
||||
class = class,
|
||||
href = '',
|
||||
target = '_blank',
|
||||
download = NA,
|
||||
"aria-disabled" = if (!enabled) "true",
|
||||
"data-shiny-disable-auto-enable" = if (!auto_enable) NA,
|
||||
tabindex = if (!enabled) "-1",
|
||||
label, ...)
|
||||
}
|
||||
|
||||
|
||||
@@ -3074,9 +3074,11 @@
|
||||
}
|
||||
renderValue(el, data) {
|
||||
el.setAttribute("href", data);
|
||||
el.classList.remove("disabled");
|
||||
el.removeAttribute("aria-disabled");
|
||||
el.removeAttribute("tabindex");
|
||||
if (!el.hasAttribute("data-shiny-disable-auto-enable") && !el.classList.contains("shinyjs-disabled")) {
|
||||
el.classList.remove("disabled");
|
||||
el.removeAttribute("aria-disabled");
|
||||
el.removeAttribute("tabindex");
|
||||
}
|
||||
}
|
||||
// Progress shouldn't be shown on the download button
|
||||
// (progress will be shown as a page level pulse instead)
|
||||
@@ -3090,9 +3092,14 @@
|
||||
"click.shinyDownloadLink",
|
||||
"a.shiny-download-link",
|
||||
function(e4) {
|
||||
const el = e4.currentTarget;
|
||||
if (el.classList.contains("disabled")) {
|
||||
e4.preventDefault();
|
||||
return;
|
||||
}
|
||||
const evt = import_jquery25.default.Event("shiny:filedownload");
|
||||
evt.name = this.id;
|
||||
evt.href = this.href;
|
||||
evt.name = el.id;
|
||||
evt.href = el.href;
|
||||
(0, import_jquery25.default)(document).trigger(evt);
|
||||
return;
|
||||
e4;
|
||||
|
||||
File diff suppressed because one or more lines are too long
2
inst/www/shared/shiny.min.css
vendored
2
inst/www/shared/shiny.min.css
vendored
File diff suppressed because one or more lines are too long
18
inst/www/shared/shiny.min.js
vendored
18
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -493,3 +493,10 @@ textarea.textarea-autoresize.form-control {
|
||||
/* override anything bootstrap sets for `.nav` */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Bootstrap only applies pointer-events: none to a.btn.disabled, not plain
|
||||
anchor-based download links. Apply it universally so disabled download
|
||||
links cannot be clicked regardless of how they were disabled. */
|
||||
a.shiny-download-link.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,17 @@ downloadButton(
|
||||
label = "Download",
|
||||
class = NULL,
|
||||
...,
|
||||
enabled = c("auto", TRUE, FALSE),
|
||||
icon = shiny::icon("download")
|
||||
)
|
||||
|
||||
downloadLink(outputId, label = "Download", class = NULL, ...)
|
||||
downloadLink(
|
||||
outputId,
|
||||
label = "Download",
|
||||
class = NULL,
|
||||
...,
|
||||
enabled = c("auto", TRUE, FALSE)
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
\item{outputId}{The name of the output slot that the \code{downloadHandler}
|
||||
@@ -25,6 +32,19 @@ is assigned to.}
|
||||
|
||||
\item{...}{Other arguments to pass to the container tag function.}
|
||||
|
||||
\item{enabled}{Controls the enabled/disabled behavior of the button.
|
||||
\itemize{
|
||||
\item \code{"auto"} (the default): the button starts disabled and is automatically
|
||||
enabled once the server has initialized the \code{downloadHandler}.
|
||||
\item \code{TRUE}: the button starts enabled immediately, without waiting for the
|
||||
\code{downloadHandler}.
|
||||
\item \code{FALSE}: the button starts disabled and Shiny will \strong{never}
|
||||
automatically enable it, even after the \code{downloadHandler} is ready.
|
||||
You are responsible for managing the enabled/disabled state yourself
|
||||
(e.g., with \code{\link[shinyjs:enable]{shinyjs::enable()}} and \code{\link[shinyjs:disable]{shinyjs::disable()}}).
|
||||
(e.g., with \code{shinyjs::enable()} and \code{shinyjs::disable()}).
|
||||
}}
|
||||
|
||||
\item{icon}{An \code{\link[=icon]{icon()}} to appear on the button. Default is \code{icon("download")}.}
|
||||
}
|
||||
\description{
|
||||
|
||||
@@ -8,9 +8,17 @@ class DownloadLinkOutputBinding extends OutputBinding {
|
||||
}
|
||||
renderValue(el: HTMLElement, data: string): void {
|
||||
el.setAttribute("href", data);
|
||||
el.classList.remove("disabled");
|
||||
el.removeAttribute("aria-disabled");
|
||||
el.removeAttribute("tabindex");
|
||||
// If we or shinyjs have marked this element as disabled (via shinyjs::disabled()),
|
||||
// skip the auto-enable behavior so that the intentional disabled state is
|
||||
// preserved. See https://github.com/rstudio/shiny/issues/4119.
|
||||
if (
|
||||
!el.hasAttribute("data-shiny-disable-auto-enable") &&
|
||||
!el.classList.contains("shinyjs-disabled")
|
||||
) {
|
||||
el.classList.remove("disabled");
|
||||
el.removeAttribute("aria-disabled");
|
||||
el.removeAttribute("tabindex");
|
||||
}
|
||||
}
|
||||
// Progress shouldn't be shown on the download button
|
||||
// (progress will be shown as a page level pulse instead)
|
||||
@@ -32,10 +40,18 @@ $(document).on(
|
||||
"click.shinyDownloadLink",
|
||||
"a.shiny-download-link",
|
||||
function (e: Event) {
|
||||
const el = e.currentTarget as HTMLAnchorElement;
|
||||
|
||||
// Prevent clicks when the button is disabled.
|
||||
if (el.classList.contains("disabled")) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const evt: FileDownloadEvent = $.Event("shiny:filedownload");
|
||||
|
||||
evt.name = this.id;
|
||||
evt.href = this.href;
|
||||
evt.name = el.id;
|
||||
evt.href = el.href;
|
||||
$(document).trigger(evt);
|
||||
|
||||
return;
|
||||
|
||||
51
tests/testthat/_snaps/downloadButton.md
Normal file
51
tests/testthat/_snaps/downloadButton.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# downloadButton snapshot (enabled = 'auto')
|
||||
|
||||
Code
|
||||
downloadButton("dl", "Download")
|
||||
Output
|
||||
<a aria-disabled="true" class="btn btn-default shiny-download-link disabled" download href="" id="dl" tabindex="-1" target="_blank">
|
||||
<i class="fas fa-download" role="presentation" aria-label="download icon"></i>
|
||||
Download
|
||||
</a>
|
||||
|
||||
# downloadButton snapshot (enabled = FALSE)
|
||||
|
||||
Code
|
||||
downloadButton("dl", "Download", enabled = FALSE)
|
||||
Output
|
||||
<a aria-disabled="true" class="btn btn-default shiny-download-link disabled" data-shiny-disable-auto-enable download href="" id="dl" tabindex="-1" target="_blank">
|
||||
<i class="fas fa-download" role="presentation" aria-label="download icon"></i>
|
||||
Download
|
||||
</a>
|
||||
|
||||
# downloadButton snapshot (enabled = TRUE)
|
||||
|
||||
Code
|
||||
downloadButton("dl", "Download", enabled = TRUE)
|
||||
Output
|
||||
<a id="dl" class="btn btn-default shiny-download-link" href="" target="_blank" download data-shiny-disable-auto-enable>
|
||||
<i class="fas fa-download" role="presentation" aria-label="download icon"></i>
|
||||
Download
|
||||
</a>
|
||||
|
||||
# downloadLink snapshot (enabled = 'auto')
|
||||
|
||||
Code
|
||||
downloadLink("dl", "Download")
|
||||
Output
|
||||
<a aria-disabled="true" class="shiny-download-link disabled" download href="" id="dl" tabindex="-1" target="_blank">Download</a>
|
||||
|
||||
# downloadLink snapshot (enabled = FALSE)
|
||||
|
||||
Code
|
||||
downloadLink("dl", "Download", enabled = FALSE)
|
||||
Output
|
||||
<a aria-disabled="true" class="shiny-download-link disabled" data-shiny-disable-auto-enable download href="" id="dl" tabindex="-1" target="_blank">Download</a>
|
||||
|
||||
# downloadLink snapshot (enabled = TRUE)
|
||||
|
||||
Code
|
||||
downloadLink("dl", "Download", enabled = TRUE)
|
||||
Output
|
||||
<a id="dl" class="shiny-download-link" href="" target="_blank" download data-shiny-disable-auto-enable>Download</a>
|
||||
|
||||
123
tests/testthat/apps/download-button/app.R
Normal file
123
tests/testthat/apps/download-button/app.R
Normal file
@@ -0,0 +1,123 @@
|
||||
library(shiny)
|
||||
|
||||
# This app covers the three `enabled` values for both downloadButton and downloadLink,
|
||||
# plus a simulated shinyjs-disabled case, with toggle switches for each scenario.
|
||||
|
||||
# Create a downloadHandler that just serves a simple text file for testing.
|
||||
handler <- function() {
|
||||
downloadHandler(
|
||||
filename = "test.txt",
|
||||
content = function(file) writeLines("test", file)
|
||||
)
|
||||
}
|
||||
|
||||
ui <- fluidPage(
|
||||
h3("downloadButton"),
|
||||
|
||||
uiOutput("btn_auto_ui"),
|
||||
bslib::input_switch("toggle_btn_auto", "Enabled", value = TRUE),
|
||||
|
||||
uiOutput("btn_off_ui"),
|
||||
bslib::input_switch("toggle_btn_off", "Enabled", value = FALSE),
|
||||
|
||||
uiOutput("btn_on_ui"),
|
||||
bslib::input_switch("toggle_btn_on", "Enabled", value = TRUE),
|
||||
|
||||
# This mimics what happens when a download button is wrapped in a
|
||||
# shinyjs::disabled() call within the UI (and therefore at render time).
|
||||
uiOutput("btn_shinyjs_ui"),
|
||||
bslib::input_switch("toggle_btn_shinyjs", "Enabled", value = FALSE),
|
||||
|
||||
h3("downloadLink"),
|
||||
|
||||
uiOutput("lnk_auto_ui"),
|
||||
bslib::input_switch("toggle_lnk_auto", "Enabled", value = TRUE),
|
||||
|
||||
uiOutput("lnk_off_ui"),
|
||||
bslib::input_switch("toggle_lnk_off", "Enabled", value = FALSE),
|
||||
|
||||
uiOutput("lnk_on_ui"),
|
||||
bslib::input_switch("toggle_lnk_on", "Enabled", value = TRUE),
|
||||
|
||||
uiOutput("lnk_shinyjs_ui"),
|
||||
bslib::input_switch("toggle_lnk_shinyjs", "Enabled", value = FALSE)
|
||||
)
|
||||
|
||||
server <- function(input, output, session) {
|
||||
output$btn_auto <- handler()
|
||||
output$btn_off <- handler()
|
||||
output$btn_on <- handler()
|
||||
output$btn_shinyjs <- handler()
|
||||
output$lnk_auto <- handler()
|
||||
output$lnk_off <- handler()
|
||||
output$lnk_on <- handler()
|
||||
output$lnk_shinyjs <- handler()
|
||||
|
||||
output$btn_auto_ui <- renderUI({
|
||||
if (isTRUE(input$toggle_btn_auto)) {
|
||||
downloadButton("btn_auto", "Auto (default)")
|
||||
} else {
|
||||
downloadButton("btn_auto", "Auto (default)", enabled = FALSE)
|
||||
}
|
||||
})
|
||||
|
||||
output$btn_off_ui <- renderUI({
|
||||
if (isTRUE(input$toggle_btn_off)) {
|
||||
downloadButton("btn_off", "Disabled", enabled = TRUE)
|
||||
} else {
|
||||
downloadButton("btn_off", "Disabled", enabled = FALSE)
|
||||
}
|
||||
})
|
||||
|
||||
output$btn_on_ui <- renderUI({
|
||||
if (isTRUE(input$toggle_btn_on)) {
|
||||
downloadButton("btn_on", "Pre-enabled", enabled = TRUE)
|
||||
} else {
|
||||
downloadButton("btn_on", "Pre-enabled", enabled = FALSE)
|
||||
}
|
||||
})
|
||||
|
||||
output$btn_shinyjs_ui <- renderUI({
|
||||
btn <- downloadButton("btn_shinyjs", "shinyjs-disabled")
|
||||
if (!isTRUE(input$toggle_btn_shinyjs)) {
|
||||
htmltools::tagAppendAttributes(btn, class = "shinyjs-disabled")
|
||||
} else {
|
||||
btn
|
||||
}
|
||||
})
|
||||
|
||||
output$lnk_auto_ui <- renderUI({
|
||||
if (isTRUE(input$toggle_lnk_auto)) {
|
||||
downloadLink("lnk_auto", "Auto (default)")
|
||||
} else {
|
||||
downloadLink("lnk_auto", "Auto (default)", enabled = FALSE)
|
||||
}
|
||||
})
|
||||
|
||||
output$lnk_off_ui <- renderUI({
|
||||
if (isTRUE(input$toggle_lnk_off)) {
|
||||
downloadLink("lnk_off", "Disabled", enabled = TRUE)
|
||||
} else {
|
||||
downloadLink("lnk_off", "Disabled", enabled = FALSE)
|
||||
}
|
||||
})
|
||||
|
||||
output$lnk_on_ui <- renderUI({
|
||||
if (isTRUE(input$toggle_lnk_on)) {
|
||||
downloadLink("lnk_on", "Pre-enabled", enabled = TRUE)
|
||||
} else {
|
||||
downloadLink("lnk_on", "Pre-enabled", enabled = FALSE)
|
||||
}
|
||||
})
|
||||
|
||||
output$lnk_shinyjs_ui <- renderUI({
|
||||
lnk <- downloadLink("lnk_shinyjs", "shinyjs-disabled")
|
||||
if (!isTRUE(input$toggle_lnk_shinyjs)) {
|
||||
htmltools::tagAppendAttributes(lnk, class = "shinyjs-disabled")
|
||||
} else {
|
||||
lnk
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
shinyApp(ui, server)
|
||||
178
tests/testthat/test-downloadButton-shinytest2.R
Normal file
178
tests/testthat/test-downloadButton-shinytest2.R
Normal file
@@ -0,0 +1,178 @@
|
||||
skip_on_cran()
|
||||
# Skip on everything but mac
|
||||
skip_on_os(c("windows", "linux", "solaris", "emscripten"))
|
||||
skip_if_not_installed("shinytest2")
|
||||
skip_if_not_installed("callr")
|
||||
library(shinytest2)
|
||||
|
||||
# Start the test app in a subprocess, loading the local dev shiny.
|
||||
# AppDriver$new(url) is used instead of AppDriver$new(app_dir) because the
|
||||
# latter's internal subprocess runner has a timing issue with devtools-loaded
|
||||
# packages that prevents the shinytest2 tracer from detecting jQuery.
|
||||
app_process <- callr::r_bg(
|
||||
function(app_file, port) {
|
||||
devtools::load_all(quiet = TRUE)
|
||||
shiny::runApp(
|
||||
shiny::shinyAppFile(app_file),
|
||||
port = port,
|
||||
host = "127.0.0.1",
|
||||
launch.browser = FALSE,
|
||||
quiet = TRUE,
|
||||
test.mode = TRUE
|
||||
)
|
||||
},
|
||||
args = list(
|
||||
app_file = testthat::test_path("apps/download-button/app.R"),
|
||||
port = 7314L
|
||||
)
|
||||
)
|
||||
withr::defer(app_process$kill())
|
||||
|
||||
# Wait for the app to be ready
|
||||
for (i in seq_len(20)) {
|
||||
Sys.sleep(0.5)
|
||||
ready <- tryCatch(
|
||||
{
|
||||
httr::GET("http://127.0.0.1:7314", httr::timeout(1))
|
||||
TRUE
|
||||
},
|
||||
error = function(e) FALSE
|
||||
)
|
||||
if (ready) break
|
||||
}
|
||||
if (!ready) skip("Download button test app failed to start")
|
||||
|
||||
app_url <- "http://127.0.0.1:7314"
|
||||
|
||||
# Start up app once and share across all tests
|
||||
app <- AppDriver$new(app_url)
|
||||
withr::defer({ app$stop() })
|
||||
app$wait_for_idle()
|
||||
|
||||
is_disabled <- function(id) {
|
||||
app$get_js(sprintf(
|
||||
"var el = document.querySelector('#%s');
|
||||
el.classList.contains('disabled') &&
|
||||
el.getAttribute('aria-disabled') === 'true' &&
|
||||
el.getAttribute('tabindex') === '-1';", id
|
||||
))
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
click_toggle <- function(id) {
|
||||
input_name <- paste0("toggle_", id)
|
||||
current <- isTRUE(app$get_value(input = input_name))
|
||||
do.call(app$set_inputs, setNames(list(!current), input_name))
|
||||
app$wait_for_idle()
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# downloadButton
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
test_that("downloadButton (enabled='auto') auto-enables after server init", {
|
||||
expect_false(is_disabled("btn_auto"))
|
||||
expect_null(app$get_js("document.querySelector('#btn_auto').getAttribute('aria-disabled')"))
|
||||
})
|
||||
|
||||
test_that("downloadButton (enabled=FALSE) stays disabled after server init", {
|
||||
expect_true(is_disabled("btn_off"))
|
||||
})
|
||||
|
||||
test_that("downloadButton (enabled=TRUE) starts and stays enabled", {
|
||||
expect_false(is_disabled("btn_on"))
|
||||
expect_null(app$get_js("document.querySelector('#btn_on').getAttribute('aria-disabled')"))
|
||||
})
|
||||
|
||||
test_that("downloadButton with shinyjs-disabled class stays disabled after server init", {
|
||||
expect_true(is_disabled("btn_shinyjs"))
|
||||
})
|
||||
|
||||
test_that("downloadButton (enabled='auto') can be toggled off and back on", {
|
||||
click_toggle("btn_auto")
|
||||
expect_true(is_disabled("btn_auto"))
|
||||
|
||||
click_toggle("btn_auto")
|
||||
expect_false(is_disabled("btn_auto"))
|
||||
})
|
||||
|
||||
test_that("downloadButton (enabled=FALSE) can be toggled on and back off", {
|
||||
click_toggle("btn_off")
|
||||
expect_false(is_disabled("btn_off"))
|
||||
|
||||
click_toggle("btn_off")
|
||||
expect_true(is_disabled("btn_off"))
|
||||
})
|
||||
|
||||
test_that("downloadButton (enabled=TRUE) can be toggled off and back on", {
|
||||
click_toggle("btn_on")
|
||||
expect_true(is_disabled("btn_on"))
|
||||
|
||||
click_toggle("btn_on")
|
||||
expect_false(is_disabled("btn_on"))
|
||||
})
|
||||
|
||||
test_that("downloadButton (shinyjs-disabled) can be toggled on and back off", {
|
||||
click_toggle("btn_shinyjs")
|
||||
expect_false(is_disabled("btn_shinyjs"))
|
||||
|
||||
click_toggle("btn_shinyjs")
|
||||
expect_true(is_disabled("btn_shinyjs"))
|
||||
})
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# downloadLink
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
test_that("downloadLink (enabled='auto') auto-enables after server init", {
|
||||
expect_false(is_disabled("lnk_auto"))
|
||||
expect_null(app$get_js("document.querySelector('#lnk_auto').getAttribute('aria-disabled')"))
|
||||
})
|
||||
|
||||
test_that("downloadLink (enabled=FALSE) stays disabled after server init", {
|
||||
expect_true(is_disabled("lnk_off"))
|
||||
})
|
||||
|
||||
test_that("downloadLink (enabled=TRUE) starts and stays enabled", {
|
||||
expect_false(is_disabled("lnk_on"))
|
||||
expect_null(app$get_js("document.querySelector('#lnk_on').getAttribute('aria-disabled')"))
|
||||
})
|
||||
|
||||
test_that("downloadLink with shinyjs-disabled class stays disabled after server init", {
|
||||
expect_true(is_disabled("lnk_shinyjs"))
|
||||
})
|
||||
|
||||
test_that("downloadLink (enabled='auto') can be toggled off and back on", {
|
||||
click_toggle("lnk_auto")
|
||||
expect_true(is_disabled("lnk_auto"))
|
||||
|
||||
click_toggle("lnk_auto")
|
||||
expect_false(is_disabled("lnk_auto"))
|
||||
})
|
||||
|
||||
test_that("downloadLink (enabled=FALSE) can be toggled on and back off", {
|
||||
click_toggle("lnk_off")
|
||||
expect_false(is_disabled("lnk_off"))
|
||||
|
||||
click_toggle("lnk_off")
|
||||
expect_true(is_disabled("lnk_off"))
|
||||
})
|
||||
|
||||
test_that("downloadLink (enabled=TRUE) can be toggled off and back on", {
|
||||
click_toggle("lnk_on")
|
||||
expect_true(is_disabled("lnk_on"))
|
||||
|
||||
click_toggle("lnk_on")
|
||||
expect_false(is_disabled("lnk_on"))
|
||||
})
|
||||
|
||||
test_that("downloadLink (shinyjs-disabled) can be toggled on and back off", {
|
||||
click_toggle("lnk_shinyjs")
|
||||
expect_false(is_disabled("lnk_shinyjs"))
|
||||
|
||||
click_toggle("lnk_shinyjs")
|
||||
expect_true(is_disabled("lnk_shinyjs"))
|
||||
})
|
||||
91
tests/testthat/test-downloadButton.R
Normal file
91
tests/testthat/test-downloadButton.R
Normal file
@@ -0,0 +1,91 @@
|
||||
test_that("downloadButton starts disabled with correct attributes", {
|
||||
btn <- downloadButton("dl", "Download")
|
||||
html <- as.character(btn)
|
||||
|
||||
expect_match(html, "class=.*disabled")
|
||||
expect_match(html, 'aria-disabled="true"')
|
||||
expect_match(html, 'tabindex="-1"')
|
||||
expect_match(html, 'href=""')
|
||||
})
|
||||
|
||||
test_that("downloadLink starts disabled with correct attributes", {
|
||||
lnk <- downloadLink("dl", "Download")
|
||||
html <- as.character(lnk)
|
||||
|
||||
expect_match(html, "class=.*disabled")
|
||||
expect_match(html, 'aria-disabled="true"')
|
||||
expect_match(html, 'tabindex="-1"')
|
||||
expect_match(html, 'href=""')
|
||||
})
|
||||
|
||||
test_that("downloadButton omits data-shiny-disable-auto-enable by default (enabled = 'auto')", {
|
||||
btn <- downloadButton("dl", "Download")
|
||||
html <- as.character(btn)
|
||||
|
||||
expect_no_match(html, "data-shiny-disable-auto-enable")
|
||||
})
|
||||
|
||||
test_that("downloadButton has data-shiny-disable-auto-enable when enabled = FALSE", {
|
||||
btn <- downloadButton("dl", "Download", enabled = FALSE)
|
||||
html <- as.character(btn)
|
||||
|
||||
expect_match(html, "data-shiny-disable-auto-enable")
|
||||
})
|
||||
|
||||
test_that("downloadButton starts enabled when enabled = TRUE", {
|
||||
btn <- downloadButton("dl", "Download", enabled = TRUE)
|
||||
html <- as.character(btn)
|
||||
|
||||
expect_no_match(html, "disabled")
|
||||
expect_no_match(html, "aria-disabled")
|
||||
expect_no_match(html, "tabindex")
|
||||
expect_match(html, "data-shiny-disable-auto-enable")
|
||||
})
|
||||
|
||||
test_that("downloadLink omits data-shiny-disable-auto-enable by default (enabled = 'auto')", {
|
||||
lnk <- downloadLink("dl", "Download")
|
||||
html <- as.character(lnk)
|
||||
|
||||
expect_no_match(html, "data-shiny-disable-auto-enable")
|
||||
})
|
||||
|
||||
test_that("downloadLink has data-shiny-disable-auto-enable when enabled = FALSE", {
|
||||
lnk <- downloadLink("dl", "Download", enabled = FALSE)
|
||||
html <- as.character(lnk)
|
||||
|
||||
expect_match(html, "data-shiny-disable-auto-enable")
|
||||
})
|
||||
|
||||
test_that("downloadLink starts enabled when enabled = TRUE", {
|
||||
lnk <- downloadLink("dl", "Download", enabled = TRUE)
|
||||
html <- as.character(lnk)
|
||||
|
||||
expect_no_match(html, "disabled")
|
||||
expect_no_match(html, "aria-disabled")
|
||||
expect_no_match(html, "tabindex")
|
||||
expect_match(html, "data-shiny-disable-auto-enable")
|
||||
})
|
||||
|
||||
test_that("downloadButton snapshot (enabled = 'auto')", {
|
||||
expect_snapshot(downloadButton("dl", "Download"))
|
||||
})
|
||||
|
||||
test_that("downloadButton snapshot (enabled = FALSE)", {
|
||||
expect_snapshot(downloadButton("dl", "Download", enabled = FALSE))
|
||||
})
|
||||
|
||||
test_that("downloadButton snapshot (enabled = TRUE)", {
|
||||
expect_snapshot(downloadButton("dl", "Download", enabled = TRUE))
|
||||
})
|
||||
|
||||
test_that("downloadLink snapshot (enabled = 'auto')", {
|
||||
expect_snapshot(downloadLink("dl", "Download"))
|
||||
})
|
||||
|
||||
test_that("downloadLink snapshot (enabled = FALSE)", {
|
||||
expect_snapshot(downloadLink("dl", "Download", enabled = FALSE))
|
||||
})
|
||||
|
||||
test_that("downloadLink snapshot (enabled = TRUE)", {
|
||||
expect_snapshot(downloadLink("dl", "Download", enabled = TRUE))
|
||||
})
|
||||
Reference in New Issue
Block a user