AppDriver can't run apps with the dev copy of shiny itself
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 53/100
Research direction
Start in R/app-driver-start.R at app_start_shiny() and trace how the background process sets up the library() / require() shim and .seed block before runApp(). Reproduce with a directory app while developing shiny itself, then check whether loading the dev package first keeps it active throughout startup. Done means the directory app starts with the dev copy of shiny; the function app behavior under devtools::test() is described separately as an unresolved limitation.
Written by the indexing model from the issue text.
Description
When the package in development is shiny itself, AppDriver can't run an app with the dev copy of shiny. For a directory app, the app never starts.
Cause
In app_start_shiny() (R/app-driver-start.R, v0.5.1), the background process installs the library() / require() shim, then runs the app:
do.call(shiny::runApp, c(list(appDir = .app_dir), .shiny_args))
shiny::runApp loads the installed shiny before app.R is sourced. When app.R then calls library(shiny), the shim runs pkgload::load_all() on the dev shiny, replacing the namespace under the runApp() that is already running. The page never becomes ready (window.shinytest2.ready never turns true). The .seed block has the same problem: getNamespace("shiny") loads installed shiny before the shim is set up.
Reprex
Run from a shiny source checkout. The installed shiny is 1.14.0, the checkout is 1.14.0.9000. app.R logs which shiny is loaded before and after its own library(shiny):
# app.R
probe <- function(when) message(sprintf("PROBE %s: path=%s", when,
if (isNamespaceLoaded("shiny")) getNamespaceInfo("shiny", "path") else "not loaded"))
probe("before library(shiny)")
library(shiny)
probe("after library(shiny)")
shinyApp(fluidPage("hi"), function(input, output) {})
# from the shiny checkout
devtools::load_all()
app <- shinytest2::AppDriver$new("path/to/app-dir")
#> Error: ... window.shinytest2 && window.shinytest2.ready === true
# app logs:
#> PROBE before library(shiny): path=<R library>/shiny (installed 1.14.0)
#> PROBE after library(shiny): path=<shiny checkout> (dev 1.14.0.9000)
Results
| App | How tests run | shiny used | Works? |
|---|---|---|---|
| directory | load_all() + test_file() |
installed, then dev reload mid-run | no |
| directory | devtools::test() |
installed, then dev reload mid-run | no |
| function | load_all() + test_file() |
dev | yes |
| function | devtools::test() |
installed | yes, but not dev |
Proposed fix
When the dev package is shiny, attach it first thing in the background process (before the .seed block), and mark it loaded so the shim only calls base::library():
if (identical(.package_name, "shiny")) {
pkgload::load_all(
.package_path,
attach = TRUE,
export_all = FALSE,
export_imports = TRUE,
attach_testthat = FALSE,
quiet = TRUE
)
has_loaded$value <- TRUE
}
I tried this by patching app_start_shiny() in memory. Both directory-app cases then run dev shiny the whole time and the app starts. Loading only the namespace (attach = FALSE) did not work: the shim's later base::library(shiny) brought the installed copy back.
Not fixed by this: function apps under devtools::test()
devtools::test() evaluates test code in an environment whose parent is shiny's namespace. callr serializes the app function with that environment, so the background process loads installed shiny while deserializing the arguments, before any shinytest2 code runs. Reloading dev shiny afterwards leaves the function's closure pointing at the old namespace, and the app never becomes stable. Callers can work around it with environment(app_fn) <- globalenv() before passing the function to AppDriver; I checked that the function app then runs dev shiny under devtools::test(). shinytest2 could do this itself, or document it.
Found while working on rstudio/shiny#4455, which runs shiny's own shinytest2 browser tests.
- Dominant language
- R
- Stars
- 123
- Forks
- 23
- Avg merge
- 3h 13m
- Merged PRs (30d)
- 12
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from rstudio/shinytest2
-
Difficulty 3/5 1-2 days Newbie friendliness 45/100
rstudio/shinytest2#432 ·
Maintainers usually reply within 1 day
-
Rhandsontable dropdown functionality breaks in Shinytest2 browser (JS permissions policy violation)Open
Difficulty 4/5 3-5 days Newbie friendliness 35/100
rstudio/shinytest2#416 ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 38/100
rstudio/shinytest2#390 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 45/100
rstudio/shinytest2#379 · 2 comments · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 42/100
rstudio/shinytest2#376 ·
Maintainers usually reply within 1 day
All issues in rstudio/shinytest2
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 1/5 Under an hour Newbie friendliness 68/100
cran-task-views/Spatial#127 · 1 comment ·
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
Add two cautions to the `simulate_dyad_responses()` helpPossibly taken A pull request linked to this issue is open or already merged. Opendocumentation priority: low
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Pascal-Kueng/dyadMLM#179 ·
Maintainers usually reply within 1 day