-
Notifications
You must be signed in to change notification settings - Fork 55
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
Allow connecting to an existing Shiny instance #348
base: main
Are you sure you want to change the base?
Conversation
Are you sure that this doesn't already work? It's not documented, but I think you can supply a url to the |
Those lines suffice to get the
Both led to errors when Only 10 lines of code needed to fix these. Adding a separate The rest of the patch is:
|
@@ -4,7 +4,7 @@ | |||
|
|||
sd_initialize <- function(self, private, path, loadTimeout, checkNames, | |||
debug, phantomTimeout, seed, cleanLogs, | |||
shinyOptions) { | |||
shinyOptions, url=NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please put spaces around =
?
@@ -21,9 +21,13 @@ sd_initialize <- function(self, private, path, loadTimeout, checkNames, | |||
self$logEvent("Getting PhantomJS port") | |||
private$phantomPort <- get_phantomPort(timeout = phantomTimeout) | |||
|
|||
if (grepl("^http(s?)://", path)) { | |||
private$setShinyUrl(path) | |||
if(!dir_exists(path)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please follow https://style.tidyverse.org here?
- Space after
if
{}
around stop<-
instead of=
#' headless browser that can be used to simulate user actions. This provides | ||
#' a full simulation of a Shiny app so that you can test user interactions | ||
#' with a live app. | ||
#' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please remove this empty line?
#' a full simulation of a Shiny app so that you can test user interactions | ||
#' with a live app. | ||
#' | ||
#' This class connects a `phantom.js` headless browser to a shiny app to enable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#' This class connects a `phantom.js` headless browser to a shiny app to enable | |
#' This class connects a `phantom.js` headless browser to a Shiny app to enable |
#' with a live app. | ||
#' | ||
#' This class connects a `phantom.js` headless browser to a shiny app to enable | ||
#' testing the effect of user interactions with a live app. Specify `url` to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the path clause should come first since that's what most people will do.
@@ -41,14 +44,15 @@ ShinyDriver <- R6Class( | |||
#' @param cleanLogs Whether to remove the stdout and stderr logs when the | |||
#' Shiny process object is garbage collected. | |||
#' @param shinyOptions A list of options to pass to [shiny::runApp()]. | |||
#' @param url Optional URL where the shiny app is executing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If not provided, ShinyDriver will automatically start a shiny instance.
client <- ShinyDriver$new(test_path("apps/outputs"), | ||
url = server$getUrl() | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
client <- ShinyDriver$new(test_path("apps/outputs"), | |
url = server$getUrl() | |
) | |
client <- ShinyDriver$new(test_path("apps/outputs"), url = server$getUrl()) |
client$waitForShiny() | ||
expect_equal(client$getValue("i"), "2") | ||
|
||
client$stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't call these explicitly in any other tests, so I think you should remove them here, unless there is something special going on.
@@ -269,6 +269,32 @@ app <- ShinyDriver$new("path/to/app") | |||
|
|||
The rest of the test script can be run unchanged. | |||
|
|||
## Debugging app issues | |||
|
|||
IF you need to debug an issue in the application that is triggered by a test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IF you need to debug an issue in the application that is triggered by a test | |
If you need to debug an issue in the application that is triggered by a test |
client <- ShinyDriver$new(test_path("apps/outputs"), | ||
url = "http://localhost:4040" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
client <- ShinyDriver$new(test_path("apps/outputs"), | |
url = "http://localhost:4040" | |
) | |
client <- ShinyDriver$new("path/to/app"), url = "http://localhost:4040") |
This would be awesome to have to be able to remotely test a deployed app. I tried this by applying the below patch. Below my experience. TLDR: It seems to work, but proxies and HTTP authentication seem to cause problems. I'd be glad about a workaround particularly to the latter issue.
diff --git a/R/initialize.R b/R/initialize.R
index 780ffdb..fc3f903 100644
--- a/R/initialize.R
+++ b/R/initialize.R
@@ -7 +7 @@ sd_initialize <- function(self, private, path, loadTimeout, checkNames,
- shinyOptions, renderArgs, options) {
+ shinyOptions, renderArgs, options, url = NULL) {
@@ -28,2 +28,7 @@ sd_initialize <- function(self, private, path, loadTimeout, checkNames,
- if (grepl("^http(s?)://", path)) {
- private$setShinyUrl(path)
+ if(!dir_exists(path))
+ stop("No such directory: ", path)
+ private$path <- path
+
+ if(!is.null(url)) {
+ "!DEBUG setting URL provided by the user"
+ private$setShinyUrl(url)
@@ -250 +255 @@ sd_finalize <- function(self, private) {
- if (isTRUE(private$cleanLogs)) {
+ if (!is.null(private$shinyProcess) && isTRUE(private$cleanLogs)) {
diff --git a/R/shiny-driver.R b/R/shiny-driver.R
index cf36003..518baee 100644
--- a/R/shiny-driver.R
+++ b/R/shiny-driver.R
@@ -50 +50 @@ ShinyDriver <- R6Class(
- shinyOptions = list(), renderArgs = NULL, options = list())
+ shinyOptions = list(), renderArgs = NULL, options = list(), url = NULL)
@@ -54 +54 @@ ShinyDriver <- R6Class(
- shinyOptions = shinyOptions, renderArgs = renderArgs, options = options)
+ shinyOptions = shinyOptions, renderArgs = renderArgs, options = options, url = url) |
I made Are there any known restrictions with HTTP auth in webdriver? (Edit: I could isolate this issue to being an SSL error in Sharing this piece of code either way: diff --git a/R/initialize.R b/R/initialize.R
index 780ffdb..34cc46e 100644
--- a/R/initialize.R
+++ b/R/initialize.R
@@ -7 +7 @@ sd_initialize <- function(self, private, path, loadTimeout, checkNames,
- shinyOptions, renderArgs, options) {
+ shinyOptions, renderArgs, options, url = NULL) {
@@ -28,2 +28,7 @@ sd_initialize <- function(self, private, path, loadTimeout, checkNames,
- if (grepl("^http(s?)://", path)) {
- private$setShinyUrl(path)
+ if(!dir_exists(path))
+ stop("No such directory: ", path)
+ private$path <- path
+
+ if(!is.null(url)) {
+ "!DEBUG setting URL provided by the user"
+ private$setShinyUrl(url)
@@ -204 +209,7 @@ sd_getShinyUrl <- function(self, private) {
- private$shinyUrlProtocol, "://", private$shinyUrlHost,
+ private$shinyUrlProtocol, "://",
+ if (!is.null(private$shinyUrlUser)) paste0(
+ private$shinyUrlUser,
+ if (!is.null(private$shinyUrlPass)) paste0(":", private$shinyUrlPass),
+ "@"
+ ),
+ private$shinyUrlHost,
@@ -225,0 +237,2 @@ sd_setShinyUrl <- function(self, private, url) {
+ private$shinyUrlUser <- res$user
+ private$shinyUrlPass <- res$pass
@@ -250 +263 @@ sd_finalize <- function(self, private) {
- if (isTRUE(private$cleanLogs)) {
+ if (!is.null(private$shinyProcess) && isTRUE(private$cleanLogs)) {
diff --git a/R/shiny-driver.R b/R/shiny-driver.R
index cf36003..152a9e4 100644
--- a/R/shiny-driver.R
+++ b/R/shiny-driver.R
@@ -50 +50 @@ ShinyDriver <- R6Class(
- shinyOptions = list(), renderArgs = NULL, options = list())
+ shinyOptions = list(), renderArgs = NULL, options = list(), url = NULL)
@@ -54 +54 @@ ShinyDriver <- R6Class(
- shinyOptions = shinyOptions, renderArgs = renderArgs, options = options)
+ shinyOptions = shinyOptions, renderArgs = renderArgs, options = options, url = url)
@@ -466,0 +467,2 @@ ShinyDriver <- R6Class(
+ shinyUrlUser = NULL,
+ shinyUrlPass = NULL,
diff --git a/R/utils.R b/R/utils.R
index d91c2ae..cecb958 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -98 +98 @@ parse_url <- function(url) {
- res <- regexpr("^(?<protocol>https?)://(?<host>[^:/]+)(:(?<port>\\d+))?(?<path>/.*)?$", url, perl = TRUE)
+ res <- regexpr("^(?<protocol>https?)://((?<user>[^:]*)(:(?<pass>.*))?@)?(?<host>[^:/]+)(:(?<port>\\d+))?(?<path>/.*)?$", url, perl = TRUE)
@@ -112,0 +113,2 @@ parse_url <- function(url) {
+ user = get_piece("user"),
+ pass = get_piece("pass"), |
I think the broader environment has changed since I last looked at this PR. @schloerke can comment if it would still be useful to finish off. |
@bersbersbers I can connect to a local shiny instance already. Reprex:
# Terminal 2
app <- ShinyDriver$new("http://127.0.0.1:6427")
app$getAllValues()$input$bins
#> [1] 30
app$setInputs(bins = 20)
app$getAllValues()$input$bins
#> [1] 20 @bersbersbers I am hesitant to support adding another parameter when Adding support for the user/pass in the url string is very reasonable. A small PR for this logic would be great! An item to remember... the app MUST be started in test mode (Ex: Debugging a live app will not work as intended as a new session will be started. Other than the user/pass support, this PR feels like this debugging effort is being forced. Instead, I'd like to push effort towards {shinytest2}. I'll make the repo public later this week. Mainly, {shinytest2} will have a method Life should be much better on the {shinytest2} side of the fence. |
I may be mistaken, but I think @warnes has given one reason in #348 (comment), which is that if (My explanations above may not be 100% accurate, but I think you get the point: when connecting to a remote instance, you still need a local reference for where the test output should go.) I am aware that the to-be-tested app has to be started in test mode for most functionality, although do note that is not stricly required: I have, in parallel, started working on making
(I think) I agree, but that is not my aim anyway. My aim is to make sure a deployed Shiny instance is fully operational each day and does not run into issues such as network connectivity, RAM exhaustion, running out of disk space, all those things that may happen to a rarely used server at some point or another. (We have had such cases twice in the past month, and we hope to be able to fix things by increasing the VM's RAM, but it is still unclear if that works.) |
To comment on this reprex:
I agree this works, but now run
|
For the record, I'd like to back the need to connect to an existing Shiny instance using rstudio/shiny#3606. That issue exists, as far as I can tell, only when the app is deployed on a Shiny Server, and not when run locally - yet there is no way to run a test suite on that deployed instance. I only detected that bug by doing (unrelated) work on that app using Python/Selenium. I don't really like to transfer all my shinytests to Selenium for that, so I will (have to) continue working using my shinytest fork based on this PR. |
@bersbersbers If possible, please transfer your tests from If you run into any bugs using a url ( |
|
One of my
shinytest
scripts triggered an error in the app that did not occur when the app ran interactively, so I needed to use the debugger on the app as the test script executed.A few additional lines of code allows running the
shiny
app in one RStudio instance, and theshinytest
script in another instance by providing an additional (optional)url
argument.This PR is independent of #324. and should resolve #85.