Skip to content
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

context options are not used inside app server #377

Open
pawelru opened this issue Mar 22, 2024 · 0 comments
Open

context options are not used inside app server #377

pawelru opened this issue Mar 22, 2024 · 0 comments

Comments

@pawelru
Copy link

pawelru commented Mar 22, 2024

Please have a look at the following example:

withr::with_options(
    list(test_option = 1),
    {
        print("outside:")
        print(getOption("test_option"))
        app <- shiny::shinyApp(
            ui = shiny::fluidPage({
                print("inside ui")
                print(getOption("test_option"))
                shiny::tags$p("hello")
            }),
            server = function(input, output) {
                print("inside srv")
                print(getOption("test_option"))
            }
        )
        app_driver <- shinytest2::AppDriver$new(app)
        app_logs <- app_driver$get_logs()
        print(app_logs)
        app_driver$stop()
    }
)
#> [1] "outside:"
#> [1] 1
#> [1] "inside ui"
#> [1] 1
#> {shinytest2} R  info   15:07:32.84 Start AppDriver initialization
#> {shinytest2} R  info   15:07:32.87 Starting Shiny app
#> {shinytest2} R  info   15:07:33.31 Creating new ChromoteSession
#> {shinytest2} R  info   15:07:33.80 Navigating to Shiny app
#> {shinytest2} R  info   15:07:33.86 Injecting shiny-tracer.js
#> {chromote}   JS info   15:07:33.87 shinytest2; jQuery not found
#> {chromote}   JS info   15:07:33.87 shinytest2; Loaded
#> {shinytest2} R  info   15:07:33.87 Waiting for Shiny to become ready
#> {chromote}   JS info   15:07:33.92 shinytest2; jQuery found
#> {chromote}   JS info   15:07:33.92 shinytest2; Waiting for shiny session to connect
#> {chromote}   JS info   15:07:33.93 shinytest2; Connected
#> {shinytest2} R  info   15:07:33.98 Waiting for Shiny to become idle for 200ms within 15000ms
#> {chromote}   JS info   15:07:33.98 shinytest2; Waiting for Shiny to be stable
#> {chromote}   JS info   15:07:34.18 shinytest2; Shiny has been idle for 200ms
#> {shinytest2} R  info   15:07:34.18 Shiny app started
#> {shiny}      R  stderr ----------- Loading required package: shiny
#> {shiny}      R  stderr ----------- Running application in test mode.
#> {shiny}      R  stderr ----------- 
#> {shiny}      R  stderr ----------- Listening on http://127.0.0.1:7453
#> {shiny}      R  stdout ----------- [1] "inside srv"
#> {shiny}      R  stdout ----------- NULL

Created on 2024-03-22 with reprex v2.1.0

In particular this:

#> {shiny}      R  stdout ----------- [1] "inside srv"
#> {shiny}      R  stdout ----------- NULL

From the inside of the app server, the pre-set option is not found.

I think I managed to find an answer, it's to pass options explicitly: app_driver <- shinytest2::AppDriver$new(app, options = options()).

Shouldn't it be a default behaviour? With options argument being additional overwrites?

This is important because some of the logic in my apps depends on the option value.

averissimo added a commit to insightsengineering/teal.modules.general that referenced this issue Apr 22, 2024
# Pull Request

<!--- Replace `#nnn` with your issue link for reference. -->

Part of #712 

#### Changes description

- Adds tests that iterate on each documentation file and runs the
examples apps by mocking `interactive` and
`shinyApp` functions.
- Checks if there are no errors nor validation errors (with exceptions)
- Implements
insightsengineering/teal.modules.clinical#983 on
this repository

#### Changes from
insightsengineering/teal.modules.clinical#983

- Adds:
  - Regex rules define "accepted" validation errors
- Fixes:
- Reverts to use `library` instead of `pkgload::load_all` due to
problems with `system.file` call that cannot find package files.

```diff
diff -u teal.modules.clinical/tests/testthat/test-examples.R teal.modules.general/tests/testthat/test-examples.R 
--- teal.modules.clinical/tests/testthat/test-examples.R	2024-04-12 10:32:33.100707738 +0200
+++ teal.modules.general/tests/testthat/test-examples.R	2024-04-12 10:26:27.645642183 +0200
@@ -38,12 +38,7 @@ with_mocked_app_bindings <- function(code) {
   # change to `print(shiny__shinyApp(...))` and remove allow warning once fixed
   mocked_shinyApp <- function(ui, server, ...) { # nolint object_name_linter.
     functionBody(server) <- bquote({
-      pkgload::load_all(
-        .(normalizePath(file.path(testthat::test_path(), "..", ".."))),
-        export_all = FALSE,
-        attach_testthat = FALSE,
-        warn_conflicts = FALSE
-      )
+      library(.(testthat::testing_package()), character.only = TRUE)
       .(functionBody(server))
     })
     print(do.call(shiny__shinyApp, append(x = list(ui = ui, server = server), list(...))))
@@ -56,16 +51,34 @@ with_mocked_app_bindings <- function(code) {
     app_driver <- shinytest2::AppDriver$new(
       x,
       shiny_args = args,
+      timeout = 20 * 1000,
+      load_timeout = 30 * 1000,
       check_names = FALSE, # explicit check below
       options = options() # rstudio/shinytest2#377
     )
     on.exit(app_driver$stop(), add = TRUE)
-    app_driver$wait_for_idle(timeout = 20000)
+    app_driver$wait_for_idle()
 
     # Simple testing
     ## warning in the app does not invoke a warning in the test
     ## rstudio/shinytest2#378
     app_logs <- subset(app_driver$get_logs(), location == "shiny")[["message"]]
+
+    # Check if the teal app has content (indicator of a Shiny App fatal error)
+    if (identical(trimws(app_driver$get_text("#teal-main_ui_container")), "")) {
+      tryCatch(
+        app_driver$wait_for_idle(duration = 2000), # wait 2 seconds for session to disconnect
+        error = function(err) {
+          stop(
+            sprintf(
+              "Teal Application is empty. An Error may have occured:\n%s",
+              paste0(subset(app_driver$get_logs(), location == "shiny")[["message"]], collapse = "\n")
+            )
+          )
+        }
+      )
+    }
+
     # allow `Warning in file(con, "r")` warning coming from pkgload::load_all()
     if (any(grepl("Warning in.*", app_logs) & !grepl("Warning in file\\(con, \"r\"\\)", app_logs))) {
       warning(
@@ -79,9 +92,17 @@ with_mocked_app_bindings <- function(code) {
     ## Throw an error instead of a warning (default `AppDriver$new(..., check_names = TRUE)` throws a warning)
     app_driver$expect_unique_names()
 
+    err_el <- Filter(
+      function(x) {
+        allowed_errors <- getOption("test_examples.discard_error_regex", "")
+        identical(allowed_errors, "") || !grepl(allowed_errors, x)
+      },
+      app_driver$get_html(".shiny-output-error")
+    )
+
     ## shinytest2 captures app crash but teal continues on error inside the module
     ## we need to use a different way to check if there are errors
-    if (!is.null(err_el <- app_driver$get_html(".shiny-output-error"))) {
+    if (!is.null(err_el) && length(err_el) > 0) {
       stop(sprintf("Module error is observed:\n%s", err_el))
     }
 
@@ -110,11 +131,14 @@ with_mocked_app_bindings <- function(code) {
 
 strict_exceptions <- c(
   # r-lib/gtable#94
-  "tm_g_barchart_simple.Rd",
-  "tm_g_ci.Rd",
-  "tm_g_ipp.Rd",
-  "tm_g_pp_adverse_events.Rd",
-  "tm_g_pp_vitals.Rd"
+  "tm_outliers.Rd",
+  "tm_g_response.Rd",
+  "tm_a_pca.Rd"
+)
+
+discard_validation_regex <- list(
+  "tm_file_viewer.Rd" = "Please select a file\\.",
+  "tm_g_distribution.Rd" = "Please select a test"
 )
 
 for (i in rd_files()) {
@@ -122,11 +146,18 @@ for (i in rd_files()) {
     paste0("example-", basename(i)),
     {
       testthat::skip_on_cran()
+      skip_if_too_deep(5)
       if (basename(i) %in% strict_exceptions) {
         op <- options()
         withr::local_options(opts_partial_match_old)
         withr::defer(options(op))
       }
+      # Allow for specific validation errors for individual examples
+      withr::local_options(
+        list(
+          "test_examples.discard_error_regex" = discard_validation_regex[[basename(i)]]
+        )
+      )
       with_mocked_app_bindings(
         # suppress warnings coming from saving qenv insightsengineering/teal.code#194
         suppress_warnings(```

---------

Signed-off-by: André Veríssimo <[email protected]>
Co-authored-by: kartikeya kirar <[email protected]>
Co-authored-by: Vedha Viyash <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant